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>