[更新]: 树形组件基础演示

This commit is contained in:
落小梅 2021-10-11 18:09:38 +08:00
parent 71e07cb0ac
commit 0617787e6a
7 changed files with 292 additions and 173 deletions

View File

@ -3,157 +3,227 @@
<template>
<lay-tree
:data="data"
:onlyIconControl="iconCtrl"
:showLine="showLine"
@node-click="handleClick"
>
</lay-tree>
</template>i
<br/>
只能通过节点左侧图标来展开收缩:
<br/>
<lay-switch v-model="iconCtrl"></lay-switch>
<br/>
只能通过节点左侧图标来展开收缩:
<br/>
<lay-switch v-model="showLine"></lay-switch>
<br/>
当前点击的节点:
<br/>
<pre>
{{ 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)
function handleClick(node) {
clickNode.value = node
}
</script>
:::

View File

@ -7,8 +7,9 @@ export default {
import LayIcon from '../icon'
import { TreeNode } from '/@src/module/tree/tree.type'
interface TreeEntityProps {
interface TreeEntityProps{
node: TreeNode
onlyIconControl: boolean
}
interface EmitEvent {
@ -31,7 +32,7 @@ const renderLineShort = (node: TreeNode): boolean => {
(node._parentNode._nextSibling === null ||
//线
(node._parentNode._nextSibling && !node._parentNode._nextSibling.children))
)
) as boolean
}
/**
* 展开收起 icon样式
@ -41,10 +42,22 @@ const nodeIconType = (node: TreeNode): string => {
return !node.spread ? 'layui-icon-addition' : 'layui-icon-subtraction'
}
/**
* 发射至外层
* @param node
*/
function handleNodeClick (node: TreeNode) {
emit('node-click', node)
}
/**
* 递归事件
* @param node
*/
function innerClick (node: TreeNode) {
emit('node-click', node)
}
</script>
<template>
<template v-if="node.children && node.children.length > 0">
@ -56,9 +69,9 @@ function handleNodeClick (node: TreeNode) {
}"
>
<div class="layui-tree-entry">
<div class="layui-tree-main" @click="handleNodeClick(node)">
<div class="layui-tree-main" @click.prevent.stop="!onlyIconControl && handleNodeClick(node)">
<span class="layui-tree-iconClick layui-tree-icon">
<LayIcon :type="nodeIconType(node)"></LayIcon>
<LayIcon :type="nodeIconType(node)" @click.prevent.stop="handleNodeClick(node)"></LayIcon>
</span>
<span class="layui-tree-txt">{{ node.title }}</span>
</div>
@ -72,7 +85,8 @@ function handleNodeClick (node: TreeNode) {
v-for="(item, index) in node.children"
:key="index"
:node="item"
@node-click="handleNodeClick"
@node-click="innerClick"
:onlyIconControl="onlyIconControl"
></LayTreeEntity>
</div>
</div>
@ -85,9 +99,9 @@ function handleNodeClick (node: TreeNode) {
}"
>
<div class="layui-tree-entry">
<div class="layui-tree-main">
<div class="layui-tree-main" @click.prevent.stop="!onlyIconControl && handleNodeClick(node)">
<span class="layui-tree-iconClick">
<LayIcon type="layui-icon-file"></LayIcon>
<LayIcon type="layui-icon-file" @click.prevent.stop="handleNodeClick(node)"></LayIcon>
</span>
<span class="layui-tree-txt">{{ node.title }}</span>
</div>

View File

@ -3,12 +3,13 @@ import { VNode, VNodeChild } from 'vue'
import TreeEntity from './TreeEntity.vue'
import { useTreeData } from '/@src/module/tree/useTreeData'
import { TreeNode } from '/@src/module/tree/tree.type'
import { getEmitNode } from '/@src/module/tree/treeHelper'
type EditAction = 'add' | 'update' | 'del'
type EditType = boolean | EditAction[]
export declare interface TreeData {
interface TreeData {
/**
* 节点唯一索引值用于对指定节点进行各类操作
*/
@ -107,40 +108,42 @@ export declare interface TreeProps {
}
export interface EmitData {
interface EmitData {
/**
* 当前点击的节点数据
*/
data: TreeData
/**
* 节点的展开状态
* remove
*/
state: 'open' | 'close' | 'normal'
state?: 'open' | 'close' | 'normal'
/**
* 当前节点元素
* remove
*/
elem: Element | VNode | VNodeChild
elem?: Element | VNode | VNodeChild
}
export interface TreeEmits {
interface TreeEmits {
/**
* 节点被点击后触发
* @param e 事件
* @param treeNode
*/
(e: 'on-click', treeNode: EmitData): void
(e: 'node-click', treeNode: EmitData): void
/**
* 点击复选框时触发
* @param e 事件
* @param treeNode
*/
(e: 'on-check', treeNode: EmitData): void
/**
* 操作节点的回
* @param e
* @param treeNode
*/
(e: 'on-operate', treeNode: EmitData): void
(e: 'node-check', treeNode: EmitData): void
// /**
// *
// * @param e
// * @param treeNode
// */
// (e: 'node-operate', treeNode: EmitData): void
(e: 'update:spreadKeys', spreadKeys: string[]): void
}
@ -163,6 +166,8 @@ const {
function handleNodeClick(node: TreeNode) {
updateInnerTreeData(innerTreeData.value, node)
const emitNode = getEmitNode(props.data!, node)
emit('node-click', { data: emitNode! })
}
</script>
@ -177,6 +182,7 @@ export default {
v-for="(node) in innerTreeData"
:key="node.id"
:node="node"
:onlyIconControl="onlyIconControl"
@node-click="handleNodeClick"
></TreeEntity>
</div>

View File

@ -116,32 +116,37 @@ export interface EmitData {
/**
*
*/
state: 'open' | 'close' | 'normal'
state?: 'open' | 'close' | 'normal'
/**
*
*/
elem: Element | VNode | VNodeChild
elem?: Element | VNode | VNodeChild
}
export interface TreeEmits {
export declare interface TreeEmits {
/**
*
* @param e
* @param treeNode
*/
(e: 'on-click', treeNode: EmitData): void
(e: 'node-click', treeNode: EmitData): void
/**
*
* @param e
* @param treeNode
*/
(e: 'on-check', treeNode: EmitData): void
(e: 'node-check', treeNode: EmitData): void
/**
*
* @param e
* @param treeNode
*/
(e: 'on-operate', treeNode: EmitData): void
// (e: 'on-operate', treeNode: EmitData): void
/**
* update:spreadKeys
* @param e
* @param spreadKeys
*/
(e: 'update:spreadKeys', spreadKeys: (string | number)[]): void
}

View File

@ -1,4 +1,5 @@
import { TreeData, TreeNode } from '/@src/module/tree/tree.type'
import { Nullable } from '/@src/module/type'
/**
* parentId
@ -83,3 +84,26 @@ export const getTreeSpreadKeys = (data: TreeData[]): (string | number)[] => {
}
return keys
}
/**
*
* @param data
* @param node
*/
export const getEmitNode = (data: TreeData[], node: TreeNode): Nullable<TreeData> => {
let item: Nullable<TreeData> = null
const len = data.length
for (let i = 0; i < len; i++) {
if (data[i].id === node.id) {
item = data[i]
break
}
if (data[i].children && data[i].children.length > 0) {
item = getEmitNode(data[i].children, node)
if (item) {
break
}
}
}
return item
}

View File

@ -12,7 +12,7 @@ export const useTreeData: UseTreeData = (props, emit) => {
}
return getTreeSpreadKeys(props.data)
},
set: (value) => {
set: (value: (string | number)[]) => {
emit('update:spreadKeys', value)
}
})