Vue中的理论在实际开发过程中的遇见

    技术2022-07-12  70

    1. 只有在初始化 Vue实例前声明的属性才具有响应式能力,后来添加的属性不具备。

    场景: 子组件是一个创建/编辑公用的配置页面,当在父组件中点击编辑时,需要将已有的配置数据传递到子组件中展示,当直接对子组件 data属性中的 对象变量 进行赋值时,少添加了一个属性,以致子组件中对该属性变更,页面都没有反应。

    <!-- 子组件 template --> <Form ref="configForm" :model="newConfig" :rules="ruleValidate" :label-width="150"> <Row :gutter="5" v-for="(item, index) in newConfig.dataList" :key="'o-' + index"> <iCol span="10"> <FormItem :label="$t('sms.common.dataList')" :prop="'dataList.' + index + '.id'" :rules="validate.id"> <!-- 遍历出来的每个 <select>中的备选项 即 options,都是 allOptions剔除其他 <select>已被选择的项之后剩下的,即可被当前 <select>选择的备选项 --> <!-- change事件中实时计算每个 <select>的备选项 --> <Select v-model="item.id" @on-change="changeData"> <Option v-for="o in item.options" :value="o.id" :key="`o-${o.id}`">{{ o.name }}</Option> </Select> </FormItem> </iCol> </Row> </Form> // 子组件 data数据 data () { return { newConfig: { allOptions: [], // 空数据结构 // 渲染到页面上是一个 <select> 列表,每个 <select> 中的备选项,即 options都是 allOptions剔除其他 <select>已被选择的项之后剩下的可被当前 <select>选择的备选项 dataList: [ { id: '', name: '', options: [] } ] } } } // 父组件 调用方法 edit(row) { // 显示子组件 this.sonShowFlag = true; // 对子组件 data中的变量赋值 this.$nextTick(() => { this.$refs.son.newConfig = { // 原先是这样写的,如果有数据就把数据直接赋值给子组件的这个对象变量,如果没有就赋一个空的对象结构,而 options这个属性是自行添加方便实时计算的,row.dataList中并没有这个属性,导致子组件根据已有数据计算出各个 <select>的 options后,页面并没有渲染出 各个 <select>的备选项,下拉框仍然是空的 itemList: row.dataList.length > 0 ? row.dataList : [ { id: '', name: '', options: [] } ], // 修正后,为 row.dataList中的每一项添加一个空的 options属性 itemList: row.dataList.length > 0 ? row.dataList.map(item => ({...item, options: []})) : [ { id: '', name: '', options: [] } ] }; }) },

    2. Vue 会尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染。如果需要强制替换元素/组件而不是重复使用它,可以为各个元素/组件分配一个唯一的 key。

    场景: Form表单中,结构相同的 <FormItem>根据 v-if 条件切换展示,切换后原先条件下的 <FormItem>的校验报错信息仍然显示在页面上。

    <template> <Form ref="configForm" :model="config" :rules="ruleValidate" :label-width="150"> <FormItem label="选择条件" prop="condition"> <Select v-model="config.condition"> <Option v-for="o in conditionOptions" :value="o.id" :key="`o-${o.id}`">{{ o.name }}</Option> </Select> </FormItem> <!-- 如果不加 key的话,条件1的情况下,“选择设备”的 FormItem 报错而不纠正的情况下直接切换成条件2,根据 Vue的渲染原则,这个 FormItem的 dom会被“选择A端设备”所复用,原先的报错信息因为没有被纠正而保留在页面上 --> <FormItem label="选择设备" prop="deviceIds" v-if="config.condition == 1" key="device"> <CheckboxGroup v-model="config.deviceIds"> <Checkbox v-for="o in deviceList" :label="o.id" :key="`o-${o.id}`">{{ o.name }}</Checkbox> </CheckboxGroup> </FormItem> <FormItem label="选择A端设备" prop="deviceAIds" v-if="config.condition == 2" key="deviceA"> <CheckboxGroup v-model="config.deviceAIds"> <Checkbox v-for="o in deviceAList" :label="o.id" :key="`o-${o.id}`">{{ o.name }}</Checkbox> </CheckboxGroup> </FormItem> <FormItem label="选择B端设备" prop="deviceBIds" v-if="config.condition == 2" key="deviceB"> <CheckboxGroup v-model="config.deviceBIds"> <Checkbox v-for="o in deviceBList" :label="o.id" :key="`o-${o.id}`">{{ o.name }}</Checkbox> </CheckboxGroup> </FormItem> </Form> </template> computed: { ruleValidate() { return { condition : [ { type: 'number', required: true, message: '请选择条件', trigger: 'change' } ], deviceIds: [ { type: 'array', required: true, message: '请选择设备', trigger: 'change' } ], deviceAIds: [ { type: 'array', required: true, message: '请选择A端设备', trigger: 'change' } ], deviceBIds: [ { type: 'array', required: true, message: '请选择B端设备', trigger: 'change' } ] } } }
    Processed: 0.011, SQL: 9