vue项目开发笔记记录(二)

简介: vue项目开发笔记记录

vue项目开发笔记记录(一):https://developer.aliyun.com/article/1483515


深克隆

/**
 * This is just a simple version of deep copy
 * Has a lot of edge cases bug
 * If you want to use a perfect deep copy, use lodash's _.cloneDeep
 * @param {Object} source
 * @returns {Object}
 */
export function deepClone(source) {
  if (!source && typeof source !== 'object') {
    throw new Error('error arguments', 'deepClone')
  }
  const targetObj = source.constructor === Array ? [] : {}
  Object.keys(source).forEach(keys => {
    if (source[keys] && typeof source[keys] === 'object') {
      targetObj[keys] = deepClone(source[keys])
    } else {
      targetObj[keys] = source[keys]
    }
  })
  return targetObj
}

数组去重

/**
 * @param {Array} arr
 * @returns {Array}
 */
export function uniqueArr(arr) {
  return Array.from(new Set(arr))
}

创建唯一ID

/**
 * @returns {string}
 */
export function createUniqueString() {
  const timestamp = +new Date() + ''
  const randomNum = parseInt((1 + Math.random()) * 65536) + ''
  return (+(randomNum + timestamp)).toString(32)
}

判断元素受否有该class

/**
 * Check if an element has a class
 * @param {HTMLElement} elm
 * @param {string} cls
 * @returns {boolean}
 */
export function hasClass(ele, cls) {
  return !!ele.className.match(new RegExp('(\\s|^)' + cls + '(\\s|$)'))
}

元素添加class

/**
 * Add class to element
 * @param {HTMLElement} elm
 * @param {string} cls
 */
export function addClass(ele, cls) {
  if (!hasClass(ele, cls)) ele.className += ' ' + cls
}

获取hasClass

/**
 * Remove class from element
 * @param {HTMLElement} elm
 * @param {string} cls
 */
export function removeClass(ele, cls) {
  if (hasClass(ele, cls)) {
    const reg = new RegExp('(\\s|^)' + cls + '(\\s|$)')
    ele.className = ele.className.replace(reg, ' ')
  }
}

时间格式化,不包含时分秒

/**
 * 时间格式化,不包含时分秒
 * @param _date
 * @returns {string}
 * @constructor
 */
export function FormatDateNoTime(_date) {
  if (_date === '' || _date === null || _date === undefined) {
    return ''
  } else {
    const now = new Date(_date)
    const year = now.getFullYear()
    const month = now.getMonth() + 1 < 10 ? '0' + (now.getMonth() + 1) : now.getMonth() + 1
    const date = now.getDate() < 10 ? '0' + now.getDate() : now.getDate()
    return year + '/' + month + '/' + date
  }
}

生成年份

<el-form-item label="统计年度" prop="opspTrtCode">
  <el-select v-model="searchForm.opspTrtCode" clearable placeholder="请选择统计年度" allow-create style="width:100%"
    :fetch-suggestions="searchType" :trigger-on-focus="false">
    <el-option label="全部" value="" />
    <el-option v-for="item in initSelectYear()" :key="item.value" :label="item.label" :value="item.value" />
  </el-select>
</el-form-item>
initSelectYear() {
  var myDate = new Date()
  var year = myDate.getFullYear() // 获取当前年
  var years = []
  for (let i = 0; i < 30; i++) {
    years.push({ value: year - i, label: year - i + '年' })
  }
  return years
}

地图组件标点

<template>
  <div class="interzone-map">
    <div id="interzoneMap" />
  </div>
