Antd+vue Input下拉Table表格

遇到需要下拉选择信息的需求,发现Select 展示信息不太友好,尝试Input标签触发展示一个Table表格

AInputTable 组件 使用文档
  • 说明: 输入框支持展示Table表格,支持翻页,多属性展示,
  • 点击选中可获取列全部属性值;
参数配置
参数类型必填说明
placeholderString输入框未填值展示提示信息
disabledBooleantrue/false 默认false
valueString绑定v-model或是v-decorator后不需要设置
columnsArray表格列的配置描述,详见https://www.antdv.com/components/table-cn/#Column
urlstringtable 数据源请求地址 查询需返回带分页的数据
sorterObject排序字段及排序方式 { column: this.sorter, order: ‘desc’ }
saveLabelstring选中实际保存字段
showLabelstring选中输入框展示字段
queryParamsstringqueryParams 额外参数如:部门人员、类型等 后台逻辑需自己书写
pageSizestring指定每页显示条数
rowKeystring指定rowKey 默认id 没有id时指定
scrollstring设置显示Table高度限制,超出指定高度 滚动展示
使用示例
<template>
    <a-input-table :="tableAIdConfig" v-model="queryParam.tableAId" @getRecord="getRecord"></a-input-table>
</template>
<script>
    import AInputTable from "@/components/assien/AInputTable";
    export default {
        name: "Test",
        components: {
          AInputTable,
        },
        data() {
            return {
                queryParam: {},
                tableAIdConfig: [{
		          title: '序号',
		          width: 60,
		          align: "center",
		          dataIndex: 'no',
		          customRender: function (t, r, index) {
		            return parseInt(index) + 1
		          },
		        },{
		          title: '用户名称',
		          align: "center",
		          dataIndex: 'realname'
		        },{
		          title: '岗位',
		          align: "center",
		          dataIndex: 'post'
		        },{
		          title: '电话',
		          align: "center",
		          dataIndex: 'telephone',
		        },{
		          title: '邮箱',
		          align: "center",
		          ellipsis: true,
		          dataIndex: 'mail',
		        }],
            }
        },  
        methods: {
          getRecord(record){
            console.log(record)
          },
        }
    }
</script>
<style scoped></style>
AInputTable.vue子组件
<!--下拉Table再探究 2.0-->
<template>
  <div class="input-table" v-clickoutside="handleHide">
    <div class="input-table-input" @click="disabled?this:handleShow()">
        <a-input
          :value="showValue"
          :disabled="disabled"
          class="select-table-input"
          :placeholder="placeholder"
          @change="inputValueChange"
        >
          <a-icon type="bars" style="color: rgba(0,0,0,.45)" slot="suffix" />
        </a-input>
    </div>
    <div v-bind:class="getTableVisible" :style="tableDivStyle()">
      <a-table
        bordered
        size="small"
        :scroll="scroll"
        :columns="columns"
        :dataSource="dataSource"
        :customRow="onCustomRow"
        :pagination="ipagination"
        @change="handleTableChange"
        :rowKey="rowKey"
      />
    </div>
  </div>
</template>

