一、项目应用场景
- 最初需求:单纯要求封装【查询名称】的弹窗组件,能够进行勾选,名称展示到页面搜索条件的搜索框内。
- 实际考虑:在名称过多的情况下,用户不可能一页页点击table列表页码去查找对应的名称,如果能够直接搜索到想要的名称进行勾选,肯定能更好的提升用户体验。
二、代码实现
第一步:封装查询名称弹窗组件
<template>
<el-dialog
width="70%"
title="名称查询"
append-to-body
class="search-name"
:visible.sync="dialogVisible"
:before-close="closeDialog"
>
<div class="search-box">
<div class="search-box-input">
<span>名称:</span>
<el-input
clearable
placeholder="请输入"
v-model.trim="Name"
></el-input>
</div>
<el-button type="primary" class="search-btn" @click="handQuery">
查 询
</el-button>
</div>
<div class="tree-box" ref="treeBox" @scroll="handleScroll">
<el-table
:data="treedata"
border
ref="multipleTable"
:row-style="rowStyle"
:cell-style="cellStyle"
@selection-change="handleChangeSelection"
empty-text="暂无数据"
>
<el-table-column
type="selection"
width="55"
align="center"
></el-table-column>
<el-table-column
type="index"
label="序号"
width="85"
align="center"
:index="(index) => indexrank(index, this.pagenumber, this.pagesize)"
></el-table-column>
<el-table-column
property="name"
label="名称"
align="center"
></el-table-column>
</el-table>
</div>
<div class="list-pagination">
<Paging
ref="refPaging"
:total="parseInt(palnTotal)"
:pagesize="parseInt(pagesize)"
@pageNumChange="pageNumChange"
></Paging>
</div>
<div slot="footer">
<el-button @click="submitVal" type="primary" class="submit-btn">
确 认
</el-button>
<el-button @click="closeDialog()" class="cancel-btn">取 消</el-button>
</div>
</el-dialog>
</template>
<script>
import commonService from '@/api/common.js';
import Paging from '@/components/paging.vue';
export default {
props: {
dialogVisible: {
type: [Boolean],
default: false,
},
// 重置时清空选中数据
resetData: {
type: Array,
default: [],
},
},
components: {
Paging,
},
data() {
return {
stopReBack: false, // 防止回显成功前对表格进行操作的标识
scrollTop: 0,
palnTotal: 0,
Name: '',
treedata: [],
pagesize: 10,
pagenumber: 1,
checkData: [], // 选中的名称集合
rowStyle: { height: '32px' },
cellStyle: { padding: '8px' },
};
},
watch: {
dialogVisible(val) {
if (val) {
this.$nextTick(() => {
this.clearInfo();
this.$refs.refPaging.pageChange(1);
});
}
},
resetData(val) {
this.checkData = val;
},
},
methods: {
clearInfo() {
this.Name = '';
},
// 手动搜索
handQuery() {
this.pagenumber = 1; // 重置页码
this.queryName();
},
// 获取名称
queryName() {
let para = {
pagesize: this.pagesize,
pagenumber: this.pagenumber,
Name: this.Name ? this.Name : ''
};
commonService.queryName(para).then((res) => {
if (res && res.code == 200) {
if (res.data) {
this.treedata = res.data.list;
this.stopReBack = true;
setTimeout(() => {
this.checkData.map((item) => {
const b = this.treedata.find(
(it) => item.id == it.id,
);
if (b) {
this.$refs.multipleTable.toggleRowSelection(b, true);
}
});
this.stopReBack = false;
}, 50);
this.Total = res.data.total;
}
} else {
this.$message.error(res.message);
}
});
},
pageNumChange(val) {
this.pagenumber = val;
this.queryName();
},
// 选择方法
handleChangeSelection(value) {
if (this.stopReBack) {
return false;
}
const userList = JSON.parse(JSON.stringify(this.treedata)); //当前页、接口返回的数组
const selected = []; // 当前页选中数据
const unSelected = []; // 当前页未选中数据
// 遍历当前页数据,查找选中数据,分别放置不同的数组中
userList.map((item) => {
const b = value.find((it) => item.id == it.id);
b ? selected.push(item) : unSelected.push(item);
});
// 当前页选中数据selected遍历,在全部选中数据匹配查找,全部选中数据checkData中没有的信息,就塞入
selected.map((item) => {
const b = this.checkData.find((it) => item.id == it.id);
if (!b) {
this.checkData.push(item);
}
});
// 当前页未选中数据unSelected遍历,在全部选中数据匹配查找,全部选中数据checkData中有的信息,就删除
unSelected.map((item) => {
this.checkData.map((it, index) => {
if (item.id == it.id) {
this.checkData.splice(index, 1);
}
});
});
},
// 确认选中的,回显在父组件输入框
submitVal() {
if (this.checkData.length === 0) {
this.$message.error('请选择名称!');
return false;
} else {
this.$emit('getData', this.checkData);
this.closeDialog();
}
},
// 关闭弹窗
closeDialog() {
this.$emit('close');
},
// 弹窗高度
handleScroll() {
this.scrollTop = this.$refs.treeBox.scrollTop;
},
},
};
</script>
<style scoped>
.search-name >>> .el-dialog__body {
padding: 10px 30px 0px;
border-top: 1px solid #ececec;
}
.search-name >>> .el-dialog__header {
padding: 15px 20px;
}
.search-name >>> .el-dialog__headerbtn {
top: 12px;
}
.search-name >>> .el-dialog__headerbtn .el-dialog__close {
font-size: 25px;
display: block;
}
.search-box >>> .el-input {
width: 230px;
}
.search-box >>> .el-input--suffix .el-input__inner {
height: 32px;
}
.search-box {
display: flex;
flex-direction: row;
align-items: center;
padding-left: 10px;
justify-content: space-between;
}
.search-box >>> .el-input {
width: 170px;
}
.search-box >>> .el-input input {
width: 170px;
height: 32px;
}
.search-box >>> .el-input__icon {
line-height: 32px;
}
.search-box-input {
display: flex;
flex-direction: column;
}
.tree-box {
margin-top: 16px;
padding: 0 12px;
max-height: 200px;
overflow: auto;
}
.search-btn {
width: 85px;
height: 32px;
padding: 0;
margin-top: 14px;
background-color: #2e78ff;
}
.submit-btn {
width: 64px;
height: 32px;
padding: 0;
background-color: #2e78ff;
}
.cancel-btn {
width: 64px;
height: 32px;
padding: 0;
background-color: #fafafa;
border-color: #ddd;
color: #666;
margin-left: 4px;
}
.list-pagination {
padding: 22px 0 10px;
box-sizing: border-box;
display: flex;
justify-content: space-between;
}
</style>
第二步:组件应用
<template>
<NameDialog
:resetData="resetData" // 页面中点击重置按钮时,要清空弹窗中全选中数据
:dialogVisible="dialogVisible"
@getData="getData"
@close="closeDialog"
></NameDialog>
</template>
第三步:组件方法
<script>
import NameDialog from '@/components/searchName.vue';
export default {
components: {
NameDialog
},
data(){
return {
form: {
name: ''
},
resetData: [], //重置选中数据
dialogVisible: false, // 名称弹窗状态
}
},
methods:{
// 获取名称
getData(val) {
let Names = [];
val.forEach((item) => {
Names.push(item.name);
});
this.form.name = Names.join(',');
},
// 关闭计划名称弹窗
closeDialog() {
this.dialogVisible = false;
},
}
}
</script>
三、总结
- 名称组件封装,关注每次【打开弹窗】或点击【重置】按钮时,组件中接口查询或者页面展示数据的清除问题;
- 需求存在多级联动,例:省、市、区这种情况下更需要注意。