vue項目基于element動態(tài)封裝列表篩選器

在實際項目中很多列表頁面的篩選器組件重復(fù)性很高,本文進行嘗試性的封裝线椰,下方是一些偽代碼簿寂,主要是記錄一下自己做這個功能時的想法股囊,可供大家參考蝉衣,不足處歡迎補充。
注:都是手擼代碼赏陵,部分標點符號不準確
主要思路:
1.把常用的篩選項抽出來進行封裝饼齿,如input輸入框,select下拉框蝙搔,date日期選擇器
2.每個列表使用一個數(shù)組對象來維護當(dāng)前列表要使用什么篩選器
3.以當(dāng)前列表頁面的route.path為唯一值缕溉,在vuex里面維護一個object對象,動態(tài)的設(shè)置對象中的ke值吃型,如object[route.path]
4.不同頁面篩選器的數(shù)據(jù)存儲在vuex里的object[route.path]证鸥,從列表點進去詳情的時候再返回列表可以保存上次的篩選條件

常用的篩選器

SearchSelect:下拉框
SearchInput:輸入框
SearchDate:日期選擇器

列表頁面中的關(guān)鍵代碼:

ListSearch組件就是封裝后的全局篩選器
首先在頁面引入ListSearch組件,需要下拉框?qū)崟r搜索的頁面勤晚,在對應(yīng)頁面import引入api枉层,然后在searchCom中對應(yīng)項的options屬性中加入remoteMethod屬性,把要用到的api傳進去赐写,在SearchSelect組件中正常的調(diào)用接口拿數(shù)據(jù)就好了
searchCom中每一項:
key:調(diào)用后端接口要傳的參數(shù)鸟蜡,也是vuex中存的參數(shù)
com:要使用的對應(yīng)組件,本文只用了三種篩選項組件挺邀,可根據(jù)業(yè)務(wù)場景增加
options:有些組件需要傳一些配置文件揉忘,如是否多選跳座,是否需要遠程實時搜索等等

<ListSearch :searchCom="searchCom" :routePath="$route.path"> // html直接用動態(tài)組件
import { getPlantList } '@/api'
// data中聲明的變量
searchCom:[
     // 下拉框
     { key: 'createdBy', com: 'SearchSelect', options: { title:'創(chuàng)建人', optionKey: 'createdByOptions',  plactholder: '請選擇創(chuàng)建人', multiple: ture } },
     // 下拉框遠程實時搜索
     { key: 'plant', com: 'SearchSelect', options: { optionsKey: 'plantOptions', title:'工廠', plactholder: '請選擇工廠', multiple: ture, remoteMethod: getPlantList } }, // 直接把當(dāng)前頁面引入的api傳進去
     // input輸入框
     { key: 'infomation', com: 'SearchInput', options: { title: '信息', plactholder: '請輸入信息'  } },
]

ListSearch組件中的關(guān)鍵代碼:

<template>
  <div class="search-box">
    <component v-for="item in searchCom"
     v-bind="$attrs" 
     v-on="$listeners"
     :key="item.key" 
     :valueKey="item.valueKey" 
     :options="item.options" 
     :routePath="routePath" 
     :is="item.com"/>
     <!-- 這里可以放搜索按鈕 -->
  </div>
</template>
// 這里引入要用到的組件泣矛,以這兩個為案例
import SearchSelect from './components/SearchSelect'
import SearchInput from './components/SearchInput'
props:{
  // 要渲染的篩選項
  searchCom:{
    type: Array,
    defualt: () => []
  },
  routePath:{
    type: String,
    defualt: () => this.$route.path
  }
},
data(){
  return {
    comMap:{
      SearchSelect,
      SearchInput
    },
    getOptions: [] // 當(dāng)前篩選器要進行提前調(diào)用下拉框數(shù)據(jù)的接口
  }
},
created() {
  this.$store.commit('listSearch/setDefultRoutePath') // 首先把當(dāng)前路由告訴vuex
  this.getOptions = []
  // 循環(huán)傳過來的searchCom參數(shù)疲眷,渲染組件
  for(let i = this.searchCom.length - 1; i >= 0; i--) {
    this.renderCom(this.searchCom[i].com)
    if(this.searchCom[i].options?.optionsKey) {
      // 如果需要調(diào)用下拉框數(shù)據(jù)
      this.getOptions.push(this.searchCom[i].options?.optionsKey)
    }
  }
},
mounted() {
  this.getOptionsList()
}
methods:{
  // 動態(tài)渲染組件
  renderCom(com) {
    // 手動給當(dāng)前實例掛載組件
    this.constructor.component(com, () => {
      return {
        loading: comLoading, // 加載組件時loading效果,自己隨便配置
        component: new Promise((resolve) => {
          resovle(this.comMap[com])
        })
      }
    })
  }您朽,
  getOptionsList() {
    // 子組件加載完后狂丝,在mounted方法中調(diào)用此方法,獲取篩選錢中所有的下拉框數(shù)據(jù)
    this.$store.dispatch('listSearch/getSearchOptions',  this.getOptions)
  }
}
<style lang="less" scoped>
   // 樣式自適應(yīng)
  .search-box{
    display: grid;
    grid-template-columns: repeat(4, 25%);
    gap:12px 0;
  }
