Iview,table,Select表格动态新增,选择框远程搜索,输入内容后才调用接口

本文介绍了一种在表单中使用动态表格的场景,特别是针对大量数据的远程搜索优化方案。通过实现实时模糊搜索,减少数据量,提高用户体验。

1.应用场景:

在一个表单中,放了一个动态新增的表格,即一个表单对应多条表格中的数据。这个表格是动态新增的,用户可以新增多条。表格的其中的一个内容是下拉选择框,选项也是动态的,来自其他的表单保存后产生的内容,需要调用查询接口,返回数据当做选项。原先我是在用户登录时,就调用查询接口,把数据当做选项,放在全局state里,这样哪里都能用的,但是问题是不能实时。再有就是用来做选项的那个查询接口,返回的数据量实在是太了,七万多条,会导致用户在登录时就因为数据量过大崩溃。

2.期望:

用户在往选择框中输入内容时,才去调用方法,相当于实时模糊搜索,减小返回的数据量,后台同事也做了控制,一次性最多只返回一百条数据,作为选项,需要客户输入的内容越精确越好。

我本身十分的菜,于是求助同事,同事重写了这个表格的子组件,这个表格我是作为子组件和表单一起放在弹框中使用的。接下来我自己学习学习同事的代码,顺便也做个记录。

3.代码:

<template>
  <div>
    <Row>
      <Col span="24">
        <div class="one-title">开户行信息</div>
      </Col>    //先抄个iview表格的样式
      <Col span="24" style="text-align: center;line-height: 20px!important;">
        <div class="ivu-table-wrapper ivu-table-wrapper-with-border" style="margin-bottom: 10px;">
          <div class="ivu-table ivu-table-default ivu-table-border">
            <div class="ivu-table-header">
              <table cellspacing="0" cellpadding="0" border="0" style="width: 100%;">
                <thead>  //标题
                  <tr> //行
                    <th  //表头
                      v-for="(item, index) in cols"
                      :width="item.width || 'auto'"
                      :key="index"
                      class="ivu-table-column ivu-table-column-center"
                    >
                      <div class="ivu-table-cell">
                        <span class>{{item.title}}</span>
                      </div>
                    </th>
                  </tr>
                </thead>
              </table>
            </div>
            <div class="ivu-table-body">
              <table cellspacing="0" cellpadding="0" border="0" style="width: 100%;">
                <tbody class="ivu-table-tbody">
                  <tr   //动态新增这行
                    class="ivu-table-row"
                    v-for="(item, index) in bankData"   //bankData是我们新增或者是父组件传来的数据
                    :key="index"
                    v-if="item._del != 1"
                  >
                    <td  //单元格1  选择框
                      :width="cols[0].width || 'auto'"
                      class="ivu-table-column ivu-table-column-center"
                    >
                      <div class="ivu-table-cell">
                        <Select
                          v-model="item.bankName"
                          filterable  //远程搜索必须1
                          clearable
                          remote   //远程搜索必须2
                          :remote-method="queryRemote"   //远程搜索必须3  远程搜索的方法
                          :loading="selLoading"   //远程搜索必须4
                          @on-select="selectItem"
                          @on-open-change="openChange"
                          style="width:250px;max-height:200px"
                          :transfer="true"
                          placeholder="请搜索选择"
                        >
                          <Option
                            v-for="o in bankArray"  //bankArray是选项数组
                            :value="o.bankName"
                            :key="o.bankCode"    // key也必备
                            :label="o.bankName"  //显示初始值需设置这个
                          ></Option>
                        </Select>
                      </div>
                    </td>
                    <td  //单元格2  输入框
                      :width="cols[1].width || 'auto'"
                      class="ivu-table-column ivu-table-column-center"
                    >
                      <div class="ivu-table-cell">
                        <Input v-model="item.bankNo" placeholder="请输入开户行账号" />
                      </div>
                    </td>
                    <td   //单元格3  操作
                      :width="cols[2].width || 'auto'"
                      class="ivu-table-column ivu-table-column-center"
                    >
                      <div class="ivu-table-cell">
                        <a href="#" @click.prevent="bankDel(item,index)">删除</a>
                      </div>
                    </td>
                  </tr>
                </tbody>
              </table>
            </div>
            <div class="ivu-table-tip" v-if="!bankData.length">  //这是表格没数据时的展示内容
              <table cellspacing="0" cellpadding="0" border="0">
                <tbody>
                  <tr>
                    <td style="width: 100%;">
                      <span>暂无筛选结果</span>
                    </td>
                  </tr>
                </tbody>
              </table>
            </div>
          </div>
          <div class="ivu-table-resize-line" v-if="!bankData.length"></div>
          <object   //这是嵌入啥了?
            tabindex="-1"
            type="text/html"
            data="about:blank"
            style="display: block; position: absolute; top: 0px; left: 0px; width: 100%; height: 100%; border: none; padding: 0px; margin: 0px; opacity: 0; z-index: -1000; pointer-events: none;"
          ></object>
        </div>

        <Button type="dashed" long @click="bankAdd" icon="md-add" style="width: 300px;">新增</Button>
      </Col>
    </Row>
  </div>
