[ElemeFE/element]Tree 的 append 和 remove 方法无法改变 data

2024-08-13 886 views
1
ElementUI version

1.2.3

OS/Browers version

Windows/Chrome 56

Vue version

2.2.1

Reproduction Link

https://codepen.io/anon/pen/ryLLVq

Steps to reproduce

随便点击一个节点,删除了该节点,查看控制台。

What is Expected?

store.data 中数据未删除。

What is actually happening?

在 Tree 文档的 自定义节点内容 一节,里面用到了 appendremove 方法,但是下方 API 未写明。我给出的 codepen 中仅把官方例子中 JSX 改为 render 函数,删除节点时,DOM 上是显示移除了,但 store.data 数据没有变化。

回答

6

同求啊,也遇到了这个问题,持续懵逼中,求大神解救

2

同求,今天折腾了一下午,问题也没有解决

0

同样遇到这个问题

3

话说难道是需要用到load加载么

3

提供半个解决方法。append可以用下面这个取代,remove怎么搞我也懵逼

     append(store, data) {
//      store.append({ id: id++, label: 'testtest', children: [] }, data);  //无法改变data的
        data.children.push({ id: id++, label: '测试', children: [] });
     }
7

同样遇到此问题.

提供个解决思路: 通过$children获取到ELTree组件的_data.root.childNodes属性.里面存放有当前Tree的一些属性(填加/删除会反映到这里).可以在点击append或者remove之后.用上面获取到的tree obj 替换tree的data. (我正在解决其中细节.这个思路已证可行)

9

折腾了差不多一天.不是从Eleme源码而是另外的角度解决了这个问题:

首先我发现,在append/remove节点之后,结果是会反映在ElTree(用VueDevTools查看)里的一些属性里的.比如_data.root.childNodes.所以在Append/Delete方法里动态获取它里面的我们想要的数据(id,label,childNodes).然后赋值给this.data就好了.

所以我就写了一个函数来做这件事:

 testFunc(){
                //我们想要的数据,在这里面.你可以打印出来研究一下.
                let tempObj = this.$refs.treeParent.$children[0]['_data'].root.childNodes;

                //在获取数据之前,需要深克隆一下上面的对象,因为后面我们需要直接处理该对象.
                // DeepCopy函数来自https://zhuanlan.zhihu.com/p/23251162
                function DeepCopy(obj) {
                // Hash表 记录所有的对象引用关系
                    let map = new WeakMap();
                    function dp(obj) {
                        let result = null;
                        let keys = null,
                            key = null,
                            temp = null,
                            existObj = null;

                        existObj = map.get(obj);
                        // 如果这个对象已被记录则直接返回
                        if (existObj) {
                            return existObj;
                        }
                        keys = Object.keys(obj);
                        result = {};
                        // 记录当前对象
                        map.set(obj,result);
                        for (let i = 0; i < keys.length; i++) {
                            key = keys[i];
                            temp = obj[key];
                            // 如果字段的值也是一个对象则递归复制
                            if (temp && typeof temp === 'object') {
                                result[key] = dp(temp);
                            } else {
                                // 否则直接赋值给新对象
                                result[key] = temp;
                            }
                        }
                        return result;
                    }
                    return dp(obj);
                }

                //dealData方法处理对象,把对象变成{"id":123,"label":"test",childNodes:[]}的形式,会删除所有其他属性
                function dealData(obj) {
                    for (let attr of Object.keys(obj)) {
                        if (attr != "data" && attr != "childNodes") {
                            delete obj[attr];
                        }
                    }
                    if (obj.hasOwnProperty('data')) {
                        obj.id = obj.data.id;
                        obj.label = obj.data.label;
                        delete obj.data;
                    }
                    for (let item in obj.childNodes) {
                        if(item){
                            dealData(obj.childNodes[item]);
                        };
                    }
                }

                //在上面DeepCopy时,把childNodes变成了object,但我们想要的是Array.所以本函数可以把它转换回来.
                function objToArray(obj) {
                    let arr = [];
                    for (let item in obj.childNodes) {
                        if (item) {
                            arr.push(obj.childNodes[item]);
                        }
                    }
                    obj.childNodes = arr;
                    for (let a of arr) {
                        objToArray(a);
                    }
                }

                // data 模拟 this.data
                let data = [];
                for (const item of Object.values(tempObj)){
                    let copied = DeepCopy(item);
                    dealData(copied);
                    copied = JSON.parse(JSON.stringify(copied));
                    objToArray(copied);                    
                    data.push(copied);
                }
                // data里的数据是我们想要的.可以直接赋值给this.data来解决Element的这个Bug.
                return data;
            },
   append(store,data) {
                store.append({
                    id: id++,
                    label: 'test',
                    children: []
                }, data);
                let obj = this.testFunc();
                this.$set(this,"data",obj);
            },
   remove(store, data) {
                store.remove(data);
                let obj = this.testFunc();
                this.$set(this,"data",obj);
            },
3

用了比较耗性能的方法:深层遍历

     append (store, data, newNode) {
        // 当前结点id
        let currentId = data.id
        // 深拷贝treeData
        let _treeData = JSON.parse(JSON.stringify(this.treeData))
        // 遍历树结点
        _treeData.map(function map (item) {
          let children = item.children = item.children || []
          if (+item.id === +currentId) {
            item.children.push(newNode)
          } else {
            item.children = children.map((child) => {
              return map(child)
            })
          }
          return item
        })
        // 替换整个树
        this.treeData = _treeData
      }

     remove (store, data) {
        let currentId = data.id
        let _treeData = JSON.parse(JSON.stringify(this.treeData))
        _treeData.map(function map (item) {
          let children = item.children || []
          let matchIndex = 0
          let childMatched = children.some((child, childIndex) => {
            if (+child.id === +currentId) {
              matchIndex = childIndex
              return true
            }
          })
          if (childMatched) {
            item.children.splice(matchIndex, 1)
          } else {
            item.children = children.map((child) => {
              return map(child)
            })
          }
          return item
        })
        this.treeData = _treeData
      }
5

ElementUI 1.3.7 依然存在这个问题,我的解决办法是直接操作数据源对象,数据源的变化能够反应到树上。

8

怎么官方都没解答一下。。。我觉得这个问题很常见的啊

0

希望官方赶紧解决啊,这个问题折腾人好久了

3

apend(store, data)这个连球说明都没

5

tree操作确实有这一块的问题 数组怎么增加 不通过请求数据的办法

2

我也是直接通过修改数据源实现,就不用它例子中store的append方法了

7

同求

5

直接操作数据源,插入操作会视图会刷新,但是做删除操作视图就没反应了。折腾两天了.......

8

我今天也遇到这样,数据源新增后会自动在tree上显示,但数据源移除一个元素后tree上还有。

2

不知道你们解决了吗,我后来是发现删除时,除了移除node.data.children里对应的data,还要移除node.childNodes里对应的node。另外调用官方的remove方法,好像没什么反应。 神奇的是如果直接修改node.data里的数据,比如里面有一条name,name绑定到tree的显示名称上,改了这个值显示会跟着变,符合vue的响应机制。但改data里的children数组,比如置空,并不会触发响应,改childNodes才会