<style/>

SearchSelect組件的關(guān)鍵代碼:

<template>
  <div class="search-item">
    <div class="title">{{options.title}}</div>
    <el-select v-module="currentValue"
     @change="onChange" 
     :clearable="options.clearable || true"
     :filterable="options.filterable || true" 
     :collapse-tags="options.collapseTags || true" 
     :multiple="options.multiple || false" 
     :remote=method="val => remoteMethod(val, options)" // 通過父組件直接把api傳過來
     :remote="options.remoteMethod?ture:false" 
     :placeholder="item.placeholder || '請選擇'" 
     :loading="loading">
      <el-options v-for="item in optionsList"
        :key="item.label + item.value"
        :label="item.label" // 默認就是value和label哗总,可以不用寫這兩行几颜,只要保證options都有這兩個屬性就可以了,如果沒有魂奥,下方還有進行轉(zhuǎn)換的配置屬性
        :value="item.value"
      />
     </el-selec>
  </div>
</template>
import {mapState} from 'vuex'
props:{
   // 當(dāng)前組件綁定的key值,也是后續(xù)進行接口搜索時傳給后端的值
  valueKey:{
    type: String,
    defualt: ''
  },
  options:{
    type: Object,
    defualt: () => ({})
  },
  routePath:{
    type: String,
    defualt: this.$route.path
  },
},
data(){
  return {
    currentValue: '', // 當(dāng)前組件維護的module
    returnValue: {}, // return出去的值耻煤,暫時沒什么用准颓,可以直接從vuex通過路由path來取
    optionsList: [], // 當(dāng)前組件下拉框數(shù)據(jù)
    loading: false // 遠程搜索時的loading
  }
},
compunted: {
  ...mapState({
    allOptions: state => state.listSearch.allOptions, // 所有的下拉框數(shù)據(jù)
    optionsUpdate: state => state.listSearch.optionsUpdate, // 更新下拉框數(shù)據(jù)時
    listSearchMap: state => state.listSearch.listSearchMap // 當(dāng)前頁面綁定的vuex對象
  })
},
watch: {
  currentValue: {
    handler(val){
      if(this.valueKey){
        this.$set(this.returnValue, `${this.valueKey}`, val)
      }
    }
  },
  listSearchMap: {
    handler(val){
      // vuex中的對象更新了攘已,并且對象鍵名===當(dāng)前路由path炮赦,更新的key值和當(dāng)前頁面綁定的valueKey一樣,就刷新當(dāng)前組件的currentValue
      if(val[this.routePath][this.valueKey]){
        this.currentValue = val[this.routePath][this.valueKey]
      }
    }样勃,
    deep: true
  },
  optionsUpdate: {
    handler(val){
      if(this.options.remoteMethod || this.options.specifyOptions) reutrn // 如果是遠程搜素或者是指定了下拉框數(shù)據(jù),不需要通過此方法來更新下拉框數(shù)據(jù)
      this.optionsList = this.allOptions[this.options.optionsKey]
      // 如果需要轉(zhuǎn)換下拉框數(shù)據(jù)
      if(this.options.transferOPtions){
        const {label,value} = this.options.transferOPtions
        const options = this.options.map(e=>({...e,{label:e[label],value:e[value]}}))
      }
    }
  }
}
methods: {
  remoteMethod(val,options){
    if(!val) return
    if(options.remoteMethods){
      this.loading = true
      // 讓后端吧所有的下拉框接口統(tǒng)一峡眶,在接口成功返回后進行switch
      options.remoteMethods({search:val,pageNum:1,pageSize:50}).then(res=>{
        if(res.code === '200'){
          switch(this.options.optionsKey === 'plant'){
            // ...進行一些操作
          }
        }
      })
    }
  },
  onChange(val){
    // 根據(jù)當(dāng)前的valueKey進行一些操作辫樱,某些操作可以放在vuex里峭拘,比如說實時更新vuex里對應(yīng)routepath的值,比如a篩選項依賴b篩選項狮暑, 只有選了c篩選項才能選d篩選項之類的邏輯鸡挠,這個看不同的業(yè)務(wù)場景搬男,可以持續(xù)的迭代
    switch(this.valueKey){
      case 'plant':
        this.$store.commit('listSearch/plantChange')
        this.$store.commit('listSearch/setListSearchRoutePathKey', {plant:val,other1:[],other2:[]})// 選擇plant的時候清空other1和other2邏輯,
        break
      // ...
    }
    this.$emit('listSearch/setListSearchMapKey', { [this.valueKey]: val})
  }
}