<script>
  import {getAction} from "../../api/manage";
  import { filterObj } from '@/utils/util';

  const clickoutside = {
    // 初始化指令
    bind(el, binding, vnode) {
      function documentHandler(e) {
        // 这里判断点击的元素是否是本身,是本身,则返回
        if (el.contains(e.target)) {
          return false
        }
        // 判断指令中是否绑定了函数
        if (binding.expression) {
          // 如果绑定了函数 则调用那个函数,此处binding.value就是handleHide方法
          binding.value(e)
        }
      }

      // 给当前元素绑定个私有变量,方便在unbind中可以解除事件监听
      el.__vueClickOutside__ = documentHandler;
      document.addEventListener('click', documentHandler)
    },
    update() {
    },
    unbind(el, binding) {
      // 解除事件监听
      document.removeEventListener('click', el.__vueClickOutside__);
      delete el.__vueClickOutside__
    }
  };

  export default {
    name: 'AInputTable',
    props: {
      placeholder: {
        type: String,
        required: false,
        default: ''
      },
      disabled: {
        type: Boolean,
        required: false,
        default: false,
      },
      url: {
        type: String,
        required: false,
        default: ''
      },
      columns: {
        type: Array,
        required: false,
        default: () => [],
      },
      value: {
        type: String,
        required: false,
        default: '',
      },
      saveLabel: {
        type: String,
        required: false,
        default: 'id',
      },
      showLabel: {
        type: String,
        required: false,
        default: 'name',
      },
      sorter: {
        type: Object,
        required: false,
        default: ()=>{},
      },
      queryParams: {
        type: Object,
        required: false,
        default: ()=>{},
      },
      pageSize: {
        type: Number,
        required: false,
        default: 10,
      },
      rowKey: {
        type: String,
        required: false,
        default: "id",
      },
      scroll: {
        type: Object,
        required: false,
        default: function () {
          return { x:200, y: 500 }
        },
      },
    },
    directives: {clickoutside},
    data() {
      return {
        tableVisible: false,
        //----- new -----
        dataSource: [],
        /* 分页参数 */
        ipagination: {
          current: 1,
          pageSize: this.pageSize,
          pageSizeOptions: ['5','10','15','20','30'],
          showTotal: (total, range) => {
            return range[0] + "-" + range[1] + " 共" + total + "条"
          },
          showSizeChanger: true,
          total: 0
        },
        isorter:  this.sorter,/* 排序参数 */
        showValue:'',//展示值
        saveValue:'',//保存值
        record:{},
        // 存储各个div的style
        style: {
          tableDiv:{
            position: "absolute",
            zIndex: "999",
            backgroundColor: "#ffffff",
            border:"#dedede 1px solid",
            padding: "5"
          },
        },
      }
    },
    created() {
    },
    computed: {
      getTableVisible() {
        if (this.tableVisible) {
          return 'showTable';
        } else {
          return 'hideTable';
        }
      },
    },
    watch: {
      value: {
        immediate: true,
        handler(val) {
          if (val) {
            this.saveValue = val;
            this.queryShowValueBySaveValue();
          } else {
            this.saveValue = '';
            this.showValue = '';
            this.record = {};
            this.$emit('getRecord',{});
            this.loadData(1);
          }
        }
      },
    },
    methods: {
      loadData(arg) {
        if(!this.url){
          this.$message.error("AInputTable组件未指定请求url,请设置url属性!")
          return
        }
        //加载数据 若传入参数1则加载第一页的内容
        if (arg === 1) {
          this.ipagination.current = 1;
        }
        var params = this.getQueryParams();//查询条件
        getAction(this.url, params).then((res) => {
           if (res.success) {
             this.dataSource = res.result.records;
             this.ipagination.total = res.result.total;
           }
           if(res.code===510){
             this.$message.warning(res.message)
           }
         })
      },
      getQueryParams() {
        let queryParam = {};
        queryParam = {
          [this.showLabel]:this.showValue,
        };
        if(this.queryParams){
          Object.assign(queryParam,this.queryParams)
        }
        var param = Object.assign({}, queryParam, this.isorter ,this.filters);
        param.field = this.getQueryField();
        param.pageNo = this.ipagination.current;
        param.pageSize = this.ipagination.pageSize;
        return filterObj(param);
      },
      getQueryField() {
        //TODO 字段权限控制
        var str = "id,";
        this.columns.forEach(function (value) {
          str += "," + value.dataIndex;
        });
        return str;
      },
      handleHide() { // 点击除了页面其他地方关闭车型选择
        this.tableVisible = false;
      },
      handleShow() {
        this.$emit('click', this.saveValue);
        this.loadData(1);
        this.tableVisible = true;
      },
      onCustomRow(record) {
        return {
          props: {},
          on: {
            click: () => {
              this.record = record;
              this.saveValue = this.record[this.saveLabel];
              this.showValue = this.record[this.showLabel];
              this.$emit('select', this.saveValue);
              this.$emit('input', this.saveValue);
              this.$emit('change', this.saveValue);
              this.$emit('getRecord',this.record);
              this.handleHide();
            },
          },
        };
      },
      inputValueChange(e) {
        this.showValue = e.target.value;
        this.$emit('inputChange',e.target.value);
        if(this.showValue === null || this.showValue === undefined || this.showValue === ''){
          this.clear();
        }
        debounce(()=>{this.loadData(1)}, 1000);
      },
      getShowValue(){
        return this.showValue;
      },
      getSaveValue(){
        return this.saveValue;
      },
      clear() {
        this.saveValue = '';
        this.showValue = '';
        this.record = {};
        this.$emit('select', '');
        this.$emit('input', '');
        this.$emit('change', '');
        this.$emit('getRecord',{});
        this.handleHide();
      },
      handleTableChange(pagination, filters, sorter) {
        //分页、排序、筛选变化时触发
        //TODO 筛选
        if (Object.keys(sorter).length > 0) {
          this.isorter.column = sorter.field;
          this.isorter.order = "ascend" == sorter.order ? "asc" : "desc"
        }
        this.ipagination = pagination;
        this.loadData();
      },

      queryShowValueBySaveValue(){
        let queryParam = {
          [this.saveLabel]:this.saveValue,
        }
         getAction(this.url, queryParam).then((res) => {
           if (res.code == 200) {
             this.dataSource = res.result.records;
             this.ipagination.total = res.result.total;
             this.dataSource.some((item) => {
               if(item){
                 if(item[this.saveLabel] == this.saveValue){
                   this.showValue = item[this.showLabel];
                   this.record = item;
                   return true;
                 }
               }
             })
           }else{
             this.$message.warning(res.message)
           }
         })
      },

      tableDivStyle() {
        let style = Object.assign({}, this.style.tableDiv)
        let width1 = this.getDivTopLength();
        let width2 = this.realTrWidth();
        if(width1>width2){
          style['width'] = width2+"px";
        }else {
          style['width'] = width1+"px";
        }
        return style
      },

      //table 列总宽度
      realTrWidth() {
        let calcWidth = 0
        this.columns.forEach((column, i) => {
          let { type, width } = column
          // 隐藏字段不参与计算
            if (typeof width === 'number') {
              calcWidth += width
            } else if (typeof width === 'string') {
              width = width.replace("px","");
              calcWidth += Number(width)
            } else {
              calcWidth += '120'
            }
        })
        return calcWidth
      },
      //获取指定第v据屏幕右侧宽度
      getDivTopLength() {
        return 600;
      },
    },
    //2.2新增 在组件内定义 指定父组件调用时候的传值属性和事件类型
    model: {
      prop: 'value',
      event: 'input'
    }
  }
</script>
<style scoped lang="less">
.input-table {
  .showTable {
    display: block;
  }
  .hideTable {
    display: none;
  }
  .select-table-input {
    margin-right: 20px;
  }
}
</style>
效果图

在这里插入图片描述

Logo

前往低代码交流专区

更多推荐