使用el-mentui中的el-select、el-input、el-popover、el-dialog、el-table实现下拉多选、搜索、滚动触底加载、新增并选中、编辑、数据返显功能

 1、效果

注意: 新增并选中、这里需要后端的支持,新增接口请求成功后端返回新增数据。

 2、在main.js中加入自定义指令

// select下拉刷新
Vue.directive('loadmore', {
  inserted(el, binding, vnode) {
    const SELECTWRAP_DOM = el.querySelector('.el-select-dropdown .el-select-dropdown__wrap')
    if (SELECTWRAP_DOM) {
      SELECTWRAP_DOM.addEventListener('scroll', function() {
        const condition = this.scrollHeight - this.scrollTop <= this.clientHeight
        const type = binding.value.type
        // const fn = binding.value.fn
        if (condition) {
          binding.value.fn(type)
        }
      })
    }
  }
})

3、防抖 

  // 防抖
  debounce: (fn, interval) => {
    var timer
    var gapTime = interval || 1500 // 间隔时间,如果interval不传,则默认1000ms
    return function() {
      clearTimeout(timer)
      var context = this
      var args = arguments // 保存此处的arguments,因为setTimeout是全局的,arguments不是防抖函数需要的。
      timer = setTimeout(function() {
        fn.apply(context, args)
      }, gapTime)
    }
  },

 4、组件代码 

<template>
  <div class="SelectAddLabel">
    <el-select
      ref="select"
      v-model="childValue"
      v-loadmore="{fn:loadMore ,type:'remoteMethod'}"
      style="width: 300px;"
      multiple
      clearable
      placeholder="请选择"
      @change="change"
    >
      <div v-loading="loading">
        <el-input
          v-model="params.search"
          class="select-input"
          prefix-icon="el-icon-search"
        />
        <el-option
          v-if="noData"
          value=""
          label="空空如也"
        />
        <el-option
          v-for="item in option"
          :key="item.value"
          :label="item.label"
          :value="item.value"
        />

        <div style="display: flex; justify-content: space-between;position: sticky; bottom: 0px ; background-color: aliceblue;">
          <el-popover
            v-model="popoverVisible"
            placement="top"
            width="160"
          >
            <el-input v-model="addForm.label_name" autocomplete="off" clearable />
            <div style="text-align: right; margin: 0">
              <el-button size="mini" type="text" @click="popoverClose">取消</el-button>
              <el-button type="primary" size="mini" @click="popoverConfirm">确定</el-button>
            </div>
            <el-button slot="reference" type="text" style="margin-left: 40px;">新增</el-button>
          </el-popover>
          <el-button type="text" style="margin-right: 40px;" @click="editShow = true ; getTableLabelData()">编辑</el-button>
        </div>
      </div>

    </el-select>

    <!-- 编辑来源 -->
    <el-dialog title="编辑标签" width="500px" :visible.sync="editShow" append-to-body>
      <el-table :loading="tableLoading" :data="tableData" height="50vh">
        <el-table-column property="label_name" label="标签名" />
        <el-table-column label="操作">
          <template slot-scope="{ row }">
            <el-button type="text" style="color: red" @click.stop="del(row.id)">删除</el-button>
          </template>
        </el-table-column>
      </el-table>
      <el-pagination
        :current-page.sync="tableParams.page"
        :page-size="tableParams.limit"
        layout="total, prev, pager, next"
        :total="tableCount"
        @size-change="handleSizeChange"
        @current-change="handleCurrentChange"
      />
    </el-dialog>
    <!-- 编辑来源 -->

  </div>
</template>

