微信小程序中渲染组件瀑布流因为spuList 深拷贝与浅拷贝当数据的引用不变时,小程序的 `observers` 或 `setData` 可能不会触发视图更新。


const themeBehavior = Behavior({
    behaviors: [],

    properties: {
        theme: Object,
    },

    /**
     * 组件的初始数据
     */
    data: {
        spuList: Array,
        topImg: String,
        randoms: Array
    },

    observers: {
        'theme': function (theme) {
            console.log(theme)
            if (!theme) {
                return
            }
            this.setData({
                spuList: theme.spu_list,
                topImg: theme.internal_top_img,
                descriptions: this.splitDescription(theme.description)
            })
        }
    },

    methods: {
        onGoToSpu(event) {
            const pid = event.currentTarget.dataset.spuId
            wx.navigateTo({
                url: `/pages/detail/detail?pid=${pid}`
            })
        },

        splitDescription(description) {
            if (!description) {
                return []
            }
            console.log(description.split('#'))
            return description.split('#');
        }
    }


})

export {
    themeBehavior
}


// components/spu-list/index.js
import {themeBehavior} from "../behaviors/theme-beh";

Component({
    behaviors: [themeBehavior],

    properties: {},

    data: {
        empty: false,
        loading: true,
        loadingType: 'loading'
    },

    methods: {
        onLoadImg(event) {
            const {height, width} = event.detail
            this.setData({
                h: height,
                w: width,
            })
        },

        empty() {
            wx.lin.showEmptyScreen({
                text: '该分类暂时还没有商品'
            })
        },

        onWaterFlowRender() {
            wx.lin.renderWaterFlow(this.data.spuList, false, () => {
                console.log('渲染成功')
            })
        }
    },

    observers: {
        'spuList': function(spuList) {
            if (spuList && spuList.length !== 0) {
                this.onWaterFlowRender()
                this.setData({
                    empty: false,
                    loadingType: 'end'
                })
            } else {
                this.empty()
            }
        }
    }
})

// components/spu-list/index.js
import {themeBehavior} from "../behaviors/theme-beh";

Component({
    behaviors: [themeBehavior],

    properties: {},

    data: {
        empty: false,
        loading: true,
        loadingType: 'loading',
        formattedSpuList: []
    },

    methods: {
        onLoadImg(event) {
            const {height, width} = event.detail
            this.setData({
                h: height,
                w: width,
            })
        },

        empty() {
            wx.lin.showEmptyScreen({
                text: '该分类暂时还没有商品'
            })
        },

        onWaterFlowRender() {
            wx.lin.renderWaterFlow(this.data.formattedSpuList, false, () => {
                console.log('渲染成功')
            })
        }
    },

    observers: {
        'spuList': function(spuList) {
            if (spuList && spuList.length !== 0) {
                const formattedSpuList = [...spuList]
                
                this.setData({
                    formattedSpuList: formattedSpuList,
                    empty: false,
                    loadingType: 'end'
                }, () => {
                    this.onWaterFlowRender()
                })
            } else {
                this.setData({
                    formattedSpuList: [],
                    empty: true,
                    loadingType: 'end'
                })
            }
        }
    }
})

对面上两个代码
第一个不可以运行

第二个可以运行
加一个中间变量formattedSpuList 转换新的就可以运行

很多时候赋值不上用一个新的变量就可以运行成功 大概率是


const themeBehavior = Behavior({
    behaviors: [],

    properties: {
        theme: Object,
    },

    /**
     * 组件的初始数据
     */
    data: {
        spuList: Array,
        topImg: String,
        randoms: Array
    },

    observers: {
        'theme': function (theme) {
            console.log(theme)
            if (!theme) {
                return
            }
            this.setData({
                spuList: theme.spu_list,
                topImg: theme.internal_top_img,
                descriptions: this.splitDescription(theme.description)
            })
        }
    },

    methods: {
        onGoToSpu(event) {
            const pid = event.currentTarget.dataset.spuId
            wx.navigateTo({
                url: `/pages/detail/detail?pid=${pid}`
            })
        },

        splitDescription(description) {
            if (!description) {
                return []
            }
            console.log(description.split('#'))
            return description.split('#');
        }
    }


})

