vue element 搜索通用组件,可动态传入下拉

1、使用方法


 表单配置
 示例:
 [{
 label: '用户名', // label文字
 prop: 'username', // 字段名
 element: 'input', // 指定elementui组件
 initValue: 'xhcss', // 字段初始值
 placeholder: '请输入用户名', // elementui组件属性
 rules: [{ required: true, message: '必填项', trigger: 'blur' }], // elementui组件属性
 events: { // elementui组件方法
  input (val) {
  console.log(val)
  },
  ...... // 可添加任意elementui组件支持的方法
 }
 ...... // 可添加任意elementui组件支持的属性
 }]

2、详细代码使用

比如,我们下拉的话,有时候需要获取数据再生成,但是我们的搜索的话,是一起传入的,可能我技术菜吧!无法实时更新到子集!所以采用了另外一种办法!

具体看注释

<template>
  <div class="x-search">
    <search-form :form-options="searchData" @onSearch="onSearch" />
  </div>
</template>

<script>
import SearchForm from '@/components/SearchForm'
export default {
  components: {
    SearchForm
  },
  data() {
    return {
      searchData: [
        {
          label: '动态获取下拉组件',
          element: 'select',
          prop: 'issho2w',
          options: this.getMenu()
        },
        {
          label: 'ID',
          element: 'input',
          prop: 'id'
        },
        {
          label: '状态',
          element: 'select',
          prop: 'one',
          options: [
            {
              label: '启用',
              value: '1'
            },
            {
              label: '停用',
              value: '0'
            }
          ]
        },
        {
          label: '第二种',
          element: 'select',
          prop: 'two',
          options: this.two()
        },
        // 时间区间选择
        // 注意的是时间区间选择返回的是一个数组,所以需要你根据返回的值拆分数据获取值
        {
          label: '访问时间',
          element: 'date-picker',
          prop: 'cycle',
          initValue: []
        },
        // 时间选择
        {
          label: '访问时间',
          element: 'date-picker-one',
          prop: 'time',
          initValue: []
        }
      ]
    }
  },
  methods: {
    // 这里是下拉组件是需要加载的
    // 这里的话如果是异步,因为初始加载的时候没获取完成,所以传入搜索组件内就是空了! 方法的话是2种,一种就是我这种,
    // 另外一种的话就直接 自行加载完成后 使用 this.searchData[0].options= res 去改变searchData,就能触发子组件更新了
    async getMenu() {
      var options = await modelList(this.listQuery)
      return options
    },
    // 下拉组件可以直接返回的
    two() {
      return [
        {
          label: '启用',
          value: '1'
        },
        {
          label: '停用',
          value: '0'
        }
      ]
    },
    // 搜索,如果传入了时间区间,则需要拷贝一份数据进行处理,切记要拷贝,不能=,会各种bug,因为要删除
    onSearch(searchData) {
      this.listQuery.page = 1 //跳转到第一页
      const data = Object.assign({}, searchData) // 获取搜索的值
      if (Array.isArray(data.cycle)) {
        data.startDate = data.cycle[0]
        data.endDate = data.cycle[1]
        delete data.cycle
      } else {
        this.listQuery.startDate = ''
        this.listQuery.endDate = ''
      }
      this.listQuery = Object.assign({}, this.listQuery, data)

      this.getList()
    },
    /*
   // 如果没有传入时间区间,就直接合并初始页码进行搜索即可!
    onSearch (searchData) {
      this.listQuery.page = 1
      this.listQuery = Object.assign({}, this.listQuery, searchData)
      this.getList()
    }
    */
  }
}
</script>

<style>
</style>

3、代码

components
--SearchForm
----FormItem.vue
----index.vue

index.vue

<template>
  <el-form ref="formRef" :model="formData" :inline="true">
    <el-form-item
      v-for="(item, index) in formOptions"
      :key="index"
      :prop="item.prop"
      :label="item.label ? item.label + '' : ''"
      :rules="item.rules"
    >
      <form-item v-model="formData[item.prop]" :item="item" @onSearch="onSearch()" />
    </el-form-item>
    <el-form-item>
      <el-button type="primary" size="small" icon="el-icon-search" @click="onSearch()">查询</el-button>
      <el-button
        v-if="btnItems.includes('reset')"
        size="small"
        icon="el-icon-refresh"
        @click="onReset()"
      >重置</el-button>
      <el-button
        v-if="btnItems.includes('export')"
        size="mini"
        type="primary"
        class="btn-export"
        @click="onExport"
      >导出</el-button>
    </el-form-item>
  </el-form>
</template>

<script>
import FormItem from './FormItem.vue'