</template>

<script>
import { invoiceBankPageData, getBanks } from "../../../api/whiteList";
export default {
  name: "bankInfo",
  props: {
    value: Boolean,
    bankList: {  //父组件传来的数据
      type: Array,
      default() {
        return [];
      }
    }
  },
  data() {
    return {
      tableLoading: false,
      selLoading: false,
      bankData: [],
      bankArray: [],
      searchLock: false,
      cols: [  //表头
        {
          title: "开户行名称",
          align: "center",
          key: "bankName",
          slot: "bankName"
        },
        { title: "开户行账号", align: "center", key: "bankNo", slot: "bankNo" },
        { title: "操作", align: "center", key: "", slot: "action", width: 150 }
      ]
    };
  },
  methods: {
    openChange(v) {  //下拉框张开收回时的触发动作
      this.searchLock = !v;
    },
    selectItem() {  // 选择项目时触发
      this.searchLock = true;
    },
    
    //当鼠标移入,输入内容的时候,距离上次调用这个接口过了0.38秒才执行。这是为了防止多次不必要调用接口?
    throttle(fn, wait) {   //节流函数
      var pre = Date.now();
      return () => {
        var ctx = this;
        var now = Date.now();
        var args = arguments;  //传进来的函数参数构成的一个数组
        if (now - pre >= wait) {
          fn.apply(ctx, args);
          pre = Date.now();
        }
      };
    },
    queryRemote(v) { //远程搜索的方法,能自己拿到搜索值
      !this.searchLock && this.throttle(this.getBankList(v), 380);
      //没选择而且展开时  
    },
    async getBankList(v) { //拿选项数据的接口
      if (v) {
        this.selLoading = true;
        let res = await getBanks({ bankName: v });
        this.selLoading = false;
        if (res.data.status == 0) this.bankArray = res.data.list;
      }
    },

    bankSave(row, index) {//表单内表格,一行一行,一个单元格一个单元格的校验
      row = row || {};
      if (row.bankName && !/^[\u4E00-\u9FA5]+$/.test(row.bankName)) {
        this.$Message.error("请输入正确开户行名称!");
        return false;
      }
      if (row.bankNo && !/^\d+$/.test(row.bankNo)) {
        this.$Message.error("请输入有效账户!");
        return false;
      }
      if (!row.bankName) {
        this.$Message.error("请完善开户行信息");
        return false;
      }
      return true;
    },
    // 删除开户行信息
    bankDel(item, index) {//删除信息是,给删除的那一条数据加上一个标识,在保存时过滤掉有删除标识的数据
      this.$Modal.confirm({
        title: "删除确认",
        content: "<p>您确定要删除该记录吗 ?</p>",
        onOk: () => {
          this.searchLock = true;
          // this.bankData.splice(index, 1);
          item._del = 1;
          this.$set(this.bankData, index, item);
        }
      });
    },
    bankAdd() {//点击新增时的动作
      let i = this.bankData.length;
      let o = {
        bankCode: "",
        bankName: "",
        bankNo: "",
        _id: `NEW_TEMP_ID_${i + 1}`
      };
      this.bankData.push(o);
    },

    saveAll() {//在父组件点击提交时做的校验,不符合校验规则则返回给父组件false结果
      let arr = this.bankData
        .filter(i => i._del != 1)
        .map(i => {
          i._id = null;
          return i;
        });


      for (let [index, item] of arr.entries()) { //校验表格数据的有效性,不符合校验规则就不能保存提交
        var result = this.bankSave(item, index);
        if (!result) return false;
      }
      this.$emit("bank-save", arr);
      return true;
    }
  },

  computed: {},
  watch: {
    bankList: {
      handler: function(n) {
        this.bankData = n && n.length ? n.slice() : n;
        this.searchLock = n.length > 0 ? true : false;
      },
      immediate: true,
      deep: true
    },
    value: function(n, o) {
      if (!n) {
        this.bankData = [];
        this.searchLock = false;
        this.bankArray = [];
      }
    }
  },
  created() {
  }
};
</script>

<style scoped>
.one-title {
  border-bottom: 1px solid #e8eaec;
  line-height: 30px;
  font-weight: 700;
  margin-bottom: 5px;
  font-size: 15px;
}
</style>

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值