| 
1 |  | -<template lang="pug">  | 
2 |  | -.tree-children(:class="{'he-tree tree-root': isRoot}" :data-tree-id="_uid")  | 
3 |  | -  .tree-branch(v-for="(node, i) in nodes" :key="metas[i].id" :id="metas[i].DOMId")  | 
4 |  | -    .tree-node()  | 
5 |  | -      slot(:node="node" :meta="metas[i]" :root="root") {{node.text}}  | 
6 |  | -    transition(v-if="node.children && node.children.length > 0" :name="root.foldingTransition")  | 
7 |  | -      Tree(v-if="!metas[i].folded" :value="node.children" :privateProps="{...childPrivateProps, parent: node}")  | 
8 |  | -        template(slot-scope="props")  | 
9 |  | -          slot(:node="props.node" :meta="props.meta" :root="props.root") {{node.text}}  | 
10 |  | -</template>  | 
11 |  | - | 
12 | 1 | <script>  | 
13 | 2 | import * as hp from 'helper-js'  | 
14 | 3 | import * as th from 'tree-helper'  | 
15 | 4 | import * as tdhp from '@/todo-utils'  | 
16 | 5 | 
  | 
 | 6 | +const template = function (h) {  | 
 | 7 | +  const treeTpl = (nodes, isRoot, parentPath) => {  | 
 | 8 | +    const branchTpl = (node, index) => {  | 
 | 9 | +      const path = [...parentPath, index]  | 
 | 10 | +      const slotDefault = () => {  | 
 | 11 | +        if (this.$scopedSlots.default) {  | 
 | 12 | +          return this.$scopedSlots.default({node, index, path, store: this})  | 
 | 13 | +        } else if (this.$slots.default) {  | 
 | 14 | +          return this.$slots.default  | 
 | 15 | +        } else {  | 
 | 16 | +          return node.text  | 
 | 17 | +        }  | 
 | 18 | +      }  | 
 | 19 | +      return <div class="tree-branch" data-tree-node-path={path.join(',')}>  | 
 | 20 | +        <div class="tree-node">{slotDefault()}</div>  | 
 | 21 | +        {(node.children && node.children.length) > 0 && <transition name={this.$props.foldingTransition}>  | 
 | 22 | +          {!node.$folded && treeTpl(node.children, false, path)}  | 
 | 23 | +        </transition>}  | 
 | 24 | +      </div>  | 
 | 25 | +    }  | 
 | 26 | +    return <div class={`${isRoot ? 'he-tree tree-root' : ''} tree-children`} data-tree-id={isRoot ? this._uid : false}>  | 
 | 27 | +      {nodes.map(branchTpl)}  | 
 | 28 | +    </div>  | 
 | 29 | +  }  | 
 | 30 | +  return treeTpl(this.value, true, [])  | 
 | 31 | +}  | 
 | 32 | +
  | 
17 | 33 | const trees = {}  | 
18 | 34 | 
  | 
