Vue.2.0开发后台系统,采坑系列组件篇(一)

5,178 阅读3分钟

前言

刚刚接手了一个公司内部的后台系统项目,刚开始的时候真的是一步一个坑,经过一周的加班,基本把常用的功能和组件都完成了,基本缓了一口气。

技术栈: ivew + vue + vue-cli

废话不多说,下面总结一下封装组件的一些问题 大致页面如下

组件的封装

  • 实现 input select radio checkbox date 的组件的封装
1.因为vue需要数据驱动视图,需要把所有属性在页面中初始化
export default {
    data() {
      return {
        list: [
          {name: 'applicationNo', title: '采购申请编号 :', type: 'input', placeholder: '', disable: true, value: '111'},
          {name: 'createUserName', title: '申请人 :', type: 'input', value: '', disable: true},
          {name: 'organLeaderName', title: '机构负责人', type: 'input', value: '', disable: true},
          {name: 'expectTime', title: '希望到货时间', type: 'input', value: '', data: [], placeholder: '', disable: true},
          {name: 'transportOrganName', title: '配送机构', type: 'input', value: '', placeholder: '', disable: true},
          {name: 'receive', title: '接车地址', type: 'input', value: '', disable: true},
          {name: 'detailAddress', title: '详细地址', type: 'input', value: '', data: [], col: '12', disable: true},
          {name: 'contract', title: '联系人', type: 'input', value: '', data: [], disable: true},
          {name: 'telphone', title: '联系电话', type: 'input', value: '', data: [], disable: true},
          {name: 'remark', title: '备注', type: 'input', value: '', data: [], disable: true, col: '20'}
        ],
1.1 封装组件,实现提交按钮的判断,因为初始化定义了type根据type来判断是什么提交按钮(如:input,select...)
<template>
  <div class="form-input-group">
    <template v-if="type == 'text'">
      <span class="form-list-text">{{ value }}</span>
    </template>
    <template v-else-if="type == 'input'">
      <Input class="input-item" v-model="inputValue" :placeholder="placeholder" :disabled="disable"></Input>
      <template v-if="detail">
        <span class="input-detail">{{detail}}</span>
      </template>
    </template>
    <template v-else-if="type == 'select'">
      <Select class="input-item" v-model="inputValue" :placeholder="placeholder" :disabled="disable">
        <Option v-for="item in selectData" :value="item" :key="item.value">{{item }}</Option>
      </Select>
    </template>
    <template v-else-if="type == 'date'">
      <DatePicker type="date" :placeholder="placeholder" @on-change="setDate" :disabled="disable"></DatePicker>
    </template>
    <template v-else-if="type == 'city'">
      <city-select :value="value" @setCity="SetCity"></city-select>
    </template>
    <template v-else-if="type == 'model'">
      <Input class="input-model-hidden" v-model="modelValue.code"></Input>
      <Input class="input-item input-model" :placeholder="modelValue.name" readonly></Input>
      <div class="input-shadow" @click="showModel = true"></div>
    </template>
    <template v-else-if="type == 'cars'">
      <car-select :value="value" @setCar="SetCar"></car-select>
    </template>
    <FormModel v-if="showModel" @closeModel="closeModel" @confirmModel="confirmModel"></FormModel>
  </div>
</template>
/**
   * [inputGroup 输入框]
   * 接受参数:[type: 输入框类型,name:要绑定的属性名, data: 下拉菜单或级联菜单数据]
   * type值:[text:普通文本,input:普通输入框,select:下拉框,date:日期选择框,city:省市区,cascader:级联菜单]
   * 接受方法:[getValue:获取属性名和返回值]
   * 返回值:{ name: name, value: value }
   * 级联菜单返回值:{ name: name, value: [value1, value2] }
   * 使用示例: <input-group v-bind="propsData"></input-group>
   */

父组件中我们不能只传递type值去判断提交按钮类型,当查看订单并不能修改的时候还需要把value值传递给子组件显示,并且设置disabled属性不可编辑。还需要传递其它属性(eg: placeholder, disable, name)等

1.2 从而在父组件和子组件需要做两件事
 <Row class="form-list-search">
      <Col :span="item.col ? item.col : '6'" v-for="(item,index) in list" :key="index">
      <span class="form-list-title">{{item.title}}</span>
      <input-group v-bind="item" @setCarCode="setCarCode" @setValue="setValue"></input-group>
      </Col>
    </Row>

使用 v-bind="item"传递属性值。那么在input组件下如何接收?看代码

// input.vue
 export default {
    data() {
      return {
        inputValue: '',
        selectData: [],
        modelValue: {},
        showModel: false,
        dateData: ''
      }
    },
    props: {
      data: {
        default: ''
      },
      value: {
        default: ''
      },
      type: {
        required: true
      },
      name: {
        required: true
      },
      disable: {
        type: Boolean
      },
      detail: {
        default: ''
      },
      placeholder: String,
      index: Number
    },
    components: {
      CitySelect,
      FormModel,
      CarSelect
    }
1.3 当子组件的发生改变时,我们需要监听组件中value的变化并把值传递给父组件,从而改变视图。$emit()
    created() {
      this.inputValue = this.value
      this.selectData = this.data
      this.inputkey = this.key
    },
    methods: {
      setDate(date) {
        this.inputValue = date
        // this.dateData = date
        // let returnData = {name: this.name, value: this.dateData}
        // this.$emit('dateData', returnData)
      },
      SetCity(val) {
        let returnData = {name: this.name, value: val}
        this.$emit('setCityCode', returnData)
      },
      SetCar(val) {
        console.log(val, 'input.vue')
        this.$emit('setCarCode', val)
      },
      confirmModel(data) {
        if (data) {
          this.showModel = false
          this.modelValue = data
        }
      },
      closeModel(data) {
        if (data) {
          this.showModel = false
        }
      }
    },
    watch: {
      value(val) {
        this.inputValue = val
      },
      data(val) {
        this.selectData = val
      },
      inputValue(val) {
        // console.log(val)
        let returnData = {name: this.name, value: val}
        if (this.index != undefined) {
          returnData.index = this.index
        }
        if (this.type == 'date') {
          returnData.value = Util.unixTime(val)
        }
        this.$emit('setValue', returnData)
      }
    }
  }
1.4 三级联动组件

大致思路

  • 结合iview组件Cascader 级联选择,动态加载,如果有下一级菜单,在对象内部定义children[],并且push新的二级对象结构,loading: false 说明还有下一级,还会调用loadData方法
<template>
  <div>
    <Cascader :data="cascaderData" :load-data="loadData" v-model="cascader" @on-change="setValue"></Cascader>
  </div>
</template>
<script>
  import Util from '../../libs/util.js'
  import {getBrand, getSeriesList, getModelList} from '../../api/index'

  export default {
    data() {
      return {
        cascaderData: [],
        cascader: []
      }
    },
    async mounted() {
    // 返回一级菜单数据
      let brandList = await getBrand()
      // 渲染视图
      Util.CommonCascader(this, brandList.result, this.cascaderData)
    },
    created() {
    },
    methods: {
      loadData(item, callback) {
        item.loading = true
        
        // 调用二级菜单接口,传入id
        getSeriesList(item.value).then((res) => {
          
          Util.CascaderChild(this, res.result, item.children, 'name', 'code')
          callback()
          item.loading = false
        }).then(() => {
        // 调用三级菜单接口,传入id
          getModelList(item.value).then((res) => {
            Util.CascaderChild(this, res.result, item.children, 'name', 'code', true)
            callback()
            item.loading = false
          })
        })
      },
      setValue(val) {
        this.$emit('setCar', val)
      }
    },
    watch: {
      value(val) {
        this.cascader = val
      }
    },
    components: {}
  }
</script>
<style scoped>
</style>