Vue JS计算属性没有重新计算

Posted

技术标签:

【中文标题】Vue JS计算属性没有重新计算【英文标题】:Vue JS computed property not recalculating 【发布时间】:2019-10-25 04:41:15 【问题描述】:

我有一个 Laravel / Vue JS 应用程序,它集成了一个谷歌地图组件以及一个 Vuetify 数据表 组件。 Vue 实例还有一个计算属性,用于计算 Google 地图的点,该属性基于 Vuetify 数据表 计算的另一个计算属性。

视图刀片中的 Vue 组件代码:

    <v-data-table :ref="model + 'Table'" v-model="selected" :headers="headers" :items="collection" :pagination.sync="pagination" select-all item-key="id" class="elevation-1" >         
    </v-data-table>

    <google-map v-if="mapPoints.length" class="google-map" :markers="mapPoints"></google-map>

Vue 实例代码:

var app = new Vue(
el: '#app',
mixins: [ crudFunctionsMixin, adminLayoutMixin ],
data: () => (
),
computed: 
    mapPoints: function() 
        return this.calcPoints(this.$refs.prospectTable.filteredItems);
    
,
methods: 
    calcPoints(items) 
        let myPts = [];
        let i = 0;

        items.forEach(function(prospect) 
            if(prospect.latitude && prospect.longitude) 
                myPts.push(
                    id:     prospect.id,
                    position: 
                        lat: prospect.latitude,
                        lng: prospect.longitude
                    ,
                    index: i++,
                    title:  prospect.address + ", " + prospect.city + ", " + prospect.zip,
                    icon:   "\/img\/numberedMapIcons\/number_" + prospect.id + ".png"
                );
            
        );

        return myPts;
    

);

这不起作用。它会引发类型错误:

TypeError:无法读取未定义的属性“filteredItems”

这是因为 Vuetify 数据表 组件中的 filteredItems 计算属性在 GoogleMap 组件评估它时尚未计算。

如果我注释掉使用 "points" 计算属性的 GoogleMap 组件,并在页面渲染后使用 Vue JS Devtools 评估 points 属性,则 points 属性数据计算正确。这是因为计算属性在您使用 Devtools 访问它之前不会第一次评估,因此页面已经呈现。因此,“points”计算属性在页面渲染后评估良好,但此时 GoogleMap 组件尝试首先计算它。


如果 "$refs.prospectTable.filteredItems" 仍未定义,我接下来尝试修改 "points" 计算属性以返回一个空数组。

computed: 
    mapPoints: function() 
        if(!this.$refs.prospectTable)
            return [];
        else
            return this.calcPoints(this.$refs.prospectTable.filteredItems);
    

但是,使用这种方法,计算属性只评估一次,在 $refs.prospectTable.filteredItems 定义之前,所以它返回空数组。即使在 $refs.prospectTable.filteredItems 更改之后,也不会再次评估计算的属性。


为什么每次“$refs.prospectTable.filteredItems”发生变化时,“mapPoints”计算属性没有重新计算,就像它从未返回初始空数组时那样?

computed: 
    mapPoints: function() 
        return this.calcPoints(this.$refs.prospectTable.filteredItems);
    


更新:

根据@larizzatg 的建议,将 ma​​pPoints 从计算属性更改为 mounted() 内的 $watch 变量就成功了:

mounted() 
    this.$watch(
        () => 
            return this.$refs.prospectTable.filteredItems;
        ,
        (items) => 
            this.mapPoints = this.calcPoints(items);
        
    );

【问题讨论】:

【参考方案1】:

创建 vue 应用程序时,会执行计算的属性。此时,应用程序在真实 dom 中没有该组件(ref 关键字的功能类似于 getElementById,因为 prostectTable 未定义,所以您未定义)

在挂载的生命周期中,组件位于 dom 中,因此您可以访问 ref。将观察者添加到 refs 前景表中,而不是计算属性

【讨论】:

在 "$refs.prospectTable.filteredItems" 上添加监视有效,但仅在 mount() 中设置 $watch 时有效。谢谢!

以上是关于Vue JS计算属性没有重新计算的主要内容,如果未能解决你的问题,请参考以下文章

Vue.js 修改计算属性?

[Vue] 计算属性Computed与函数function的异同

vue-computed计算属性

使用带有 Avoriaz 的 AVA 在 Vue.js 中测试计算属性

在编辑另一个文本字段 vue.js 时获取计算属性并传递其值

Vue的计算属性