通過一個很常用的場景來展示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

  把接口數據賦值給paramList。

  因爲數據量不大,爲了提升性能,數據是接口一次性返回的,數據的聯動是在內存當中進行數據篩選,從而避免頻繁的接口調用。

  在數據結構當中,當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: "" }],
      deviceIds: [],
paramList:[],//參數列表,包含操作名稱、操作值列表(JSon數據結構)
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 = ''; } } } };

  當第一個下拉框選項變化時,如果第三個組件是相同類型(下拉框或文本框),則第二個下拉框的選項不清空,否則清空。因爲文本框可以選4個選項,下拉框只能選兩個,不能記錄上一次的選中狀態。

  只有一組查詢條件當中三個選項的值都不爲空時,纔會把參數傳遞給後端,所以前端通過計算熟悉filterDataListParams進行了數據過濾。

  由於數據結構是動態變化的,所以爲了保存查詢條件的保存狀態,下拉框的數據列表項也應當是動態的(數組存儲)。

  這裏其實還漏了東西,那就是查詢條件去重,我雖然知道,但是我並沒有在前端進行去重,因爲需求不提、產品不提,待他們發現這個問題並且提時bug時,我會把鍋帥給後端,讓後端對查詢條件的數據進行去重處理...O(∩_∩)O哈哈~(^_^)

  還有查詢條件參數值是文本框時的輸入值的合法性校驗,這個產品不提、測試不提、我也不做,因爲做也不知道要做成什麼樣,到時候,接口報錯了,我一併再把鍋甩給後端~O(∩_∩)O哈哈~甩鍋非我願,然而,我這樣做,都是爲了高效的完成開發任務,然後留出時間搞自己的事情,畢竟我一個前端要對接4個後端,每天淨幹些打雜的事情,太浪費時間了...像我們這樣的小企業,每天都講產出,有時候自己花太多時間和精力去想把東西做好,領導一句:搞個這麼簡單的玩意怎麼要花費那麼久。爲此,對於所有開發任務,你給一天時間我有一天時間的玩法,你給三天時間我有三天的玩法,你給一週我有一週的玩法,反正最終都是結果導向:按時完成開發和上線。一分價錢一分貨,一分時間也是一分貨。我相信有許多像我一樣的老程序員、老油條,面對一些很不合理的要求,總是有各種辦法偷工減料,然後讓領導滿意。

  最後把filterDataListParams作爲參數傳遞給後端接口就可以了,這是一個很典型的vue動態數據驅動應用。

  數據驅動的核心,在於構造數據結構,因爲dom的變化都是根據數據來渲染的,在過去用js或者jquery的方式,會頻繁的操作dom,不單要寫一大坨代碼,而且性能還很低,數據驅動之後,只要定義好了數據結構,程序員可以把更多的精力投入到業務場景當中,而並非dom操作當中。

  在實際工作中,關於接口的數據結構,可能是後端開發人員自定義的,也可能是前端開發人員自定義好後給後端你的,也可能是前後端一起協商的。當後端接口提供的數據若是無法直接滿足前端的需求時,前端人員將不得不對數據進行二次構造,這是很痛苦的一件事情,作爲前端開發者而言,必然希望接口返回的數據是不需要二次構造和清洗的,拿來賦值就可以使用。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章