diff --git a/devui/tree/index.ts b/devui/tree/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..6639f0e84a7a6c5b3c7465f98a624537a8d8104b --- /dev/null +++ b/devui/tree/index.ts @@ -0,0 +1,18 @@ +import type { App } from 'vue' +import Tree from './src/tree' + +Tree.install = function(app: App): void { + app.component(Tree.name, Tree) +} + +export { Tree } + +export default { + title: 'Tree 树', + category: '数据展示', + status: undefined, // TODO: 组件若开发完成则填入"已完成",并删除该注释 + install(app: App): void { + + app.use(Tree as any) + } +} diff --git a/devui/tree/src/assets/close.svg b/devui/tree/src/assets/close.svg new file mode 100644 index 0000000000000000000000000000000000000000..2bb8e7f8194373d0c40e23af4cc80c684c9c140a --- /dev/null +++ b/devui/tree/src/assets/close.svg @@ -0,0 +1,17 @@ + + + + + + diff --git a/devui/tree/src/assets/open.svg b/devui/tree/src/assets/open.svg new file mode 100644 index 0000000000000000000000000000000000000000..a69af88b169b95da702114d77e49b9a510ecfd21 --- /dev/null +++ b/devui/tree/src/assets/open.svg @@ -0,0 +1,14 @@ + + + + + + \ No newline at end of file diff --git a/devui/tree/src/composables/use-toggle.ts b/devui/tree/src/composables/use-toggle.ts new file mode 100644 index 0000000000000000000000000000000000000000..542ba2630ccf998b73a5d66aabbcb9b38a3ac672 --- /dev/null +++ b/devui/tree/src/composables/use-toggle.ts @@ -0,0 +1,24 @@ +import { ref } from 'vue' + +export default function useToggle(data: unknown): any { + const openedTree = (tree) => { + return tree.reduce((acc, item) => ( + item.open + ? acc.concat(item, openedTree(item.children)) + : acc.concat(item) + ), []) + } + + const openedData = ref(openedTree(data)) + + const toggle = (item) => { + console.log('toggle', item, item.id, item.open); + item.open = !item.open + openedData.value = openedTree(data) + } + + return { + openedData, + toggle, + } +} diff --git a/devui/tree/src/tree-types.ts b/devui/tree/src/tree-types.ts new file mode 100644 index 0000000000000000000000000000000000000000..1af7c611a55f22af2c21479f717c0115f772f71f --- /dev/null +++ b/devui/tree/src/tree-types.ts @@ -0,0 +1,19 @@ +import type { PropType, ExtractPropTypes } from 'vue' + +export interface TreeItem { + label: string + children: TreeData + [key: string]: any +} + +export type TreeData = Array + +export const treeProps = { + data: { + type: Array as PropType, + required: true, + default: () => [], + } +} as const + +export type TreeProps = ExtractPropTypes diff --git a/devui/tree/src/tree.scss b/devui/tree/src/tree.scss new file mode 100644 index 0000000000000000000000000000000000000000..84bcb33768b94b19c67558b4713a2349fc391093 --- /dev/null +++ b/devui/tree/src/tree.scss @@ -0,0 +1,3 @@ +.devui-tree { + // +} diff --git a/devui/tree/src/tree.tsx b/devui/tree/src/tree.tsx new file mode 100644 index 0000000000000000000000000000000000000000..99b4fcccac9de305baeac11d50856fd1f6623edb --- /dev/null +++ b/devui/tree/src/tree.tsx @@ -0,0 +1,64 @@ +import { defineComponent, toRefs } from 'vue' +import { treeProps, TreeProps } from './tree-types' +import { flatten } from './util' +import useToggle from './composables/use-toggle' +import IconOpen from './assets/open.svg' +import IconClose from './assets/close.svg' +import './tree.scss' + +export default defineComponent({ + name: 'DTree', + props: treeProps, + emits: [], + setup(props: TreeProps) { + const { data } = toRefs(props) + const flatData = flatten(data.value) + + const { openedData, toggle } = useToggle(data.value) + + const Indent = () => { + return + } + + const renderNode = (item) => { + return ( +
toggle(item)} + > + { + item.children + ? item.open ? : + : + } + { item.label } +
+ ) + } + + const renderTree = (tree) => { + return tree.map(item => { + if (!item.children) { + return renderNode(item) + } else { + return ( + <> + {renderNode(item)} + {renderTree(item.children)} + + ) + } + }) + } + + return () => { + return ( +
+ {/* { renderTree(data.value) } */} + { openedData.value.map(item => renderNode(item)) } +
+ ) + } + } +}) diff --git a/devui/tree/src/util.ts b/devui/tree/src/util.ts new file mode 100644 index 0000000000000000000000000000000000000000..1517f1c35bc66f0bee8fba45e4b315371a617011 --- /dev/null +++ b/devui/tree/src/util.ts @@ -0,0 +1,11 @@ +export const omit = (obj: unknown, key: string): unknown => { + return Object.entries(obj) + .filter(item => item[0] !== key) + .reduce((acc, item) => Object.assign({}, acc, { [item[0]]: item[1] }), {}) +} + +export const flatten = (tree: Array, key = 'children'): Array => { + return tree.reduce((acc, item) => ( + !item[key] ? acc.concat(item) : acc.concat(item, flatten(item[key], key)) + ), []) +} diff --git a/docs/components/tree/data.ts b/docs/components/tree/data.ts new file mode 100644 index 0000000000000000000000000000000000000000..c47ddfb16aad01726ac4f747d829f4e1ae5ce4f4 --- /dev/null +++ b/docs/components/tree/data.ts @@ -0,0 +1,35 @@ +export default [{ + label: '一级 1', + children: [{ + label: '二级 1-1', + children: [{ + label: '三级 1-1-1' + }] + }] +}, { + label: '一级 2', + children: [{ + label: '二级 2-1', + children: [{ + label: '三级 2-1-1' + }] + }, { + label: '二级 2-2', + children: [{ + label: '三级 2-2-1' + }] + }] +}, { + label: '一级 3', + children: [{ + label: '二级 3-1', + children: [{ + label: '三级 3-1-1' + }] + }, { + label: '二级 3-2', + children: [{ + label: '三级 3-2-1' + }] + }] +}]; diff --git a/docs/components/tree/index.md b/docs/components/tree/index.md new file mode 100644 index 0000000000000000000000000000000000000000..2369be78032a4260ef7e036166488503071a022f --- /dev/null +++ b/docs/components/tree/index.md @@ -0,0 +1,66 @@ +# Tree 树 + +一种表现嵌套结构的组件。 + +### 何时使用 + +文件夹、组织架构、生物分类、国家地区等等,世间万物的大多数结构都是树形结构。使用树控件可以完整展现其中的层级关系,并具有展开收起选择等交互功能。 + +:::demo + +```vue + + +``` + +::: + + diff --git a/docs/vite.config.ts b/docs/vite.config.ts index e605580f533d95950ee24d5d8065823a85e6a3a4..b29e091dd28b047c7b803cb42d1ca25586bdddad 100644 --- a/docs/vite.config.ts +++ b/docs/vite.config.ts @@ -1,6 +1,7 @@ -import path from 'path'; -import { defineConfig } from 'vite'; -import vueJsx from '@vitejs/plugin-vue-jsx'; +import path from 'path' +import { defineConfig } from 'vite' +import vueJsx from '@vitejs/plugin-vue-jsx' +import svgLoader from 'vite-svg-loader' export default defineConfig({ resolve: { @@ -10,5 +11,6 @@ export default defineConfig({ }, plugins: [ vueJsx({}), + svgLoader(), ], }) diff --git a/package.json b/package.json index cfe0a4f4cb07bd6817c42a2273999bb99bae4f26..cf98ae329b01563a60a8d7e8046a47efe14e94de 100644 --- a/package.json +++ b/package.json @@ -88,6 +88,7 @@ "typescript": "^4.3.2", "vite": "^2.4.4", "vite-plugin-md": "^0.6.0", + "vite-svg-loader": "^2.2.0", "vitepress": "^0.15.6", "vitepress-theme-demoblock": "1.0.7", "vue-tsc": "^0.2.2", diff --git a/yarn.lock b/yarn.lock index 9ec1e783b109c039a6629a8268336f438097fc9e..3ae3a8f1867ef0f29a7a10dec90fe558b2d034c5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1623,6 +1623,11 @@ resolved "https://registry.nlark.com/@tootallnate/once/download/@tootallnate/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" integrity sha1-zLkURTYBeaBOf+av94wA/8Hur4I= +"@trysound/sax@0.2.0": + version "0.2.0" + resolved "https://registry.nlark.com/@trysound/sax/download/@trysound/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad" + integrity sha1-zMqrdYr1Z2Hre/N69vA/Mm3XmK0= + "@types/babel__core@^7.0.0", "@types/babel__core@^7.1.14": version "7.1.16" resolved "https://registry.nlark.com/@types/babel__core/download/@types/babel__core-7.1.16.tgz#bc12c74b7d65e82d29876b5d0baf5c625ac58702" @@ -2004,7 +2009,7 @@ "@vue/compiler-core" "3.2.12" "@vue/shared" "3.2.12" -"@vue/compiler-sfc@^3.0.5", "@vue/compiler-sfc@^3.1.1": +"@vue/compiler-sfc@^3.0.11", "@vue/compiler-sfc@^3.0.5", "@vue/compiler-sfc@^3.1.1": version "3.2.12" resolved "https://registry.nlark.com/@vue/compiler-sfc/download/@vue/compiler-sfc-3.2.12.tgz#39555550d96051508753ba934f7260dc5ee5211e" integrity sha1-OVVVUNlgUVCHU7qTT3Jg3F7lIR4= @@ -2563,6 +2568,11 @@ bluebird@^3.7.2: resolved "https://registry.npm.taobao.org/bluebird/download/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" integrity sha1-nyKcFb4nJFT/qXOs4NvueaGww28= +boolbase@^1.0.0: + version "1.0.0" + resolved "https://registry.npm.taobao.org/boolbase/download/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" + integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24= + brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.npm.taobao.org/brace-expansion/download/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" @@ -3013,11 +3023,42 @@ cross-spawn@^7.0.2, cross-spawn@^7.0.3: shebang-command "^2.0.0" which "^2.0.1" +css-select@^4.1.3: + version "4.1.3" + resolved "https://registry.nlark.com/css-select/download/css-select-4.1.3.tgz#a70440f70317f2669118ad74ff105e65849c7067" + integrity sha1-pwRA9wMX8maRGK10/xBeZYSccGc= + dependencies: + boolbase "^1.0.0" + css-what "^5.0.0" + domhandler "^4.2.0" + domutils "^2.6.0" + nth-check "^2.0.0" + +css-tree@^1.1.2, css-tree@^1.1.3: + version "1.1.3" + resolved "https://registry.npm.taobao.org/css-tree/download/css-tree-1.1.3.tgz?cache=0&sync_timestamp=1617191853562&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcss-tree%2Fdownload%2Fcss-tree-1.1.3.tgz#eb4870fb6fd7707327ec95c2ff2ab09b5e8db91d" + integrity sha1-60hw+2/XcHMn7JXC/yqwm16NuR0= + dependencies: + mdn-data "2.0.14" + source-map "^0.6.1" + +css-what@^5.0.0: + version "5.0.1" + resolved "https://registry.nlark.com/css-what/download/css-what-5.0.1.tgz#3efa820131f4669a8ac2408f9c32e7c7de9f4cad" + integrity sha1-PvqCATH0ZpqKwkCPnDLnx96fTK0= + cssesc@^3.0.0: version "3.0.0" resolved "https://registry.npm.taobao.org/cssesc/download/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" integrity sha1-N3QZGZA7hoVl4cCep0dEXNGJg+4= +csso@^4.2.0: + version "4.2.0" + resolved "https://registry.nlark.com/csso/download/csso-4.2.0.tgz#ea3a561346e8dc9f546d6febedd50187cf389529" + integrity sha1-6jpWE0bo3J9UbW/r7dUBh884lSk= + dependencies: + css-tree "^1.1.2" + cssom@^0.4.4: version "0.4.4" resolved "https://registry.nlark.com/cssom/download/cssom-0.4.4.tgz#5a66cf93d2d0b661d80bf6a44fb65f5c2e4e0a10" @@ -3220,7 +3261,7 @@ domutils@^1.5.1: dom-serializer "0" domelementtype "1" -domutils@^2.5.2: +domutils@^2.5.2, domutils@^2.6.0: version "2.8.0" resolved "https://registry.nlark.com/domutils/download/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135" integrity sha1-RDfe9dtuLR9dbuhZvZXKfQIEgTU= @@ -5156,6 +5197,11 @@ mdast-util-to-string@^2.0.0: resolved "https://registry.nlark.com/mdast-util-to-string/download/mdast-util-to-string-2.0.0.tgz?cache=0&sync_timestamp=1619427925844&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fmdast-util-to-string%2Fdownload%2Fmdast-util-to-string-2.0.0.tgz#b8cfe6a713e1091cb5b728fc48885a4767f8b97b" integrity sha1-uM/mpxPhCRy1tyj8SIhaR2f4uXs= +mdn-data@2.0.14: + version "2.0.14" + resolved "https://registry.nlark.com/mdn-data/download/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50" + integrity sha1-cRP8QoGRfWPOKbQ0RvcB5owlulA= + mdurl@^1.0.1: version "1.0.1" resolved "https://registry.nlark.com/mdurl/download/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" @@ -5378,6 +5424,13 @@ npm-run-path@^4.0.1: dependencies: path-key "^3.0.0" +nth-check@^2.0.0: + version "2.0.1" + resolved "https://registry.nlark.com/nth-check/download/nth-check-2.0.1.tgz#2efe162f5c3da06a28959fbd3db75dbeea9f0fc2" + integrity sha1-Lv4WL1w9oGoolZ+9PbddvuqfD8I= + dependencies: + boolbase "^1.0.0" + num2fraction@^1.2.2: version "1.2.2" resolved "https://registry.nlark.com/num2fraction/download/num2fraction-1.2.2.tgz#6f682b6a027a4e9ddfa4564cd2589d1d4e669ede" @@ -6437,6 +6490,11 @@ sprintf-js@~1.0.2: resolved "https://registry.nlark.com/sprintf-js/download/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= +stable@^0.1.8: + version "0.1.8" + resolved "https://registry.nlark.com/stable/download/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf" + integrity sha1-g26zyDgv4pNv6vVEYxAXzn1Ho88= + stack-utils@^2.0.3: version "2.0.5" resolved "https://registry.nlark.com/stack-utils/download/stack-utils-2.0.5.tgz#d25265fca995154659dbbfba3b49254778d2fdd5" @@ -6665,6 +6723,19 @@ svg-tags@^1.0.0: resolved "https://registry.nlark.com/svg-tags/download/svg-tags-1.0.0.tgz#58f71cee3bd519b59d4b2a843b6c7de64ac04764" integrity sha1-WPcc7jvVGbWdSyqEO2x95krAR2Q= +svgo@^2.3.0: + version "2.6.1" + resolved "https://registry.nlark.com/svgo/download/svgo-2.6.1.tgz#60b613937e0081028cffc2369090e366b08f1f0e" + integrity sha1-YLYTk34AgQKM/8I2kJDjZrCPHw4= + dependencies: + "@trysound/sax" "0.2.0" + colorette "^1.4.0" + commander "^7.2.0" + css-select "^4.1.3" + css-tree "^1.1.3" + csso "^4.2.0" + stable "^0.1.8" + symbol-tree@^3.2.4: version "3.2.4" resolved "https://registry.npm.taobao.org/symbol-tree/download/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" @@ -7019,6 +7090,14 @@ vite-plugin-md@^0.6.0: gray-matter "^4.0.3" markdown-it "^12.0.6" +vite-svg-loader@^2.2.0: + version "2.2.0" + resolved "https://registry.nlark.com/vite-svg-loader/download/vite-svg-loader-2.2.0.tgz#b5d6ca948b03e45320cb4f96c44bf88f5bef0a2c" + integrity sha1-tdbKlIsD5FMgy0+WxEv4j1vvCiw= + dependencies: + "@vue/compiler-sfc" "^3.0.11" + svgo "^2.3.0" + vite@^2.3.7, vite@^2.4.4: version "2.5.8" resolved "https://registry.nlark.com/vite/download/vite-2.5.8.tgz?cache=0&sync_timestamp=1631843727130&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fvite%2Fdownload%2Fvite-2.5.8.tgz#e2da21540411e91cb1c4a62e133c652a787cf116"