0e896c6d22af2b1aa2f269e4fab71761a2bd41a332ab1e29f045621dbab277488a3fd529ca34d938344f4db9bd140d25fcef1f72149eda1eecdb85aeebb338 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. import { walkTreeNode, getRowIdentity } from '../util';
  2. export default {
  3. data() {
  4. return {
  5. states: {
  6. // defaultExpandAll 存在于 expand.js 中,这里不重复添加
  7. // 在展开行中,expandRowKeys 会被转化成 expandRows,expandRowKeys 这个属性只是记录了 TreeTable 行的展开
  8. // TODO: 拆分为独立的 TreeTable,统一用法
  9. expandRowKeys: [],
  10. treeData: {},
  11. indent: 16,
  12. lazy: false,
  13. lazyTreeNodeMap: {},
  14. lazyColumnIdentifier: 'hasChildren',
  15. childrenColumnName: 'children'
  16. }
  17. };
  18. },
  19. computed: {
  20. // 嵌入型的数据,watch 无法是检测到变化 https://github.com/ElemeFE/element/issues/14998
  21. // TODO: 使用 computed 解决该问题,是否会造成性能问题?
  22. // @return { id: { level, children } }
  23. normalizedData() {
  24. if (!this.states.rowKey) return {};
  25. const data = this.states.data || [];
  26. return this.normalize(data);
  27. },
  28. // @return { id: { children } }
  29. // 针对懒加载的情形,不处理嵌套数据
  30. normalizedLazyNode() {
  31. const { rowKey, lazyTreeNodeMap, lazyColumnIdentifier } = this.states;
  32. const keys = Object.keys(lazyTreeNodeMap);
  33. const res = {};
  34. if (!keys.length) return res;
  35. keys.forEach(key => {
  36. if (lazyTreeNodeMap[key].length) {
  37. const item = { children: [] };
  38. lazyTreeNodeMap[key].forEach(row => {
  39. const currentRowKey = getRowIdentity(row, rowKey);
  40. item.children.push(currentRowKey);
  41. if (row[lazyColumnIdentifier] && !res[currentRowKey]) {
  42. res[currentRowKey] = { children: [] };
  43. }
  44. });
  45. res[key] = item;
  46. }
  47. });
  48. return res;
  49. }
  50. },
  51. watch: {
  52. normalizedData: 'updateTreeData',
  53. normalizedLazyNode: 'updateTreeData'
  54. },
  55. methods: {
  56. normalize(data) {
  57. const {
  58. childrenColumnName,
  59. lazyColumnIdentifier,
  60. rowKey,
  61. lazy
  62. } = this.states;
  63. const res = {};
  64. walkTreeNode(
  65. data,
  66. (parent, children, level) => {
  67. const parentId = getRowIdentity(parent, rowKey);
  68. if (Array.isArray(children)) {
  69. res[parentId] = {
  70. children: children.map(row => getRowIdentity(row, rowKey)),
  71. level
  72. };
  73. } else if (lazy) {
  74. // 当 children 不存在且 lazy 为 true,该节点即为懒加载的节点
  75. res[parentId] = {
  76. children: [],
  77. lazy: true,
  78. level
  79. };
  80. }
  81. },
  82. childrenColumnName,
  83. lazyColumnIdentifier
  84. );
  85. return res;
  86. },
  87. updateTreeData() {
  88. const nested = this.normalizedData;
  89. const normalizedLazyNode = this.normalizedLazyNode;
  90. const keys = Object.keys(nested);
  91. const newTreeData = {};
  92. if (keys.length) {
  93. const {
  94. treeData: oldTreeData,
  95. defaultExpandAll,
  96. expandRowKeys,
  97. lazy
  98. } = this.states;
  99. const rootLazyRowKeys = [];
  100. const getExpanded = (oldValue, key) => {
  101. const included =
  102. defaultExpandAll ||
  103. (expandRowKeys && expandRowKeys.indexOf(key) !== -1);
  104. return !!((oldValue && oldValue.expanded) || included);
  105. };
  106. // 合并 expanded 与 display,确保数据刷新后,状态不变
  107. keys.forEach(key => {
  108. const oldValue = oldTreeData[key];
  109. const newValue = { ...nested[key] };
  110. newValue.expanded = getExpanded(oldValue, key);
  111. if (newValue.lazy) {
  112. const { loaded = false, loading = false } = oldValue || {};
  113. newValue.loaded = !!loaded;
  114. newValue.loading = !!loading;
  115. rootLazyRowKeys.push(key);
  116. }
  117. newTreeData[key] = newValue;
  118. });
  119. // 根据懒加载数据更新 treeData
  120. const lazyKeys = Object.keys(normalizedLazyNode);
  121. if (lazy && lazyKeys.length && rootLazyRowKeys.length) {
  122. lazyKeys.forEach(key => {
  123. const oldValue = oldTreeData[key];
  124. const lazyNodeChildren = normalizedLazyNode[key].children;
  125. if (rootLazyRowKeys.indexOf(key) !== -1) {
  126. // 懒加载的 root 节点,更新一下原有的数据,原来的 children 一定是空数组
  127. if (newTreeData[key].children.length !== 0) {
  128. throw new Error('[ElTable]children must be an empty array.');
  129. }
  130. newTreeData[key].children = lazyNodeChildren;
  131. } else {
  132. const { loaded = false, loading = false } = oldValue || {};
  133. newTreeData[key] = {
  134. lazy: true,
  135. loaded: !!loaded,
  136. loading: !!loading,
  137. expanded: getExpanded(oldValue, key),
  138. children: lazyNodeChildren,
  139. level: ''
  140. };
  141. }
  142. });
  143. }
  144. }
  145. this.states.treeData = newTreeData;
  146. this.updateTableScrollY();
  147. },
  148. updateTreeExpandKeys(value) {
  149. this.states.expandRowKeys = value;
  150. this.updateTreeData();
  151. },
  152. toggleTreeExpansion(row, expanded) {
  153. this.assertRowKey();
  154. const { rowKey, treeData } = this.states;
  155. const id = getRowIdentity(row, rowKey);
  156. const data = id && treeData[id];
  157. if (id && data && ('expanded' in data)) {
  158. const oldExpanded = data.expanded;
  159. expanded = typeof expanded === 'undefined' ? !data.expanded : expanded;
  160. treeData[id].expanded = expanded;
  161. if (oldExpanded !== expanded) {
  162. this.table.$emit('expand-change', row, expanded);
  163. }
  164. this.updateTableScrollY();
  165. }
  166. },
  167. loadOrToggle(row) {
  168. this.assertRowKey();
  169. const { lazy, treeData, rowKey } = this.states;
  170. const id = getRowIdentity(row, rowKey);
  171. const data = treeData[id];
  172. if (lazy && data && 'loaded' in data && !data.loaded) {
  173. this.loadData(row, id, data);
  174. } else {
  175. this.toggleTreeExpansion(row);
  176. }
  177. },
  178. loadData(row, key, treeNode) {
  179. const { load } = this.table;
  180. const { treeData: rawTreeData } = this.states;
  181. if (load && !rawTreeData[key].loaded) {
  182. rawTreeData[key].loading = true;
  183. load(row, treeNode, data => {
  184. if (!Array.isArray(data)) {
  185. throw new Error('[ElTable] data must be an array');
  186. }
  187. const { lazyTreeNodeMap, treeData } = this.states;
  188. treeData[key].loading = false;
  189. treeData[key].loaded = true;
  190. treeData[key].expanded = true;
  191. if (data.length) {
  192. this.$set(lazyTreeNodeMap, key, data);
  193. }
  194. this.table.$emit('expand-change', row, true);
  195. });
  196. }
  197. }
  198. }
  199. };