vue项目基于element动态封装列表筛选器

在实际项目中很多列表页面的筛选器组件重复性很高,本文进行尝试性的封装,下方是一些伪代码,主要是记录一下自己做这个功能时的想法,可供大家参考,不足处欢迎补充。
注:都是手撸代码,部分标点符号不准确
主要思路:
1.每个列表使用一个数组对象来维护当前列表要使用的筛选器
2.以当前列表页面的route.path为唯一值
3.筛选器的数据存储在vuex里面,vuex中维护一个对象,键名为当前列表页的route.path
###列表页面中的关键代码:

<ListSearch :searchCom="searchCom" :routePath="$route.path"> // html直接用动态组件
import { getPlantList } '@/api'
// data中声明的变量
searchCom:[
     // 下拉框
     { key: 'createdBy', com: 'SearchSelect', options: { optionsKey: 'createdByOptions', title:'创建人', plactholder: '请选择创建人', multiple: ture } },
     // 下拉框远程实时搜索
     { key: 'plant', com: 'SearchSelect', options: { optionsKey: 'plantOptions', title:'工厂', plactholder: '请选择工厂', multiple: ture, remoteMethod: getPlantList } }, // 直接把当前页面引入的api传进去
     // input输入框
     { key: 'infomation', com: 'SearchInput', options: { title: '信息', plactholder: '请输入信息'  } },
]

###ListSearch组件中的关键代码:

<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,
      SearchSelect 
    },
    getOptions: [] // 当前筛选器要进行提前调用下拉框数据的接口
  }
},
created() {
  this.$store.commit('listSearch/setDefultRoutePath') // 首先把当前路由告诉vuex
  this.getOptions = []
  // 循环传过来的searchCom参数,渲染组件
  for(let i = this.searchCom.length - 1; i >= 0; i--) {
    this.renderCom(this.searchCom[i].com)
    if(this.searchCom[i].options?.optionsKey) {
      // 下拉框数据
      this.getOptions.push(this.searchCom[i].options?.optionsKey)
    }
  }
},
mounted() {
  this.getOptionsList()
}
methods:{
  // 动态渲染组件
  renderCom(com) {
    // 手动给当前实例挂载组件
    this.constructor.component(com, () => {
      return {
        loading: comLoading, // 加载组件时loading效果,自己随便配置
        component: new Promise((resolve) => {
          resovle(this.comMap[com])
        })
      }
    })
  },
  getOptionsList() {
    // 子组件加载完后,在mounted方法中调用此方法,获取筛选钱中所有的下拉框数据
    this.$store.dispatch('listSearch/getSearchOptions',  this.getOptions)
  }
}
<style lang="less" scoped>
   // 样式自适应
  .search-box{
    display: grid;
    grid-template-columns: repeat(4, 25%);
    gap:12px 0;
  }
<style/>

###SearchSelect组件的关键代码:

<template>
  <div class="search-item">
    <div class="title">{{options.title}}</div>
    <el-select v-module="currentValue"
     @change="onChange" 
     :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都有这两个属性就可以了,如果没有,下方还有进行转换的配置属性
        :value="item.value"
      />
     </el-selec>
  </div>
</template>
import {mapState} from 'vuex'
props:{
   // 当前组件绑定的key值,也是后续进行接口搜索时传给后端的值
  valueKey:{
    type: String,
    defualt: ''
  },
  options:{
    type: Object,
    defualt: () => ({})
  },
  routePath:{
    type: String,
    defualt: this.$route.path
  },
},
data(){
  return {
    currentValue: '', // 当前组件维护的module
    returnValue: {}, // return出去的值,暂时没什么用,可以直接从vuex通过路由path来取
    optionsList: [], // 当前组件下拉框数据
    loading: false // 远程搜索时的loading
  }
},
compunted: {
  ...mapState({
    allOptions: state => state.listSearch.allOptions, // 更新下拉框数据时
    optionsUpdate: state => state.listSearch.optionsUpdate, // 更新下拉框数据时
    listSearchMap: state => state.listSearch.listSearchMap // 当前页面绑定的vuex对象
  })
},
watch: {
  currentValue: {
    handler(val){
      if(this.valueKey){
        this.$set(this.returnValue, `${this.valueKey}`, val)
      }
    }
  },
  listSearchMap: {
    handler(val){
      // vuex中的对象更新了,并且对象键名===当前路由path,更新的key值和当前页面绑定的valueKey一样,就刷新当前组件的currentValue
      if(val[this.routePath][this.valueKey]){
        this.currentValue = val[this.routePath][this.valueKey]
      }
    },
    deep: true
  },
  optionsUpdate: {
    handler(val){
      if(this.options.remoteMethod) reutrn // 如果是远程搜素,不需要通过此方法来更新下拉框数据
      this.optionsList = this.allOptions[this.options.optionsKey]
      // 如果需要转换下拉框数据
      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
      // 让后端吧所有的下拉框接口统一,在接口成功返回后进行switch
      options.remoteMethods({search:val,pageNum:1,pageSize:50}).then(res=>{
        if(res.code === '200'){
          switch(this.options.optionsKey === 'plant'){
            // ...进行一些操作
          }
        }
      })
    }
  },
  onChange(val){
    // 根据当前的valueKey进行一些操作,某些操作可以放在vuex里,比如说实时更新vuex里对应routepath的值,比如a筛选项依赖b筛选项, 只有选了c筛选项才能选d筛选项之类的逻辑,这个看不同的业务场景,可以持续的迭代
    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('onChange', val)
  }
}