</template>
<script>
import echarts from 'echarts'
import './map/js/china'
// import './map/js/province/anhui'
// import './map/js/province/zhejiang'
// import './map/js/province/aomen'
// import './map/js/province/xianggang'
// import './map/js/province/guangdong'
// import './map/js/province/jiangxi'
// import './map/js/province/jiangsu'
// import './map/js/province/fujian'
// import './map/js/province/gansu'
// import './map/js/province/guizhou'
// import './map/js/province/sichuan'
// import './map/js/province/hubei'
export default {
  name: 'EchartMap',
  components: {},
  mixins: [],
  props: {},
  data() {
    return {
      myChart: null,
      map_name: 'china', // 地图
      mapData: [],
      geoCoordMap: {}
    }
  },
  computed: {},
  watch: {},
  created() {},
  mounted() {
    this.myChart = echarts.init(document.getElementById('interzoneMap'))
    window.onresize = () => {
      // 根据窗口大小调整曲线大小
      this.myChart.resize()
    }
    this.init_map() // 地图初始化
  },
  methods: {
    init_map() {
      var data = [
        { name: '海门', value: 88.76 },
        { name: '鄂尔多斯', value: 88.6 },
        { name: '招远', value: 39.21 },
        { name: '舟山', value: 87.54 },
        { name: '齐齐哈尔', value: 19.64 },
        { name: '盐城', value: 54.2 }
      ]
      var geoCoordMap = {
        海门: [121.15, 31.89],
        鄂尔多斯: [109.781327, 39.608266],
        招远: [120.38, 37.35],
        舟山: [122.207216, 29.985295],
        齐齐哈尔: [123.97, 47.33],
        盐城: [120.13, 33.38]
      }
      // 获取数据和坐标
      var convertData = function(data) {
        var res = []
        for (var i = 0; i < data.length; i++) {
          var geoCoord = geoCoordMap[data[i].name]
          if (geoCoord) {
            res.push({
              name: data[i].name,
              value: geoCoord.concat(data[i].value)
            })
          }
        }
        return res
      }

      var optionMap = {
        backgroundColor: '#FFFFFF',
        title: {
          text: '全国参保覆盖情况',
          subtext: '2020年',
          x: 'center'
        },
        // 提示框
        tooltip: {
          trigger: 'item',
          formatter: function(params) {
            // 添加数字,否则为坐标
            return (
              params.name +
              '<br>' +
              '参保覆盖率' +
              '' +
              ':' +
              '' +
              params.value[2] +
              '' +
              '%'
            )
          },
          padding: [
            5, // 上
            10, // 右
            5, // 下
            10 // 左
          ],
          textStyle: {
            color: '#fff',
            fontSize: '13'
          }
        },
        // 左侧小导航图标
        visualMap: {
          show: false
        },
        // 地图
        geo: {
          map: 'china',
          roam: false,
          itemStyle: {
            // 正常状态下
            normal: {
              areaColor: '#ffe7b2',
              borderColor: '#111'
            },
            // 选定某一区域下 相当于 hover
            emphasis: {
              areaColor: '#ff6341'
            }
          },
          z: 1
        },
        // 配置属性
        series: [
          {
            name: '参保覆盖率',
            type: 'scatter',
            coordinateSystem: 'geo',
            data: convertData(data),
            roam: false,
            label: {
              normal: {
                show: true // 省份名称
              },
              emphasis: {
                show: false
              }
            },
            symbolSize: function(val) {
              return val[2] / 8 // 也可以根据这里的数值更改大小  val[2] / x  x越小,标点越大
            }
          },
          {
            name: '参保覆盖率',
            type: 'effectScatter',
            coordinateSystem: 'geo',
            data: convertData(
              data
                .sort(function(a, b) {
                  // 这里是多个数据比较大小
                  return b.value - a.value
                })
                .slice(0, 1000)
            ), // slice里面的数可以是0 ,意思是全部显示  0,1000 意思是显示这组数据中最大前1000组
            symbolSize: function(val) {
              return val[2] / 5
            },
            showEffectOn: 'render',
            rippleEffect: {
              brushType: 'stroke'
            },
            hoverAnimation: true,
            label: {
              normal: {
                formatter: '{b}',
                position: 'right',
                show: false
              },
              emphasis: {
                show: false
              }
            }
          }
        ]
      }
      // 使用制定的配置项和数据显示图表
      this.myChart.setOption(optionMap)
      this.myChart.on('click', (params) => {
        console.log(params)
      })
    }
  }
}
</script>
<style scoped lang="scss">
.interzone-map {
  width: 100%;
  height: 100%;
  #interzoneMap {
    width: 100%;
    height: 100%;
  }
}
</style>

Echart组件封装

<template>
  <div class="My_Charts_Wrapper">
    <div :id="id" :class="className" class="My_Charts" :style="{height:height,width:width}" />
  </div>
</template>

<script>
import echarts from 'echarts'
require('echarts/theme/macarons')
import resize from './mixins/resize'

