【 vue / uniapp 】延迟加载数据的特殊处理

在用vue实现一个无限层级的树型结构时,遇到了这个问题。

页面结构如图:

其中,父页面的处理逻辑:

步骤一:引用并挂载组件,同时向组件props传递树型JSON列表数据(this.list),当然这时候的 this.list 还只是一个空数组。

步骤二:在 onload 事件中从服务器获取树型JSON数据并回写到 this.list,同时这个 this.list 也会自动通过 props 传递给组件。

 

当时考虑到对数据的解耦,不想在父页面中对数据进行过多的处理,拿到服务端的JSON后直接交给组件,剩下的都在组件里实现。

所以对于组件来说,就要对 props 中接收到的数据进一步处理,用来满足树型的相关要求。

首先,为了实现对树型节点的展开/闭合操作,每个节点的数据对象都需要增加一个属性(opened),用来记忆节点的状态,同时自动渲染到Dom。

 

组件的处理逻辑:

步骤一:接收 props 中的 list 数据;

步骤二:在组件的 mounted 事件中遍历 list 中当前层级的节点列表数据对象,增加并初始化属性 item.opened = false,即默认闭合节点。

步骤三:如果存在子节点,则递归引用并挂载组件,同时将子节点列表数传递给组件,实现无限层级的树型渲染。

 

注意:步骤二中为节点数据对象增加 opened 属性需要使用 this.$set 函数,否则新增加的属性将不支持与视图的自动响应。

 

按照以上方式完成之后,发现第一层节点的 opened 属性并没有自动响应,通过调试发现组件的 mounted 事件只处理了第一次挂载时接收到的空数组,之后父页面传过来的真实数据压根没经过处理。

想了一下,才反应过来,因为父页面在创建时就已经触发了组件的 mounted 事件;

后来从服务端返回JSON后,修改 props 时不会再次触发组件的 mounted 事件,反而会触发 updated 事件,所以才造成了新增属性无效的情况。

 

弄明白了问题所在,解决起来也很纠结,因为只有第一层组件的数据传入是异步的,需要从 updated 事件进行处理;

而更下层的组件都是挂载时就会传入的,还需要从 mounted 进行处理。

另一个问题就是,每次点击节点时要修改 opened 属性,而这时也会触发 updated 事件,所以初始化操作还是不能在 updated 中处理。

 

想明白了问题所在,就尝试通过 this.$refs 来实现,在父页面引用组件时,默认先不通过 props 传入 list 数据,而是在获取服务端JSON之后,使用 this.$refs.comp.treeRoot(list) 向组件传入,而组件本身的 mounted 事件用来处理第二层之后的组件数据初始化。

后来又尝试用 watch 来解决,感觉比 ref 要简洁一些,核心代码如下:

watch: {
    list: {
        handler(newVal, oldVal){
            if(kit.isEmpty(oldVal) || oldVal.length === 0){
                this.opened = this.currentLevel < this.openLevel;
                let list = JSON.parse(JSON.stringify(newVal));
                list.forEach((item, i) => {
                    item[this.attrOpened] = this.opened;
                })
                this.treeList = list;
            }
        },
        immediate: true
    }
}

 

posted @ 2020-02-18 21:06  网无忌  阅读(1801)  评论(0编辑  收藏