背景介绍
Checkbox 多选框勾选选项后,界面上的选项按照勾选的先后顺序进行排列,实时更新选项顺序
图片预览
需求分析
- 勾选时设置顺序并把所选项提前
- 对未勾选的选项根据选项本身再进行排序
- 取消勾选时去掉排序后再按选项本身进行排序
- 实时更新组件,避免选项改变位置时,补位的选项无法选择问题
- 编辑时按顺序对选项进行回显
组件代码(以Element ui 组件Checkbox 多选框为例)
参数解析(已封装好组件,传对应参数即可)
componentName:"elCheckboxGroup", //组件名称
multiple:true, //是否多选
vModel:'newSelectEffectList', //v-model
checkboxGroupKey:'checkboxGroupKey', //更新组件值
checkboxListName:'allNewEffect' //选择列表
import(建议在main.js中引入)
import _ from "lodash";
data
data(){
return {
sortSelectEffectList:[], //勾选顺序列表
newSelectEffectList:[], //勾选值列表
checkboxGroupKey:'', //组件key
allNewEffect:[
{
label:'章鱼小丸子',
url:require('@/static/image/zyxwz.svg'),
value:'1'
},
{
label:'奥尔良烤翅',
url:require('@/static/image/aelkc.svg'),
value:'2'
},
{
label:'慕斯',
url:require('@/static/image/ms.svg'),
value:'3'
},
{
label:'布朗尼',
url:require('@/static/image/bln.svg'),
value:'4'
},
{
label:'提拉米苏',
url:require('@/static/image/tlms.svg'),
value:'5'
},
{
label:'牛肉干',
url:require('@/static/image/nrg.svg'),
value:'6'
},
{
label:'奶昔',
url:require('@/static/image/nx.svg'),
value:'7'
},
{
label:'奶茶',
url:require('@/static/image/nc.svg'),
value:'8'
},
{
label:'双皮奶',
url:require('@/static/image/spn.svg'),
value:'9'
},
{
label:'手抓饼',
url:require('@/static/image/szb.svg'),
value:'10'
},
{
label:'咖喱鱼丸',
url:require('@/static/image/klyw.svg'),
value:'11'
},
{
label:'寿司',
url:require('@/static/image/ss.svg'),
value:'12'
},
{
label:'北极贝',
url:require('@/static/image/bjb.svg'),
value:'13'
},
{
label:'三文治',
url:require('@/static/image/smz.svg'),
value:'14'
},
{
label:'冰激凌',
url:require('@/static/image/bql.svg'),
value:'15'
},
{
label:'烧烤',
url:require('@/static/image/sk.svg'),
value:'16'
},
{
label:'咚咚烧',
url:require('@/static/image/dds.svg'),
value:'17'
}
]
}
}
勾选时设置顺序并把所选项提前、对未勾选的选项根据选项本身再进行排序、取消勾选时去掉排序后再按选项本身进行排序
watch:{
newSelectEffectList:function (val,oldVal) {
if(val.length == oldVal.length){ //相等时默认按选项的排序进行勾选
this.allNewEffect.filter(v=>{
this.$set(v,'orderNum',v.value);
})
}else if(val.length > oldVal.length){
var differenceVal = _.difference(val,oldVal); //找出勾选的值
if(differenceVal.length > 1){ //编辑
this.sortSelectEffectList = differenceVal; //勾选的顺序
}else { //新增
this.sortSelectEffectList.push(differenceVal[0]);
}
this.sortSelectEffectList.filter((v,index)=>{ //按勾选顺序,重新排列选项
var effectIndex = _.findIndex(this.allNewEffect,['value',v]);
this.$set(this.allNewEffect[effectIndex],'orderNum',(index+1));
})
var orderNumList = [];
var orderList = [];
this.allNewEffect.filter((v,index)=>{
if(v.orderNum){
orderNumList.push(v);
}else {
orderList.push({label:v.label,url:v.url,value:Number(v.value)});
}
})
orderNumList = _.sortBy(orderNumList, 'orderNum'); //按orderNum排序
orderList = _.sortBy(orderList, 'value');//按orderList排序
this.allNewEffect = [];
this.allNewEffect = [...orderNumList,...orderList]; //合并数组
this.checkboxGroupKey = Math.round(); //更新组件
}else {
if(val.length == 0){
this.sortSelectEffectList = [];
}
var differenceVal = _.difference(oldVal,val)[0]; //找出取消勾选的值
if(differenceVal){
//将删除取消勾选的值对应的orderNumer
var clearTargetIndex = _.findIndex(this.allNewEffect,['value',differenceVal]);
delete this.allNewEffect[clearTargetIndex].orderNum; //删除orderNum参数
//按顺序设置(除已删除)以外的值
this.sortSelectEffectList = _.filter(this.sortSelectEffectList, function(o){return o !== differenceVal});
this.sortSelectEffectList.filter((v,index)=>{
var effectIndex = _.findIndex(this.allNewEffect,['value',v]);
this.$set(this.allNewEffect[effectIndex],'orderNum',(index+1));
})
var orderNumList = [];
var orderList = [];
this.allNewEffect.filter(v=>{
if(v.orderNum){
orderNumList.push(v);
}else {
orderList.push({label:v.label,url:v.url,value:Number(v.value)});
}
})
orderNumList = _.sortBy(orderNumList, 'orderNum'); //按orderNum排序
orderList = _.sortBy(orderList, 'value'); //按orderList排序
this.allNewEffect = [...orderNumList,...orderList]; //合并数组
this.checkboxGroupKey = Math.round(); //更新组件
}
}
}
}
编辑时按顺序对选项进行回显(触发监听方法)
methods:{
var that = this;
//请求数据进行回显
apiRequestParams(productManage,'getProduct',data,function (res) {
if(that.form.effectType.length > 0){ //存在选项时再进行操作
var selectList = [];
res.newSelectEffectList.filter(v=>{
selectList.push(v.value);
})
that.newSelectEffectList = selectList; //对newSelectEffectList进行赋值,赋值后会触发监听方法进行排序
}else{
//选项列表为空时,默认选择全部
that.allNewEffect.filter(v=>{
that.newSelectEffectList.push(v.value);
})
}
})
}
首次进界面时进行初始化
created(){
this.newSelectEffectList = [];
//默认选择全部
this.allNewEffect.filter(v=>{
this.newSelectEffectList.push(v.value);
})
}
效果
勾选后选项提前,取消勾选后会按照选项本身顺序进行排序,提交后会已勾选的选项参数会添加orderNum(按勾选顺序),回显时会按照orderNum顺序进行勾选,未勾选的按照选项本身进行排序
checkboxGroupKey
组件的Key用于更新组件 由于选项位置发生变化,勾选选项后,选项被提前,选项默认位置进行补位,会出现无法勾选的情况 所以需要添加checkboxGroupKey属性对组件进行更新
watch
在watch中添加合适的逻辑进行处理,在回显数据时直接触发这些逻辑达到实时更新效果
代码逻辑优化(三级菜单添加同级)
效果
//查找归属于某个类的菜单列表
searchCurrentMenu(id,list){ //目前菜单只有两个三层
//children,type,parentId 下级永远拥有一个父级(parentId)指向父级
var menuList = [];
if(list){
list.filter(v=>{
this.deepPermTreeData.filter(p=>{
if(v.id == p.parentId && !p.permissionsId){
menuList.push(p);
}
})
})
}else {
this.deepPermTreeData.filter(v=>{
if(v.parentId == id){
menuList.push(v);
}
})
}
return menuList;
},
//查找归属于某个类的权限菜单列表
searchPermissionsMenu(id,list){
var menuList = [];
if(list.length > 0){
this.deepPermTreeData.filter(p=>{
if(id == p.permissionsId){
menuList.push(p);
}
})
}
return menuList;
},
//递归菜单列表
deepMenuList(data){
data.filter(v=>{
this.$set(v,'checked',false);
var menuPermissionsList = _.filter(this.permissionsList, ['menuId', v.id]);
if(menuPermissionsList.length > 0){
_.forEach(menuPermissionsList,item=>{
item.rootId = item.id;
item.id = v.id + Math.random(5); // 避免权限菜单id与菜单id重复
item.type = 2; // 设置为三级菜单类型(层级)
item.parentId = v.id; // 归属于某个菜单下面
item.permissionsId = v.parentId; // 二级菜单父Id
// item.checked = false; 这种赋值形式会让动态列表无法勾选
this.$set(item,'checked',false);
this.$set(v.children,v.children.length,item); //往当前二级菜单子数组里添加权限菜单
});
}
this.deepPermTreeData.push(v);
if(v.children){ // 不能添加v.children.length > 0否则会跳过后面的执行
this.deepMenuList(v.children);
}
})
},
//勾选菜单(主要逻辑)
checkMenu(row){
// 查找当前节点父级
const parentList = this.findparent(row.parentId, [])
// 查找当前节点子级
const childList = this.findChild(row, [])
_.forEach(childList, item=>{
item.checked = row.checked
})
//取消勾选并且满足取消勾选条件
if(!row.checked && parentList.length>0) {
this.deepUncheck(row,parentList)
return ;
}
_.forEach(parentList, item=>{
item.checked = row.checked
})
},
//递归勾选条件(主要逻辑)
deepUncheck(row, parentList){
const allParentBrother = _.filter(this.deepPermTreeData, item=>{ // 找出所有比当前类型(级别)高的父级并且已勾选
return (item.type < row.type) && item.checked == true;
})
const sameple = _.filter(this.deepPermTreeData, item=>{ // 找出相同父级的兄弟元素并且已勾选
return (item.parentId == row.parentId) && item.checked == true;
})
// 规则:取消勾选时每一个父级都为一个时,代表当前列表的层级
if(allParentBrother.length >= row.type && sameple.length == 0){ // 父级元素大于等于当前层级并且相同父级的兄弟元素并且已勾选
const currentParent = _.find(parentList, ['id', row.parentId]); // 在parentList 找出与当前父级id匹配的父级并取消勾选
if(!!currentParent) {
currentParent.checked = false;
const currentParentList = this.findparent(currentParent.parentId,[]);
return this.deepUncheck(currentParent, currentParentList);
}
}
},
//找到对应父节点列表
findparent(id, parentList){
const parent = _.find(this.deepPermTreeData, ['id', id])
if(parent){
parentList.push(parent)
}
if(!parent || parent.parentId ==0) {
return parentList;
}
return this.findparent(parent.parentId, parentList)
},
//找到对应子节点列表
findChild(row, childList){
if(row.children){
_.forEach(row.children, item=>{
childList.push(item);
this.findChild(item, childList)
})
}
return childList;
}