vue列表的公共搜索组件设计

937 阅读1分钟

本来要撤退了,实在饿得不行了,不过jenkins编译前端代码又卡主了,那就再来说说搜索组件的设计吧

1.烦人的搜索条件

既然搜索条件繁琐而烦人,真的应该整成一个组件,还是按照我们之前的思路,使用数据配置驱动它。

提取模板文件如下,支持的组件并不是很多,重在思路,已经包含了日期范围、下拉框、输入框,不够可以自己添加。

<template>
  <div>   
        <el-collapse v-model="showSearch" accordion>
            <el-collapse-item name="1">
                <template slot="title">
                <i class="header-icon el-icon-search"> 搜索条件,点击显示/隐藏</i>                
                </template>
                <div class="search">
                    <template v-for="(item,index) in model">
                        <el-input v-if="item.control=='text'" class="input" v-model="item.value" size="mini"  clearable :key="index" >
                            <template slot="prepend">{{item.label}}:</template>
                        </el-input>  
                        <div v-else-if="item.control=='dropdown'" :key="index" class="dropdown">
                            <span class="span">{{item.label}}:</span>
                            <el-select   v-model="item.value" size="mini"  clearable  >                                
                                <el-option
                                    v-for="dItem in getdict(item.dictType -1,item.custom)"
                                    :key="dItem.value"
                                    :label="dItem.name"
                                    :value="dItem.value">
                                </el-option>
                            </el-select> 
                        </div>
                        <div v-else-if="item.control=='age'" class="age" :key="index" >
                            <span class="span">{{item.label}}:</span>
                            <div class="ageSlider">
                                <el-slider  v-model="item.value" range :max="150">                            
                                </el-slider> 
                            </div> 
                        </div>
                        <div v-else-if="item.control=='dateRange'" class="dateRange"  :key="index" >
                            <span class="span">{{item.label}}:</span>
                            <el-date-picker
                                clearable 
                                v-model="item.value"                            
                                type="daterange"
                                align="center"
                                size="small"
                                unlink-panels
                                range-separator="—-"
                                start-placeholder="开始日期"
                                end-placeholder="结束日期"
                                value-format="yyyy-MM-dd"                                 
                                :picker-options="pickerOptions">
                            </el-date-picker>    
                        </div>              
                    </template>
                    
                    <slot>buttons area</slot>
                </div>                             
            </el-collapse-item>
        </el-collapse>    
  </div>
</template>

2、组件脚本

组件脚本相当简单,我们只需要提供参数的获取方法,以及其他的初始化工作即可。

<script>

export default { 
  name:'WSearch',
  props: {
      model:{
          type:Array,
          default:()=>{
              return [                 
              ]
          }
      },  
      dict:{type:Array,default:()=>[] },
      show:{type:String,default:''}
  },
  created(){    
  },
  data() {
    return {   
      marks:{          
          50:'50岁',
          100:'100岁'
      },
      pickerOptions: {
          shortcuts: [
              {
            text: '今天',
            onClick(picker) {
              const end = new Date();
              const start = new Date();             
              picker.$emit('pick', [start, end]);
            }
          },{
            text: '昨天',
            onClick(picker) {
              const end = new Date();
              const start = new Date();   
              start.setTime(start.getTime() - 3600 * 1000 * 24);          
              picker.$emit('pick', [start, end]);
            }
          },
          {
            text: '最近一周',
            onClick(picker) {
              const end = new Date();
              const start = new Date();
              start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
              picker.$emit('pick', [start, end]);
            }
          }, {
            text: '最近一个月',
            onClick(picker) {
              const end = new Date();
              const start = new Date();
              start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
              picker.$emit('pick', [start, end]);
            }
          }, {
            text: '最近三个月',
            onClick(picker) {
              const end = new Date();
              const start = new Date();
              start.setTime(start.getTime() - 3600 * 1000 * 24 * 90);
              picker.$emit('pick', [start, end]);
            }
          }]
        },    
      listQuery: {
        page: 1,
        limit: 10,
        account: undefined,
        name: undefined
      }, 
      customDict: [],
      showSearch : this.show    
    }
  },   
  methods: {  
    handleInput(e,index) {  
      //this.$emit("input", this.model);
    },
    getCustomDict(url) {
      return this.$http.fetch({
        url: url,
        method: "get"
      });
    },
    getdict(index,url){
        if(url){          
          return this.customDict[url] || []          
        }
        else if(this.dict && this.dict.length > index){
            var d = [{
                name:'全选',
                value: ''
            },...this.dict[index]]            
            return d
        }
        else{
          //console.log('dict',this.dict)
          return []
        }
    } ,   
  }
}