<script>
import fn from '@/utils/fn'   //内有防抖节流方法
import Label from '@/api/label'  // 获取数据接口
export default {
  model: { // 定义model
    // 父组件v-model绑定的值传递给props中的fatherValue
    prop: 'fatherValue',
    // 通过emit触发childValueChange将内部值传递给父组件v-model绑定的值
    event: 'childValueChange'
  },
  props: {
    type: {
      type: Number,
      default: null
    },
    fatherValue: { // 接受父组件传递的值
      type: Array,
      default: () => []
    },
    fatherOption: {
      type: Array,
      default: () => []
    }
  },
  data() {
    return {
      noData: false,
      loading: false,
      popoverVisible: false,
      childValue: this.fatherValue,
      option: [],
      editShow: false,
      addShow: false,
      addForm: {
        label_name: ''
      },
      params: {
        search: '',
        page: 1,
        limit: 10
      },
      tableParams: {
        search: '',
        page: 1,
        limit: 10
      },
      tableData: [],
      tableLoading: false,
      tableCount: 0
    }
  },
  watch: {
    fatherValue(val) { // 这一步重新赋值 是因为props里面的fatherValue改变了 但是data里面的childValue不会改变 从而视图不会更新
      this.childValue = val
    },
    tableParams: {
      deep: true,
      handler() {
        this.getTableLabelData()
      }
    },
    fatherOption: {
      immediate: true,
      deep: true,
      handler(val) {
        if (val && val.length > 0) {
          val.forEach(item => {
            this.judgeAdd(item)
          })
        }
      }
    },
    'params.search': {
      handler() {
        this.loading = true
        this.params.page = 1
        this.getLabelData()
      }
    }
  },
  created() {
    this.getLabelData()
  },
  methods: {
    // 判断是否能插入
    judgeAdd(obj) {
      if (!obj || Object.keys(obj).length === 0) {
        return
      }
      const have = this.option.some(item => item.value === obj.value)
      if (!have) {
        this.option.push(obj)
      }
    },
    handleSizeChange(val) {
      console.log(`每页 ${val} 条`)
    },
    handleCurrentChange(val) {
      this.tableParams.page = val
    },
    // 获取table数据
    getTableLabelData() {
      this.tableLoading = true
      Label.getLabelData(this.tableParams).then(res => {
        this.tableData = res.data
        this.tableCount = res.count
        this.tableLoading = false
      })
    },
    // 滚动触底
    loadMore(type) {
      if (!this.loading && !this.noData) {
        this.params.page++
      }
      this.loading = true
      this.getLabelData('add')
    },
    // 删除
    del(val) {
      Label.deleteLabelData({ id: val }).then(res => {
        this.getLabelData()
      })
    },
    change() {
      // 通过$emit触发childValueChange(model内定义)事件,将内部值传递给给父组件
      this.$emit('childValueChange', this.childValue)
    },

    // popover确定
    popoverConfirm() {
      if (!this.addForm.label_name) {
        this.$message({
          type: 'error',
          message: '不能为空'
        })
        return
      }
      Label.saveLabelData({ ...this.addForm, label_type: this.type }).then(res => {
        const obj = {
          value: res.data.id,
          label: res.data.label_name
        }
        this.option.push(obj)
        this.childValue.push(res.data.id)
        this.change()
        this.params.page = 1
        this.getLabelData()
        this.popoverClose()
      })
    },
    // popover取消
    popoverClose() {
      this.popoverVisible = false
      this.addForm.label_name = ''
    },
    // 获取标签
    getLabelData: fn.debounce(async function(type) {
      this.loading = true
      await Label.getLabelData({ ...this.params, label_type: 4 }).then(res => {
        const getArrData = res.data.map(item => ({ value: item.id, label: item.label_name }))
        if (type === 'add') {
          getArrData.forEach(item => {
            this.judgeAdd(item)
          })
          // this.option.push(...getArrData)
        } else {
          this.option = getArrData
        }
        if (!getArrData || getArrData.length === 0) {
          this.noData = true
        } else {
          this.noData = false
        }
      }).catch((res) => {
        this.$message.error(res.message || '获取下拉选项失败')
      }).finally(() => {
        	this.loading = false
      })
    }, 1000)
  }
}
</script>

<style lang="scss" scoped>
  .select-input{
    padding: 0 12px;
    box-sizing: border-box;
    margin-bottom: 12px;
    position: sticky;
    top: 0px;
    z-index: 9999;
    ::v-deep .el-input__inner {
      border: none;
      border-bottom: 1px solid #EBEBEB;
      border-radius: 0;
    }
  }
.SelectAddLabel{
  ::v-deep .el-dialog{
.el-dialog__body{
  .el-form-item{
    .el-form-item__label{
      width:11em !important;
    }
    .el-form-item__content{
      margin-left:12em !important;
    }
  }
}
}
}
</style>

5、全局引入组件

import SelectAddLabel from './SelectAddLabel'
export default {
  install(Vue) {
    Vue.component('SelectAddLabel', SelectAddLabel)
  }
}

 6、template

 
<SelectAddLabel v-model="addContactForm.label_id" :father-option="labelOption" :type="4" />

 7、data

data(){
    return{
        addContactForm:{
          label_id: []
        },
        labelOption:[]  //用于数据返现
    }
}

 8、methods

    //  需要获取数据用于返显
    editContact(row) {
      this.labelOption = row.customer_contact_to_label.map(item => {
        return {
          value: item.id,
          label: item.label_name
        }
      })
      this.dialogFormVisible = true
    },

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值