93f0b2ee3b569577e854f1e232d0ef2b171ca0b17f16a6eed7f5c391a1d252d5fe1311bc59ae5d8b1332d0950a7e190683a7ae41b3dfd7c1c2cb267e819db0 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. import { defineComponent, inject, ref, computed, watch, provide, getCurrentInstance, resolveComponent, openBlock, createElementBlock, normalizeClass, Fragment, renderList, createBlock, renderSlot, createElementVNode, toDisplayString, createCommentVNode, withDirectives, vShow } from 'vue';
  2. import { selectKey } from '../../select/src/token.mjs';
  3. import TreeStore from './model/tree-store.mjs';
  4. import { getNodeKey, handleCurrentChange } from './model/util.mjs';
  5. import ElTreeNode from './tree-node.mjs';
  6. import { useNodeExpandEventBroadcast } from './model/useNodeExpandEventBroadcast.mjs';
  7. import { useDragNodeHandler } from './model/useDragNode.mjs';
  8. import { useKeydown } from './model/useKeydown.mjs';
  9. import { ROOT_TREE_INJECTION_KEY } from './tokens.mjs';
  10. import { isEqual } from 'lodash-unified';
  11. import _export_sfc from '../../../_virtual/plugin-vue_export-helper.mjs';
  12. import { definePropType } from '../../../utils/vue/props/runtime.mjs';
  13. import { iconPropType } from '../../../utils/vue/icon.mjs';
  14. import { useLocale } from '../../../hooks/use-locale/index.mjs';
  15. import { useNamespace } from '../../../hooks/use-namespace/index.mjs';
  16. import { formItemContextKey } from '../../form/src/constants.mjs';
  17. const _sfc_main = defineComponent({
  18. name: "ElTree",
  19. components: { ElTreeNode },
  20. props: {
  21. data: {
  22. type: definePropType(Array),
  23. default: () => []
  24. },
  25. emptyText: {
  26. type: String
  27. },
  28. renderAfterExpand: {
  29. type: Boolean,
  30. default: true
  31. },
  32. nodeKey: String,
  33. checkStrictly: Boolean,
  34. defaultExpandAll: Boolean,
  35. expandOnClickNode: {
  36. type: Boolean,
  37. default: true
  38. },
  39. checkOnClickNode: Boolean,
  40. checkOnClickLeaf: {
  41. type: Boolean,
  42. default: true
  43. },
  44. checkDescendants: Boolean,
  45. autoExpandParent: {
  46. type: Boolean,
  47. default: true
  48. },
  49. defaultCheckedKeys: Array,
  50. defaultExpandedKeys: Array,
  51. currentNodeKey: [String, Number],
  52. renderContent: {
  53. type: definePropType(Function)
  54. },
  55. showCheckbox: Boolean,
  56. draggable: Boolean,
  57. allowDrag: {
  58. type: definePropType(Function)
  59. },
  60. allowDrop: {
  61. type: definePropType(Function)
  62. },
  63. props: {
  64. type: Object,
  65. default: () => ({
  66. children: "children",
  67. label: "label",
  68. disabled: "disabled"
  69. })
  70. },
  71. lazy: Boolean,
  72. highlightCurrent: Boolean,
  73. load: Function,
  74. filterNodeMethod: Function,
  75. accordion: Boolean,
  76. indent: {
  77. type: Number,
  78. default: 18
  79. },
  80. icon: {
  81. type: iconPropType
  82. }
  83. },
  84. emits: [
  85. "check-change",
  86. "current-change",
  87. "node-click",
  88. "node-contextmenu",
  89. "node-collapse",
  90. "node-expand",
  91. "check",
  92. "node-drag-start",
  93. "node-drag-end",
  94. "node-drop",
  95. "node-drag-leave",
  96. "node-drag-enter",
  97. "node-drag-over"
  98. ],
  99. setup(props, ctx) {
  100. const { t } = useLocale();
  101. const ns = useNamespace("tree");
  102. const selectInfo = inject(selectKey, null);
  103. const store = ref(new TreeStore({
  104. key: props.nodeKey,
  105. data: props.data,
  106. lazy: props.lazy,
  107. props: props.props,
  108. load: props.load,
  109. currentNodeKey: props.currentNodeKey,
  110. checkStrictly: props.checkStrictly,
  111. checkDescendants: props.checkDescendants,
  112. defaultCheckedKeys: props.defaultCheckedKeys,
  113. defaultExpandedKeys: props.defaultExpandedKeys,
  114. autoExpandParent: props.autoExpandParent,
  115. defaultExpandAll: props.defaultExpandAll,
  116. filterNodeMethod: props.filterNodeMethod
  117. }));
  118. store.value.initialize();
  119. const root = ref(store.value.root);
  120. const currentNode = ref(null);
  121. const el$ = ref(null);
  122. const dropIndicator$ = ref(null);
  123. const { broadcastExpanded } = useNodeExpandEventBroadcast(props);
  124. const { dragState } = useDragNodeHandler({
  125. props,
  126. ctx,
  127. el$,
  128. dropIndicator$,
  129. store
  130. });
  131. useKeydown({ el$ }, store);
  132. const isEmpty = computed(() => {
  133. const { childNodes } = root.value;
  134. const hasFilteredOptions = selectInfo ? selectInfo.hasFilteredOptions !== 0 : false;
  135. return (!childNodes || childNodes.length === 0 || childNodes.every(({ visible }) => !visible)) && !hasFilteredOptions;
  136. });
  137. watch(() => props.currentNodeKey, (newVal) => {
  138. store.value.setCurrentNodeKey(newVal != null ? newVal : null);
  139. });
  140. watch(() => props.defaultCheckedKeys, (newVal, oldVal) => {
  141. if (isEqual(newVal, oldVal))
  142. return;
  143. store.value.setDefaultCheckedKey(newVal != null ? newVal : []);
  144. });
  145. watch(() => props.defaultExpandedKeys, (newVal) => {
  146. store.value.setDefaultExpandedKeys(newVal != null ? newVal : []);
  147. });
  148. watch(() => props.data, (newVal) => {
  149. store.value.setData(newVal);
  150. }, { deep: true });
  151. watch(() => props.checkStrictly, (newVal) => {
  152. store.value.checkStrictly = newVal;
  153. });
  154. const filter = (value) => {
  155. if (!props.filterNodeMethod)
  156. throw new Error("[Tree] filterNodeMethod is required when filter");
  157. store.value.filter(value);
  158. };
  159. const getNodeKey$1 = (node) => {
  160. return getNodeKey(props.nodeKey, node.data);
  161. };
  162. const getNodePath = (data) => {
  163. if (!props.nodeKey)
  164. throw new Error("[Tree] nodeKey is required in getNodePath");
  165. const node = store.value.getNode(data);
  166. if (!node)
  167. return [];
  168. const path = [node.data];
  169. let parent = node.parent;
  170. while (parent && parent !== root.value) {
  171. path.push(parent.data);
  172. parent = parent.parent;
  173. }
  174. return path.reverse();
  175. };
  176. const getCheckedNodes = (leafOnly, includeHalfChecked) => {
  177. return store.value.getCheckedNodes(leafOnly, includeHalfChecked);
  178. };
  179. const getCheckedKeys = (leafOnly) => {
  180. return store.value.getCheckedKeys(leafOnly);
  181. };
  182. const getCurrentNode = () => {
  183. const currentNode2 = store.value.getCurrentNode();
  184. return currentNode2 ? currentNode2.data : null;
  185. };
  186. const getCurrentKey = () => {
  187. if (!props.nodeKey)
  188. throw new Error("[Tree] nodeKey is required in getCurrentKey");
  189. const currentNode2 = getCurrentNode();
  190. return currentNode2 ? currentNode2[props.nodeKey] : null;
  191. };
  192. const setCheckedNodes = (nodes, leafOnly) => {
  193. if (!props.nodeKey)
  194. throw new Error("[Tree] nodeKey is required in setCheckedNodes");
  195. store.value.setCheckedNodes(nodes, leafOnly);
  196. };
  197. const setCheckedKeys = (keys, leafOnly) => {
  198. if (!props.nodeKey)
  199. throw new Error("[Tree] nodeKey is required in setCheckedKeys");
  200. store.value.setCheckedKeys(keys, leafOnly);
  201. };
  202. const setChecked = (data, checked, deep) => {
  203. store.value.setChecked(data, checked, deep);
  204. };
  205. const getHalfCheckedNodes = () => {
  206. return store.value.getHalfCheckedNodes();
  207. };
  208. const getHalfCheckedKeys = () => {
  209. return store.value.getHalfCheckedKeys();
  210. };
  211. const setCurrentNode = (node, shouldAutoExpandParent = true) => {
  212. if (!props.nodeKey)
  213. throw new Error("[Tree] nodeKey is required in setCurrentNode");
  214. handleCurrentChange(store, ctx.emit, () => {
  215. broadcastExpanded(node);
  216. store.value.setUserCurrentNode(node, shouldAutoExpandParent);
  217. });
  218. };
  219. const setCurrentKey = (key, shouldAutoExpandParent = true) => {
  220. if (!props.nodeKey)
  221. throw new Error("[Tree] nodeKey is required in setCurrentKey");
  222. handleCurrentChange(store, ctx.emit, () => {
  223. broadcastExpanded();
  224. store.value.setCurrentNodeKey(key != null ? key : null, shouldAutoExpandParent);
  225. });
  226. };
  227. const getNode = (data) => {
  228. return store.value.getNode(data);
  229. };
  230. const remove = (data) => {
  231. store.value.remove(data);
  232. };
  233. const append = (data, parentNode) => {
  234. store.value.append(data, parentNode);
  235. };
  236. const insertBefore = (data, refNode) => {
  237. store.value.insertBefore(data, refNode);
  238. };
  239. const insertAfter = (data, refNode) => {
  240. store.value.insertAfter(data, refNode);
  241. };
  242. const handleNodeExpand = (nodeData, node, instance) => {
  243. broadcastExpanded(node);
  244. ctx.emit("node-expand", nodeData, node, instance);
  245. };
  246. const updateKeyChildren = (key, data) => {
  247. if (!props.nodeKey)
  248. throw new Error("[Tree] nodeKey is required in updateKeyChild");
  249. store.value.updateChildren(key, data);
  250. };
  251. provide(ROOT_TREE_INJECTION_KEY, {
  252. ctx,
  253. props,
  254. store,
  255. root,
  256. currentNode,
  257. instance: getCurrentInstance()
  258. });
  259. provide(formItemContextKey, void 0);
  260. return {
  261. ns,
  262. store,
  263. root,
  264. currentNode,
  265. dragState,
  266. el$,
  267. dropIndicator$,
  268. isEmpty,
  269. filter,
  270. getNodeKey: getNodeKey$1,
  271. getNodePath,
  272. getCheckedNodes,
  273. getCheckedKeys,
  274. getCurrentNode,
  275. getCurrentKey,
  276. setCheckedNodes,
  277. setCheckedKeys,
  278. setChecked,
  279. getHalfCheckedNodes,
  280. getHalfCheckedKeys,
  281. setCurrentNode,
  282. setCurrentKey,
  283. t,
  284. getNode,
  285. remove,
  286. append,
  287. insertBefore,
  288. insertAfter,
  289. handleNodeExpand,
  290. updateKeyChildren
  291. };
  292. }
  293. });
  294. function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
  295. const _component_el_tree_node = resolveComponent("el-tree-node");
  296. return openBlock(), createElementBlock("div", {
  297. ref: "el$",
  298. class: normalizeClass([
  299. _ctx.ns.b(),
  300. _ctx.ns.is("dragging", !!_ctx.dragState.draggingNode),
  301. _ctx.ns.is("drop-not-allow", !_ctx.dragState.allowDrop),
  302. _ctx.ns.is("drop-inner", _ctx.dragState.dropType === "inner"),
  303. { [_ctx.ns.m("highlight-current")]: _ctx.highlightCurrent }
  304. ]),
  305. role: "tree"
  306. }, [
  307. (openBlock(true), createElementBlock(Fragment, null, renderList(_ctx.root.childNodes, (child) => {
  308. return openBlock(), createBlock(_component_el_tree_node, {
  309. key: _ctx.getNodeKey(child),
  310. node: child,
  311. props: _ctx.props,
  312. accordion: _ctx.accordion,
  313. "render-after-expand": _ctx.renderAfterExpand,
  314. "show-checkbox": _ctx.showCheckbox,
  315. "render-content": _ctx.renderContent,
  316. onNodeExpand: _ctx.handleNodeExpand
  317. }, null, 8, ["node", "props", "accordion", "render-after-expand", "show-checkbox", "render-content", "onNodeExpand"]);
  318. }), 128)),
  319. _ctx.isEmpty ? (openBlock(), createElementBlock("div", {
  320. key: 0,
  321. class: normalizeClass(_ctx.ns.e("empty-block"))
  322. }, [
  323. renderSlot(_ctx.$slots, "empty", {}, () => {
  324. var _a;
  325. return [
  326. createElementVNode("span", {
  327. class: normalizeClass(_ctx.ns.e("empty-text"))
  328. }, toDisplayString((_a = _ctx.emptyText) != null ? _a : _ctx.t("el.tree.emptyText")), 3)
  329. ];
  330. })
  331. ], 2)) : createCommentVNode("v-if", true),
  332. withDirectives(createElementVNode("div", {
  333. ref: "dropIndicator$",
  334. class: normalizeClass(_ctx.ns.e("drop-indicator"))
  335. }, null, 2), [
  336. [vShow, _ctx.dragState.showDropIndicator]
  337. ])
  338. ], 2);
  339. }
  340. var Tree = /* @__PURE__ */ _export_sfc(_sfc_main, [["render", _sfc_render], ["__file", "tree.vue"]]);
  341. export { Tree as default };
  342. //# sourceMappingURL=tree.mjs.map