layui tree复选框初始化父类菜单,子类菜单不全选

本文介绍了如何在前端使用tree.js库实现一个权限管理树,通过`checkChild`参数控制父级选中时子级的状态,并展示了同步选中子节点的代码和切换参数的技巧。关键点在于理解`checkChild`的使用和后台数据同步操作。
		//渲染
		tree.render({
			elem: '#access_tree'  //绑定元素
			,id: 'accessId'
			, data: getAllAccess("1,3,4,5,6,9")
			, accordion: true
			, onlyIconControl: true
			, showCheckbox: true
			, checkChild: false /*false 设置选中父级不选中子级*/
			, click: function (obj) {}
		});
		/**
		access_ids 是初始化要选中的id值字符串,用“,”隔开
		后台获取数据设置 选中的信息 加上 checked=True,没选中 checked=False
		*/
		function getAllAccess(access_ids){
			var data = [];
			var csrfToken = $("[name='csrfmiddlewaretoken']").val();
			$.ajax({
				url: "{% url 'access_all_list' %}", //后台数据请求地址
				type: "post",
				data: {"csrfmiddlewaretoken": csrfToken, "ids": access_ids},
				async: false,
				success: function(result){
					data = result.list;
				}
			});
			return data;
		}
/**
	tree.js中修改如下
**/

在这里插入图片描述checkChild:true 设置参数,true 则父级选中则一起选中所有子级,false 则父级选中,不选中子级

在这里插入图片描述这边是同步选中父级下的子级代码

在这里插入图片描述设置不全中父级下的子级后,再把参数设置为true。

