ivue-material-plus
Version:
A high quality UI components Library with Vue.js
1 lines • 19.4 kB
Source Map (JSON)
{"version":3,"file":"index2.mjs","sources":["../../../../../src/components/ivue-tree/index.vue"],"sourcesContent":["<template>\r\n <div :class=\"wrapperClasses\" ref=\"treeRef\">\r\n <!-- 节点 -->\r\n <tree-node\r\n v-for=\"child in root.childNodes\"\r\n :node=\"child\"\r\n :accordion=\"accordion\"\r\n :show-checkbox=\"showCheckbox\"\r\n :render-after-expand=\"renderAfterExpand\"\r\n :render-content=\"renderContent\"\r\n :props=\"props\"\r\n :key=\"getTreeNodeKey(child)\"\r\n @on-node-expand=\"handleNodeExpand\"\r\n ></tree-node>\r\n <!-- 没有数据 -->\r\n <div :class=\"`${prefixCls}-no-data`\" v-if=\"isEmpty\">{{ emptyText }}</div>\r\n <!-- 拖动下划线 -->\r\n <div\r\n v-show=\"dragState.showDropIndicator\"\r\n ref=\"dropIndicator\"\r\n :class=\"`${prefixCls}-drop-indicator`\"\r\n ></div>\r\n </div>\r\n</template>\r\n\r\n<script lang=\"ts\">\r\nimport {\r\n computed,\r\n defineComponent,\r\n ref,\r\n provide,\r\n ComponentInternalInstance,\r\n PropType,\r\n watch,\r\n} from 'vue';\r\nimport TreeStore from './store/tree-store';\r\nimport { getNodeKey, handleCurrentChange } from './utils';\r\nimport { useNodeExpandEventBroadcast } from './hooks/useNodeExpandEventBroadcast';\r\nimport { useKeydown } from './hooks/useKeydown';\r\nimport { useDragNodeHandler } from './hooks/useDragNode';\r\nimport { throwError } from '../../utils/error';\r\n\r\nimport TreeNode from './node.vue';\r\n\r\n// type\r\nimport type Node from './store/node';\r\nimport type { Props, TreeNodeData, TreeKey, TreeData } from './types/tree';\r\nimport { TreeContextKey, IconPropType } from './types/tree';\r\n\r\nconst prefixCls = 'ivue-tree';\r\n\r\nexport default defineComponent({\r\n name: prefixCls,\r\n emits: [\r\n 'on-current-change',\r\n 'on-node-collapse',\r\n 'on-node-expand',\r\n 'on-node-click',\r\n 'on-check',\r\n 'on-check-change',\r\n 'on-node-drag-start',\r\n 'on-node-drag-leave',\r\n 'on-node-drag-enter',\r\n 'on-node-drag-over',\r\n 'on-node-drag-end',\r\n 'on-node-drop',\r\n ],\r\n props: {\r\n /**\r\n * tree数据\r\n *\r\n * @type {Array}\r\n */\r\n data: {\r\n type: Array,\r\n default: () => [],\r\n },\r\n /**\r\n * 是否懒加载子节点,需与 load 方法结合使用\r\n *\r\n * @type {Boolean}\r\n */\r\n lazy: {\r\n type: Boolean,\r\n default: false,\r\n },\r\n /**\r\n * tree 配置选项\r\n *\r\n * @type {Object}\r\n */\r\n props: {\r\n type: Object as PropType<Props['props']>,\r\n default: () => ({\r\n children: 'children',\r\n label: 'label',\r\n disabled: 'disabled',\r\n }),\r\n },\r\n /**\r\n * 暂无数据文案\r\n *\r\n * @type {String}\r\n */\r\n emptyText: {\r\n type: String,\r\n default: '暂无数据',\r\n },\r\n /**\r\n * 每个树节点用来作为唯一标识的属性,整棵树应该是唯一的\r\n *\r\n * @type {String}\r\n */\r\n nodeKey: {\r\n type: String,\r\n },\r\n /**\r\n * 相邻级节点间的水平缩进,单位为像素\r\n *\r\n * @type {Number}\r\n */\r\n indent: {\r\n type: Number,\r\n default: 18,\r\n },\r\n /**\r\n * 自定义树节点扩展图标\r\n *\r\n * @type {IconPropType}\r\n */\r\n icon: {\r\n type: IconPropType,\r\n default: 'arrow_right',\r\n },\r\n /**\r\n * 树节点的内容区的渲染方法\r\n *\r\n * @type {Function}\r\n */\r\n renderContent: {\r\n type: Function as PropType<Props['renderContent']>,\r\n },\r\n /**\r\n * 是否在点击节点的时候展开或者收缩节点\r\n *\r\n * @type {Boolean}\r\n */\r\n expandOnClickNode: {\r\n type: Boolean,\r\n default: true,\r\n },\r\n /**\r\n * 是否每次只打开一个同级树节点展开\r\n *\r\n * @type {Boolean}\r\n */\r\n accordion: {\r\n type: Boolean,\r\n default: false,\r\n },\r\n /**\r\n * 设置节点是否被选中\r\n *\r\n * @type {Boolean}\r\n */\r\n showCheckbox: {\r\n type: Boolean,\r\n default: false,\r\n },\r\n /**\r\n * 在显示复选框的情况下,是否严格的遵循父子不互相关联的做法\r\n *\r\n * @type {Boolean}\r\n */\r\n checkBoxStrictly: {\r\n type: Boolean,\r\n default: false,\r\n },\r\n /**\r\n * 加载子树数据的方法,仅当 lazy 属性为true 时生效\r\n *\r\n * @type {Function}\r\n */\r\n load: {\r\n type: Function as PropType<Props['load']>,\r\n },\r\n /**\r\n * 默认勾选的节点的 key 的数组\r\n *\r\n * @type {Array}\r\n */\r\n defaultCheckedKeys: {\r\n type: Array as PropType<Props['defaultCheckedKeys']>,\r\n },\r\n /**\r\n * 默认展开的节点的 key 的数组\r\n *\r\n * @type {Array}\r\n */\r\n defaultExpandedKeys: {\r\n type: Array as PropType<Props['defaultExpandedKeys']>,\r\n },\r\n /**\r\n * 展开子节点的时候是否自动展开父节点\r\n *\r\n * @type {Boolean}\r\n */\r\n autoExpandParent: {\r\n type: Boolean,\r\n default: true,\r\n },\r\n /**\r\n * 是否默认展开所有节点\r\n *\r\n * @type {Boolean}\r\n */\r\n defaultExpandAll: {\r\n type: Boolean,\r\n default: false,\r\n },\r\n /**\r\n * 是否在第一次展开某个树节点后才渲染其子节点\r\n *\r\n * @type {Boolean}\r\n */\r\n renderAfterExpand: {\r\n type: Boolean,\r\n default: true,\r\n },\r\n /**\r\n * 是否高亮当前选中节点\r\n *\r\n * @type {Boolean}\r\n */\r\n highlightCurrent: {\r\n type: Boolean,\r\n default: false,\r\n },\r\n /**\r\n * 当前选中的节点\r\n *\r\n * @type {String | Number}\r\n */\r\n currentNodeKey: {\r\n type: [String, Number],\r\n },\r\n /**\r\n * 对树节点进行筛选时执行的方法, 返回 false 则表示这个节点会被隐藏\r\n *\r\n * @type {Function}\r\n */\r\n filterNodeMethod: {\r\n type: Function as PropType<Props['filterNodeMethod']>,\r\n },\r\n /**\r\n * 是否在点击节点的时候选中节点\r\n *\r\n * @type {Boolean}\r\n */\r\n checkOnClickNode: {\r\n type: Boolean,\r\n default: false,\r\n },\r\n /**\r\n * 是否开启拖拽节点功能\r\n *\r\n * @type {Boolean}\r\n */\r\n draggable: {\r\n type: Boolean,\r\n default: false,\r\n },\r\n /**\r\n * 判断节点能否被拖拽 如果返回 false ,节点不能被拖动\r\n *\r\n * @type {Function}\r\n */\r\n allowDrag: {\r\n type: Function as PropType<Props['allowDrag']>,\r\n },\r\n /**\r\n * 拖拽时判定目标节点能否成为拖动目标位置\r\n *\r\n * @type {Function}\r\n */\r\n allowDrop: {\r\n type: Function as PropType<Props['allowDrop']>,\r\n },\r\n },\r\n setup(props: Props, ctx) {\r\n // 派发事件到所有子节点是否关闭展开\r\n const { broadcastExpanded } = useNodeExpandEventBroadcast(props);\r\n\r\n // data\r\n\r\n // tree 存储\r\n const store = ref<TreeStore>(\r\n new TreeStore({\r\n key: props.nodeKey,\r\n data: props.data,\r\n lazy: props.lazy,\r\n props: props.props,\r\n checkBoxStrictly: props.checkBoxStrictly,\r\n load: props.load,\r\n defaultCheckedKeys: props.defaultCheckedKeys,\r\n defaultExpandedKeys: props.defaultExpandedKeys,\r\n autoExpandParent: props.autoExpandParent,\r\n defaultExpandAll: props.defaultExpandAll,\r\n filterNodeMethod: props.filterNodeMethod,\r\n })\r\n );\r\n\r\n // 初始化\r\n store.value.initialize();\r\n\r\n // 根节点数据\r\n const root = ref<Node>(store.value.root);\r\n // 当前节点\r\n const currentNode = ref<Node>(null);\r\n // 跟节点\r\n const treeRef = ref<HTMLElement>(null);\r\n\r\n // 拖动时显示的线条\r\n const dropIndicator = ref<HTMLElement>(null);\r\n\r\n // 键盘事件\r\n useKeydown(treeRef, store);\r\n\r\n // 拖动事件\r\n const { dragState } = useDragNodeHandler({\r\n props,\r\n ctx,\r\n treeRef,\r\n dropIndicator,\r\n store,\r\n });\r\n\r\n // computed\r\n\r\n // 外层样式\r\n const wrapperClasses = computed(() => {\r\n return [\r\n prefixCls,\r\n {\r\n [`${prefixCls}-highlight-current`]: props.highlightCurrent,\r\n },\r\n ];\r\n });\r\n\r\n // 是否没有数据\r\n const isEmpty = computed(() => {\r\n const { childNodes } = root.value;\r\n\r\n return (\r\n !childNodes ||\r\n childNodes.length === 0 ||\r\n childNodes.every(({ visible }) => !visible)\r\n );\r\n });\r\n\r\n // methods\r\n\r\n // 获取节点key\r\n const getTreeNodeKey = (node: Node) => {\r\n return getNodeKey(props.nodeKey, node.data);\r\n };\r\n\r\n // 节点展开\r\n const handleNodeExpand = (\r\n nodeData: TreeNodeData,\r\n node: Node,\r\n instance: ComponentInternalInstance\r\n ) => {\r\n // 派发展开事件\r\n broadcastExpanded(node);\r\n // 节点被展开时触发的事件\r\n ctx.emit(\r\n 'on-node-expand',\r\n // 传递给 data 属性的数组中该节点所对应的对象\r\n nodeData,\r\n // 节点对应的 Node\r\n node,\r\n // 节点组件本身\r\n instance\r\n );\r\n };\r\n\r\n // 返回当前选中节点的数组\r\n const getCheckedNodes = (\r\n // 返回当前选中节点的子节点\r\n leafOnly?: boolean,\r\n // 返回值包含半选中节点数据\r\n includeHalfChecked?: boolean\r\n ): TreeNodeData[] => {\r\n return store.value.getCheckedNodes(leafOnly, includeHalfChecked);\r\n };\r\n\r\n // 返回当前选中节点 key 的数组\r\n const getCheckedKeys = (leafOnly?: boolean): TreeKey[] => {\r\n return store.value.getCheckedKeys(leafOnly);\r\n };\r\n\r\n // 通过 Node 节点数据设置复选框勾选的节点,使用此方法必须提前设置 node-key 属性\r\n const setCheckedNodes = (nodes: Node[], leafOnly?: boolean) => {\r\n if (!props.nodeKey) {\r\n throwError(prefixCls, 'nodeKey is required in setCheckedNodes');\r\n }\r\n\r\n store.value.setCheckedNodes(nodes, leafOnly);\r\n };\r\n\r\n // 通过 key 数组设置复选框勾选的节点,使用此方法必须设置 node-key 属性\r\n const setCheckedKeys = (keys: TreeKey[], leafOnly?: boolean) => {\r\n if (!props.nodeKey) {\r\n throwError(prefixCls, 'nodeKey is required in setCheckedKeys');\r\n }\r\n\r\n store.value.setCheckedKeys(keys, leafOnly);\r\n };\r\n\r\n // 为节点设置新数据,只有当设置 node-key 属性的时候才可用\r\n const updateKeyChildren = (key: TreeKey, data: TreeData) => {\r\n if (!props.nodeKey) {\r\n throwError(prefixCls, 'nodeKey is required in updateKeyChild');\r\n }\r\n\r\n store.value.updateChildren(key, data);\r\n };\r\n\r\n // 过滤所有树节点,过滤后的节点将被隐藏\r\n const filter = (value) => {\r\n if (!props.filterNodeMethod) {\r\n throwError(prefixCls, 'filterNodeMethod is required when filter');\r\n }\r\n\r\n store.value.filter(value);\r\n };\r\n\r\n // 插入到节点前面\r\n const insertBefore = (\r\n // 要增加的节点的 data\r\n data: TreeNodeData,\r\n // 参考节点的 data, key\r\n refNode: TreeKey | TreeNodeData\r\n ) => {\r\n store.value.insertBefore(data, refNode);\r\n };\r\n\r\n // 插入到节点后面\r\n const insertAfter = (\r\n // 要增加的节点的 data\r\n data: TreeNodeData,\r\n // 参考节点的 data, key\r\n refNode: TreeKey | TreeNodeData\r\n ) => {\r\n store.value.insertAfter(data, refNode);\r\n };\r\n\r\n // 设置节点是否被选中, 使用此方法必须设置 node-key 属性\r\n const setChecked = (\r\n data: TreeKey | TreeNodeData,\r\n checked: boolean,\r\n deep: boolean\r\n ) => {\r\n store.value.setChecked(data, checked, deep);\r\n };\r\n\r\n // 如果节点可用被选中 (show-checkbox 为 true), 它将返回当前半选中的节点组成的数组\r\n const getHalfCheckedNodes = (): TreeNodeData[] => {\r\n return store.value.getHalfCheckedNodes();\r\n };\r\n\r\n // 若节点可被选中(show-checkbox 为 true),则返回目前半选中的节点的 key 所组成的数组\r\n const getHalfCheckedKeys = (): TreeKey[] => {\r\n return store.value.getHalfCheckedKeys();\r\n };\r\n\r\n // 返回当前被选中节点的数据 (如果没有则返回 null)\r\n const getCurrentNode = (): TreeNodeData => {\r\n const currentNode = store.value.getCurrentNode();\r\n\r\n return currentNode ? currentNode.data : null;\r\n };\r\n\r\n // 返回当前被选中节点的数据的key (如果没有则返回 null)\r\n const getCurrentKey = (): any => {\r\n if (!props.nodeKey) {\r\n throwError(prefixCls, 'nodeKey is required in getCurrentKey');\r\n }\r\n\r\n const currentNode = getCurrentNode();\r\n\r\n return currentNode ? currentNode[props.nodeKey] : null;\r\n };\r\n\r\n // 通过 key 设置某个节点的当前选中状态,使用此方法必须设置 node-key 属性\r\n const setCurrentKey = (\r\n // 需要选中节点的 key, 如果为 null, 取消当前选中的节点\r\n key?: TreeKey,\r\n // 是否自动展开父节点\r\n shouldAutoExpandParent = true\r\n ) => {\r\n if (!props.nodeKey) {\r\n throwError(prefixCls, 'nodeKey is required in setCurrentKey');\r\n }\r\n\r\n // 发送点击事件\r\n handleCurrentChange(store, ctx.emit, () =>\r\n store.value.setCurrentNodeKey(key, shouldAutoExpandParent)\r\n );\r\n };\r\n\r\n // 设置节点为选中状态,使用此方法必须设置 node-key 属性\r\n const setCurrentNode = (\r\n // 待被选中的节点\r\n node: Node,\r\n // 是否自动展开父节点\r\n shouldAutoExpandParent = true\r\n ) => {\r\n if (!props.nodeKey) {\r\n throwError(prefixCls, 'nodeKey is required in setCurrentNode');\r\n }\r\n\r\n // 发送点击事件\r\n handleCurrentChange(store, ctx.emit, () =>\r\n store.value.setUserCurrentNode(node, shouldAutoExpandParent)\r\n );\r\n };\r\n\r\n // 根据 data 或者 key 拿到 Tree 组件中的 node\r\n const getNode = (\r\n // 节点的 data 或 key\r\n data: TreeKey | TreeNodeData\r\n ): Node => {\r\n return store.value.getNode(data);\r\n };\r\n\r\n // 删除 Tree 中的一个节点\r\n const remove = (\r\n // 要删除的节点的 data 或者 node 对象\r\n data: TreeNodeData | Node\r\n ) => {\r\n store.value.remove(data);\r\n };\r\n\r\n // 为 Tree 中的一个节点追加一个子节点\r\n const append = (\r\n // 要追加的子节点的 data\r\n data: TreeNodeData,\r\n // 父节点的 data, key 或 node\r\n parentNode: TreeNodeData | TreeKey | Node\r\n ) => {\r\n store.value.append(data, parentNode);\r\n };\r\n\r\n // watch\r\n\r\n // 监听数据变化\r\n watch(\r\n () => props.data,\r\n (value) => {\r\n store.value.setData(value);\r\n },\r\n {\r\n deep: true,\r\n }\r\n );\r\n\r\n // 监听在显示复选框的情况下,是否严格的遵循父子不互相关联的做法\r\n watch(\r\n () => props.checkBoxStrictly,\r\n (newVal) => {\r\n store.value.checkBoxStrictly = newVal;\r\n }\r\n );\r\n\r\n // 监听当前选中的节点\r\n watch(\r\n () => props.currentNodeKey,\r\n (newVal) => {\r\n store.value.setCurrentNodeKey(newVal);\r\n }\r\n );\r\n\r\n // 监听默认勾选的节点的 key 的数组\r\n watch(\r\n () => props.defaultCheckedKeys,\r\n (newVal) => {\r\n store.value.setDefaultCheckedKey(newVal);\r\n }\r\n );\r\n\r\n // 监听默认展开的节点的 key 的数组\r\n watch(\r\n () => props.defaultExpandedKeys,\r\n (newVal) => {\r\n store.value.setDefaultExpandedKeys(newVal);\r\n }\r\n );\r\n\r\n // 监听在显示复选框的情况下,是否严格的遵循父子不互相关联的做法\r\n watch(\r\n () => props.checkBoxStrictly,\r\n (newVal) => {\r\n store.value.checkBoxStrictly = newVal;\r\n }\r\n );\r\n\r\n // provide\r\n provide(TreeContextKey, {\r\n props,\r\n ctx,\r\n store,\r\n currentNode,\r\n });\r\n\r\n return {\r\n prefixCls,\r\n\r\n // dom\r\n treeRef,\r\n dropIndicator,\r\n\r\n // data\r\n root,\r\n dragState,\r\n\r\n // computed\r\n wrapperClasses,\r\n isEmpty,\r\n\r\n // methods\r\n handleNodeExpand,\r\n getTreeNodeKey,\r\n getCheckedNodes,\r\n getCheckedKeys,\r\n getHalfCheckedNodes,\r\n getHalfCheckedKeys,\r\n getCurrentNode,\r\n getCurrentKey,\r\n getNode,\r\n\r\n setCheckedNodes,\r\n setCheckedKeys,\r\n setChecked,\r\n setCurrentKey,\r\n setCurrentNode,\r\n\r\n remove,\r\n append,\r\n updateKeyChildren,\r\n insertBefore,\r\n insertAfter,\r\n filter,\r\n };\r\n },\r\n components: {\r\n TreeNode,\r\n },\r\n});\r\n</script>\r\n"],"names":["_resolveComponent","_openBlock","_createElementBlock","_normalizeClass","_createCommentVNode","_Fragment","_renderList","_createBlock","_toDisplayString","_withDirectives","_createElementVNode"],"mappings":";;;;;+BACEA,iBAqBM,WAAA,CAAA,CAAA;EArB2B,OAAAC,SAAA,EAAS,EAAAC,kBAAA,CAAA,KAAA,EAAA;AAAA,IAAA,KAAA,EAAAC,cAAA,CAAA,IAAA,CAAA,cAAA,CAAA;AAAA,IACxC,GAAA,EAAA,SAAA;AAAA,GAAA,EAAA;AAAA,IACAC,mBAAA,gBAAA,CAAA;AAAA,KAAAH,SAAA,CAES,IAAK,CAAA,EAAAC,kBAAA,CAAAG,QAAA,EAAA,IAAA,EAAAC,UAAA,CAAA,IAAA,CAAA,IAAA,CAAA,UAAA,EAAA,CAAA,KAAA,KAAA;AACX,MAAA,OAAAL,SAAA,EAAoB,EAAAM,WAAA,CAAA,oBAAA,EAAA;AAAA,QACpB,IAAA,EAAA,KAAA;AAAA,QACA,WAAA,IAAA,CAAA,SAAA;AAAA,QACA,iBAAc,IAAE,CAAA,YAAA;AAAA,QAChB,uBAAY,IAAA,CAAA,iBAAA;AAAA,QACZ,kBAAK,IAAA,CAAA,aAAA;AAAA,QACL,OAAA,IAAA,CAAA,KAAA;AAAA,QAAA,GAAA,EAAA,IAAA,CAAA,cAAA,CAAA,KAAA,CAAA;AAAA;OAEH,EAAa,IAAA,EAAA,CAAA,EAAA,CAAA,MAAA,EAAA,WAAA,EAAA,eAAA,EAAA,qBAAA,EAAA,gBAAA,EAAA,OAAA,EAAA,gBAAA,CAAA,CAAA,CAAA;AAAA,KAC8B,GAAO,GAAA,CAAA;AAAA,IAAlDH,mBAAA,4BAAA,CAAA;AAAA,IAAA,IAAA,CAAA,OAAA,IAAAH,SAAW,EAAA,qBAAK,KAAS,EAAA;AAAA,MAAA,GAAA,EAAA,CAAA;AAAA;KACzB,EAAAO,gBAAA,IAAA,CAAA,SAAc,2BACd,CAAA,MAAA,EAIO,IAAA,CAAA;AAAA,IAAAJ,mBAFD,kCAAe,CAAA;AAAA,IAAAK,cAAA,CACbC,mBAAK,KAAS,EAAA;AAAA,MAAA,GAAA,EAAA,eAAA;AAAA,MAFH,KAAA,EAAAP,cAAA,CAAA,CAAC,EAAA,IAAA,CAAiB,SAAA,CAAA,eAAA,CAAA,CAAA;AAAA,KAAA,EAAA,IAAA,EAAA,CAAA,CAAA,EAAA;AAAA;;;;;;;;"}