export default {
  name: 'MyCharts',
  components: {},
  mixins: [resize],
  props: {
    id: {
      type: String,
      default: 'myCharts'
    },
    className: {
      type: String,
      default: 'chart'
    },
    width: {
      type: String,
      default: '100%'
    },
    height: {
      type: String,
      default: '100%'
    },
    options: {
      type: Object,
      default: function() {
        return {}
      }
    }
  },
  data() {
    return {
      chart: null,
      defaultOptions: {
        grid: { left: '3%', right: '4%', bottom: '3%', top: '30', containLabel: true },
        tooltip: {
          trigger: 'axis',
          axisPointer: { type: 'shadow' }
        }
      }
    }
  },
  computed: {},
  watch: {
    options: {
      deep: true,
      handler(val) {
        this.setOptions(Object.assign(val, this.options))
      }
    }
  },
  created() {
  },
  mounted() {
    this.$nextTick(() => {
      this.init()
    })
  },
  beforeDestroy() {
    if (!this.chart) {
      return
    }
    this.chart.dispose()
    this.chart = null
  },
  methods: {
    init() {
      this.chart = echarts.init(document.getElementById(this.id), 'macarons')
      this.setOptions()
    },
    setOptions() {
      this.chart.setOption(Object.assign(this.defaultOptions, this.options))
    }
  }
}
</script>

<style scoped lang="scss">
  .My_Charts_Wrapper {
    width: 100%;
    height: 100%;
  }
  .My_Charts {
    >div {
      margin: 0 auto;
    }
    /deep/ .charts-table {
      width: 100%;
      border: 1px solid #dfe6ec;
      text-align: center;
      border-collapse: collapse;
      >thead{
        >tr{
          >th{
            height: 40px;
            background: #F0F2F5;
            border-right: 1px solid #cecece;
            border-bottom: 1px solid #dfe6ec;
            &:last-child {
              border-right: none;
            }
          }
        }
      }
      >tbody {
        >tr{
          >td{
            height: 40px;
            border-right: 1px solid #cecece;
            border-bottom: 1px solid #dfe6ec;
            &:last-child {
              border-right: none;
            }
          }
          &:last-child {
            >td {
              border-bottom: none;
            }
          }
        }
      }
    }
  }
</style>

引入码表字段

import { getInsutype } from '@/api/PaymentInAdvance/PaymentInAdvanceManage/Request'
import { CHK_STAS } from '@/utils/constant'

获取码表对应字段,塞入下拉

import { getCodeTableDetailConvergence } from '@/api/Common/Request'
// 查码表
getCodeTableDetailConvergence() {
  const codeType = CHK_STAS
  getCodeTableDetailConvergence({ codeType }).then(res => {
    this.$set(this.itemsDatas[2], 'options', res.data[CHK_STAS])
  })
}

引入colunms

import Columns from './columns'

标准参考页面

<!-- 单位待转金查询 -->
<template>
  <normal-layer
    :search-number="itemsDatas.length"
    title-name="单位待转金查询列表"
    title-need-handle
  >
    <template slot="search-header">
      <form-items :items-datas="itemsDatas" :form-datas="queryForm">
        <el-button @click="reset">重置</el-button>
        <el-button type="primary" @click="search">查询</el-button>
      </form-items>
    </template>
    <template slot="title-btns">
      <el-button type="primary" @click="printClick">打印</el-button>
    </template>
    <my-table-view
      v-loading="loading"
      :data="tableData"
      :columns="columns"
    />
    <Pagination />
  </normal-layer>
</template>
<script>
import NormalLayer from '@/views/components/PageLayers/normalLayer'
import FormItems from '@/views/components/PageLayers/form-items'
import PageHandle from '@/mixins/pageHandle'
import Columns from './listCloumns'
export default {
  components: {
    NormalLayer,
    FormItems
  },
  mixins: [PageHandle],
  data() {
    return {
      loading: false,
      itemsDatas: [
        { label: '单位编号', prop: 'xxx', type: 'input' },
        { label: '单位名称', prop: 'xxx', type: 'input' },
        { label: '单位类型', prop: 'xxx', type: 'select' }
      ],
      queryForm: {
        xxx: ''
      },
      columns: Columns,
      tableData: [
        { name: '白兰花', code: 'xxx', nameCode: 'xxx' },
        { name: '白兰花', code: 'xxx', nameCode: 'xxx' }
      ]
    }
  },
  watch: {
  },
  methods: {
    printClick() {
      window.print()
    }
  }
}
</script>
<style lang='scss' scoped>
</style>

审核和批量审核弹窗

<audit-dialog v-model="showAuditDialog" dialog-title="单位注销审核" @submit="submit" @closeAll="AuditDialogIsShow" />
import AuditDialog from '@/views/components/AuditDialog'
// 批量审核
    batchAuditClick() {
      if (this.multipleSelection.length <= 0) {
        this.$msgConfirm('请选择')
      } else {
        this.showAuditDialog = true
      }
    },

