Vuejs刷新页面子组件数据丢失问题的一点笔记

来源:互联网 发布:面包板与单片机的连接 编辑:程序博客网 时间:2024/06/06 11:46

最近在学Vuejs, 发现在路由中给子组件传递数据后,刷新页面出现数据丢失问题。

// 子组件代码props: {    // 用于接收父组件的数据goodsData      goodsData: {        type: Array,        required: true      }    },computed: {      ...      item () {         // 计算属性item根据地址栏查询关键字在goodsData中筛选并返回符合条件的数据         // http://localhost:8080/#/goods/food_detail?i_S=0&i_F=1        const indexS = this.$route.query.i_S        const indexF = this.$route.query.i_F        return this.goodsData[indexS].foods[indexF]      }    },

从父路由点进去非常正常,但是重新刷新页面子组件会直接消失,返回父页面。页面地址显示正常,子组件渲染出错,按出dev-tool 组件内部的数据存储也是没有问题的,该有的都有。但是控制台还是报错typeError,无法获取undefinded的foods属性。

在子组件created钩子函数,添加了一条在控制台打印 this.goodsData 的命令, 运行后输出了一个空数组,dev-tool中依旧显示this.goodsData非常正常,甚至item也是正常的,应该是加载数据的时候出错了,也就是 计算属性item第一次运行时由于this.goodsData还没有传过来,所以渲染出错了。说到底应该是生命周期的问题?(不太熟悉)

解决方法是给计算属性添加一个判断条件

    item () {        const indexS = this.$route.query.i_S        const indexF = this.$route.query.i_F        if (this.goodsData.length > 0) return this.goodsData[indexS].foods[indexF]        return false      }

依靠该数据进行初始化的数据也不能再放到created,因为它需要在item加载后调取里面的数据进行初始化。

我这里就需要提交item里面的ratings属性到vuex,本来是created的时候就可以执行的,但是现在created阶段item数据并没有准备好,所以需要准备一个函数,在item返回值不为false的时候替我初始化ratings数据并提交到vuex中。

我选择用watch去观察item,computed应该也可以。但是自己感觉用watch好像更适合点,就用watch了。

    watch: {      item: function (newVal, oldVal) {        if (newVal) {          this._initComments()          this.refreshScroll() // bscroll 对象更新dom        }      }    },

问题解决。
主要解决方案就是给computed加个条件判断,计算属性获取失败时返回false,在this.goodsData变化(获取成功)时, 计算属性自动执行并更新,watch属性通过监视该计算属性的值,进行其他初始化操作。


2017 / 09 / 07 更新

其实没有解决。
今天搞评价页面(path: /ratings)的时候又发现了新问题,这个页面也是有一堆评论,从评价页面和商品详情页面(path: /goods/food_detail, query: { i_s = :indexS, i_f = indexF })来回切换,comment组件的数据没有更新,但是如果在页面上刷新一次就可以正常显示……

负责初始化vuex中的comment数据的是watch观察属性,按理说,只要$route.query.i_S, $route.query.i_F发生变化,计算属性item就会更新,同时更新dom,并且观察属性也会被触发,初始化新的comment数据,然而vue-devtool里面看到的item的计算属性是已经更新了的状态。

watch对象item函数添加两个命令: console.log(newVal); console.log(oldVal)。 来回切换路由依然是没有反应,控制台没有打印任何数据,只有刷新当前页面时才会有输出。说到底就是,计算属性item更新了,但是观察属性item没反应。

折腾了一下,发现问题在于观察属性观察的对象是个计算属性,改成data属性就什么破事都没有了。

但是还是要计算属性返回需要的数据给data里面的属性,而且如果计算属性自己没有在dom里面被读取,或者它依赖的响应属性没有被更新,它就不会自动执行。

要么把初始化comments数据放到计算属性item里面,要么在data中造个属性来存放计算属性每次更新改变的值(当然你要让计算属性自动执行,也就是说你要改变它依赖的响应属性,或者在dom中引用它里边的数据,让它在更新的过程中,顺带更新下data里面的那个用于被观察属性观察的值)。

当dom的数据准备加载了,被引用的computed属性就会自动执行
这时候,当计算属性获得有效的goodsData后,就会根据$route.query的两个属性获取这个页面需要的那条数据,然后赋值(不一定要赋值该数据,只要能被观察属性观测到都可以……)给data里面的那个用于观察的值,同时自己返回这条数据,dom中数据更新。

因为data里面的那个属性发生了变化(暂时喊它 dataItem), watch也就被正常触发了,这是所有的初始化操作都能正常执行了,问题解决,可喜可贺。结论是:不要用watch属性去观察一个computed属性。

当然不搞watch属性初始化,直接在计算属性item里面初始化也是可以的。但是如果使用了created里用 $nextTick 初始化一个对象,并在这个item里面使用该对象的方法的话, 可能会导致出错。

我的情况是这样:

created函数中的$nextTick初始化一个BScroll对象,

然后在计算属性item成功获取数据,更新comment数据后在$nextTick回调函数里调用BScroll对象的refresh()方法,重新获取dom高度。

听起来好像也没什么不对。然而如果我从/foods这个路由进去 /foods/food_detail?…的话,就会报错: bscroll对象未定义。刷新页面后又完全正常。

在created的$nextTick回调里面控制台输出,在计算属性里面的
$nextTick 也搞个控制台输出。路由切换时,nextTick是computed属性中的执行得快,created的慢。 刷新页面的时候倒是反过来。

为了避免它搞事,老老实实在计算属性里面初始化BScroll算了

阅读全文
0 0