DirectoryTree.js 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
  2. import _extends from "@babel/runtime/helpers/esm/extends";
  3. import { resolveDirective as _resolveDirective, createVNode as _createVNode } from "vue";
  4. var __rest = this && this.__rest || function (s, e) {
  5. var t = {};
  6. for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p];
  7. if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
  8. if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]];
  9. }
  10. return t;
  11. };
  12. import { nextTick, onUpdated, ref, watch, defineComponent, computed } from 'vue';
  13. import debounce from 'lodash-es/debounce';
  14. import FolderOpenOutlined from "@ant-design/icons-vue/es/icons/FolderOpenOutlined";
  15. import FolderOutlined from "@ant-design/icons-vue/es/icons/FolderOutlined";
  16. import FileOutlined from "@ant-design/icons-vue/es/icons/FileOutlined";
  17. import classNames from '../_util/classNames';
  18. import Tree, { treeProps } from './Tree';
  19. import initDefaultProps from '../_util/props-util/initDefaultProps';
  20. import { convertDataToEntities, convertTreeToData, fillFieldNames } from '../vc-tree/utils/treeUtil';
  21. import { conductExpandParent } from '../vc-tree/util';
  22. import { calcRangeKeys, convertDirectoryKeysToNodes } from './utils/dictUtil';
  23. import useConfigInject from '../config-provider/hooks/useConfigInject';
  24. import { filterEmpty } from '../_util/props-util';
  25. import { someType } from '../_util/type';
  26. export const directoryTreeProps = () => _extends(_extends({}, treeProps()), {
  27. expandAction: someType([Boolean, String])
  28. });
  29. function getIcon(props) {
  30. const {
  31. isLeaf,
  32. expanded
  33. } = props;
  34. if (isLeaf) {
  35. return _createVNode(FileOutlined, null, null);
  36. }
  37. return expanded ? _createVNode(FolderOpenOutlined, null, null) : _createVNode(FolderOutlined, null, null);
  38. }
  39. export default defineComponent({
  40. compatConfig: {
  41. MODE: 3
  42. },
  43. name: 'ADirectoryTree',
  44. inheritAttrs: false,
  45. props: initDefaultProps(directoryTreeProps(), {
  46. showIcon: true,
  47. expandAction: 'click'
  48. }),
  49. slots: Object,
  50. // emits: [
  51. // 'update:selectedKeys',
  52. // 'update:checkedKeys',
  53. // 'update:expandedKeys',
  54. // 'expand',
  55. // 'select',
  56. // 'check',
  57. // 'doubleclick',
  58. // 'dblclick',
  59. // 'click',
  60. // ],
  61. setup(props, _ref) {
  62. let {
  63. attrs,
  64. slots,
  65. emit,
  66. expose
  67. } = _ref;
  68. var _a;
  69. // convertTreeToData 兼容 a-tree-node 历史写法,未来a-tree-node移除后,删除相关代码,不要再render中调用 treeData,否则死循环
  70. const treeData = ref(props.treeData || convertTreeToData(filterEmpty((_a = slots.default) === null || _a === void 0 ? void 0 : _a.call(slots))));
  71. watch(() => props.treeData, () => {
  72. treeData.value = props.treeData;
  73. });
  74. onUpdated(() => {
  75. nextTick(() => {
  76. var _a;
  77. if (props.treeData === undefined && slots.default) {
  78. treeData.value = convertTreeToData(filterEmpty((_a = slots.default) === null || _a === void 0 ? void 0 : _a.call(slots)));
  79. }
  80. });
  81. });
  82. // Shift click usage
  83. const lastSelectedKey = ref();
  84. const cachedSelectedKeys = ref();
  85. const fieldNames = computed(() => fillFieldNames(props.fieldNames));
  86. const treeRef = ref();
  87. const scrollTo = scroll => {
  88. var _a;
  89. (_a = treeRef.value) === null || _a === void 0 ? void 0 : _a.scrollTo(scroll);
  90. };
  91. expose({
  92. scrollTo,
  93. selectedKeys: computed(() => {
  94. var _a;
  95. return (_a = treeRef.value) === null || _a === void 0 ? void 0 : _a.selectedKeys;
  96. }),
  97. checkedKeys: computed(() => {
  98. var _a;
  99. return (_a = treeRef.value) === null || _a === void 0 ? void 0 : _a.checkedKeys;
  100. }),
  101. halfCheckedKeys: computed(() => {
  102. var _a;
  103. return (_a = treeRef.value) === null || _a === void 0 ? void 0 : _a.halfCheckedKeys;
  104. }),
  105. loadedKeys: computed(() => {
  106. var _a;
  107. return (_a = treeRef.value) === null || _a === void 0 ? void 0 : _a.loadedKeys;
  108. }),
  109. loadingKeys: computed(() => {
  110. var _a;
  111. return (_a = treeRef.value) === null || _a === void 0 ? void 0 : _a.loadingKeys;
  112. }),
  113. expandedKeys: computed(() => {
  114. var _a;
  115. return (_a = treeRef.value) === null || _a === void 0 ? void 0 : _a.expandedKeys;
  116. })
  117. });
  118. const getInitExpandedKeys = () => {
  119. const {
  120. keyEntities
  121. } = convertDataToEntities(treeData.value, {
  122. fieldNames: fieldNames.value
  123. });
  124. let initExpandedKeys;
  125. // Expanded keys
  126. if (props.defaultExpandAll) {
  127. initExpandedKeys = Object.keys(keyEntities);
  128. } else if (props.defaultExpandParent) {
  129. initExpandedKeys = conductExpandParent(props.expandedKeys || props.defaultExpandedKeys || [], keyEntities);
  130. } else {
  131. initExpandedKeys = props.expandedKeys || props.defaultExpandedKeys;
  132. }
  133. return initExpandedKeys;
  134. };
  135. const selectedKeys = ref(props.selectedKeys || props.defaultSelectedKeys || []);
  136. const expandedKeys = ref(getInitExpandedKeys());
  137. watch(() => props.selectedKeys, () => {
  138. if (props.selectedKeys !== undefined) {
  139. selectedKeys.value = props.selectedKeys;
  140. }
  141. }, {
  142. immediate: true
  143. });
  144. watch(() => props.expandedKeys, () => {
  145. if (props.expandedKeys !== undefined) {
  146. expandedKeys.value = props.expandedKeys;
  147. }
  148. }, {
  149. immediate: true
  150. });
  151. const expandFolderNode = (event, node) => {
  152. const {
  153. isLeaf
  154. } = node;
  155. if (isLeaf || event.shiftKey || event.metaKey || event.ctrlKey) {
  156. return;
  157. }
  158. // Call internal rc-tree expand function
  159. // https://github.com/ant-design/ant-design/issues/12567
  160. treeRef.value.onNodeExpand(event, node);
  161. };
  162. const onDebounceExpand = debounce(expandFolderNode, 200, {
  163. leading: true
  164. });
  165. const onExpand = (keys, info) => {
  166. if (props.expandedKeys === undefined) {
  167. expandedKeys.value = keys;
  168. }
  169. // Call origin function
  170. emit('update:expandedKeys', keys);
  171. emit('expand', keys, info);
  172. };
  173. const onClick = (event, node) => {
  174. const {
  175. expandAction
  176. } = props;
  177. // Expand the tree
  178. if (expandAction === 'click') {
  179. onDebounceExpand(event, node);
  180. }
  181. emit('click', event, node);
  182. };
  183. const onDoubleClick = (event, node) => {
  184. const {
  185. expandAction
  186. } = props;
  187. // Expand the tree
  188. if (expandAction === 'dblclick' || expandAction === 'doubleclick') {
  189. onDebounceExpand(event, node);
  190. }
  191. emit('doubleclick', event, node);
  192. emit('dblclick', event, node);
  193. };
  194. const onSelect = (keys, event) => {
  195. const {
  196. multiple
  197. } = props;
  198. const {
  199. node,
  200. nativeEvent
  201. } = event;
  202. const key = node[fieldNames.value.key];
  203. // const newState: DirectoryTreeState = {};
  204. // We need wrap this event since some value is not same
  205. const newEvent = _extends(_extends({}, event), {
  206. selected: true
  207. });
  208. // Windows / Mac single pick
  209. const ctrlPick = (nativeEvent === null || nativeEvent === void 0 ? void 0 : nativeEvent.ctrlKey) || (nativeEvent === null || nativeEvent === void 0 ? void 0 : nativeEvent.metaKey);
  210. const shiftPick = nativeEvent === null || nativeEvent === void 0 ? void 0 : nativeEvent.shiftKey;
  211. // Generate new selected keys
  212. let newSelectedKeys;
  213. if (multiple && ctrlPick) {
  214. // Control click
  215. newSelectedKeys = keys;
  216. lastSelectedKey.value = key;
  217. cachedSelectedKeys.value = newSelectedKeys;
  218. newEvent.selectedNodes = convertDirectoryKeysToNodes(treeData.value, newSelectedKeys, fieldNames.value);
  219. } else if (multiple && shiftPick) {
  220. // Shift click
  221. newSelectedKeys = Array.from(new Set([...(cachedSelectedKeys.value || []), ...calcRangeKeys({
  222. treeData: treeData.value,
  223. expandedKeys: expandedKeys.value,
  224. startKey: key,
  225. endKey: lastSelectedKey.value,
  226. fieldNames: fieldNames.value
  227. })]));
  228. newEvent.selectedNodes = convertDirectoryKeysToNodes(treeData.value, newSelectedKeys, fieldNames.value);
  229. } else {
  230. // Single click
  231. newSelectedKeys = [key];
  232. lastSelectedKey.value = key;
  233. cachedSelectedKeys.value = newSelectedKeys;
  234. newEvent.selectedNodes = convertDirectoryKeysToNodes(treeData.value, newSelectedKeys, fieldNames.value);
  235. }
  236. emit('update:selectedKeys', newSelectedKeys);
  237. emit('select', newSelectedKeys, newEvent);
  238. if (props.selectedKeys === undefined) {
  239. selectedKeys.value = newSelectedKeys;
  240. }
  241. };
  242. const onCheck = (checkedObjOrKeys, eventObj) => {
  243. emit('update:checkedKeys', checkedObjOrKeys);
  244. emit('check', checkedObjOrKeys, eventObj);
  245. };
  246. const {
  247. prefixCls,
  248. direction
  249. } = useConfigInject('tree', props);
  250. return () => {
  251. const connectClassName = classNames(`${prefixCls.value}-directory`, {
  252. [`${prefixCls.value}-directory-rtl`]: direction.value === 'rtl'
  253. }, attrs.class);
  254. const {
  255. icon = slots.icon,
  256. blockNode = true
  257. } = props,
  258. otherProps = __rest(props, ["icon", "blockNode"]);
  259. return _createVNode(Tree, _objectSpread(_objectSpread(_objectSpread({}, attrs), {}, {
  260. "icon": icon || getIcon,
  261. "ref": treeRef,
  262. "blockNode": blockNode
  263. }, otherProps), {}, {
  264. "prefixCls": prefixCls.value,
  265. "class": connectClassName,
  266. "expandedKeys": expandedKeys.value,
  267. "selectedKeys": selectedKeys.value,
  268. "onSelect": onSelect,
  269. "onClick": onClick,
  270. "onDblclick": onDoubleClick,
  271. "onExpand": onExpand,
  272. "onCheck": onCheck
  273. }), slots);
  274. };
  275. }
  276. });