表格详情弹窗

 <!-- 详情弹窗 -->
    <Details :show="DetaVisible" @update:show="DetaIsShow" />
DetaIsShow() {
 this.DetaVisible = false
}
<my-table-view
      v-loading="loading"
      :data="tableData"
      :columns="columns"
      :multiple-selection.sync="multipleSelection"
    >
      <template slot="operation" slot-scope="scope">
        <my-button icon="detail" @click="detailsClick(scope.row)" />
        <my-button icon="audit" @click="review(scope.row)" />
      </template>
    </my-table-view>
detailsClick(row) {
      this.DetaVisible = true
    }

获取查询条件

search() {
    let params = {}
    params = Object.assign({}, this.searchForm)
    console.log('查询条件', params)
}

常用字段

'formCode':'表格编码'
'formNum':'金额'
'formDepart':'制表部门'
'formTime':'制表时间'
'formDealer':'经办人'
'status':'状态'
'operation':'操作'

获取银行类型

import { BANK_TYPE_CODE } from '@/utils/constant'
import { getCodeTableDetailConvergence } from '@/api/Common/Request'

getTableCode() {
    getCodeTableDetailConvergence({ codeType: BANK_TYPE_CODE }).then(res => {
        this.$set(this.itemsDatas[2], 'options', res.data[BANK_TYPE_CODE])
    })
}

搜索重置

<template slot="search-header">
  <form-items ref="queryForm" :items-datas="itemsDatas" :form-datas="queryForm" :rules="rules" :model="queryForm">
    <el-button @click="reset('queryForm')">重置</el-button>
    <el-button type="primary" @click="search">查询</el-button>
  </form-items>
</template>
reset(formName) {
    this.$refs[formName]['elForm'].resetFields()
}

批量审核

<template slot="title-btns">
  <el-button type="primary" @click="addClick">批量审核</el-button>
</template>
addClick(row) {
    if (this.multipleSelection.length > 0) {
        this.showAuditDialog = true
    } else {
        this.$msgError('请至少选择一行!')
    }
}
submit(v) {
    const params = {
        rchkFlag: v.data.statue,
        memo: v.data.content,
        taxItrcEvtId: this.multipleSelection.map(item => item.taxItrcEvtId)
    }
    // 保存灵活就业征集信息发送审核
    Api.saveTaxFlexiblePaySendAud(params).then(res => {
        if (res.code === 0) {
            v.fn()
            this.search()
        } else {
            this.$msgError(res.message)
        }
    })
}

vue项目开发笔记记录(三):https://developer.aliyun.com/article/1483520

相关文章
|
5天前
|
JavaScript 前端开发
【vue】iview如何把input输入框和点击输入框之后的边框去掉
【vue】iview如何把input输入框和点击输入框之后的边框去掉
12 0
|
4天前
|
监控 JavaScript
Vue中的数据变化监控与响应——深入理解Watchers
Vue中的数据变化监控与响应——深入理解Watchers
|
4天前
|
JavaScript 安全 前端开发
Vue 项目中的权限管理:让页面也学会说“你无权访问!
Vue 项目中的权限管理:让页面也学会说“你无权访问!
13 3
|
4天前
|
JavaScript 前端开发 开发者
Vue的神奇解锁:冒险的开始
Vue的神奇解锁:冒险的开始
5 1
|
5天前
|
JavaScript
【vue实战】父子组件互相传值
【vue实战】父子组件互相传值
11 1
|
6天前
|
资源调度 JavaScript 前端开发
Vue的路由管理:VueRouter的配置和使用
【4月更文挑战第24天】VueRouter是Vue.js的官方路由管理器,用于在单页面应用中管理URL路径与组件的映射。通过安装并引入VueRouter,设置路由规则和创建router实例,可以实现不同路径下显示不同组件。主要组件包括:`&lt;router-link&gt;`用于创建导航链接,`&lt;router-view&gt;`负责渲染当前路由对应的组件。此外,VueRouter还支持编程式导航和各种高级特性,如嵌套路由、路由参数和守卫,以应对复杂路由场景。
|
5天前
|
JavaScript
vue2_引入Ant design vue
vue2_引入Ant design vue
9 0
|
5天前
|
JavaScript
vue知识点
vue知识点
13 4
|
6天前
|
存储 JavaScript 前端开发
【Vue】绝了!这生命周期流程真...
【Vue】绝了!这生命周期流程真...
|
6天前
|
JavaScript 索引
【vue】框架搭建
【vue】框架搭建
8 1