diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..3dce4145 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,9 @@ +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 2 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true \ No newline at end of file diff --git a/docs/docs/zh-CN/components/tree.md b/docs/docs/zh-CN/components/tree.md index 678e5215..3d48176a 100644 --- a/docs/docs/zh-CN/components/tree.md +++ b/docs/docs/zh-CN/components/tree.md @@ -201,7 +201,7 @@ const iconCtrl = ref(false); const showLine = ref(true); const clickNode = ref(null); const showCheckbox = ref(true); -const checkedKeys = ref([9, 10, 24]); +const checkedKeys = ref([1]); function handleClick(node) { clickNode.value = node @@ -215,9 +215,9 @@ function handleClick(node) { ::: | Name | Description | Accepted Values | -| -------- | ---- | ----------------------- | -| name | 原始属性 name | -- | -| data | 树型组件数据,类型TreeData[] | null | +| -------- | ---- | ----------------------- | +| name | 原始属性 name | -- | +| data | 树型组件数据,类型TreeData[] | null | | showCheckbox | 是否显示复选框 | false | | onlyIconControl | 是否仅允许节点左侧图标控制展开收缩 | false | | showLine | 是否开启连接线 | true | @@ -229,5 +229,5 @@ function handleClick(node) { ::: | Name | Description | Accepted Params | -| -------- | ---- | ----------------------- | -| node-click | 节点 click 事件 | -- | +| -------- | ---- | ----------------------- | +| node-click | 节点 click 事件 | -- | diff --git a/src/module/tree/TreeEntity.vue b/src/module/tree/TreeEntity.vue index 72b73120..bad949ba 100644 --- a/src/module/tree/TreeEntity.vue +++ b/src/module/tree/TreeEntity.vue @@ -70,7 +70,7 @@ function handleNodeClick(node: TreeNode) { * @param node * @param type */ -function innerClick(node: TreeNode, type: EventType) { +function innerClick(node: TreeNode, type: EventType, e?: Event) { emit('node-click', node, type) } diff --git a/src/module/tree/index.ts b/src/module/tree/index.ts index 464cae2e..c8c5b39a 100644 --- a/src/module/tree/index.ts +++ b/src/module/tree/index.ts @@ -1,5 +1,6 @@ import type { App } from 'vue' import Component from './index.vue' +// import Component from './new-tree/index.vue' import type { IDefineComponent } from '../type/index' Component.install = (app: App) => { diff --git a/src/module/tree/new-tree/TreeNode.vue b/src/module/tree/new-tree/TreeNode.vue new file mode 100644 index 00000000..9d715e26 --- /dev/null +++ b/src/module/tree/new-tree/TreeNode.vue @@ -0,0 +1,170 @@ + + + + + + + diff --git a/src/module/tree/new-tree/index.vue b/src/module/tree/new-tree/index.vue new file mode 100644 index 00000000..51bc47e6 --- /dev/null +++ b/src/module/tree/new-tree/index.vue @@ -0,0 +1,94 @@ + + + + diff --git a/src/module/tree/new-tree/tree.ts b/src/module/tree/new-tree/tree.ts new file mode 100644 index 00000000..4d1064a4 --- /dev/null +++ b/src/module/tree/new-tree/tree.ts @@ -0,0 +1,166 @@ +/* + * @Date: 2021-10-16 02:50:17 + * @LastEditors: 落小梅 + * @LastEditTime: 2021-10-16 13:07:14 + * @FilePath: \layui-vue\src\module\tree\new-tree\tree.ts + */ +import { + OriginalTreeData, + StringOrNumber, +} from '/@src/module/tree/new-tree/tree.type' +import { Nullable } from '/@src/module/type' +import { Ref, ref } from 'vue' + +type CustomKey = string | number +type CustomString = (() => string) | string + +export interface TreeData { + id: CustomKey + title: CustomString + children: TreeData[] + parentKey: Nullable + isRoot: boolean + isChecked: Ref + isDisabled: Ref + isLeaf: Ref + hasNextSibling: boolean + parentNode: Nullable +} + +interface ReplaceFields { + id: string + title: string + children: string +} + +interface TreeConfig { + disabled: boolean + showCheckbox: boolean + checkedKeys: StringOrNumber[] + nodeMap: Map + replaceFields: ReplaceFields +} + +function getNode( + config: TreeConfig, + origin: OriginalTreeData, + parentKey: StringOrNumber, + hasNextSibling: boolean +): TreeData { + const { + disabled, + checkedKeys, + showCheckbox, + nodeMap, + replaceFields: { children, id, title }, + } = config + + const nodeKey = Reflect.get(origin, id) + const nodeTitle = Reflect.get(origin, title) + const nodeChildren = Reflect.get(origin, children) + const nodeDisabled = !!Reflect.get(origin, 'disabled') + const nodeIsLeaf = !!Reflect.get(origin, 'spread') + + // const parent = nodeMap.get(parentKey) + + // console.log((parent && parent.isChecked.value) || checkedKeys.includes(nodeKey)) + + // const isCheckedValue = (parent && parent.isChecked.value) || checkedKeys.includes(nodeKey) + + const node = Object.assign({}, origin, { + id: nodeKey, + title: nodeTitle, + children: nodeChildren ? nodeChildren : [], + parentKey: parentKey, + isRoot: parentKey === '', + isDisabled: ref(nodeDisabled), + isChecked: showCheckbox ? ref(checkedKeys.includes(nodeKey)) : ref(false), + // isChecked: ref(isCheckedValue), + isLeaf: ref(nodeIsLeaf), + hasNextSibling: hasNextSibling, + parentNode: null, + }) + // 如果全局设置了disabled,则全部至为true + if (disabled) { + node.isDisabled.value = true + } + + if (!nodeMap.has(nodeKey)) { + nodeMap.set(nodeKey, node) + } + + return node +} + +export function setParentNode( + nodes: TreeData[], + parentNode: Nullable = null +) { + const len = nodes.length + for (let i = 0; i < len; i++) { + Reflect.set(nodes[i], 'parentNode', parentNode) + if (nodes[i].children && nodes[i].children.length > 0) { + setParentNode(nodes[i].children, nodes[i]) + } + } +} + +class Tree { + private readonly config: TreeConfig + protected treeData: TreeData[] + + constructor( + config: TreeConfig, + origin: OriginalTreeData | OriginalTreeData[] + ) { + this.config = config + this.treeData = this.createTree(origin) + } + + createTree( + origin: OriginalTreeData | OriginalTreeData[], + parentKey: StringOrNumber = '' + ): TreeData[] { + let data + if (!Array.isArray(origin)) { + data = Array.of( + Object.assign({}, origin, { + // isRoot: true, + // isChecked: ref(false), + // isExpand: ref(false), + // isDisabled: ref(false), + // isLeaf: ref(false), + }) + ) + } else { + data = origin + } + const nodeList: TreeData[] = [] + const { children } = this.config.replaceFields + + const len = data.length + for (let i = 0; i < len; i++) { + const node = getNode(this.config, data[i], parentKey, i < len - 1) + const nodeChildren = Reflect.get(node, children) + const nodeHasChildren = !!Reflect.get(node, children) + + if (nodeHasChildren) { + Reflect.set(node, children, this.createTree(nodeChildren, node.id)) + } + + nodeList.push(node) + } + return nodeList + } + + getData() { + return this.treeData + } + + setChecked(node: TreeData) { + const item = this.config.nodeMap.get(node.id) + console.log(item) + } +} + +export { Tree } diff --git a/src/module/tree/new-tree/tree.type.ts b/src/module/tree/new-tree/tree.type.ts new file mode 100644 index 00000000..2e643498 --- /dev/null +++ b/src/module/tree/new-tree/tree.type.ts @@ -0,0 +1,44 @@ +/* + * @Date: 2021-10-16 13:07:34 + * @LastEditors: 落小梅 + * @LastEditTime: 2021-10-16 13:29:06 + * @FilePath: \layui-vue\src\module\tree\new-tree\tree.type.ts + */ +export type StringFn = () => string +export type StringOrNumber = string | number +export type KeysType = (number | string)[] +export type EditType = boolean | ('add' | 'update' | 'delete') + +export interface OriginalTreeData { + title: StringFn | string + id: StringOrNumber + field: StringFn | string + children?: OriginalTreeData[] + disabled?: boolean +} + +export interface TreeProps { + checkedKeys?: KeysType + data: OriginalTreeData + showCheckbox?: boolean + edit?: EditType + accordion?: boolean + onlyIconControl?: boolean + showLine?: boolean + replaceFields?: { + id?: string + children?: string + title?: string + } +} + +export interface TreeEmits { + (e: 'update:checkedKeys', keys: KeysType): void + (e: 'node-click', node: OriginalTreeData, event: Event): void +} + +/** + * Tree + */ + +export interface Tree {} diff --git a/src/module/tree/new-tree/useTree.ts b/src/module/tree/new-tree/useTree.ts new file mode 100644 index 00000000..4ab7279f --- /dev/null +++ b/src/module/tree/new-tree/useTree.ts @@ -0,0 +1,51 @@ +import { TreeEmits, TreeProps } from '/@src/module/tree/new-tree/tree.type' +import { computed, ComputedRef, watch } from 'vue' +import { setParentNode, Tree, TreeData } from '/@src/module/tree/new-tree/tree' + +export declare type UseTree = ( + props: TreeProps, + emit: TreeEmits +) => { + nodeList: ComputedRef + handleCheckbox: (node: TreeData) => void +} + +export const useTree: UseTree = (props: TreeProps, emit: TreeEmits) => { + const tree = computed(() => { + return new Tree( + { + disabled: false, + nodeMap: new Map(), + replaceFields: { + id: 'id', + title: 'title', + children: 'children', + }, + showCheckbox: props.showCheckbox ?? false, + checkedKeys: props.checkedKeys ?? [], + }, + props.data + ) + }) + const nodeList = computed(() => { + const nodes = tree.value.getData() + setParentNode(nodes) + return nodes + }) + + watch( + () => nodeList, + (list) => { + }, + { deep: true } + ) + + function handleCheckbox(node: TreeData) { + tree.value.setChecked(node) + } + + return { + nodeList, + handleCheckbox, + } +} diff --git a/src/module/tree/treeHelper.ts b/src/module/tree/treeHelper.ts index 794ca562..e25ddfc0 100644 --- a/src/module/tree/treeHelper.ts +++ b/src/module/tree/treeHelper.ts @@ -6,7 +6,6 @@ import { WritableComputedRef } from 'vue' * 添加父级parentId * @param data * @param parentId - * @param checkedKeys */ export const generatorTreeData = ( data: TreeData[] | TreeNode[],