export {
    themeBehavior
}


// components/spu-list/index.js
import {themeBehavior} from "../behaviors/theme-beh";

Component({
    behaviors: [themeBehavior],

    properties: {},

    data: {
        empty: false,
        loading: true,
        loadingType: 'loading'
    },

    methods: {
        onLoadImg(event) {
            const {height, width} = event.detail
            this.setData({
                h: height,
                w: width,
            })
        },

        empty() {
            wx.lin.showEmptyScreen({
                text: '该分类暂时还没有商品'
            })
        },

        onWaterFlowRender() {
            wx.lin.renderWaterFlow(this.data.spuList, false, () => {
                console.log('渲染成功')
            })
        }
    },

    observers: {
        'spuList': function(spuList) {
            if (spuList && spuList.length !== 0) {
                this.onWaterFlowRender()
                this.setData({
                    empty: false,
                    loadingType: 'end'
                })
            } else {
                this.empty()
            }
        }
    }
})

// components/spu-list/index.js
import {themeBehavior} from "../behaviors/theme-beh";

Component({
    behaviors: [themeBehavior],

    properties: {},

    data: {
        empty: false,
        loading: true,
        loadingType: 'loading',
        formattedSpuList: []
    },

    methods: {
        onLoadImg(event) {
            const {height, width} = event.detail
            this.setData({
                h: height,
                w: width,
            })
        },

        empty() {
            wx.lin.showEmptyScreen({
                text: '该分类暂时还没有商品'
            })
        },

        onWaterFlowRender() {
            wx.lin.renderWaterFlow(this.data.formattedSpuList, false, () => {
                console.log('渲染成功')
            })
        }
    },

    observers: {
        'spuList': function(spuList) {
            if (spuList && spuList.length !== 0) {
                const formattedSpuList = [...spuList]
                
                this.setData({
                    formattedSpuList: formattedSpuList,
                    empty: false,
                    loadingType: 'end'
                }, () => {
                    this.onWaterFlowRender()
                })
            } else {
                this.setData({
                    formattedSpuList: [],
                    empty: true,
                    loadingType: 'end'
                })
            }
        }
    }
})

对面上两个代码
第一个不可以运行

第二个可以运行
加一个中间变量formattedSpuList 转换新的就可以运行

很多时候赋值不上用一个新的变量就可以运行成功 大概率是就能运行

在小程序开发中,有时会遇到数据绑定更新不及时或者无法触发的问题。这个现象通常与小程序的视图层和逻辑层之间的数据同步机制有关。以下是一些可能导致这种现象的原因和解决方法:

1. 数据绑定机制

小程序的 setData 方法用于将数据从逻辑层发送到视图层,并触发视图的更新。如果直接修改绑定的数据,有时可能不会触发视图更新,特别是在复杂的数据结构或较大的数据量时。

2. 异步渲染

小程序的 setData 是异步的,某些情况下直接修改数据可能不会立即反映在界面上。通过设置新的中间变量,可以确保数据变化被正确捕获和渲染。

3. 深拷贝与浅拷贝

在某些情况下,直接修改对象的属性可能不会触发视图更新。使用 JSON.parse(JSON.stringify(obj))Object.assign({}, obj) 创建对象的深拷贝,确保数据变动被正确捕获。

4. 数据结构变化

小程序的视图层可能对数据结构的变化不敏感。通过设置新的变量,可以显式地通知视图层数据发生了变化。

具体分析你的代码