19 | 35 | const Tree = {  | 
20 |  | -  name: 'Tree',  | 
 | 36 | +  render: template,  | 
21 | 37 |   props: {  | 
22 | 38 |     value: {},  | 
23 |  | -    privateProps: {},  | 
24 |  | -    idMode: {default: 'object'}, // object, id(node must has id)  | 
25 |  | -    dataModification: {default: 'modify_old'}, // new, modify_old. create new data or modify old  | 
26 |  | -    DOM_ID_PREFIX: {default: 'he_tree'},  | 
27 | 39 |   },  | 
28 | 40 |   // components: {},  | 
29 | 41 |   data() {  | 
30 | 42 |     return {  | 
31 |  | -      metas: [], // metas of current level nodes  | 
32 | 43 |       trees,  | 
33 | 44 |     }  | 
34 | 45 |   },  | 
35 |  | -  computed: {  | 
36 |  | -    root() { return this.privateProps && this.privateProps.root || this },  | 
37 |  | -    isRoot() { return this.root === this },  | 
38 |  | -    level() { return this.privateProps ? this.privateProps.level : 1 },  | 
39 |  | -    parent() { return this.privateProps && this.privateProps.parent },  | 
40 |  | -    nodes() { return this.value || [] },  | 
41 |  | -    childPrivateProps() {  | 
42 |  | -      return {  | 
43 |  | -        root: this.root,  | 
44 |  | -        level: this.level + 1,  | 
45 |  | -      }  | 
46 |  | -    },  | 
47 |  | -  },  | 
48 |  | -  watch: {},  | 
 | 46 | +  // computed: {},  | 
 | 47 | +  // watch: {},  | 
49 | 48 |   methods: {  | 
50 |  | -    nodesWatcher(nodes, oldNodes) {  | 
51 |  | -      if (oldNodes) {  | 
52 |  | -        // removed metas  | 
53 |  | -        if (this.root.idMode === 'id') {  | 
54 |  | -          const t = {}  | 
55 |  | -          nodes.forEach(node => {t[node.id]=true})  | 
56 |  | -          oldNodes.forEach(node => {  | 
57 |  | -            if (!t[node.id]) {  | 
58 |  | -              // delete node and children meta  | 
59 |  | -              th.depthFirstSearch(node, (childNode) => {  | 
60 |  | -                delete this.root.metaMap[childNode.id]  | 
61 |  | -                delete this.root.idMap[childNode.id]  | 
62 |  | -              })  | 
63 |  | -            }  | 
64 |  | -          })  | 
65 |  | -        } else {  | 
66 |  | -          const t = new Map()  | 
67 |  | -          nodes.forEach(node => t.set(node, null))  | 
68 |  | -          oldNodes.forEach(node => {  | 
69 |  | -            if (!t.has(node)) {  | 
70 |  | -              // delete node and children meta  | 
71 |  | -              th.depthFirstSearch(node, (childNode) => {  | 
72 |  | -                const meta = this.root.metaMap.get(childNode)  | 
73 |  | -                this.root.metaMap.delete(childNode)  | 
74 |  | -                delete this.root.idMap[meta.id]  | 
75 |  | -              })  | 
76 |  | -            }  | 
77 |  | -          })  | 
78 |  | -        }  | 
79 |  | -      }  | 
80 |  | -      //  | 
81 |  | -      this.metas = nodes.map(node => {  | 
82 |  | -        const oldMeta = this.idMode === 'id' ? this.root.metaMap[node.id] : this.root.metaMap.get(node)  | 
83 |  | -        const newMeta = {}  | 
84 |  | -        // initial meta  | 
85 |  | -        if (node.$meta) {  | 
86 |  | -          Object.assign(newMeta, node.$meta)  | 
87 |  | -        }  | 
88 |  | -        //  | 
89 |  | -        let id, DOMId  | 
90 |  | -        if (oldMeta) {  | 
91 |  | -          id = oldMeta.id  | 
92 |  | -          DOMId = oldMeta.DOMId  | 
93 |  | -        } else {  | 
94 |  | -          id = node.id || hp.strRand()  | 
95 |  | -          DOMId = `${this.DOM_ID_PREFIX}_${this.root._uid}_branch_${id}`  | 
96 |  | -        }  | 
97 |  | -        Object.assign(newMeta, {  | 
98 |  | -          id,  | 
99 |  | -          DOMId,  | 
100 |  | -        })  | 
101 |  | -        if (this.$options._afterMetaCreateds) {  | 
102 |  | -          for (const func of this.$options._afterMetaCreateds) {  | 
103 |  | -            func.call(this, newMeta, node)  | 
104 |  | -          }  | 
105 |  | -        }  | 
106 |  | -        if (oldMeta) {  | 
107 |  | -          Object.assign(newMeta, oldMeta)  | 
108 |  | -        }  | 
109 |  | -        Object.assign(newMeta, {  | 
110 |  | -          parent: this.parent,  | 
111 |  | -          level: this.level,  | 
112 |  | -        })  | 
113 |  | -        if (this.idMode === 'id') {  | 
114 |  | -          this.root.metaMap[id] = newMeta  | 
115 |  | -        } else {  | 
116 |  | -          this.root.metaMap.set(node, newMeta)  | 
117 |  | -        }  | 
118 |  | -        this.root.idMap[id] = node  | 
119 |  | -        return newMeta  | 
120 |  | -      })  | 
121 |  | -    },  | 
122 |  | -    getMetaByNode(node) {  | 
123 |  | -      return this.root.idMode === 'id' ? this.root.metaMap[node.id] : this.root.metaMap.get(node)  | 
124 |  | -    },  | 
125 |  | -    convertDOMIDToID(DOMId) {  | 
126 |  | -      let r = DOMId  | 
127 |  | -      if (DOMId.startsWith(this.DOM_ID_PREFIX)) {  | 
128 |  | -        r = DOMId.split('_branch_')[1]  | 
129 |  | -      }  | 
130 |  | -      return r  | 
131 |  | -    },  | 
132 |  | -    // by DOMId or ID  | 
133 |  | -    getNodeByID(DOMIdOrID) {  | 
134 |  | -      const id = this.convertDOMIDToID(DOMIdOrID)  | 
135 |  | -      return this.root.idMap[id]  | 
136 |  | -    },  | 
137 |  | -    getMetaByID(DOMIdOrID) {  | 
138 |  | -      const node = this.getNodeByID(DOMIdOrID)  | 
139 |  | -      return this.getMetaByNode(node)  | 
140 |  | -    },  | 
141 |  | -    getNodeParent(node) {  | 
142 |  | -      const meta = this.getMetaByNode(node)  | 
143 |  | -      return meta ? meta.parent : null  | 
144 |  | -    },  | 
145 |  | -    getNodeSiblings(node, opt = {}) {  | 
146 |  | -      opt = {  | 
147 |  | -        convertToArray: true,  | 
148 |  | -        ...opt,  | 
149 |  | -      }  | 
150 |  | -      const parent = this.getNodeParent(node)  | 
151 |  | -      let r = parent ? parent.children : this.root.value  | 
152 |  | -      if (opt.convertToArray) {  | 
153 |  | -        r = hp.toArrayIfNot(r)  | 
154 |  | -      }  | 
155 |  | -      return r  | 
156 |  | -    },  | 
157 |  | -    * iterateParents(node, opt = {}) {  | 
158 |  | -      if (opt.withSelf) {  | 
159 |  | -        yield node  | 
160 |  | -      }  | 
161 |  | -      let cur = this.getNodeParent(node)  | 
162 |  | -      while (cur) {  | 
163 |  | -        yield cur  | 
164 |  | -        cur = this.getNodeParent(cur)  | 
165 |  | -      }  | 
166 |  | -    },  | 
 | 49 | +    // * iterateParents(node, opt = {}) {  | 
 | 50 | +    //   if (opt.withSelf) {  | 
 | 51 | +    //     yield node  | 
 | 52 | +    //   }  | 
 | 53 | +    //   let cur = this.getNodeParent(node)  | 
 | 54 | +    //   while (cur) {  | 
 | 55 | +    //     yield cur  | 
 | 56 | +    //     cur = this.getNodeParent(cur)  | 
 | 57 | +    //   }  | 
 | 58 | +    // },  | 
167 | 59 |     traverseDescendants(nodeOrNodes, handler) {  | 
168 | 60 |       return th.depthFirstSearch(nodeOrNodes, handler)  | 
169 | 61 |     },  | 
170 |  | -    cloneTreeData(nodeOrNodes) {  | 
171 |  | -      const nodes = hp.toArrayIfNot(nodeOrNodes)  | 
172 |  | -      const walk = (arr) => arr.map(node => {  | 
173 |  | -        const newNode = Object.assign({}, node)  | 
174 |  | -        if (newNode.children) {  | 
175 |  | -          newNode.children = walk(newNode.children)  | 
176 |  | -        }  | 
177 |  | -        return newNode  | 
178 |  | -      })  | 
179 |  | -      let r = walk(nodes)  | 
180 |  | -      return hp.isArray(nodeOrNodes) ? r : r[0]  | 
181 |  | -    },  | 
 | 62 | +    // cloneTreeData(nodeOrNodes) {  | 
 | 63 | +    //   const nodes = hp.toArrayIfNot(nodeOrNodes)  | 
 | 64 | +    //   const walk = (arr) => arr.map(node => {  | 
 | 65 | +    //     const newNode = Object.assign({}, node)  | 
 | 66 | +    //     if (newNode.children) {  | 
 | 67 | +    //       newNode.children = walk(newNode.children)  | 
 | 68 | +    //     }  | 
 | 69 | +    //     return newNode  | 
 | 70 | +    //   })  | 
 | 71 | +    //   let r = walk(nodes)  | 
 | 72 | +    //   return hp.isArray(nodeOrNodes) ? r : r[0]  | 
 | 73 | +    // },  | 
182 | 74 |     getTreeVmByTreeEl(treeEl) {  | 
183 | 75 |       return this.root.trees[treeEl.getAttribute('data-tree-id')]  | 
184 | 76 |     },  | 
 | 77 | +    getNodeByPath(path) {  | 
 | 78 | +      return hp.arrayLast(this.getAllNodesByPath(path))  | 
 | 79 | +    },  | 
 | 80 | +    getAllNodesByPath(path) {  | 
 | 81 | +      let nodes = []  | 
 | 82 | +      let cur  | 
 | 83 | +      let curChildren = this.value  | 
 | 84 | +      for (const index of path) {  | 
 | 85 | +        cur = curChildren[index]  | 
 | 86 | +        nodes.push(cur)  | 
 | 87 | +        curChildren = cur.children  | 
 | 88 | +      }  | 
 | 89 | +      return nodes  | 
 | 90 | +    },  | 
185 | 91 |     // todo extract hooks to vue-functions  | 
186 | 92 |     // get hooks in this._hooks, without which in props  | 
187 | 93 |     _getNonPropHooksByName(name) {  | 
@@ -221,22 +127,7 @@ const Tree = {  | 
221 | 127 |       }  | 
222 | 128 |     },  | 
223 | 129 |   },  | 
224 |  | -  created() {  | 
225 |  | -    if (this === this.root) {  | 
226 |  | -      this.metaMap = this.idMode === 'id' ? {} : new Map()  | 
227 |  | -      this.idMap = {}  | 
228 |  | -      this.trees[this._uid] = this  | 
229 |  | -      this.$once('hook:beforeDestroy', () => {  | 
230 |  | -        this.$delete(this.trees, this._uid)  | 
231 |  | -      })  | 
232 |  | -    }  | 
233 |  | -    this.$watch('nodes', this.nodesWatcher, {immediate: true})  | 
234 |  | -    this.$watch('level', (level, oldLevel) => {  | 
235 |  | -      for (const node of this.nodes) {  | 
236 |  | -        this.getMetaByNode(node).level = level  | 
237 |  | -      }  | 
238 |  | -    }, {immediate: true})  | 
239 |  | -  },  | 
 | 130 | +  // created() {},  | 
240 | 131 |   // mounted() {},  | 
241 | 132 |   // beforeDestroy() {},  | 
242 | 133 | 
  | 
 | 
0 commit comments