├── .browserslistrc
├── .github
└── workflows
│ └── main.yml
├── .gitignore
├── .npmrc
├── README-CN.md
├── README.md
├── babel.config.js
├── package-lock.json
├── package.json
├── public
├── favicon.ico
└── index.html
├── server.js
├── src
├── App.vue
├── ant-use.ts
├── assets
│ └── styles
│ │ ├── highlight.github.css
│ │ ├── iconfont.css
│ │ ├── index.scss
│ │ ├── reset.scss
│ │ └── variable.scss
├── components
│ ├── VirtualCheckbox
│ │ ├── demo.vue
│ │ ├── index.scss
│ │ └── index.tsx
│ ├── VirtualList
│ │ ├── demo.vue
│ │ ├── index.tsx
│ │ └── types.ts
│ ├── VirtualTree
│ │ ├── demo.vue
│ │ ├── index.scss
│ │ ├── index.tsx
│ │ ├── node.tsx
│ │ ├── render.tsx
│ │ ├── service.ts
│ │ ├── types.ts
│ │ └── uses备份.ts
│ ├── index.ts
│ ├── selections.ts
│ └── tsconfig.json
├── doc
│ ├── AsyncDataDemo.vue
│ ├── BaseDemo.vue
│ ├── CheckboxDemo.vue
│ ├── CustomIconDemo.vue
│ ├── CustomNodeDemo.vue
│ ├── DemoBox.vue
│ ├── HighlightCodes.json
│ ├── index.vue
│ ├── principle.png
│ ├── tableData.ts
│ ├── temp.vue
│ └── uses
│ │ └── index.ts
├── main.ts
└── shims-vue.d.ts
├── tsconfig.json
└── vue.config.js
/.browserslistrc:
--------------------------------------------------------------------------------
1 | > 1%
2 | last 2 versions
3 | not dead
4 |
--------------------------------------------------------------------------------
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | name: GitHub Actions Build and Deploy
2 | on:
3 | push:
4 | tags:
5 | - 'v*'
6 | jobs:
7 | build-and-deploy:
8 | runs-on: ubuntu-latest
9 | steps:
10 | - name: Checkout
11 | uses: actions/checkout@main # If you're using actions/checkout@v2 you must set persist-credentials to false in most cases for the deployment to work correctly.
12 | with:
13 | persist-credentials: false
14 | - name: Install and Build
15 | run: |
16 | npm install
17 | npm run-script build
18 | - name: Deploy
19 | uses: JamesIves/github-pages-deploy-action@3.7.1
20 | with:
21 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
22 | BRANCH: gh-pages
23 | FOLDER: dist
24 | CLEAN: true
25 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | dist
4 | lib
5 |
6 | # local env files
7 | .env.local
8 | .env.*.local
9 |
10 | # Log files
11 | npm-debug.log*
12 | yarn-debug.log*
13 | yarn-error.log*
14 | pnpm-debug.log*
15 |
16 | # Editor directories and files
17 | .idea
18 | .vscode
19 | *.suo
20 | *.ntvs*
21 | *.njsproj
22 | *.sln
23 | *.sw?
24 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | # registry=https://registry.npm.taobao.org
2 | # sass_binary_site=http://cdn.npm.taobao.org/dist/node-sass
3 |
--------------------------------------------------------------------------------
/README-CN.md:
--------------------------------------------------------------------------------
1 | # vue-virtual-tree
2 |
3 | > **该库已经废弃,请使用重构后的[virtual-tree](https://github.com/lycHub/ysx-library/blob/master/projects/VirtualTree/README.md)**
4 |
5 |
6 | ### 基于vue3封装的,大数据量专用的tree组件,如果数据量不大,用本组件有些浪费了
7 |
8 | [English](README.md) & 简体中文
9 |
10 | ## [文档 & 示例](https://lychub.github.io/vue-virtual-tree)
11 | ### [在线demo](https://stackblitz.com/edit/vue-virtual-tree-demos?file=src/App.vue)
12 | ### [在线demo v4](https://stackblitz.com/edit/vue-virtual-tree-demos-bvicgw?file=src/App.vue)
13 |
14 | ## 基本使用
15 |
16 | ```
17 | npm i vue-virtual-tree
18 | ```
19 |
20 | 全局注册, 但这会丢失类型,如果你用了typescript, 不推荐这种方式
21 | ``` js
22 | import { createApp } from 'vue';
23 | import VirTree from 'vue-virtual-tree';
24 |
25 | createApp(App).use(VirTree).mount('#app');
26 |
27 | In components:
28 |
<template>\n <div class=\"demo\">\n <a-button @click=\"selectedNode\">获取选中节点</a-button>\n <vir-tree\n ref=\"virTree\"\n :source=\"list\"\n :default-disabled-keys=\"defaultDisabledKeys\"\n :default-selected-key=\"defaultSelectedKey\"\n :default-expanded-keys=\"defaultExpandedKeys\"\n />\n </div>\n</template>\n\n<script lang=\"tsx\">\n import {defineComponent, onMounted, ref} from 'vue';\n import {TreeInstance, TreeNodeOptions} from \"vue-virtual-tree\";\n\n function recursion(path = '0', level = 3): TreeNodeOptions[] {\n const list = [];\n for (let i = 0; i < 10; i += 1) {\n const nodeKey = `${path}-${i}`;\n const treeNode: TreeNodeOptions = {\n nodeKey,\n name: nodeKey,\n children: [],\n hasChildren: true\n };\n\n if (level > 0) {\n treeNode.children = recursion(nodeKey, level - 1);\n } else {\n treeNode.hasChildren = false;\n }\n\n list.push(treeNode);\n }\n return list;\n }\n\n export default defineComponent({\n name: 'BaseDemo',\n setup() {\n const list = ref<TreeNodeOptions[]>([]);\n const virTree = ref<TreeInstance | null>(null);\n const defaultExpandedKeys = ref(['0-0', '0-1', '0-1-0']);\n const defaultSelectedKey = ref('0-0-1-0');\n const defaultDisabledKeys = ref(['0-0-1']);\n\n onMounted(() => {\n list.value = recursion();\n });\n const selectedNode = () => {\n\t\tconst node = virTree.value!.getSelectedNode();\n\t\tconsole.log('selected node', node);\n }\n return {\n list,\n virTree,\n selectedNode,\n defaultExpandedKeys,\n defaultSelectedKey,\n defaultDisabledKeys\n }\n }\n });\n</script>\n
"
5 | },
6 | "checkbox": {
7 | "source": "\n <template>\n <div class=\"demo\">\n <section>\n <h5>默认父子节点联动</h5>\n <a-button @click=\"halfNodes\">获取半选节点</a-button>\n <vir-tree ref=\"virTreeOne\" show-checkbox :source=\"list\" :default-checked-keys=\"defaultCheckedKeys\" />\n </section>\n <section>\n <h5>父子节点不联动</h5>\n <a-button @click=\"checkedNodes\">获取勾选节点</a-button>\n <vir-tree ref=\"virTreeTwo\" show-checkbox check-strictly :source=\"list\" :default-checked-keys=\"defaultCheckedKeys\" />\n </section>\n </div>\n</template>\n\n<script lang=\"tsx\">\n import {defineComponent, onMounted, ref} from 'vue';\n import {TreeInstance, TreeNodeOptions} from \"vue-virtual-tree\";\";\n\n function recursion(path = '0', level = 3): TreeNodeOptions[] {\n const list = [];\n for (let i = 0; i < 10; i++) {\n const nodeKey = `${path}-${i}`;\n const treeNode: TreeNodeOptions = {\n nodeKey,\n name: nodeKey,\n children: [],\n hasChildren: true\n };\n\n if (level > 0) {\n treeNode.children = recursion(nodeKey, level - 1);\n } else {\n treeNode.hasChildren = false;\n }\n\n list.push(treeNode);\n }\n return list;\n }\n\n export default defineComponent({\n name: 'CheckboxDemo',\n setup() {\n const list = ref<TreeNodeOptions[]>([]);\n const virTreeOne = ref<TreeInstance | null>(null);\n const virTreeTwo = ref<TreeInstance | null>(null);\n const defaultCheckedKeys = ref(['0-0-0', '0-2']);\n\n\n onMounted(() => {\n list.value = recursion();\n });\n const halfNodes = () => {\n\t\tconst node = virTree.value!.getHalfCheckedNodes();\n\t\tconsole.log('halfNodes', node);\n }\n const checkedNodes = () => {\n\t\tconst node = virTree.value!.getCheckedNodes();\n\t\tconsole.log('checkedNodes node', node);\n }\n return {\n list,\n virTreeOne,\n virTreeTwo,\n halfNodes,\n checkedNodes,\n defaultCheckedKeys\n }\n }\n });\n</script>\n<style scoped lang=\"scss\">\n .demo {\n display: flex;\n justify-content: space-between;\n section {\n width: 45%;\n }\n }\n</style>\n
"
9 | },
10 | "asyncData": {
11 | "source": "\n <template>\n <div class=\"demo\">\n <button @click=\"checkedNodes\">获取勾选节点</button>\n <vir-tree ref=\"virTree\" :source=\"list\" show-checkbox :loadData=\"loadData\" />\n </div>\n</template>\n\n<script lang=\"tsx\">\n import {defineComponent, onMounted, ref} from 'vue';\n import { VirTree } from \"vue-virtual-tree\";\n import {TreeInstance, TreeNodeOptions} from \"vue-virtual-tree\";\n\n function recursion(path = '0'): TreeNodeOptions[] {\n const list = [];\n for (let i = 0; i < 2; i += 1) {\n const nodeKey = `${path}-${i}`;\n const treeNode: TreeNodeOptions = {\n nodeKey,\n name: nodeKey,\n children: [],\n hasChildren: true\n };\n list.push(treeNode);\n }\n return list;\n }\n\n export default defineComponent({\n name: 'AsyncDataDemo',\n components: { VirTree },\n setup(prop, {emit}) {\n const list = ref<TreeNodeOptions[]>([]);\n const virTree = ref<TreeInstance | null>(null);\n onMounted(() => {\n list.value = recursion();\n });\n const loadData = (node: TreeNodeOptions, callback: (children: TreeNodeOptions[]) => void) => {\n console.log('loadData', node);\n const result: TreeNodeOptions[] = [];\n for (let i = 0; i < 2; i += 1) {\n const nodeKey = `${node.nodeKey}-${i}`;\n const treeNode: TreeNodeOptions = {\n nodeKey,\n name: nodeKey,\n children: [],\n hasChildren: true\n };\n result.push(treeNode);\n }\n setTimeout(() => {\n callback(result);\n }, 500);\n }\n const checkedNodes = () => {\n const checks = virTree.value!.getCheckedNodes();\n console.log('checks', checks);\n }\n return {\n list,\n virTree,\n loadData,\n checkedNodes\n }\n }\n });\n</script>\n
"
13 | },
14 | "customNode": {
15 | "source": "\n <template>\n <div class=\"demo\">\n <vir-tree :source=\"list\" show-checkbox :render=\"renderNode\" />\n </div>\n</template>\n\n<script lang=\"tsx\">\n import {defineComponent, onMounted, ref} from 'vue';\n import { VirTree } from \"vue-virtual-tree\";\n import {TreeInstance, TreeNodeOptions} from \"vue-virtual-tree\";\n\n function recursion(path = '0', level = 3): TreeNodeOptions[] {\n const list = [];\n for (let i = 0; i < 10; i++) {\n const nodeKey = `${path}-${i}`;\n const treeNode: TreeNodeOptions = {\n nodeKey,\n name: nodeKey,\n children: [],\n hasChildren: true\n };\n\n if (level > 0) {\n treeNode.children = recursion(nodeKey, level - 1);\n } else {\n treeNode.hasChildren = false;\n }\n\n list.push(treeNode);\n }\n return list;\n }\n\n export default defineComponent({\n name: 'CustomNodeDemo',\n setup(prop, {emit}) {\n const list = ref<TreeNodeOptions[]>([]);\n onMounted(() => {\n list.value = recursion();\n });\n const renderNode = (node: TreeNodeOptions) => {\n return <div style=\"padding: 0 4px;\"><b style=\"color: #f60;\">{ node.name }</b></div>\n }\n return {\n list,\n renderNode\n }\n }\n });\n</script>"
17 | },
18 | "customIcon": {
19 | "source": "\n \n \n \n \n \n \n \n \n\n\n\n",
20 | "highlight": "<template>\n <div class=\"demo\">\n <vir-tree :source=\"list\" show-checkbox :loadData=\"loadData\">\n <template #icon=\"loading\">\n <i v-if=\"loading\" class=\"iconfont iconcustom-icon ico-loading\"></i>\n <i v-else class=\"iconfont iconzhankai\"></i>\n </template>\n </vir-tree>\n </div>\n</template>\n\n<script lang=\"tsx\">\nimport {defineComponent, onMounted, ref} from 'vue';\nimport { VirTree } from \"vue-virtual-tree\";\nimport { TreeNodeOptions } from \"vue-virtual-tree\";\n\nfunction recursion(path = '0'): TreeNodeOptions[] {\n const list = [];\n for (let i = 0; i < 2; i += 1) {\n const nodeKey = `${path}-${i}`;\n const treeNode: TreeNodeOptions = {\n nodeKey,\n name: nodeKey,\n children: [],\n hasChildren: true\n };\n list.push(treeNode);\n }\n return list;\n}\n\nexport default defineComponent({\n name: 'CustomIcon',\n setup(prop, {emit}) {\n const list = ref<TreeNodeOptions[]>([]);\n onMounted(() => {\n list.value = recursion();\n });\n const loadData = (node: TreeNodeOptions, callback: (children: TreeNodeOptions[]) => void) => {\n console.log('loadData', node);\n const result: TreeNodeOptions[] = [];\n for (let i = 0; i < 2; i += 1) {\n const nodeKey = `${node.nodeKey}-${i}`;\n const treeNode: TreeNodeOptions = {\n nodeKey,\n name: nodeKey,\n children: [],\n hasChildren: true\n };\n result.push(treeNode);\n }\n setTimeout(() => {\n callback(result);\n }, 500);\n }\n return {\n list,\n loadData\n }\n }\n});\n</script>\n
"
21 | },
22 | "searchNode": {
23 | "source": "\n \n \n \n \n \n \n\n\n\n",
24 | "highlight": "\n<template>\n <div class=\"demo\">\n <a-input placeholder=\"回车搜索\" @pressEnter=\"search\" />\n <section>\n <vir-tree show-checkbox :source=\"list\" :render=\"renderNode\" :default-expanded-keys=\"expandKeys\" />\n </section>\n </div>\n</template>\n\n<script lang=\"tsx\">\n import {defineComponent, onMounted, ref} from 'vue';\n import {TreeNodeOptions, NodeKey} from \"vue-virtual-tree\";\n\n interface TreeNodeOptionsWithParentPath extends TreeNodeOptions {\n parentPath: NodeKey;\n }\n\n const UNIQUE_WRAPPERS = ['##==-open_tag-==##', '##==-close_tag-==##'];\n function getParentPath (parent: TreeNodeOptionsWithParentPath | null): Array<string | number> {\n let result: Array<string | number> = [];\n if (parent) {\n const base = parent.parentPath || [];\n result = base.concat(parent.nodeKey);\n }\n return result;\n }\n function recursion(path = '0', level = 3, parent: TreeNodeOptionsWithParentPath | null = null): TreeNodeOptionsWithParentPath[] {\n const list = [];\n for (let i = 0; i < 10; i++) {\n const nodeKey = `${path}-${i}`;\n const treeNode: TreeNodeOptionsWithParentPath = {\n nodeKey,\n name: nodeKey,\n children: [],\n hasChildren: true,\n parentPath: getParentPath(parent)\n };\n\n if (level > 0) {\n treeNode.children = recursion(nodeKey, level - 1, treeNode);\n } else {\n treeNode.hasChildren = false;\n }\n\n list.push(treeNode);\n }\n return list;\n }\n\n export default defineComponent({\n name: 'SearchNodeDemo',\n setup() {\n const keywords = ref('');\n const list = ref<TreeNodeOptionsWithParentPath[]>([]);\n const expandKeys = ref<NodeKey[]>([]);\n onMounted(() => {\n list.value = recursion();\n // console.log('list', list.value);\n });\n const formatSearchValue = (value: string) => {\n return new RegExp(value.replace(/([.*+?^=!:${}()|[\\]\\/\\\\])/g, '\\\\$&'), 'i');\n }\n const findMatchedNodes = (keywords: string): TreeNodeOptionsWithParentPath[] => {\n const result: TreeNodeOptionsWithParentPath[] = [];\n const recursion = (list: TreeNodeOptionsWithParentPath[], parent: TreeNodeOptionsWithParentPath | null = null) => {\n for (const item of list) {\n const matched = formatSearchValue(keywords).test(item.name);\n if (matched) {\n result.push(item);\n }\n if (parent) {\n // parent.expanded = matched;\n }\n if (item.children?.length) {\n recursion(item.children as TreeNodeOptionsWithParentPath[], item);\n }\n }\n }\n if (keywords) {\n recursion(list.value);\n }\n return result;\n }\n const search = (event: KeyboardEvent) => {\n keywords.value = (event.target as HTMLInputElement).value;\n const matchedNodes = findMatchedNodes(keywords.value);\n if (matchedNodes.length) {\n // 取出parentPath > 拍扁 > 去重\n expandKeys.value = [...new Set(matchedNodes.map(item => item.parentPath).flat())];\n }\n }\n\n const transform = (value: string, matchValue: string) => {\n if (matchValue) {\n const wrapValue = value.replace(formatSearchValue(matchValue), `${UNIQUE_WRAPPERS[0]}$&${UNIQUE_WRAPPERS[1]}`);\n return wrapValue\n .replace(new RegExp(UNIQUE_WRAPPERS[0], 'g'), '<span style=\"color: #ff2041;\">')\n .replace(new RegExp(UNIQUE_WRAPPERS[1], 'g'), '</span>');\n }\n return value;\n }\n const renderNode = (node: TreeNodeOptions) => {\n const content = transform(node.name, keywords.value);\n return <div style=\"padding: 0 4px;\" innerHTML={ content } />;\n }\n return {\n list,\n search,\n renderNode,\n expandKeys\n }\n }\n });\n</script>\n
"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/doc/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 使用说明
5 |
6 |
7 | 安装
8 |
9 | npm i vue-virtual-tree
10 |
11 |
12 |
13 | 必须要传size属性
14 |
15 | 由于虚拟组件要监听滚动事件,动态替换node节点,所以需要知道每个节点的高度,
16 | 默认size=27,如果您要自定义渲染node或图标,那么务必将真实的size传进来,
17 | 另外还有remain属性,控制高度,超出隐藏,默认remain = 8
18 | 所以默认的tree.maxHeight = 27 * 8
19 |
20 |
21 |
22 |
23 | 关于自定义样式
24 |
25 | 组件已经提供自定义node节点和图标的功能(见下面示例),
26 | 如果还有些样式需要更细致的修改,请自行用css覆盖
27 |
28 |
29 |
30 | 关于刷新整个tree
31 |
32 | 处于性能考虑,tree内部监听 source时,并没有开启 deep
33 | 当你只改变source中的某个属性而view并未更新时,可能需要改变source的引用,比如 list.value = list.value.slice()
34 |
35 |
36 |
37 |
38 |
39 | 代码演示
40 |
41 |
42 |
47 |
48 |
49 |
54 |
55 |
56 |
61 |
62 |
63 |
64 |
65 |
70 |
71 |
72 |
77 |
78 |
79 |
80 |
81 |
82 |
83 | API
84 | Props
85 |
86 |
87 | 事件
88 |
89 |
90 | 方法
91 |
92 |
93 | TreeNodeOptions
94 |
101 |
102 |
103 |
104 |
105 |
133 |
134 |
152 |
--------------------------------------------------------------------------------
/src/doc/principle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lycHub/vue-virtual-tree/568d45ba4e179af3827193f67c6f05f910a1f172/src/doc/principle.png
--------------------------------------------------------------------------------
/src/doc/tableData.ts:
--------------------------------------------------------------------------------
1 | const columns = [
2 | {
3 | title: '参数',
4 | dataIndex: 'argument'
5 | },
6 | {
7 | title: '说明',
8 | dataIndex: 'description'
9 | },
10 | {
11 | title: '类型',
12 | dataIndex: 'type'
13 | },
14 | {
15 | title: '默认值',
16 | dataIndex: 'defaultValue'
17 | },
18 | {
19 | title: '版本号',
20 | dataIndex: 'version'
21 | }
22 | ];
23 | const methodColumns = [
24 | {
25 | title: '名称',
26 | dataIndex: 'name'
27 | },
28 | {
29 | title: '说明',
30 | dataIndex: 'description'
31 | },
32 | {
33 | title: '参数',
34 | dataIndex: 'type'
35 | },
36 | {
37 | title: '版本号',
38 | dataIndex: 'version'
39 | }
40 | ];
41 |
42 | const propData = [
43 | {
44 | argument: 'size',
45 | description: '用于虚拟计算,每个节点的高度',
46 | type: 'number',
47 | defaultValue: 27
48 | },
49 | {
50 | argument: 'remain',
51 | description: '用于虚拟计算,可视区内显示多少个节点',
52 | type: 'number',
53 | defaultValue: 8
54 | },
55 | {
56 | argument: 'source',
57 | description: '数据源',
58 | type: 'TreeNodeOptions[]',
59 | defaultValue: '[]'
60 | },
61 | {
62 | argument: 'showCheckbox',
63 | description: '勾选模式',
64 | type: 'boolean',
65 | defaultValue: 'false'
66 | },
67 | {
68 | argument: 'checkStrictly',
69 | description: '勾选时,父子不联动',
70 | type: 'boolean',
71 | defaultValue: 'false'
72 | },
73 | {
74 | argument: 'loadData',
75 | description: '异步加载',
76 | type: '(node: TreeNodeOptions, callback: (children: TreeNodeOptions[]) => void) => void',
77 | defaultValue: 'undefined'
78 | },
79 | {
80 | argument: 'render',
81 | description: '自定义渲染节点',
82 | type: '() => JSX.Element',
83 | defaultValue: 'undefined'
84 | },
85 | {
86 | argument: 'defaultExpandedKeys',
87 | description: '默认展开的nodeKey数组',
88 | type: 'Array',
89 | defaultValue: '[]',
90 | version: '4.0.0'
91 | },
92 | {
93 | argument: 'defaultDisabledKeys',
94 | description: '默认禁用的nodeKey数组',
95 | type: 'Array',
96 | defaultValue: '[]',
97 | version: '4.0.0'
98 | },
99 | {
100 | argument: 'defaultCheckedKeys',
101 | description: '默认勾选的nodeKey数组',
102 | type: 'Array',
103 | defaultValue: '[]',
104 | version: '4.0.0'
105 | },
106 | {
107 | argument: 'defaultSelectedKey',
108 | description: '默认选中的nodeKey',
109 | type: 'string | number',
110 | defaultValue: '',
111 | version: '4.0.0'
112 | },
113 | ];
114 | const eventData = [
115 | {
116 | name: 'selectChange',
117 | description: '选择节点时触发',
118 | type: '{ preSelectedNode: TreeNodeOptions; node: TreeNodeOptions; },preSelectedNode和node分别是之前选中和当前选中的节点'
119 | },
120 | {
121 | name: 'checkChange',
122 | description: '勾选节点时触发',
123 | type: '{ checked: boolean; node: TreeNodeOptions }'
124 | },
125 | {
126 | name: 'toggleExpand',
127 | description: '展开收起时触发',
128 | type: '{ status: boolean; node: TreeNodeOptions; },status是当前的展开状态'
129 | }
130 | ];
131 | const methodData = [
132 | {
133 | name: 'getSelectedNode',
134 | description: '获取选中的节点',
135 | type: '() => TreeNodeOptions | undefined'
136 | },
137 | {
138 | name: 'getCheckedNodes',
139 | description: '获取已勾选的节点',
140 | type: '() => TreeNodeOptions'
141 | },
142 | {
143 | name: 'getHalfCheckedNodes',
144 | description: '获取半勾选的节点',
145 | type: '() => TreeNodeOptions'
146 | },
147 | {
148 | name: 'getExpandedKeys',
149 | description: '获取已展开的nodeKeys',
150 | type: '() => Array',
151 | version: '4.0.0'
152 | }
153 | ];
154 | const nodeOptionData = [
155 | {
156 | argument: 'nodeKey',
157 | description: '必传,节点的唯一标识',
158 | type: 'string | number'
159 | },
160 | {
161 | argument: 'name',
162 | description: '必传,显示的节点名称',
163 | type: 'string'
164 | },
165 | {
166 | argument: 'hasChildren',
167 | description: '必传,用于判断是否还有children,控制展开图标的显示',
168 | type: 'boolean'
169 | },
170 | {
171 | argument: 'level',
172 | description: '层级,内部计算',
173 | type: 'number'
174 | },
175 | {
176 | argument: 'loading',
177 | description: '是否正在加载数据',
178 | type: 'boolean',
179 | defaultValue: 'false'
180 | },
181 | {
182 | argument: 'disabled',
183 | description: '是否禁用',
184 | type: 'boolean',
185 | defaultValue: 'false',
186 | version: '4.0.0已废弃'
187 | },
188 | {
189 | argument: 'expanded',
190 | description: '是否展开',
191 | type: 'boolean',
192 | defaultValue: 'false',
193 | version: '4.0.0已废弃'
194 | },
195 | {
196 | argument: 'selected',
197 | description: '是否选中',
198 | type: 'boolean',
199 | defaultValue: 'false',
200 | version: '4.0.0已废弃'
201 | },
202 | {
203 | argument: 'checked',
204 | description: '是否勾选',
205 | type: 'boolean',
206 | defaultValue: 'false',
207 | version: '4.0.0已废弃'
208 | },
209 | {
210 | argument: 'children',
211 | description: '子集',
212 | type: 'TreeNodeOptions[]',
213 | defaultValue: '[]'
214 | },
215 | {
216 | argument: 'parentKey',
217 | description: '父节点的nodeKey, 组件内部自动设置',
218 | type: 'string | number | null',
219 | defaultValue: 'null'
220 | },
221 | ];
222 |
223 | export { columns, methodColumns, propData, eventData, methodData, nodeOptionData };
224 |
--------------------------------------------------------------------------------
/src/doc/temp.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
113 |
--------------------------------------------------------------------------------
/src/doc/uses/index.ts:
--------------------------------------------------------------------------------
1 | import { message } from 'ant-design-vue';
2 | import {TreeInstance, TreeNodeOptions} from '../../components';
3 |
4 |
5 | function getSelectedNode(tree: TreeInstance) {
6 | const node = tree.getSelectedNode();
7 | console.log('selected node', node);
8 | if (node) {
9 | message.info(`选中了${node.name}`);
10 | } else {
11 | message.info('未选中节点');
12 | }
13 | }
14 |
15 |
16 | function getHalfCheckNodes(tree: TreeInstance) {
17 | const checks = tree.getHalfCheckedNodes();
18 | console.log('checks', checks);
19 | message.info(`${checks.length}个半选节点`);
20 | }
21 |
22 | function getCheckNodes(tree: TreeInstance) {
23 | const checks = tree.getCheckedNodes();
24 | console.log('checks', checks);
25 | message.info(`选中了${checks.length}条数据`);
26 | }
27 |
28 |
29 | export { getCheckNodes, getSelectedNode, getHalfCheckNodes }
30 |
--------------------------------------------------------------------------------
/src/main.ts:
--------------------------------------------------------------------------------
1 | import { createApp } from 'vue';
2 | import App from './App.vue';
3 | import AntUse from './ant-use';
4 | import VirTree from './components';
5 | import './assets/styles/index.scss';
6 | createApp(App)
7 | .use(AntUse)
8 | .use(VirTree)
9 | .mount('#app');
10 |
--------------------------------------------------------------------------------
/src/shims-vue.d.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | declare module '*.vue' {
3 | import type { DefineComponent } from 'vue'
4 | const component: DefineComponent<{}, {}, any>
5 | export default component
6 | }
7 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "esnext",
4 | "module": "esnext",
5 | "strict": true,
6 | "jsx": "preserve",
7 | "importHelpers": true,
8 | "moduleResolution": "node",
9 | "skipLibCheck": true,
10 | "esModuleInterop": true,
11 | "allowSyntheticDefaultImports": true,
12 | "sourceMap": true,
13 | "baseUrl": ".",
14 | "types": [
15 | "webpack-env"
16 | ],
17 | "lib": [
18 | "esnext",
19 | "dom",
20 | "dom.iterable",
21 | "scripthost"
22 | ]
23 | },
24 | "include": [
25 | "src/**/*.ts",
26 | "src/**/*.tsx",
27 | "src/**/*.vue",
28 | "tests/**/*.ts",
29 | "tests/**/*.tsx"
30 | ],
31 | "exclude": [
32 | "node_modules"
33 | ]
34 | }
35 |
--------------------------------------------------------------------------------
/vue.config.js:
--------------------------------------------------------------------------------
1 | const tsImportPluginFactory = require('ts-import-plugin');
2 | const lazyImport = () => ({
3 | before: [tsImportPluginFactory({
4 | libraryName: 'ant-design-vue',
5 | style: 'css'
6 | })]
7 | });
8 |
9 | module.exports = {
10 | productionSourceMap: false,
11 | css: {
12 | extract: false
13 | },
14 | pluginOptions: {
15 | 'style-resources-loader': {
16 | preProcessor: 'scss',
17 | patterns: ['./src/assets/styles/variable.scss']
18 | }
19 | },
20 | parallel: false,
21 | publicPath: process.env.NODE_ENV === 'production' ? '/vue-virtual-tree' : '/',
22 | chainWebpack(config) {
23 | config.module
24 | .rule('tsx')
25 | .use('ts-loader')
26 | .tap(options => {
27 | options.getCustomTransformers = lazyImport;
28 | // options.happyPackMode = false;
29 | return options
30 | })
31 | .end();
32 |
33 | config.module
34 | .rule('ts')
35 | .use('ts-loader')
36 | .tap(options => {
37 | options.getCustomTransformers = lazyImport;
38 | // options.happyPackMode = false;
39 | return options
40 | })
41 | .end();
42 | }
43 | }
44 |
--------------------------------------------------------------------------------