export default {
  name: 'SearchForm',
  components: { FormItem },
  props: {
    formOptions: {
      type: Array,
      default: () => []
    },
    // 提交按钮项,多个用逗号分隔(query, export, reset)
    btnItems: {
      type: String,
      default: "reset"
    }
  },
  data() {
    return {
      formData: {}
    }
  },
  computed: {
    widthSize() {
      const dataSize = this.formOptions.length
      if (dataSize < 4) {
        return 24 / (dataSize + 1)
      } else {
        return 6
      }
    }
  },
  created() {
    this.addInitValue()
  },
  methods: {
    // 校验
    onValidate(callback) {
      this.$refs.formRef.validate(valid => {
        if (valid) {
          callback()
        }
      })
    },

    // 搜索
    onSearch() {
      this.onValidate(() => {
        this.$emit('onSearch', this.formData)
      })
    },
    // 导出
    onExport() {
      this.onValidate(() => {
        this.$emit('onExport', this.formData)
      })
    },
    // 重置
    onReset() {
      this.$refs.formRef.resetFields()
      this.addInitValue()// 重置后需要初始化数据
      this.$emit('onSearch', this.formData)
    },
    // 添加初始值
    addInitValue() {
      const obj = {}
      this.formOptions.forEach(v => {
        if (v.initValue !== undefined) {
          obj[v.prop] = v.initValue
          // this.$set(this.formData)
        }
      })
      this.formData = Object.assign({}, this.formData, obj)
    }
  }
}
</script>

<style>
</style>

FormItem.vue

<template>
  <div class="form-item">
    <!-- 文本 -->
    <el-input
      v-if="item.element === 'input'"
      v-model.trim="currentVal"
      clearable
      v-bind="bindProps"
      size="small"
      @clear="clearInput()"
      @keyup.enter.native="handleFilter()"
    />

    <el-input
      v-if="item.element === 'numberinput'"
      v-model.number="currentVal"
      clearable
      size="small"
      @keyup.enter.native="handleFilter()"
    />

    <!-- 数字 -->
    <el-input-number
      v-if="item.element === 'number'"
      v-model="currentVal"
      v-bind="bindProps"
      clearable
      size="small"
      :controls-position="item['controls-position'] || 'left'"
      v-on="bindEvents"
    />

    <!-- select -->
    <el-select
      v-if="item.element === 'select'"
      v-model="currentVal"
      v-bind="bindProps"
      clearable
      size="small"
      v-on="bindEvents"
      @change="handleFilter"
    >
      <el-option v-for="v in options" :key="v.value" :label="v.label" :value="v.value" />
    </el-select>
    <!-- date-picker -->
    <el-date-picker
      v-if="item.element === 'date-picker'"
      v-model="currentVal"
      v-bind="bindProps"
      size="small"
      type="daterange"
      clearable
      :picker-options="pickerOptions"
      start-placeholder="开始日期"
      range-separator="至"
      end-placeholder="结束日期"
      value-format="yyyy-MM-dd"
      v-on="bindEvents"
    />
    <!-- date-picker-one -->
    <el-date-picker
      v-if="item.element === 'date-picker-one'"
      v-model="currentVal"
      type="date"
      placeholder="选择日期"
      v-bind="bindProps"
      size="small"
      value-format="yyyy-MM-dd"
      v-on="bindEvents"
    />
  </div>
</template>

<script>
export default {
  name: 'FormItem',
  props: {
    value: {},
    item: {
      type: Object,
      default: () => { }
    }
  },
  data() {
    return {
      options: [],
      pickerOptions: {
        shortcuts: [
          {
            text: '最近一天',
            onClick(picker) {
              const end = new Date()
              const start = new Date()
              start.setTime(start.getTime() - 3600 * 1000 * 24 * 1)
              picker.$emit('pick', [start, end])
            }
          },
          {
            text: '最近三天',
            onClick(picker) {
              const end = new Date()
              const start = new Date()
              start.setTime(start.getTime() - 3600 * 1000 * 24 * 3)
              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])
            }
          }
        ]
      }
    }
  },
  created() {
    if (this.item.options) {
      this.option(this.item.options)
    }
  },
  computed: {
    // 双向绑定数据值
    currentVal: {
      get() {
        return this.value
      },
      set(val) {
        this.$emit('input', val)
      }
    },

    // 绑定属性
    bindProps() {
      const objs = { ...this.item }
      // 默认填充placeholder
      if (!objs.placeholder) {
        const msg = objs.element === 'input' ? '请输入' : '请选择'
        objs.placeholder = msg + objs.label
      }
      // 移除冗余属性
      delete objs.prop
      delete objs.initValue
      delete objs.rules
      delete objs.events

      if (objs.element === 'select') {
        delete objs.options
      }
      delete objs.element
      console.log(objs)
      return objs

    },
    // 绑定方法
    bindEvents() {
      return this.item.events || {}
    }
  },

  methods: {
    // 选中即执行
    handleFilter() {
      this.$emit('onSearch')
    },
    // 清空亦执行搜索
    clearInput() {
      this.$emit('onSearch')
    },
    // 判断option是否是Promise对象,如果是的话,把Promise对象输出
    option(obj) {
      var isPromise = !!obj && (typeof obj === 'object' || typeof obj === 'function') && typeof obj.then === 'function'
      if (isPromise) {
        obj.then(res => {
          console.log(res)
          this.options = res.data.list
        })
      } else {
        this.options = obj
      }

    }
  }
}
</script>

<style></style>


相关内容

发表评论

验证码:
点击我更换图片

最新评论