需求:
列表中有多条分页数据,可复选框也可单选,要求能将每页所选的数据展示出来,并传给后端,且能正常回显,后端存储时不会完整存储所选数据(如果后端存储完整,可将其做更大优化);保证在列表外删除其中任意数据也可以正常回显。
单选还是多选:
首先你在自己的组件中接收一个参数来区分是单选还是多选:
checkType: {//单选还是多选,radio单选;checkBox多选
required: false,
type: String,
default: 'radio'
},
其次如果是多选的话你还需要接收你已选择的数据,可能是服务器发过来的也可能是你上一次选了点确定后的数据:
selectionArray: {
//多选相关的数据对象是一个一维数组,而实际我们使用的是[[],[],[]],二维数组,数组的下标代表页码
required: false,
type: Array,
default: () => {
return []
}
}
若是单选就用不到element的selection复选框,可以直接在末尾新建一个操作列,里面放上选择按钮即可;绑定一个选择后触发的单选事件即可。
saveSelectVideo(row){//直接替换选择的数据即可,回显都可以不要,也可以根据ID高亮已选择的数据
//其他逻辑.....一般为清空和重置一些数据
/**这是我的代码,要用可以去掉注释
* this.selectVideoData.name = row.name;
this.selectVideoData.vod_id = row.vod_id;
this.selectVideoVisible = false;
this.keyWord = '';
*/
this.$emit('select', this.selectVideoData);
}
单选我就不多讲了,基本上就是刚刚说了你选择了哪个你就用v-if来控制那条数据高亮或者变色即可,根据产品需求来就是,我这里使用的是按钮选择数据;下面复选的我就按照业务逻辑和数据流转的顺序来一一把代码讲解了。这里以一个选择视频的复选框业务逻辑来讲,不要抠业务,业务跟你没关系。
data数据中应该声明的数据,这里有些数据不会用在渲染dom上,但是为了讲解还是放到data中便于大家理解,data信息如下:
data() {
return {
keyWord: '',//搜索用的关键字
selectVideoVisible: true,//控制弹窗的显隐
tableData: [],//可被选择的数据
pagination: {// 页码设置
perPage: 5,
totalCount: 1,
currentPage: 1
},
selectVideoData: {//被选择的数据,单选
name: '',
vod_id: ''
},
selectionArrayOrigin: [],//分页存储所选数据
assembleArr:[],//记录保存非本页被选中的数据
selectionArrayNow:[],//复制传过来的数据,避免控制台报错,很烦人,不要也行
};
页面构造我也给出来,可以适当更改:
<template>
<section>
<el-dialog class="create-live__vhall-select" :visible.sync="selectVideoVisible" width="750px" title="选择数据">
<section>
<header class="create-live__vh-search-warp">
<el-input placeholder="名称" v-model="keyWord" class="input-with-select" @keyup.enter.native="searchVideoFun">
<em slot="prepend" class="el-icon-search" />
</el-input>
</header>
<main class="create-live__vh-video-lists">
<el-table :data="tableData" style="width: 100%;min-height: 350px;" @select="selectionSelect" @select-all="selectionSelectAll" ref="multipleTable">
<el-table-column type="selection" width="60" v-if="checkType==='checkBox'" align='center' />
<el-table-column prop="id" label="ID" width="120" />
<el-table-column prop="name" label="名称" width="300" />
<el-table-column prop="created_at" label="创建时间" />
<el-table-column label="操作" width="83px" v-if="checkType!='checkBox'">
<span slot-scope="{ row }" @click="saveSelectVideo(row)" class="con-table-operate-btn">选择</span>
</el-table-column>
</el-table>
</main>
<footer class="con-pagination-wrapper" v-if="pagination['perPage'] < pagination['totalCount']">
<el-pagination background layout="prev, pager, next" :total="pagination['totalCount']" :page-size="5" @current-change="onPageChange" />
</footer>
<div class="checkBoxBtn">
<el-button type="primary" @click="sureSelect()" v-if="checkType==='checkBox'">确认</el-button>
</div>
</section>
</el-dialog>
</section>
</template>
- 组件被创建时:created()
第一步你需要做的就是把父组件传过来的数据保存起来,主要是用来对比你选择完数据后的新老数据差异来返回给父组件;有人就要问了,这有什么好比较的直接用你选择后的不就行了?其实不然,问题就在于你有些数据根本就没有看到还在其他分页呢,你必须要对比,没有的你不能改了,有的你要去重,在那一页的没有了你要删除。然后你还需要初始化数据,获取你要进行选择的列表。
this.selectionArrayNow=JSON.parse(JSON.stringify(this.selectionArray))
this.onShow();//获取你要进行选择的列表
- 获取数据
获取数据就很简单,直接从数据库拉取,并进行处理,这里我把翻页代码也写进来;
onShow() {
this.selectionArrayOrigin = [];
this.searchVideoFun();
},
async searchVideoFun() {//搜索
this.pagination.currentPage = 1;
this.tableData = [];
await this.getUploadList();
this.setSelction();//处理数据,数据回显的方法,下面会讲
},
async getUploadList() {//获取数据
const params = {
search: this.keyWord,
page: this.pagination.currentPage,
page_size: this.pagination.perPage
};
let res=await this.$http('getVodList', params);
this.pagination.totalCount = res.data.total;
this.tableData = res.data.list;
},
async onPageChange(page) {
this.pagination.currentPage = page;
await this.getUploadList();
this.setSelction()//处理数据,数据回显的方法,下面会讲
},
- 数据回显
回显这里就比较复杂,代码简单,就看你脑子转的快不快了,我直接在代码中进行讲解,使用时可以直接复制到你的代码中方便后人理解你的逻辑;
setSelction() {
//一进来首先就要判断是不是复选框,不是的话就不管了,也可以用return语句,但是我有两个条件,所以就不用了,另一个条件就是判断一下你已经选择的数据和可被选择的数据是不是有,没有的话你还对比什么呢?
if (this.checkType === 'checkBox' && this.selectionArrayNow.length > 0 && this.tableData.length > 0) {
//如果符合条件,那么久开始重置和清空一些变量保证每一次翻页或者打开弹窗不会被老数据干扰;
let selectionArr = []//这个就是你在需要返回给element的回显数据,记住一定要有你绑定的id,不然你都没法区分数据的唯一性,element看的是整个数据是不是一样的,包括一个符号;我这里有个特别坑的地方就是服务器返回给我的数据只有id和name,没有别的信息,必须要我去重新赋值一次才能用,但是不增加性能,因为你必须循环对比数据;注意细节就能够避免这个问题;
let dataIdS = []
this.assembleArr=[]
this.tableData.forEach(element => {//这一步就是把本页的id变成一个数组,方便后面用includes方法
dataIdS = dataIdS.concat(element.vod_id)
});
this.selectionArrayNow.forEach((element,index) => {//这里呢,就是来看我们有哪些数据是被选择的,只要包含了id就证明是被选择的
if (dataIdS.includes(element.vod_id)) {
this.selectionArrayNow[index]=this.tableData[dataIdS.indexOf(element.vod_id)]
selectionArr = selectionArr.concat(dataIdS.indexOf(element.vod_id))
}else{//记录不在此页且被选中的数据,以便在点击确认的时候会出现不知道被取消勾选的数据是不是本页的
this.assembleArr=this.assembleArr.concat(this.selectionArrayNow[index])
}
});
this.toggleSelection(selectionArr)//数据出来了,那么我们就要去显示在页面上
}
},
toggleSelection(rows) {//回显被选中的数据
this.$nextTick(() => {
if (rows) {
rows.forEach(row => {
this.$refs.multipleTable.toggleRowSelection(this.tableData[row]);
});
} else {//这个必须要不然你第二页如果没有选择的有数据,你不清就会有显示勾选
this.$refs.multipleTable.clearSelection();
}
})
},
- 选择数据
回显有了,咱是不是还得选啊?那么现在继续讲怎么选数据,并且插入;
selectionSelect(selection, row) {//单点
this.selectionArrayOrigin[this.pagination.currentPage - 1] = selection;//选了的就给他放进去就行了,是按分页存储的
//这个必须要,因为selectionArrayNow是没法记录顺序的,也没法不停的去重,否则性能消耗太大,同时你选择数据后,有可能就会出现当有人把某一条数据删除了或者增加了数据,你之前选择的某条数据本应该在第一页显示时,由于新增了数据就跑到后面页去了,删除的就是后面页数的数据跑到前面页了,选择的数据就会有差异[重复或缺失]
this.selectionArrayNow=this.assembleArr.concat(selection)//同时也别忘了更新当前的数据
},
selectionSelectAll(selection) {//全选
this.selectionArrayOrigin[this.pagination.currentPage - 1] = selection;
this.selectionArrayNow=this.assembleArr.concat(selection)
},
- 去重,反显数据到父组件
选完了,你还得点确定,然后返回给父组件吧?但是这里记得去重,因为有数据变动的话,你翻页的时候并不知道啊,你还以为你选择的数组是对的呢,但是有可能别人加了一条数据,你第二页的数据就出现了一条你第一页的数据,这样你就选择了两次;同时我们最后是把现有分页存储【selectionArrayOrigin】的已选择数据和当前所有被选择的数据合并了的,所以去重必须要。
sureSelect() {
let sureData = []
if (this.selectionArrayOrigin.length == 0 && this.selectionArrayNow.length == 0) {
this.$message.error("您还未选择视频!")
return
}
for (let i = 0; i < this.selectionArrayOrigin.length; i++) {
if (this.selectionArrayOrigin[i]) sureData = sureData.concat(this.selectionArrayOrigin[i])
}
sureData=sureData.concat(this.selectionArrayNow);
sureData=this.unique(sureData);
if (sureData.length > 10) {
this.$message.error("视频选择最多选择10个视频,请删除已选择的视频后在选择")
return
}
this.selectionArrayNow=sureData
this.$emit('select', sureData);
},
unique(arr) {
for (var i = 0; i < arr.length; i++) {
for (var j = i + 1; j < arr.length; j++) {
if (JSON.stringify(arr[i]) == JSON.stringify(arr[j])) { //第一个等同于第二个,splice方法删除第二个
arr.splice(j, 1);
j--;
}
}
}
return arr;
},
以上就是对《回显分页复选框》的总结,反正我在别的博客上没找到我这种,有的只是只显示本页的,一翻页或者一确定或者一保存刷新就没了;