<template> <view :class=“{ ‘next-tree’: !toEject, ‘next-tree-eject’: toEject }” v-if=“showTree”> <view v-if=“toEject” class=“next-tree-mask” :class=“{ show: showTree }” @tap=“_cancel(1)”></view> <view class=“next-tree-cnt” :class=“{ show: showTree }”> <view class=“next-tree-bar” v-if=“needBtn”> <view class=“next-tree-bar-cancel” :style=“{ color: cancelColor }” hover-class=“hover-c” @tap=“_cancel” >取消</view > <view class=“next-tree-bar-title” :style=“{ color: titleColor }”>{{ title }}</view> <view class=“next-tree-bar-confirm” :style=“{ color: confirmColor }” hover-class=“hover-c” @tap=“_confirm(1)” >确定</view > </view> <slot></slot> <view class=“next-tree-view” :style=“{ height: boxHeight, minHeight: ‘112px’ }”> <scroll-view class=“next-tree-view-sc” :scroll-y=“true” :style=“{ minHeight: ‘112px’ }”> <block v-for=“(item, index) in treeList” :key=“index”> <view class=“next-tree-item” :style=“[ { marginLeft: item.rank * 25 + ‘px’, zIndex: item.rank * -1 + 50 } ]” :class=“{ border: border === true, show: item.show, last: item.lastRank, showchild: item.showChild, open: item.open }” > <view class=“next-tree-label” :class=“{ checked: item.checked, disabled: item.disabled }” @tap.stop=“_treeItemTap(item, index)” > {{ item.name }} </view> <view class=“next-tree-check” @tap.stop=“_treeItemSelect(item, index)” v-if=“selectParent ? true : item.lastRank” > <view class=“next-tree-check-yes” v-if=“item.checked” :class=“{ radio: !multiple }”> <!-- <text class=“icon-text”>✔</text> --> <uni-icons :type=“checkIcon” color=“#0f56d5” /> </view> <view class=“next-tree-check-no” v-else :class=“{ radio: !multiple }”></view> </view> </view> </block> </scroll-view> </view> </view> <view v-if=“!toEject” class=“next-tree-mask-eject” :class=“{ show: showTree }” @tap=“_cancel(1)”></view> </view> </template> <script> /** zy-tree 树组件 @description 树组件 @property {Array} treeData 组件数据{needShowChild: true,当前项与父级展开,当前项子级展开 needOpen: true,当前项子级与父级展开,checked: true默认选中的,选中的父级自动打开} @property {String} valueKey 选中键名 @property {String} labelKey 展示键名 @property {String} childrenKey 子类数据键名 @property {String} title 标题 @property {Boolean} multiple 是否可以多选 @property {Boolean} selectParent = 是否可以选父级 @property {Boolean} foldAll = 折叠时关闭所有已经打开的子集,再次打开时需要一级一级打开 @property {String} confirmColor = 确定按钮颜色 @property {String} cancelColor = 取消按钮颜色 @property {String} titleColor = 标题颜色 @property {String} currentIcon = 展开时候的icon @property {String} checkIcon = 选中时候的icon @property {String} defaultIcon = 折叠时候的icon @property {String} lastIcon = 没有子集的icon @property {Boolean} border = 是否有分割线 @property {Boolean} needBtn = 是否有操作按钮 @property {Boolean} toEject = 是否是从底部弹出 @property {String} boxHeight = 是否是从底部弹出时组件可选区域的高度默认112px @property {Boolean} clickMask = 点击遮罩层关闭组件 @event {Function} 弹窗关闭触发的方法 @event {Function} 数据选中或有按钮时点击‘确定’触发的方法 @event {Function} 可通过ref调用组件内方法,进行组件的展示 @event {Function} 可通过ref调用组件内方法,进行组件的关闭但触发cancel事件 */ export default { name: ‘ZyTree’, props: { treeData: { type: Array, default: function () { return [] } }, valueKey: { type: String, default: ‘id’ }, labelKey: { type: String, default: ‘label’ }, childrenKey: { type: String, default: ‘children’ }, title: { type: String, default: ‘’ }, multiple: { // 是否可以多选 type: Boolean, default: true }, selectParent: { //是否可以选父级 type: Boolean, default: true }, foldAll: { //折叠时关闭所有已经打开的子集,再次打开时需要一级一级打开 type: Boolean, default: false }, confirmColor: { // 确定按钮颜色 type: String, default: ‘#0f56d5’ }, cancelColor: { // 取消按钮颜色 type: String, default: ‘#0f56d5’ }, titleColor: { // 标题颜色 type: String, default: ‘’ }, currentIcon: { // 展开时候的icon type: String, default: ‘folder’ }, checkIcon: { // 选中时候的icon type: String, default: ‘checkmarkempty’ }, defaultIcon: { // 折叠时候的icon type: String, default: ‘folder’ }, lastIcon: { // 没有子集的icon type: String, default: ‘’ }, border: { // 是否有分割线 type: Boolean, default: true }, needBtn: { // 是否有操作按钮 type: Boolean, default: false }, toEject: { // 是否是从底部弹出 type: Boolean, default: false }, boxHeight: { // 是否是从底部弹出时组件可选区域的高度默认100% type: String, default: ‘500px’ }, clickMask: { // 点击遮罩层关闭组件 type: Boolean, default: true } }, data() { return { showTree: false, treeList: [], selectIndex: -1, childNums: [], rt: [], rtName: [] } }, computed: {}, methods: { _show() { this.showTree = true this._confirm() }, _hide() { this.showTree = false }, _cancel(val) { if (val == 1 && !this.clickMask) return this._hide() this.$emit(‘cancel’, ‘’) }, _confirm(val) { this.rt = [] this.rtName = [] // 处理所选数据 this.treeList.forEach((item, i) => { if (item.id == 100 && item.checked) { return this.confirmEach(this.treeData) } if (item.checked && item.parentId && item.parentId != ‘100’) { this.rt.push(item.id) this.rtName.push(item.name) } }) if (val == 1) { this._cancel() } this.$emit(‘confirm’, { id: this.rt, name: this.rtName }) }, confirmEach(list) { list.forEach((item, index) => { if (item.isDy) { this.rtName.push(item.name) this.rt.push(item.id) } if (item.children && item.children.length > 0) this.confirmEach(item.children) }) }, //扁平化树结构 _renderTreeList(list = [], rank = 0, parentId = [], parents = []) { list.forEach(item => { this.treeList.push({ id: item[this.valueKey], name: item[this.labelKey], source: item, parentIdNub: item.parentId, parentId, // 父级id数组 parents, // 父级id数组 rank, // 层级 showChild: false, //子级是否显示 needShowChild: item.needShowChild ? item.needShowChild : false, //子级是否显示 open: false, //是否打开 needOpen: item.needOpen ? item.needOpen : false, //是否打开 show: rank === 0, // 自身是否显示 hideArr: [], orChecked: item.checked ? item.checked : false, checked: item.checked ? item.checked : false, disabled: item.disabled ? item.disabled : false }) if (Array.isArray(item[this.childrenKey]) && item[this.childrenKey].length > 0) { let parentid = […parentId], parentArr = […parents], childrenid = [] delete parentArr.children parentid.push(item[this.valueKey]) parentArr.push({ [this.valueKey]: item[this.valueKey], [this.labelKey]: item[this.labelKey] }) this._renderTreeList(item[this.childrenKey], rank + 1, parentid, parentArr) } else { this.treeList[this.treeList.length - 1].lastRank = true } }) }, _defaultSelect() { this.treeList.forEach(v => { if (v.checked) { this._handleCheckedNode(v) } if (v.needOpen) { this._handleOpenNode(v) } if (v.needShowChild) { this._handleShowChildNode(v) } }) }, _handleCheckedNode(v) { this.treeList.forEach(v2 => { if (v.parentId.toString().indexOf(v2.parentId.toString()) >= 0) { v2.show = true if (v.parentId.includes(v2.id)) { v2.showChild = true v2.open = true } } }) }, _handleOpenNode(v) { v.showChild = true v.open = true v.show = true this.treeList.forEach(v2 => { if (v2.parentId.toString().indexOf(v.id.toString()) >= 0) { v2.show = true if (v2.parentId.includes(v.id)) { v2.showChild = true v2.open = true } } if (v.parentId.includes(v2.id)) { v2.showChild = true v2.open = true } }) }, _handleShowChildNode(v) { this.treeList.forEach(v2 => { if (v.parentId.toString().indexOf(v2.parentId.toString()) >= 0) { v2.show = true if (v.parentId.includes(v2.id)) { v2.showChild = true v.showChild = true } } if (v.id === v2.id) { v.showChild = false v.open = false } }) }, // 点击 _treeItemTap(item, index) { if (item.disabled) return if (item.lastRank === true) { //点击最后一级时触发事件 this.treeList[index].checked = !this.treeList[index].checked this._fixMultiple(index) return } let list = this.treeList let id = item.id if (item.showChild && !item.open) { item.showChild = false item.open = false } else { item.showChild = !item.showChild } item.open = item.showChild ? true : !item.open list.forEach((childItem, i) => { if (item.showChild === false) { //隐藏所有子级 if (!childItem.parentId.includes(id)) { return } if (!this.foldAll) { if (childItem.lastRank !== true && !childItem.open) { childItem.showChild = false } // 为隐藏的内容添加一个标记 if (childItem.show) { childItem.hideArr[item.rank] = id } } else { if (childItem.lastRank !== true) { childItem.showChild = false } } childItem.show = false } else { // 打开子集 if (childItem.parentId[childItem.parentId.length - 1] === id) { childItem.show = true } // 打开被隐藏的子集 if (childItem.parentId.includes(id) && !this.foldAll) { if (childItem.hideArr[item.rank] === id) { childItem.show = true if (childItem.open && childItem.showChild) { childItem.showChild = true } else { childItem.showChild = false } childItem.hideArr[item.rank] = null } } } }) if (!this.needBtn) { this._confirm() } }, _treeItemSelect(item, index) { if (item.disabled) return this.treeList[index].checked = !this.treeList[index].checked // 选父级, 子级自动全选 this.syncChecked(this.treeList, item.id, this.treeList[index].checked) if (item.rank > 0) { item.parentId.forEach((pid, indexP) => { const parent = this.treeList.filter(i => i.id === pid) const childNum = parent.length > 0 ? parent[0].childNum : 0 if (this.childNums[pid] === undefined) { this.childNums[pid] = 1 } else if (this.childNums[pid] < childNum) { this.childNums[pid]++ } }) //子级选择/选满/取消选择, 父级往上同步状态 this.setAncestors(item.parentId, this.treeList[index].checked) } this._fixMultiple(index) if (!this.needBtn) { this._confirm() } }, syncChecked(trees, pid, checked) { trees.forEach((item, index) => { if (item.disabled) return if (item.parentId.includes(pid)) { this.treeList[index].checked = checked this.syncChecked(trees, item.id, checked) } else if (item.children !== undefined) { this.syncChecked(item.children, pid, checked) } }) }, setAncestors(pids, checked) { this.treeList.forEach((item, index) => { if (pids.includes(item.id)) { if (checked && this.childNums[item.id] !== undefined && item.childNum === this.childNums[item.id]) { // 子级全部选中, 父级才选中 this.treeList[index].checked = true } else { this.treeList[index].checked = false } this.setAncestors(item.parentId, checked) } }) }, // _treeItemSelect(item, index) { // this.treeList[index].checked = !this.treeList[index].checked // this._fixMultiple(index) // }, // 处理单选多选 _fixMultiple(index) { if (!this.multiple) { // 如果是单选 this.treeList.forEach((v, i) => { if (i != index) { this.treeList[i].checked = false } else { if (this.treeList[i].checked) { this.treeList[i].checked = true } else { this.treeList[i].checked = false } } }) } }, // 重置数据 _reTreeList() { this.treeList.forEach((v, i) => { this.treeList[i].checked = v.orChecked }) }, _initTree(treeData = this.treeData) { this.treeList = [] this._renderTreeList(treeData) this.$nextTick(() => { this._defaultSelect(treeData) }) } }, mounted() { console.log(‘----------next-tree组件完成挂载demo------------’) this._initTree() this.$watch( () => this.treeData, list => { this._initTree(list) }, { deep: true, immediate: true } ) this.$watch( () => [this.multiple, this.selectParent], () => { if (this.treeData.length) { this._reTreeList() } }, { deep: true, immediate: true } ) } } </script> <style lang=“scss”> @import ‘./style.scss’; </style> 改动当前组件next-tree-view内的内容,让其左右布局做多三列每一列,默认选中展开每一列的第一项,
06-06
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

风之梦丽

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值