第一个版本
observers: {
    'spuList': function(spuList) {
        if (spuList && spuList.length !== 0) {
            this.onWaterFlowRender()
            this.setData({
                empty: false,
                loadingType: 'end'
            })
        } else {
            this.empty()
        }
    }
}

这个版本中,spuList 直接被观察并用于触发渲染。然而,如果 spuList 的内容发生变化但引用不变,可能不会触发视图更新。

第二个版本
observers: {
    'spuList': function(spuList) {
        if (spuList && spuList.length !== 0) {
            const formattedSpuList = [...spuList]
            
            this.setData({
                formattedSpuList: formattedSpuList,
                empty: false,
                loadingType: 'end'
            }, () => {
                this.onWaterFlowRender()
            })
        } else {
            this.setData({
                formattedSpuList: [],
                empty: true,
                loadingType: 'end'
            })
        }
    }
}

在这个版本中,spuList 被复制到一个新的变量 formattedSpuList。这种做法确保了数据变化被正确捕获和渲染。

总结

  1. 使用中间变量:通过创建新的变量,可以确保数据变化被正确捕获和渲染。
  2. 深拷贝:在必要时,使用深拷贝确保数据结构的变化被捕获。
  3. 确保数据引用变化:直接修改对象属性可能不会触发视图更新,确保引用发生变化。

通过这些方法,可以更好地控制数据绑定和视图更新,避免数据绑定更新不及时的问题。

在小程序开发中,数据绑定的更新机制有时可能不如预期般顺畅。为了更好地理解这一点,我们需要先理解 JavaScript 中的引用类型和浅拷贝、深拷贝的概念。

引用类型和引用变化

在 JavaScript 中,数组和对象是引用类型。当我们直接赋值或传递数组或对象时,实际上是传递它们的引用而不是实际的值。

例如:

let array1 = [1, 2, 3];
let array2 = array1;
array2.push(4);

console.log(array1); // [1, 2, 3, 4]

在这个例子中,array2array1 引用的是同一个数组,所以对 array2 的修改会反映在 array1 上。

引用不变

当数据的引用不变时,小程序的 observerssetData 可能不会触发视图更新。

例如:

this.setData({
    spuList: this.data.spuList
});

在这个例子中,spuList 的引用没有发生变化,即使内容发生了变化,小程序也可能不会触发视图的更新。

深拷贝和浅拷贝

为了确保视图更新,我们可以创建一个新引用。常用的方法有:

  • 浅拷贝:const newList = [...this.data.spuList];
  • 深拷贝:const newList = JSON.parse(JSON.stringify(this.data.spuList));

浅拷贝适用于一维数组或简单对象,而深拷贝适用于复杂的嵌套结构。

示例

假设我们有一个数组 spuList,当内容发生变化时,我们希望视图能够更新:

// 原始数据
this.data.spuList = [1, 2, 3];

// 修改数据
this.data.spuList.push(4);

// 更新视图 - 引用不变,可能不会触发更新
this.setData({
    spuList: this.data.spuList
});

// 创建新引用
const newList = [...this.data.spuList];

// 更新视图 - 引用改变,触发更新
this.setData({
    spuList: newList
});

在这个示例中,newListspuList 的一个新引用,因此 setData 会触发视图的更新。

你的代码中的应用

在你的第二个版本的代码中,通过创建 formattedSpuList 新的引用来确保视图更新:

observers: {
    'spuList': function(spuList) {
        if (spuList && spuList.length !== 0) {
            const formattedSpuList = [...spuList];

            this.setData({
                formattedSpuList: formattedSpuList,
                empty: false,
                loadingType: 'end'
            }, () => {
                this.onWaterFlowRender();
            });
        } else {
            this.setData({
                formattedSpuList: [],
                empty: true,
                loadingType: 'end'
            });
        }
    }
}

通过这种方式,即使 spuList 的内容发生了变化但引用不变,创建 formattedSpuList 的新引用确保了数据变化能够被捕获并触发视图更新。

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值