Input 下拉Table表格

  • 遇到需要下拉选择信息的需求,Select 展示信息不太友好,尝试展示一个Table表格 一开始写了两版,一个Input标签触发Table 一个Select标签触发 ,后放弃了Select ;经过一段时间试水,还凑合满足需求,唉!后端的竟搞起了前端也是醉了
  • 本着开源精神,共同进步!
    在这里插入图片描述
    在这里插入图片描述

AInputTable 组件 使用文档

  • 说明: 输入框支持展示Table表格,支持翻页,多属性展示,
  • 点击选中可获取列全部属性值;
  • 输入查询已节流,频繁输入 1s查询一次 ,感觉影响体验可去掉;

参数配置

参数类型必填说明
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高度限制,超出指定高度 滚动展示

使用示例

1.组件带有v-model的使用方法

<a-input-table :="tableAIdConfig" v-model="queryParam.tableAId"></a-input-table>
computed: {
      tableAIdConfig() {
        return Object.assign({
          isProxy: false,
          placeholder: "请输入",
          columns: [
            {
              title: '编码',
              width: 60,
              align: "center",
              dataIndex: 'code'
            },
            {
              title: '名称',
              width: 60,
              align: "center",
              dataIndex: 'name'
            },
            {
              title: '备注',
              width: 80,
              align: "center",
              //对字段内容较长属性 超出字段 ... 代替 鼠标浮动展现
              ellipsis: true,
              dataIndex: 'remark',
            },
          ],
          url: "/test/selecTable/list",
          saveLabel: 'id',
          showLabel: 'name'
        }, this.$attrs)
      }
}

2.组件带有v-decorator的使用方法
a).设置 initialValue 默认值

  <a-input-table :="tableAIdConfig" v-decorator="['tableAId', {initialValue: ''}]"/>

b).tableAIdConfig 设置同上

3.项目中引入 组件未全局声明需导入

<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: {},
            }
        },
        computed: {
            tableAIdConfig() {
                return Object.assign({
                  isProxy: false,
                  placeholder: "请输入",
                  columns: [
                    {
                      title: '编码',
                      width: 60,
                      align: "center",
                      dataIndex: 'code'
                    },
                    {
                      title: '名称',
                      width: 60,
                      align: "center",
                      dataIndex: 'name'
                    },
                    {
                      title: 'ID',
                      width: 80,
                      align: "center",
                      dataIndex: 'id',
                      //对字段内容较长属性 超出字段 ... 代替 鼠标浮动展现 - 废弃
                      customRender: (text) => <a-ellipsis value={text} length={3} />
                    },
                    {
                      title: '备注',
                      width: 80,
                      align: "center",
                      //对字段内容较长属性 超出字段 ... 代替 鼠标浮动展现
                      ellipsis: true,
                      dataIndex: 'remark',
                    },
                  ],
                  url: "/test/selecTable/list",
                  saveLabel: 'id',
                  showLabel: 'name'
                }, this.$attrs)
              }
            },
        methods: {
          getRecord(record){
            console.log(record)
          },
        }
    }
</script>

<style scoped>

</style>

4.后台使用

class A{
    /**
     * id 即 saveLabel 根据saveLabel 查询输入框及下拉table应展示内容
     * name 即 showLabel 输入框输入内容所对应key 
     * 代码生成的查询不用处理 QueryGenerator.initQueryWrapper 会自动装配
     */
    @AutoLog(value = "获取执行科室")
    @ApiOperation(value = "获取执行科室", notes = "获取执行科室")
    @GetMapping(value = "/getExecuteDepartment")
    public Result getExecuteDepartment(
            @RequestParam(name = "id",required = false) String id,
            @RequestParam(name = "name",required = false) String name,
            @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
            @RequestParam(name = "pageSize", defaultValue = "5") Integer pageSize) {
        Page<Map<String, Object>> page = new Page<>(pageNo, pageSize);
        Page<Map<String, Object>> pageList = accountService.getExecuteDepartment(id, name, page);
        return Result.result(pageList);
    }
}

源码

<!--下拉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 {getProxyAction} from "../../api/proxymanage";
  import { filterObj } from '@/utils/util';
  import debounce from "@/utils/debounce";
  import {FormTypes} from "@/utils/AEditableTableUtil";

  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:"fixed",
            position: "absolute",
            // marginTop: "0px",
            // marginRight: "0px",
            // width: "500px",
            // top:"15px",
            zIndex: "999",
            backgroundColor: "#ffffff",
            border:"#dedede 1px solid",
            padding: "5",

            // position: "relative",
            // top: 0,
            // left: 0,
            // overflowX: "hidden",
            // overflowY: "hidden",
            // minHeight: "61px",
            /*max-height: 400px;*/
            // minWidth: "100%",
          },
        },
      }
    },
    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.success) {
             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;
                 }
               }
             })
           }
           if(res.code===510){
             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 (type !== FormTypes.hidden) {
            if (typeof width === 'number') {
              calcWidth += width
            } else if (typeof width === 'string') {
              width = width.replace("px","");
              calcWidth += Number(width)
            } else {
              calcWidth += '120'
            }
            if (i < this.columns.length - 1) {
              // calcWidth += ' + '
            }
          }
        })
        // calcWidth += ')'
        return calcWidth
      },

      //获取指定第v据屏幕右侧宽度
      getDivTopLength() {
        // var div = document.getElementsByClassName('input-table-input');
        // console.log(div);
        // var width1 = div.offsetWidth; //宽度
        // // var width2 =  div.getBoundingClientRect();
        // console.log(width1)
        // console.log(width2)
        // return  width2 - width1;
        return 600;
      },
    },
    //2.2新增 在组件内定义 指定父组件调用时候的传值属性和事件类型
    model: {
      prop: 'value',
      event: 'input'
    }
  }
</script>
<style scoped lang="less">
.input-table {
  //width: 100%;
  //padding: 1px;
  //position: relative;

  .showTable {
    display: block;
  }

  .hideTable {
    display: none;
  }

  .iconStyle {
    /*position: absolute;*/
    /*right: -200px;*/
    /*bottom:30px ;*/
    /*left: 60%;*/
  }
  .select-table-input {
    margin-right: 20px;
  }
}
</style>

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值