</script>
<style rel="stylesheet/scss" lang="scss" scoped>
    .search {
        display: flex;
        display: -webkit-flex; /* Safari */
        flex-direction: row;
        flex-wrap: wrap ;
        justify-content:left;
        align-items: center;
        .span{
             border-left: 1px solid #DCDFE6;
                border-top: 1px solid #DCDFE6;
                border-bottom: 1px solid #DCDFE6;
                border-right: 0;
                border-top-left-radius: 4px;
                border-bottom-left-radius: 4px;                
                //width:60px;
                background-color: #F5F7FA;
                color: #909399;
                vertical-align: middle;
                display: table-cell;
                position: relative;
                margin-right:0px;
                padding: 0 20px;                
                white-space: nowrap;
                height: 28px;
        }
        .input{
            width:240px;
            margin:  5px;            
        }
        .dropdown{
            width:240px;
            margin: 5px;            
            display: flex;
            display: -webkit-flex; /* Safari */
            flex-direction: row;
            flex-wrap: nowrap ;
            justify-content:center;
            align-items: center;           
            
             ::v-deep input{
                border-top-left-radius: 0;
                border-bottom-left-radius: 0;   
                width:100%;
                min-width: 150px;             
            }
        }
        .age{
            width:240px;
            margin: 5px;           
            display: flex;
            display: -webkit-flex; /* Safari */
            flex-direction: row;
            flex-wrap: nowrap ;
            justify-content:center;
            align-items: center;            
            .ageSlider{
                width:100%;
                min-width:150px;
                border: 1px solid #DCDFE6;               
                border-top-right-radius: 4px;
                border-bottom-right-radius: 4px;   
                height:28px;
                align-self:flex-start;
                padding:0 10px 0 10px;
            }
            ::v-deep .el-slider__bar{
                background-color:#aaa
            }
        }
        .dateRange{
            min-width:250px;
            margin: 5px;            
            display: flex;
            display: -webkit-flex; /* Safari */
            flex-direction: row;
            flex-wrap: nowrap ;
            justify-content:left;
            align-items: center;   
            flex-grow:1;        
            ::v-deep .el-input__inner{
                border-top-left-radius: 0;
                border-bottom-left-radius: 0;
            }
            .span{
                height:32px;
            }
            ::v-deep input{
                 width:100%;
                min-width: 80px;             
            }
        }
    }
</style>

3.使用组件

记得引用文件和定义组件.然后直接使用标签

<w-search ref="search" :model="searchList" v-bind:dict=dict>
            <el-button type="success" size="mini" icon="el-icon-search" @click.native="search">{{ $t('button.search') }}</el-button>
            <el-button type="primary" size="mini" icon="el-icon-refresh" @click.native="reset">{{ $t('button.reset') }}</el-button>
        </w-search>     

这里model定义了搜索组件的元数据,dict给定了搜索框的词典。

元数据信息形如:

searchList:[
        {
          label:this.$t(myConfig.model+'.cpShowType'),
          control:'dropdown', //br换行
          name:'CpShowType',
          dictType:'1',
          value: null,
          default: null,
        },
        {
          label:this.$t(myConfig.model+'.cpCode'),
          control:'text', //br换行
          name:'CpCode',
          dictType:'',
          value: null,
          default: '',
        },        
      ], 

4.界面如下:

Jenkins终于编译好了,界面可以看到了。
在这里插入图片描述

当然,根据元数据的不同可以随便扩展搜索条件了,开开心心码完代码,下班。

5. 小结

我是vue新手,多多关照,大家可以提提问题哦,