通过一个很常用的场景来展示vue数据驱动的应用
需求:可以动态增减组合条件来进行数据查询。
界面运行效果如下图所示:
界面第一次加载时,默认会显示一个空的查询条件,如下图所示:
点击“加”图标,可以无限增加查询条件,也可以点击“减”图标删除新增的查询条件,如下图所示:
说明:第一个下拉框的数据变化时,第三个下拉框的数据要进行联动,第三个组件可以是下拉框也可以是文本框,它是根据第一个下拉框的数据来决定的。第二个下拉框是固定的四个选项>、<、=、!=。如下图所示:
定义数据结构:
{ "data": { "array": [{ "opts": [{ "val": "0", "name": "停止" }, { "val": "1", "name": "运行" }], "paramCode": "runStatus", "name": "运行状态" }, { "opts": [{ "val": "0", "name": "否" }, { "val": "1", "name": "是" }], "paramCode": "alarmStatus", "name": "报警与否" }, { "opts": [{ "val": "0", "name": "就地" }, { "val": "1", "name": "远程" }], "paramCode": "remoteLocal", "name": "远程就地" }, { "opts": [{ "val": 0, "name": "禁用" }, { "val": 1, "name": "启用" }], "paramCode": "startUse", "name": "是否启用" }, { "opts": [{ "val": "0", "name": "变频" }, { "val": "1", "name": "工频" }], "paramCode": "runMode", "name": "工频启停" }, { "opts": [{ "val": 0, "name": "手动" }, { "val": 1, "name": "自动" }], "paramCode": "controlMode", "name": "控制模式" }, { "opts": [{ "val": "0", "name": "手动" }, { "val": "1", "name": "自动" }], "paramCode": "frequencyMode", "name": "频率手自动" }, { "opts": [], "paramCode": "frequencySetValue", "name": "频率设定" }, { "opts": [], "paramCode": "frequencyReturnValue", "name": "频率反馈" }, { "opts": [], "paramCode": "tempSetValue", "name": "温度设定" }, { "opts": [], "paramCode": "tempReturnValue", "name": "温度反馈" }, { "opts": [{ "val": 0, "name": "关" }, { "val": 1, "name": "开" }], "paramCode": "newWindValveOnOff", "name": "新风阀启停" }, { "opts": [], "paramCode": "newWindValveOpen", "name": "新风阀开度" }, { "opts": [], "paramCode": "newWindTemp", "name": "新风阀温度" }, { "opts": [], "paramCode": "newWindHumidity", "name": "新风阀湿度" }, { "opts": [{ "val": 0, "name": "关" }, { "val": 1, "name": "开" }], "paramCode": "returnWindValveOnOff", "name": "回风阀启停" }, { "opts": [], "paramCode": "returnWindValveOpen", "name": "回风阀开度" }, { "opts": [], "paramCode": "returnWindHumidity", "name": "回风阀湿度" }, { "opts": [], "paramCode": "co2", "name": "回风阀co2" }, { "opts": [{ "val": "0", "name": "手动" }, { "val": "1", "name": "自动" }], "paramCode": "waterValveHandAuto", "name": "水阀手自动" }, { "opts": [{ "val": 0, "name": "关" }, { "val": 1, "name": "开" }], "paramCode": "waterValveOnOff", "name": "水阀启停" }, { "opts": [], "paramCode": "waterValveOpenSet", "name": "水阀开度设定" }, { "opts": [], "paramCode": "waterValveOpenReturn", "name": "水阀开度反馈" }, { "opts": [], "paramCode": "supplyAirTemp", "name": "送风温度" }, { "opts": [], "paramCode": "supplyAirHumidity", "name": "送风湿度" }, { "opts": [], "paramCode": "supplyAirPressure", "name": "送风静压" }, { "opts": [{ "val": 0, "name": "关" }, { "val": 1, "name": "开" }], "paramCode": "humidityValveOnOff", "name": "加湿阀启停" }, { "opts": [], "paramCode": "humidityValveOpen", "name": "加湿阀开度" }, { "opts": [], "paramCode": "filterDiffPressure", "name": "过滤网压差" }, { "opts": [{ "val": 0, "name": "关" }, { "val": 1, "name": "开" }], "paramCode": "elecHeatOnOff", "name": "电加热" }, { "opts": [], "paramCode": "power", "name": "功率" }, { "opts": [], "paramCode": "runTime", "name": "运行时间" }, { "opts": [], "paramCode": "loadPower", "name": "供冷负荷" }, { "opts": [], "paramCode": "cold", "name": "累计供冷量" }, { "opts": [{ "val": 0, "name": "正常" }, { "val": 1, "name": "中断" }], "paramCode": "commuInterrupt", "name": "通讯是否正常" }] }, "code": 200, "msg": "", "errors": null }
View Code
因为数据量不大,为了提升性能,数据是接口一次性返回的,数据的联动是在内存当中进行数据筛选,从而避免频繁的接口调用。
在数据结构当中,当opts属性值为空数组时,第三个组件显示为文本框,否则显示为下拉框,并把opts中的数据作为第三个组件的下拉框内容展示出来。当第三个组件是下拉框时,第二个下拉框只能显示=和!=这两项,如果是文本框时,都可以显示。
后端接口需要的查询参数是:
dataListParams: [{paramName: “runStatus”, operator: 2, value: “0”}, {paramName: “startUse”, operator: 2, value: 0}]
接下来,我们定义vue组件中的内容,Dom部分:
<div class='search-item'> <label>组合条件:</label> </div> <div class="search-item" v-for="(paramObj,index) in dataListParams" :key="index"> <!-- 参数名 --> <el-select v-model="paramObj.paramName" filterable clearable @change="(e)=>changeParam(e,index)" placeholder="请选择" style="width:100px"> <el-option v-for="item in paramList" :key="item.paramCode" :label="item.name" :value="item.paramCode"></el-option> </el-select> <!-- 操作符列表 --> <el-select v-model="paramObj.operator" clearable placeholder="" style="width:60px"> <el-option v-for="(item,sindex) in operatorOptions" :disabled="getDisabled(sindex,index)" :key="item.id" :label="item.name" :value="item.id"></el-option> </el-select> <!-- 参数值 --> <el-select v-if="listOpts[index].length>0" v-model="paramObj.value" filterable clearable placeholder="请选择" style="width:100px"> <el-option v-for="item in listOpts[index]" :key="item.val" :label="item.name" :value="item.val"></el-option> </el-select> <el-input v-else v-model="paramObj.value" :clearable="true" placeholder="请输入" style="width:100px"></el-input> <span v-if="index==0" class="add-where"><i class="iconfont icon-add" @click="addWhere"></i></span> <span v-else class="remove-where"><i class="iconfont icon-shanchu1" @click="removeWhere(index)"></i></span> </div>
js部分:
export default { mixins: [indexOptions], data () { return { //操作符列表 operatorOptions: [ { id: 0, name: '>' }, { id: 1, name: '<' }, { id: 2, name: '=' }, { id: 3, name: '!=' } ], //组合条件 dataListParams: [{ paramName: "", operator: '', value: "" }], checkedAll: false, //全选所有 deviceIds: [], listOpts: [[]]//操作列表 } }, computed: {//筛选参数列表,如果参数列表dataListParams当中有任何一个属性值为空,则不传递 filterDataListParams () { return this.dataListParams.filter(f => { return f.paramName !== "" && f.operator !== "" && f.value !== "" }); } }, methods: {//获取操作选项启用、禁用 getDisabled (sindex, index) { if (this.listOpts.length > 0 && this.listOpts[index].length > 0) { return [0, 1].includes(sindex); } else { return false; } }, //添加组合条件 addWhere () { this.dataListParams.push({ paramName: '', operator: '', value: '' }); this.listOpts.push([]); }, //移除组合条件 removeWhere (index) { this.dataListParams.splice(index, 1); this.listOpts.splice(index, 1); }, //根据参数编码获取操作列表 getOptsByParamCode (code,) { let res = this.paramList.find(f => f.paramCode == code); return res ? res.opts : []; }, //参数选项变化 changeParam (code, index) { //变化之前的类型 let preType = this.listOpts[index].length > 0; //是否下拉框 let arr = this.getOptsByParamCode(code); this.listOpts[index] = arr; this.dataListParams[index].value = ''; //变化之后的类型 let nextType = arr.length > 0;//是否是下拉框 //前后类型不一致时,清空操作符 if (preType != nextType) { this.dataListParams[index].operator = ''; } } } };
当第一个下拉框选项变化时,如果第三个组件是相同类型(下拉框或文本框),则第二个下拉框的选项不清空,否则清空。
只有一组查询条件当中三个选项的值都不为空时,才会把参数传递给后端,所以前端通过计算熟悉filterDataListParams进行了数据过滤。
由于数据结构是动态变化的,所以为了保存查询条件的保存状态,下拉框的数据列表项也应当是动态的(数组存储)。
最后把filterDataListParams作为参数传递给后端接口就可以了,这是一个很典型的vue动态数据驱动应用。