SearchInput的關(guān)鍵代碼:

// 跟SearchSelect差不多缔逛,邏輯更簡單溜腐,參考著寫吧

vuex的關(guān)鍵代碼:

const currentState= {
  listSearchMap: {},// 所有列表篩選器的儲存對象瓜喇,動態(tài)添加routePath屬性
  currentPath: '',// 當(dāng)前路由信息挺益,每次新頁面加載篩選器的時候先更新這個變量 
  originAllOptions: {},// 保留原始的下拉框?qū)ο蟪撕疵總€人不同的業(yè)務(wù)場景
  allOptions: {},// 組件要用到的下拉框數(shù)據(jù)
  optionsUpdate: 0 // 更新下拉框數(shù)據(jù)的時候改變此數(shù)值,讓篩選器里面的組件通過watch監(jiān)聽此變量伞辛,完成實時更新
}
const mutations ={
  setListSearchMapPathKey(state,payload){
    if(!state.listSearchMap[state.currentPath]){
      // 以頁面路由為key設(shè)置listSearchMap ,用object.assign方法蚤氏,可以讓listSearchMap 中的新的屬性可以雙向綁定,類似于組件中的$set()的作用
      state.listSearchMap = Object.assign({},state.listSearchMap ,{[state.currentPath]:[]})
    }
    state.listSearchMap[state.currentPath] = Object.assign({},state.listSearchMap[state.currentPath] ,{...payload})
  }竿滨,
    // 設(shè)置一些默認值,如當(dāng)前篩選器的路由毁葱,篩選器的默認選項之類的
   setdefaultSearch(state, payload){
    const {routePath} = payload
    state.currentPath = routePath
   },
  plantChange(state, payload){
    // SearchSelect組件里面的change事件倾剿,這里根據(jù)不同業(yè)務(wù)場景不同寫法
    // 如果涉及到了篩選器下拉框數(shù)據(jù)變更,就加下方這段代碼
    // state.optionsUpdate++
  }
}
const actions= {
  getSearchOptions({state},payload){
    for(let i = 0;i<payload.length;i++){
      switch(payload[i]){
        case 'plant'{
        //比如plant需要獲取下拉框數(shù)據(jù)前痘,就在這里執(zhí)行代碼
        }
      }
    }
    // 等所有的下拉框數(shù)據(jù)都獲取到后進行更新
    state.optionsUpdate++
  }
}
export default{
namespaced:true,
state:currentState,
mutations,
actions
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末担忧,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子涵妥,更是在濱河造成了極大的恐慌,老刑警劉巖蓬网,帶你破解...
    沈念sama閱讀 219,039評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異吵取,居然都是意外死亡,警方通過查閱死者的電腦和手機皮官,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來捺氢,“玉大人,你說我怎么就攤上這事摄乒∮品矗” “怎么了馍佑?”我有些...
    開封第一講書人閱讀 165,417評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長茵臭。 經(jīng)常有香客問我,道長旦委,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,868評論 1 295
  • 正文 為了忘掉前任社证,我火速辦了婚禮,結(jié)果婚禮上评凝,老公的妹妹穿的比我還像新娘腺律。我一直安慰自己,他們只是感情好匀钧,可當(dāng)我...
    茶點故事閱讀 67,892評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著日杈,像睡著了一般。 火紅的嫁衣襯著肌膚如雪莉擒。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,692評論 1 305
  • 那天涨冀,我揣著相機與錄音,去河邊找鬼麦萤。 笑死扁眯,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的姻檀。 我是一名探鬼主播,決...
    沈念sama閱讀 40,416評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼绣版,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了僵娃?” 一聲冷哼從身側(cè)響起腋妙,我...
    開封第一講書人閱讀 39,326評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎骤素,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體济竹,經(jīng)...
    沈念sama閱讀 45,782評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,957評論 3 337
  • 正文 我和宋清朗相戀三年送浊,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片袭景。...
    茶點故事閱讀 40,102評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖荒澡,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情单山,我是刑警寧澤,帶...
    沈念sama閱讀 35,790評論 5 346
  • 正文 年R本政府宣布米奸,位于F島的核電站,受9級特大地震影響躏升,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜膨疏,卻給世界環(huán)境...
    茶點故事閱讀 41,442評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望佃却。 院中可真熱鬧,春花似錦饲帅、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽赦邻。三九已至,卻和暖如春惶洲,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背恬吕。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留铐料,地道東北人。 一個月前我還...
    沈念sama閱讀 48,332評論 3 373
  • 正文 我出身青樓芯义,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子耘分,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,044評論 2 355

推薦閱讀更多精彩內(nèi)容