###SearchInput的关键代码:

// 跟SearchSelect差不多,逻辑更简单,参考着写吧

###vuex的关键代码:

const currentState= {
  listSearchMap: {},// 所有列表筛选器的储存对象,动态添加routePath属性
  currentPath: '',// 当前路由信息,每次新页面加载筛选器的时候先更新这个变量 
  originAllOptions: {},// 保留原始的下拉框对象,看每个人不同的业务场景
  allOptions: {},// 组件要用到的下拉框数据
  optionsUpdate: 0 // 更新下拉框数据的时候改变此数值,让筛选器里面的组件通过watch监听此变量,完成实时更新
}
const mutations ={
  setListSearchMapPathKey(state,payload){
    if(!state.listSearchMap[state.currentPath]){
      // 以页面路由为key设置listSearchMap ,用object.assign方法,可以让listSearchMap 中的新的属性可以双向绑定,类似于组件中的$set()的作用
      state.listSearchMap = Object.assign({},state.listSearchMap ,{[state.currentPath]:[]})
    }
    state.listSearchMap[state.currentPath] = Object.assign({},state.listSearchMap[state.currentPath] ,{...payload})
  },
    // 设置一些默认值,如当前筛选器的路由,筛选器的默认选项之类的
   setdefaultSearch(state, payload){
    const {routePath} = payload
    state.currentPath = routePath
   },
  plantChange(state, payload){
    // SearchSelect组件里面的change事件,这里根据不同业务场景不同写法
    // 如果涉及到了筛选器下拉框数据变更,就加下方这段代码
    // state.optionsUpdate++
  }
}
const actions= {
  getSearchOptions({state},payload){
    for(let i = 0;i<payload.length;i++){
      switch(payload[i]){
        case 'plant'{
        //比如plant需要获取下拉框数据,就在这里执行代码
        }
      }
    }
    // 等所有的下拉框数据都获取到后进行更新
    state.optionsUpdate++
  }
}
export default{
namespaced:true,
state:currentState,
mutations,
actions
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vue基于Element UI Table的二次封装可以通过创建一个自定义的组件来实现。以下是一个简单的示例,演示了如何封装一个基于Element UI Table的组件: ```vue <template> <el-table :data="tableData" :row-key="rowKey" :height="height"> <!-- 渲染表头 --> <el-table-column v-for="column in columns" :key="column.prop" :prop="column.prop" :label="column.label"> <!-- 自定义插槽 --> <template slot-scope="scope"> <slot :column="column" :scope="scope"></slot> </template> </el-table-column> </el-table> </template> <script> export default { name: 'CustomTable', props: { tableData: { type: Array, required: true }, columns: { type: Array, required: true }, rowKey: { type: String, required: true }, height: { type: String, default: 'auto' } } } </script> ``` 在这个示例中,我们创建了一个名为`CustomTable`的组件。它接受`tableData`、`columns`、`rowKey`和`height`作为props,分别表示表格数据、表格列配置、行数据的唯一标识以及表格的高度。 在模板中,我们使用`el-table`和`el-table-column`来渲染Element UI的表格。我们使用了`v-for`指令来循环渲染表格列,并通过`slot-scope`来传递数据给插槽。插槽可以在父组件中定义,并在插槽中使用自定义的组件来渲染表格单元格内容。 通过这种方式,我们可以在父组件中使用这个封装的自定义表格组件,并通过插槽来定制表格的内容和样式。 希望这个简单的示例能帮助到你进行Vue基于Element UI Table的二次封装。如果有任何问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值