Vue數據更新頁面沒有更新問題總結


Vue數據更新頁面沒有更新問題總結

1. Vue無法檢測實例別創建時不存在於data中的property

  • 原因: 由於Vue會在初始化實例時對property執行getter/setter轉化,所以property必須在data對象上存在才能讓vue轉換為響應式
    // 問題
    var vm = new Vue({
        data: {},
        template: '<div>{{item}}</div>'
    })
    vm.item = 'hello world!!!'

    // 解決
    var vm = new Vue({
        data: {
            item: '', // 聲明
        },
        template: '<div>{{item}}</div>'
    })
    vm.item = 'hello world!!!'

2. Vue無法檢測對象property的添加或者刪除

  • 原因: 這是由於ECMAJavaScript 5 的限制,vue.js不能檢測到對象屬性的添加或者刪除.
    // 問題
    var vm = new Vue({
        data: {
            obj: {
                id: 1,
            },
        },
        template: '<div>{{obj.item}}</div>' // 沒有變化
    })
    vm.obj.item = 'hello world!!!'
    delete vm.obj.id 

    // 解決
    // 動態添加
    Vue.set(vm.obj, propertyName, newValue)
    Vue.$set(vm.obj, propertyName, newValue)
    // 動態添加多個
    this.obj = Object.assign({}, this.obj, {a: 1, b: 2})
    // 動態刪除
    Vue.delete(vm.obj, propertyName)
    Vue.$delete(vm.obj, propertyName)

3. Vue不能檢測通過數組索引直接修改一個數組項,也不能檢測直接修改數組長度的變化

  • 原因: 官方,由於js的限制,Vue不能檢測數組和對象的變化,尤雨溪-性能代價和獲得用戶體驗不成正比
    // 問題
    var vm = new Vue({
        data: {
            items: ['a', 'b', 'c']
        }
    })
    vm.items[1] = 'x' // 這不是響應性的
    vm.items.length = 4 // 不是響應的

    // 解決
    // Vue.set
    Vue.set(vm.items, indexOfItem, newValue)
    // vm.$set
    vm.$set(vm.items, indexOfItem, newValue)
    // Array.prototype.splice
    vm.items.splice(indexOfItem, 1, newValue)
    // 解決長度
    vm.items.splice(newLength)

拓展:Object.defineProperty() 可以監測數組的變化

  • Object.defineProperty() 可以監測數組的變化。但對數組新增一個屬性是不會監測到數據變化,因為無法監測到新增數組的下標,刪除一個屬性也是。
    var arr = [1, 2, 3, 4]
    arr.forEach(function(item, index) {
        Object.defineProperty(arr, index, {
        set: function(value) {
        console.log('觸發 setter')
        item = value
        },
        get: function() {
        console.log('觸發 getter')
        return item
        }
    })
    })
    arr[1] = '123'  // 觸發 setter
    arr[1]          // 觸發 getter 返回值為 "123"
    arr[5] = 5      // 不會觸發 setter 和 getter

4. 在異步更新執行之前操作 DOM 數據不會變化

  • 原因: Vue在更新DOM時是異步執行,只要偵聽到數據變化,Vue將開啟一個隊列.並緩沖在統一事件循環中發生的所有數據變更,如果同一個watcher被多次觸發,只會別推入到隊列中一次!這種在緩沖時去除重復數據對於避免不必要的計算和DOM操作是非常重要的.然后在下一個事件循環nextTick中,Vue刷新隊列並執行實際工作,Vue 在內部對異步隊列嘗試使用原生的 Promise.then``、MutationObserversetImmediate,如果執行環境不支持,則會采用 setTimeout(fn, 0)代替。
    <div id="box">{{item}}</div>

    var vm = new Vue({
        el: '#box',
        data: {
            item: 'abc'
        },
    })
    vm.item = 'ABC' // 數據改變
    vm.$el.textContent === 'ABC' // 返回false
    vm.$el.style.color = 'red' // 沒有變化

    // 解決
    Vue.nextTick(function () {
        vm.$el.textContent === 'ABC'
        vm.$el.style.color = 'red' 
    })

5. 路由參數變化時,頁面不更新,也就是數據不更新

  • 原因: 路由視圖組件引用了相同組件時,當路由參會變化時,會導致該組件無法更新,也就是我們常說的頁面無法更新的問題
    <div id="app">
        <ul>
            <li><router-link to="/home/a">To A</router-link></li>    
            <li><router-link to="/home/b">To B</router-link></li>    
            <li><router-link to="/home/c">To C</router-link></li>    
        </ul>    
        <router-view></router-view>
    </div>
    const Home = {
    template: `<div>{{item}}</div>`,
    data() {
        return {
        item: this.$route.params.name
        }
    }
    }

    const router = new VueRouter({
    mode:'history',
        routes: [
        {path: '/home', component: Home },
        {path: '/home/:name', component: Home }
    ]
    })

    new Vue({
    el: '#app',
    router
    })
  • 這段代碼中,在路由構建選項router中配置了一個動態路由/home/:name,它們共用一個路由組件.當路由切換時,頁面只會渲染第一次匹配到的參數,之后再進行路由切換,item是沒有變化的
    // 解決
    // 通過watch監聽$route的變化
    const Home = {
    template: `<div>{{item}}</div>`,
    data() {
        return {
        item: this.$route.params.name
        }
    },
    watch: {
        '$route': function() {
        this.item = this.$route.params.name
        }
        }
    }
    ...
    new Vue({
    el: '#app',
    router
    })

異步更新帶來的數據響應的誤解參考 - https://github.com/xiaofuzi/deep-in-vue/issues/11


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM