feat(tree): 完成树形组件复选框功能
This commit is contained in:
		
							parent
							
								
									c559a2d74a
								
							
						
					
					
						commit
						7caf70281c
					
				@ -60,6 +60,7 @@ module.exports = {
 | 
			
		||||
    '@typescript-eslint/explicit-module-boundary-types': 'off',
 | 
			
		||||
    'vue/one-component-per-file': 'off',
 | 
			
		||||
    '@typescript-eslint/no-non-null-assertion': 'off',
 | 
			
		||||
    'vue/no-mutating-props': 'off',
 | 
			
		||||
    'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
 | 
			
		||||
    'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
@ -6,6 +6,7 @@
 | 
			
		||||
    :onlyIconControl="iconCtrl"
 | 
			
		||||
    :showLine="showLine"
 | 
			
		||||
    :showCheckbox="showCheckbox"
 | 
			
		||||
    v-model:checkedKeys="checkedKeys"
 | 
			
		||||
    @node-click="handleClick"
 | 
			
		||||
  >
 | 
			
		||||
  </lay-tree>
 | 
			
		||||
@ -14,6 +15,10 @@
 | 
			
		||||
  <br/>
 | 
			
		||||
  <lay-switch v-model="showCheckbox"></lay-switch>
 | 
			
		||||
  <br/>
 | 
			
		||||
  checkedKeys:
 | 
			
		||||
  <pre>
 | 
			
		||||
    {{ checkedKeys }}
 | 
			
		||||
  </pre>
 | 
			
		||||
  只能通过节点左侧图标来展开收缩:
 | 
			
		||||
  <br/>
 | 
			
		||||
  <lay-switch v-model="iconCtrl"></lay-switch>
 | 
			
		||||
@ -25,207 +30,178 @@
 | 
			
		||||
  当前点击的节点:
 | 
			
		||||
  <br/>
 | 
			
		||||
  <pre>
 | 
			
		||||
{{ clickNode }}
 | 
			
		||||
    {{ clickNode }}
 | 
			
		||||
  </pre>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script setup>
 | 
			
		||||
import { ref } from 'vue';
 | 
			
		||||
 | 
			
		||||
const data = ref([
 | 
			
		||||
  {
 | 
			
		||||
    title: '一级1',
 | 
			
		||||
    id: 1,
 | 
			
		||||
    field: 'name1',
 | 
			
		||||
    checked: true,
 | 
			
		||||
    spread: true,
 | 
			
		||||
    children: [
 | 
			
		||||
      {
 | 
			
		||||
        title: '二级1-1 可允许跳转',
 | 
			
		||||
        id: 3,
 | 
			
		||||
        field: 'name11',
 | 
			
		||||
        href: 'https://www.layui.com/',
 | 
			
		||||
        children: [
 | 
			
		||||
          {
 | 
			
		||||
            title: '三级1-1-3',
 | 
			
		||||
            id: 23,
 | 
			
		||||
            field: '',
 | 
			
		||||
            children: [
 | 
			
		||||
              {
 | 
			
		||||
                title: '四级1-1-3-1',
 | 
			
		||||
                id: 24,
 | 
			
		||||
                field: '',
 | 
			
		||||
                children: [
 | 
			
		||||
                  {
 | 
			
		||||
                    title: '五级1-1-3-1-1',
 | 
			
		||||
                    id: 30,
 | 
			
		||||
                    field: '',
 | 
			
		||||
                  },
 | 
			
		||||
                  {
 | 
			
		||||
                    title: '五级1-1-3-1-2',
 | 
			
		||||
                    id: 31,
 | 
			
		||||
                    field: '',
 | 
			
		||||
                  },
 | 
			
		||||
                ],
 | 
			
		||||
              },
 | 
			
		||||
            ],
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            title: '三级1-1-1',
 | 
			
		||||
            id: 7,
 | 
			
		||||
            field: '',
 | 
			
		||||
            children: [
 | 
			
		||||
              {
 | 
			
		||||
                title: '四级1-1-1-1 可允许跳转',
 | 
			
		||||
                id: 15,
 | 
			
		||||
                field: '',
 | 
			
		||||
                href: 'https://www.layui.com/doc/',
 | 
			
		||||
              },
 | 
			
		||||
            ],
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            title: '三级1-1-2',
 | 
			
		||||
            id: 8,
 | 
			
		||||
            field: '',
 | 
			
		||||
            children: [
 | 
			
		||||
              {
 | 
			
		||||
                title: '四级1-1-2-1',
 | 
			
		||||
                id: 32,
 | 
			
		||||
                field: '',
 | 
			
		||||
              },
 | 
			
		||||
            ],
 | 
			
		||||
          },
 | 
			
		||||
        ],
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        title: '二级1-2',
 | 
			
		||||
        id: 4,
 | 
			
		||||
        spread: true,
 | 
			
		||||
        children: [
 | 
			
		||||
          {
 | 
			
		||||
            title: '三级1-2-1',
 | 
			
		||||
            id: 9,
 | 
			
		||||
            field: '',
 | 
			
		||||
            disabled: true,
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            title: '三级1-2-2',
 | 
			
		||||
            id: 10,
 | 
			
		||||
            field: '',
 | 
			
		||||
          },
 | 
			
		||||
        ],
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        title: '二级1-3',
 | 
			
		||||
        id: 20,
 | 
			
		||||
        field: '',
 | 
			
		||||
        children: [
 | 
			
		||||
          {
 | 
			
		||||
            title: '三级1-3-1',
 | 
			
		||||
            id: 21,
 | 
			
		||||
            field: '',
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            title: '三级1-3-2',
 | 
			
		||||
            id: 22,
 | 
			
		||||
            field: '',
 | 
			
		||||
          },
 | 
			
		||||
        ],
 | 
			
		||||
      },
 | 
			
		||||
    ],
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    title: '一级2',
 | 
			
		||||
    id: 2,
 | 
			
		||||
    field: '',
 | 
			
		||||
    spread: true,
 | 
			
		||||
    children: [
 | 
			
		||||
      {
 | 
			
		||||
        title: '二级2-1',
 | 
			
		||||
        id: 5,
 | 
			
		||||
        field: '',
 | 
			
		||||
        spread: true,
 | 
			
		||||
        children: [
 | 
			
		||||
          {
 | 
			
		||||
            title: '三级2-1-1',
 | 
			
		||||
            id: 11,
 | 
			
		||||
            field: '',
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            title: '三级2-1-2',
 | 
			
		||||
            id: 12,
 | 
			
		||||
            field: '',
 | 
			
		||||
          },
 | 
			
		||||
        ],
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        title: '二级2-2',
 | 
			
		||||
        id: 6,
 | 
			
		||||
        field: '',
 | 
			
		||||
        children: [
 | 
			
		||||
          {
 | 
			
		||||
            title: '三级2-2-1',
 | 
			
		||||
            id: 13,
 | 
			
		||||
            field: '',
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            title: '三级2-2-2',
 | 
			
		||||
            id: 14,
 | 
			
		||||
            field: '',
 | 
			
		||||
            disabled: true,
 | 
			
		||||
          },
 | 
			
		||||
        ],
 | 
			
		||||
      },
 | 
			
		||||
    ],
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    title: '一级3',
 | 
			
		||||
    id: 16,
 | 
			
		||||
    field: '',
 | 
			
		||||
    children: [
 | 
			
		||||
      {
 | 
			
		||||
        title: '二级3-1',
 | 
			
		||||
        id: 17,
 | 
			
		||||
        field: '',
 | 
			
		||||
        fixed: true,
 | 
			
		||||
        children: [
 | 
			
		||||
          {
 | 
			
		||||
            title: '三级3-1-1',
 | 
			
		||||
            id: 18,
 | 
			
		||||
            field: '',
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            title: '三级3-1-2',
 | 
			
		||||
            id: 19,
 | 
			
		||||
            field: '',
 | 
			
		||||
          },
 | 
			
		||||
        ],
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        title: '二级3-2',
 | 
			
		||||
        id: 27,
 | 
			
		||||
        field: '',
 | 
			
		||||
        children: [
 | 
			
		||||
          {
 | 
			
		||||
            title: '三级3-2-1',
 | 
			
		||||
            id: 28,
 | 
			
		||||
            field: '',
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            title: '三级3-2-2',
 | 
			
		||||
            id: 29,
 | 
			
		||||
            field: '',
 | 
			
		||||
          },
 | 
			
		||||
        ],
 | 
			
		||||
      },
 | 
			
		||||
    ],
 | 
			
		||||
  },
 | 
			
		||||
]);
 | 
			
		||||
const data = ref([{
 | 
			
		||||
	title: '一级1',
 | 
			
		||||
	id: 1,
 | 
			
		||||
	field: 'name1',
 | 
			
		||||
	checked: true,
 | 
			
		||||
	spread: true,
 | 
			
		||||
	children: [{
 | 
			
		||||
		title: '二级1-1 可允许跳转',
 | 
			
		||||
		id: 3,
 | 
			
		||||
		field: 'name11',
 | 
			
		||||
		href: 'https://www.layui.com/',
 | 
			
		||||
		children: [{
 | 
			
		||||
			title: '三级1-1-3',
 | 
			
		||||
			id: 23,
 | 
			
		||||
			field: '',
 | 
			
		||||
			children: [{
 | 
			
		||||
				title: '四级1-1-3-1',
 | 
			
		||||
				id: 24,
 | 
			
		||||
				field: '',
 | 
			
		||||
				children: [{
 | 
			
		||||
					title: '五级1-1-3-1-1',
 | 
			
		||||
					id: 30,
 | 
			
		||||
					field: ''
 | 
			
		||||
				},
 | 
			
		||||
				{
 | 
			
		||||
					title: '五级1-1-3-1-2',
 | 
			
		||||
					id: 31,
 | 
			
		||||
					field: ''
 | 
			
		||||
				}]
 | 
			
		||||
			}]
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			title: '三级1-1-1',
 | 
			
		||||
			id: 7,
 | 
			
		||||
			field: '',
 | 
			
		||||
			children: [{
 | 
			
		||||
				title: '四级1-1-1-1 可允许跳转',
 | 
			
		||||
				id: 15,
 | 
			
		||||
				field: '',
 | 
			
		||||
				href: 'https://www.layui.com/doc/'
 | 
			
		||||
			}]
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			title: '三级1-1-2',
 | 
			
		||||
			id: 8,
 | 
			
		||||
			field: '',
 | 
			
		||||
			children: [{
 | 
			
		||||
				title: '四级1-1-2-1',
 | 
			
		||||
				id: 32,
 | 
			
		||||
				field: ''
 | 
			
		||||
			}]
 | 
			
		||||
		}]
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		title: '二级1-2',
 | 
			
		||||
		id: 4,
 | 
			
		||||
		spread: true,
 | 
			
		||||
		children: [{
 | 
			
		||||
			title: '三级1-2-1',
 | 
			
		||||
			id: 9,
 | 
			
		||||
			field: '',
 | 
			
		||||
			disabled: true
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			title: '三级1-2-2',
 | 
			
		||||
			id: 10,
 | 
			
		||||
			field: ''
 | 
			
		||||
		}]
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		title: '二级1-3',
 | 
			
		||||
		id: 20,
 | 
			
		||||
		field: '',
 | 
			
		||||
		children: [{
 | 
			
		||||
			title: '三级1-3-1',
 | 
			
		||||
			id: 21,
 | 
			
		||||
			field: ''
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			title: '三级1-3-2',
 | 
			
		||||
			id: 22,
 | 
			
		||||
			field: ''
 | 
			
		||||
		}]
 | 
			
		||||
	}]
 | 
			
		||||
},
 | 
			
		||||
{
 | 
			
		||||
	title: '一级2',
 | 
			
		||||
	id: 2,
 | 
			
		||||
	field: '',
 | 
			
		||||
	spread: true,
 | 
			
		||||
	children: [{
 | 
			
		||||
		title: '二级2-1',
 | 
			
		||||
		id: 5,
 | 
			
		||||
		field: '',
 | 
			
		||||
		spread: true,
 | 
			
		||||
		children: [{
 | 
			
		||||
			title: '三级2-1-1',
 | 
			
		||||
			id: 11,
 | 
			
		||||
			field: ''
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			title: '三级2-1-2',
 | 
			
		||||
			id: 12,
 | 
			
		||||
			field: ''
 | 
			
		||||
		}]
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		title: '二级2-2',
 | 
			
		||||
		id: 6,
 | 
			
		||||
		field: '',
 | 
			
		||||
		children: [{
 | 
			
		||||
			title: '三级2-2-1',
 | 
			
		||||
			id: 13,
 | 
			
		||||
			field: ''
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			title: '三级2-2-2',
 | 
			
		||||
			id: 14,
 | 
			
		||||
			field: '',
 | 
			
		||||
			disabled: true
 | 
			
		||||
		}]
 | 
			
		||||
	}]
 | 
			
		||||
},
 | 
			
		||||
{
 | 
			
		||||
	title: '一级3',
 | 
			
		||||
	id: 16,
 | 
			
		||||
	field: '',
 | 
			
		||||
	children: [{
 | 
			
		||||
		title: '二级3-1',
 | 
			
		||||
		id: 17,
 | 
			
		||||
		field: '',
 | 
			
		||||
		fixed: true,
 | 
			
		||||
		children: [{
 | 
			
		||||
			title: '三级3-1-1',
 | 
			
		||||
			id: 18,
 | 
			
		||||
			field: ''
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			title: '三级3-1-2',
 | 
			
		||||
			id: 19,
 | 
			
		||||
			field: ''
 | 
			
		||||
		}]
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		title: '二级3-2',
 | 
			
		||||
		id: 27,
 | 
			
		||||
		field: '',
 | 
			
		||||
		children: [{
 | 
			
		||||
			title: '三级3-2-1',
 | 
			
		||||
			id: 28,
 | 
			
		||||
			field: ''
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			title: '三级3-2-2',
 | 
			
		||||
			id: 29,
 | 
			
		||||
			field: ''
 | 
			
		||||
		}]
 | 
			
		||||
	}]
 | 
			
		||||
}]);
 | 
			
		||||
 | 
			
		||||
const iconCtrl = ref(false);
 | 
			
		||||
const showLine = ref(true);
 | 
			
		||||
const clickNode = ref(null);
 | 
			
		||||
const showCheckbox = ref(true);
 | 
			
		||||
const checkedKeys = ref([9, 10, 24]);
 | 
			
		||||
 | 
			
		||||
function handleClick(node) {
 | 
			
		||||
 clickNode.value = node
 | 
			
		||||
 | 
			
		||||
@ -12,7 +12,8 @@ type EventType = 'icon' | 'node'
 | 
			
		||||
 | 
			
		||||
interface TreeEntityProps {
 | 
			
		||||
  node: TreeNode
 | 
			
		||||
  showCheckbox?: boolean
 | 
			
		||||
  showCheckbox?: boolean,
 | 
			
		||||
  updateCheckedByNode: (node: TreeNode) => void
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface EmitEvent {
 | 
			
		||||
@ -73,7 +74,14 @@ function innerClick(node: TreeNode, type: EventType) {
 | 
			
		||||
  emit('node-click', node, type)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
console.log(props.showCheckbox)
 | 
			
		||||
/**
 | 
			
		||||
 * checkbox click
 | 
			
		||||
 * @param arg
 | 
			
		||||
 * @param node
 | 
			
		||||
 */
 | 
			
		||||
function handleCheckboxChange (arg: { checked: boolean, value: string }, node: TreeNode) {
 | 
			
		||||
  props.updateCheckedByNode(node)
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
<template>
 | 
			
		||||
  <template v-if="node.children && node.children.length > 0">
 | 
			
		||||
@ -96,13 +104,12 @@ console.log(props.showCheckbox)
 | 
			
		||||
            v-if="showCheckbox"
 | 
			
		||||
            name="name"
 | 
			
		||||
            skin="primary"
 | 
			
		||||
            label="1"
 | 
			
		||||
            :checked="true"
 | 
			
		||||
            v-model:checked="node._checked"
 | 
			
		||||
            @change="(args) => { handleCheckboxChange(args, node) }"
 | 
			
		||||
          >
 | 
			
		||||
            {{ node.title }}
 | 
			
		||||
<!--            {{ node.title }} || {{node.id}}-->
 | 
			
		||||
          </LayCheckbox>
 | 
			
		||||
          <span
 | 
			
		||||
            v-else
 | 
			
		||||
            class="layui-tree-txt"
 | 
			
		||||
            @click.prevent.stop="handleNodeClick(node, 'node')"
 | 
			
		||||
          >
 | 
			
		||||
@ -119,8 +126,9 @@ console.log(props.showCheckbox)
 | 
			
		||||
          v-for="(item, index) in node.children"
 | 
			
		||||
          :key="index"
 | 
			
		||||
          :node="item"
 | 
			
		||||
          :show-checkbox="showCheckbox"
 | 
			
		||||
          @node-click="innerClick"
 | 
			
		||||
          :showCheckbox="showCheckbox"
 | 
			
		||||
          :updateCheckedByNode="updateCheckedByNode"
 | 
			
		||||
        />
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
@ -145,12 +153,11 @@ console.log(props.showCheckbox)
 | 
			
		||||
            name="name"
 | 
			
		||||
            skin="primary"
 | 
			
		||||
            label="1"
 | 
			
		||||
            :checked="true"
 | 
			
		||||
            v-model:checked="node._checked"
 | 
			
		||||
            @change="(args) => { handleCheckboxChange(args, node) }"
 | 
			
		||||
          >
 | 
			
		||||
            {{ node.title }}
 | 
			
		||||
          </LayCheckbox>
 | 
			
		||||
          <span
 | 
			
		||||
            v-else
 | 
			
		||||
            class="layui-tree-txt"
 | 
			
		||||
            @click.prevent.stop="handleNodeClick(node, 'node')"
 | 
			
		||||
          >
 | 
			
		||||
 | 
			
		||||
@ -163,10 +163,12 @@ const props = withDefaults(defineProps<TreeProps>(), {
 | 
			
		||||
 | 
			
		||||
const emit = defineEmits<TreeEmits>()
 | 
			
		||||
 | 
			
		||||
const { innerTreeData, updateInnerTreeData, treeWrapperClass } = useTreeData(
 | 
			
		||||
  props,
 | 
			
		||||
  emit
 | 
			
		||||
)
 | 
			
		||||
const {
 | 
			
		||||
  innerTreeData,
 | 
			
		||||
  updateInnerTreeData,
 | 
			
		||||
  treeWrapperClass,
 | 
			
		||||
  updateCheckedByNode,
 | 
			
		||||
} = useTreeData(props, emit)
 | 
			
		||||
 | 
			
		||||
function handleNodeClick(node: TreeNode, type: 'node' | 'icon') {
 | 
			
		||||
  // 是否只通过icon控制展开收起
 | 
			
		||||
@ -191,8 +193,9 @@ export default {
 | 
			
		||||
      v-for="(node, index) in innerTreeData"
 | 
			
		||||
      :key="node.id || index"
 | 
			
		||||
      :node="node"
 | 
			
		||||
      :show-checkbox="showCheckbox"
 | 
			
		||||
      @node-click="handleNodeClick"
 | 
			
		||||
      :showCheckbox="showCheckbox"
 | 
			
		||||
      :updateCheckedByNode="updateCheckedByNode"
 | 
			
		||||
    />
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
@ -176,6 +176,7 @@ export interface TreeNode extends TreeData {
 | 
			
		||||
  _parentNode?: Nullable<TreeNode>
 | 
			
		||||
  _nextSibling?: Nullable<TreeNode>
 | 
			
		||||
  _expand?: boolean
 | 
			
		||||
  _checked?: boolean
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** hook type **/
 | 
			
		||||
@ -188,4 +189,5 @@ export type UseTreeData = (
 | 
			
		||||
  spreadKeys: WritableComputedRef<(string | number)[]>
 | 
			
		||||
  treeWrapperClass: ComputedRef<Recordable>
 | 
			
		||||
  updateInnerTreeData: (treeData: TreeData[], node: TreeData) => void
 | 
			
		||||
  updateCheckedByNode: (treeNode: TreeNode) => void
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
import { TreeData, TreeNode } from '/@src/module/tree/tree.type'
 | 
			
		||||
import { Nullable } from '/@src/module/type'
 | 
			
		||||
import { WritableComputedRef } from 'vue'
 | 
			
		||||
import { Ref, WritableComputedRef } from "vue";
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 添加父级parentId
 | 
			
		||||
@ -10,8 +10,7 @@ import { WritableComputedRef } from 'vue'
 | 
			
		||||
 */
 | 
			
		||||
export const generatorTreeData = (
 | 
			
		||||
  data: TreeData[] | TreeNode[],
 | 
			
		||||
  parentId: TreeNode['parentId'] = '',
 | 
			
		||||
  checkedKeys: WritableComputedRef<(string | number)[]>
 | 
			
		||||
  parentId: TreeNode['parentId'] = ''
 | 
			
		||||
): TreeNode[] => {
 | 
			
		||||
  const innerTreeData: TreeNode[] = []
 | 
			
		||||
  const len = data.length
 | 
			
		||||
@ -20,10 +19,10 @@ export const generatorTreeData = (
 | 
			
		||||
    const inner = {
 | 
			
		||||
      ...item,
 | 
			
		||||
      parentId: parentId,
 | 
			
		||||
      spread: item.spread || false,
 | 
			
		||||
      spread: item.spread || false
 | 
			
		||||
    }
 | 
			
		||||
    if (item.children && item.children.length > 0) {
 | 
			
		||||
      inner.children = generatorTreeData(item.children, item.id, checkedKeys)
 | 
			
		||||
      inner.children = generatorTreeData(item.children, item.id)
 | 
			
		||||
    }
 | 
			
		||||
    innerTreeData.push(inner as TreeNode)
 | 
			
		||||
  }
 | 
			
		||||
@ -71,9 +70,10 @@ export const initialTreeData = (
 | 
			
		||||
  data: TreeData[],
 | 
			
		||||
  checkedKeys: WritableComputedRef<(string | number)[]>
 | 
			
		||||
): TreeNode[] => {
 | 
			
		||||
  const innerTree = generatorTreeData(data, '', checkedKeys)
 | 
			
		||||
  const innerTree = generatorTreeData(data, '')
 | 
			
		||||
  setNextSiblings(innerTree)
 | 
			
		||||
  setParentNode(innerTree)
 | 
			
		||||
  patchCheckedKeys(innerTree, checkedKeys)
 | 
			
		||||
  return innerTree
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -123,3 +123,88 @@ export const getEmitNode = (
 | 
			
		||||
  }
 | 
			
		||||
  return item
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * checkedKes分发到node
 | 
			
		||||
 * @param tree
 | 
			
		||||
 * @param checkedKeys
 | 
			
		||||
 * @param checked
 | 
			
		||||
 */
 | 
			
		||||
export const patchCheckedKeys = (tree: TreeNode[], checkedKeys: WritableComputedRef<(string | number)[]>, checked = false): void => {
 | 
			
		||||
  if (!checkedKeys.value) {
 | 
			
		||||
    return
 | 
			
		||||
  }
 | 
			
		||||
  const len = tree.length
 | 
			
		||||
  for (let i = 0; i < len; i++){
 | 
			
		||||
    tree[i]._checked = checked
 | 
			
		||||
    const node = tree[i]
 | 
			
		||||
    // 该节点是checked
 | 
			
		||||
    if (checkedKeys.value.indexOf(node.id) > -1) {
 | 
			
		||||
      node._checked = true
 | 
			
		||||
      if (node.children && node.children.length > 0) {
 | 
			
		||||
        patchCheckedKeys(node.children, checkedKeys, true)
 | 
			
		||||
      }
 | 
			
		||||
    } else {
 | 
			
		||||
      if (node.children && node.children.length > 0) {
 | 
			
		||||
        patchCheckedKeys(node.children, checkedKeys, false)
 | 
			
		||||
        // 判断children是否为都选中,如果是都选中的情况下,父组件也得是选中
 | 
			
		||||
        const allChildrenChecked = node.children.every(it => it._checked)
 | 
			
		||||
        if (allChildrenChecked) {
 | 
			
		||||
          node._checked = true
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function updateChildren(data: TreeNode[], flag: boolean) {
 | 
			
		||||
  for (let i = 0; i < data.length; i++) {
 | 
			
		||||
    data[i]._checked = flag
 | 
			
		||||
    if (data[i].children && data[i].children.length > 0) {
 | 
			
		||||
      updateChildren(data[i].children, flag)
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 更新树
 | 
			
		||||
 * @param data
 | 
			
		||||
 * @param clickNode
 | 
			
		||||
 * @param parentNode
 | 
			
		||||
 */
 | 
			
		||||
export function updateInnerTreeDataChecked(data: TreeNode[], clickNode: TreeNode, parentNode?: TreeNode) {
 | 
			
		||||
  const len = data.length
 | 
			
		||||
  for (let i = 0; i < len; i++) {
 | 
			
		||||
    const currentNode = data[i]
 | 
			
		||||
    // 找到当前更新的节点
 | 
			
		||||
    if (currentNode.id === clickNode.id) {
 | 
			
		||||
      // 如果当前节点有子节点,更新子节点
 | 
			
		||||
      if (currentNode.children && currentNode.children.length > 0) {
 | 
			
		||||
        updateChildren(data[i].children, currentNode._checked!)
 | 
			
		||||
      }
 | 
			
		||||
    } else {
 | 
			
		||||
      if (currentNode.children && currentNode.children.length > 0) {
 | 
			
		||||
        updateInnerTreeDataChecked(currentNode.children, clickNode, currentNode)
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    // 当前节点有选中,父节点一定选中
 | 
			
		||||
    if (currentNode.children && currentNode.children.length > 0) {
 | 
			
		||||
      currentNode._checked = currentNode.children.some(it => it._checked)
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function getCheckedKeys(tree: TreeNode[]): (string | number)[] {
 | 
			
		||||
  let keys: (string | number) [] = []
 | 
			
		||||
  const len = tree.length
 | 
			
		||||
  for (let i = 0; i < len; i++) {
 | 
			
		||||
    const current = tree[i]
 | 
			
		||||
    if (current._checked) {
 | 
			
		||||
      keys.push(current.id)
 | 
			
		||||
      if (current.children && current.children.length > 0) {
 | 
			
		||||
        keys = [...keys, ...getCheckedKeys(current.children)]
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  return keys
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,9 +1,10 @@
 | 
			
		||||
import { TreeData, TreeNode, UseTreeData } from '/@src/module/tree/tree.type'
 | 
			
		||||
import { computed, ref, unref, watch } from 'vue'
 | 
			
		||||
import {
 | 
			
		||||
  getCheckedKeys,
 | 
			
		||||
  getTreeSpreadKeys,
 | 
			
		||||
  initialTreeData,
 | 
			
		||||
} from '/@src/module/tree/treeHelper'
 | 
			
		||||
  initialTreeData, updateInnerTreeDataChecked
 | 
			
		||||
} from "/@src/module/tree/treeHelper";
 | 
			
		||||
import { Recordable } from '/@src/module/type'
 | 
			
		||||
 | 
			
		||||
export const useTreeData: UseTreeData = (props, emit) => {
 | 
			
		||||
@ -43,6 +44,16 @@ export const useTreeData: UseTreeData = (props, emit) => {
 | 
			
		||||
    { immediate: true, deep: true }
 | 
			
		||||
  )
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * watch innerTreeDate to emit checkedKeys
 | 
			
		||||
   * @param treeData
 | 
			
		||||
   * @param node
 | 
			
		||||
   */
 | 
			
		||||
  watch(innerTreeData, tree => {
 | 
			
		||||
    const emitCheckedKeys = getCheckedKeys(tree)
 | 
			
		||||
    checkedKeys.value = emitCheckedKeys
 | 
			
		||||
  }, { deep: true })
 | 
			
		||||
 | 
			
		||||
  function updateInnerTreeData(treeData: TreeData[], node: TreeData): void {
 | 
			
		||||
    for (let i = 0; i < treeData.length; i++) {
 | 
			
		||||
      if (treeData[i].id === node.id) {
 | 
			
		||||
@ -67,11 +78,20 @@ export const useTreeData: UseTreeData = (props, emit) => {
 | 
			
		||||
    }
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 更新checked状态到node中
 | 
			
		||||
   * @param node
 | 
			
		||||
   */
 | 
			
		||||
  function updateCheckedByNode (node: TreeNode) {
 | 
			
		||||
    updateInnerTreeDataChecked(innerTreeData.value, node)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return {
 | 
			
		||||
    spreadKeys,
 | 
			
		||||
    checkedKeys,
 | 
			
		||||
    innerTreeData,
 | 
			
		||||
    updateInnerTreeData,
 | 
			
		||||
    treeWrapperClass,
 | 
			
		||||
    updateCheckedByNode
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user