欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

vue中遇到的坑之變化檢測問題(數(shù)組相關(guān))

 更新時間:2017年10月13日 11:05:14   作者:Wayne-Zhu  
這篇文章主要介紹了vue中遇到的坑之變化檢測問題(數(shù)組相關(guān)) ,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

最近在項目中遇到了一個問題,不知道為什么,所以最后通過動手做demo實踐、查文檔的方式解決了,這里做一個總結(jié)。

例1

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <title>vue</title>
 <script src="https://unpkg.com/vue@2.3.3/dist/vue.js"></script>
 <style>
  li:hover {
   cursor: pointer;
  }
 </style>
</head>
<body>
 <div class="wrap">
  <ul>
   <li v-for="item,index in items" v-on:click="handle(index)">
    <span>{{item.name}}</span>
    <span>{{numbers[index]}}</span>
   </li>
  </ul>
 </div>
 <script>
  var vm = new Vue({
   el: ".wrap",
   data: {
    numbers: [],
    items: [
     {name: 'jjj'},
     {name: 'kkk'},
     {name: 'lll'},
    ]
   },
   methods: {
    handle: function (index) {
     // WHY: 更新數(shù)據(jù),view層未渲染,但通過console這個數(shù)組可以發(fā)現(xiàn)數(shù)據(jù)確實更新了
      if (typeof(this.numbers[index]) === "undefined" ) {
       this.numbers[index] = 1;
      } else {
       this.numbers[index]++;
      }
    }
   }
  });
 </script>
</body>
</html>

這里的實現(xiàn)目的很明確 --- 我希望在點擊li時先檢測是否存在,當然是不存在的,所以就將值設(shè)置為1, 如果再次點擊,就讓數(shù)字累加。

但是出現(xiàn)的問題是: 點擊之后數(shù)字并沒有在view層更新,而通過console打印發(fā)現(xiàn)數(shù)據(jù)確實更新了,只是view層沒有及時的檢測到, 而我一直以來的想法就是: 既然vue實現(xiàn)的時數(shù)據(jù)雙向綁定,那么在model層發(fā)生了變化之后為什么就沒有在view層更新呢? 

首先,我就考慮了這是不是數(shù)組的問題,于是,我測試了下面的例子:

例2

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <title>vue</title>
 <script src="https://unpkg.com/vue@2.3.3/dist/vue.js"></script>
 <style>
  li:hover {
   cursor: pointer;
  }
 </style>
</head>
<body>
 <div class="wrap">
  <ul>
   <li v-for="item,index in items" v-on:click="handle(index)">
    <span>{{item.name}}</span>
    <span>{{numbers[index]}}</span>
   </li>
  </ul>
 </div>
 <script>
  var vm = new Vue({
   el: ".wrap",
   data: {
    numbers: [],
    items: [
     {name: 'jjj'},
     {name: 'kkk'},
     {name: 'lll'},
    ]
   },
   methods: {
    handle: function (index) {
     // 不是數(shù)組,這里更新數(shù)據(jù)就可以直接在view層渲染
     this.items[index].name += " success";
    }
   }
  });
 </script>
</body>
</html>

這時,我再測試時就發(fā)現(xiàn),這里的model層發(fā)生了變化時,view層就能及時、有效的得到更新。

而數(shù)組為什么不可以呢? 

于是在文檔上的一個不起眼的地方找到了下面的說明:

其中最重要的一句話就是 --- 如果對象是響應(yīng)式的,確保屬性被創(chuàng)建后也是響應(yīng)式的,同時觸發(fā)視圖更新,這個方法主要用于避開Vue不能檢測到屬性被添加的限制。

那么什么情況下Vue是不能檢測到屬性被添加呢?  根據(jù)參考鏈接,我們在文檔上看到了很好的說明 --- 深入響應(yīng)式原理

首先,我們要了解Vue是如何實現(xiàn)數(shù)據(jù)的雙向綁定的! 

把一個普通 JavaScript 對象傳給 Vue 實例的 data 選項,Vue 將遍歷此對象所有的屬性,并使用 Object.defineProperty 把這些屬性全部轉(zhuǎn)為 getter/setter。Object.defineProperty 是僅 ES5 支持,且無法 shim 的特性,這也就是為什么 Vue 不支持 IE8 以及更低版本瀏覽器的原因。

知識補充:

訪問器屬性不包含數(shù)據(jù)值,他們包含一對getter函數(shù)和setter函數(shù)(這兩個函數(shù)不是必須的)。在讀取訪問器屬性時,會調(diào)用getter函數(shù),這個函數(shù)負責返回有效的值;在寫入訪問器屬性是,會調(diào)用setter函數(shù)并傳入新值,這個函數(shù)負責決定如何處理數(shù)據(jù)。

訪問器屬性不能直接定義,必須是用Object.defineProperty()來定義。

下面是一個例子:

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <title>vue</title>
</head>
<body>
 <script>
  var book={
    _year:2004,
    edition:1
  };
  Object.defineProperty(book,"year",{
    get:function(){
      return this._year;
    },
    set:function(newValue){
      if(newValue>2004){
        this._year=newValue;
        this.edition+=newValue-2004;
      }
    }
  });
  console.log(book.year); // 2004 在讀取訪問器屬性時會調(diào)用get函數(shù)
  book.year=2005; // 在給訪問器屬性賦值時會調(diào)用set函數(shù)
  console.log(book.edition); // 2
 </script>
</body>
</html>

這個例子應(yīng)該可以很好的理解訪問器屬性了。

所以,當對象下的訪問器屬性值發(fā)生了改變之后(vue會將屬性都轉(zhuǎn)化為訪問器屬性,之前提到了), 那么就會調(diào)用set函數(shù),這時vue就可以通過這個set函數(shù)來追蹤變化,調(diào)用相關(guān)函數(shù)來實現(xiàn)view視圖的更新。

每個組件實例都有相應(yīng)的 watcher 實例對象,它會在組件渲染的過程中把屬性記錄為依賴,之后當依賴項的 setter 被調(diào)用時,會通知 watcher 重新計算,從而致使它關(guān)聯(lián)的組件得以更新。

即在渲染的過程中就會調(diào)用對象屬性的getter函數(shù),然后getter函數(shù)通知wather對象將之聲明為依賴,依賴之后,如果對象屬性發(fā)生了變化,那么就會調(diào)用settter函數(shù)來通知watcher,watcher就會在重新渲染組件,以此來完成更新。

OK!既然知道了原理,我們就可以進一步了解為什么出現(xiàn)了之前數(shù)組的問題了!

變化檢測問題

收到現(xiàn)代JavaScript瀏覽器的限制,其實主要是 Object.observe() 方法支持的不好,Vue不能檢測到對象的添加或者刪除。然而Vue在初始化實例時就對屬性執(zhí)行了setter/getter轉(zhuǎn)化過程,所以屬性必須開始就在對象上,這樣才能讓Vue轉(zhuǎn)化它。

所以對于前面的例子就不能理解了 --- 數(shù)組中index都可以看做是屬性,當我們添加屬性并賦值時,Vue并不能檢測到對象中屬性的添加或者刪除,但是其的確是添加或刪除了,故我們可以通過console看到變化,所以就沒有辦法做到響應(yīng)式; 而在第二個例子中,我們是在已有的屬性的基礎(chǔ)上進行修改的,這些屬性是在最開始就被Vue初始化實例時執(zhí)行了setter/getter的轉(zhuǎn)化過程,所以說他們的修改是有效的,model的數(shù)據(jù)可以實時的在view層中得到相應(yīng)。

補充知識: 什么是 Object.observe() ?

在介紹之前,不得不殘忍的說,盡管這個方法可以在某些瀏覽器上運行,但事實是這個方法已經(jīng)廢棄!

概述: 此方法用于異步地監(jiān)視一個對象的修改。當對象的屬性被修改時,方法的回調(diào)函數(shù)會提供一個有序的修改流,然而這個接口已經(jīng)從各大瀏覽器移除,可以使用通用的proxy 對象。      

方法:

Object.observe(obj, callback[, acceptList])

其中obj就是被監(jiān)控的對象, callback是一個回調(diào)函數(shù),其中的參數(shù)包括changes和acceptList,

changes一個數(shù)組,其中包含的每一個對象代表一個修改行為。每個修改行為的對象包含:

  • name: 被修改的屬性名稱。
  • object: 修改后該對象的值。
  • type: 表示對該對象做了何種類型的修改,可能的值為"add", "update", or "delete"。
  • oldValue: 對象修改前的值。該值只在"update"與"delete"有效。

acceptList在給定對象上給定回調(diào)中要監(jiān)視的變化類型列表。如果省略, ["add", "update", "delete", "reconfigure", "setPrototype", "preventExtensions"] 將會被使用。

var obj = {
 foo: 0,
 bar: 1
};

Object.observe(obj, function(changes) {
 console.log(changes);
});

obj.baz = 2;
// [{name: 'baz', object: <obj>, type: 'add'}]

obj.foo = 'hello';
// [{name: 'foo', object: <obj>, type: 'update', oldValue: 0}]

delete obj.baz;
// [{name: 'baz', object: <obj>, type: 'delete', oldValue: 2}]

如上所示: 但是chrome也是不支持的,瀏覽器的兼容性如下:

參考文檔: Object.ovserve()

推薦閱讀文章: Object.observe() 引爆數(shù)據(jù)綁定革命

解決方法

使用 Vue.set(object, key, value) 方法將響應(yīng)屬性添加到嵌套的對象上。 還可以使用 vm.$set 實例方法,這也是全局 Vue.set 方法的別名。

例3

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <title>vue</title>
 <script src="https://unpkg.com/vue@2.3.3/dist/vue.js"></script>
 <style>
  li:hover {
   cursor: pointer;
  }
 </style>
</head>
<body>
 <div class="wrap">
  <ul>
   <li v-for="item,index in items" v-on:click="handle(index)">
    <span>{{item.name}}</span>
    <span>{{numbers[index]}}</span>
   </li>
  </ul>
 </div>
 <script>
  var vm = new Vue({
   el: ".wrap",
   data: {
    numbers: [],
    items: [
     {name: 'jjj'},
     {name: 'kkk'},
     {name: 'lll'},
    ]
   },
   methods: {
    handle: function (index) {
     // WHY: 更新數(shù)據(jù),view層未渲染,但通過console這個數(shù)組可以發(fā)現(xiàn)數(shù)據(jù)確實更新了
      if (typeof(this.numbers[index]) === "undefined" ) {
       this.$set(this.numbers, index, 1);
      } else {
       this.$set(this.numbers, index, ++this.numbers[index]);
      }
    }
   }
  });
 </script>
</body>
</html>

這樣,我們就可以實現(xiàn)最終的目的了!

第二部分

上面一部分是指在data下的數(shù)組,而如果是在store中的數(shù)組,一般可以這樣:

[ADD_ONE] (state, index) {
   if ( typeof state.numbers[index] == "undefined") {
    Vue.set(state.numbers, index, 1)
   } else {
    Vue.set(state.numbers, index, ++state.numbers[index])
   }
  }

即使用 Vue.set() 的方式來改變、增加。

注意:這里是確定index的增加和減少,所以用 Vue.set() 的方式

減的方式如下:

 [REMOVE_ONE] (state, index) {
   Vue.set(state.numbers, index, --state.numbers[index]);
  }

第四部分

如果是在store的actions中我們需要對stroe中的數(shù)組進行填充,方法如下:

state內(nèi)容:

kindnames: []

Mutations內(nèi)容:

  [ADD_KIND_NAME] (state, name) {
   state.kindnames.push(name);
  } 

注意: 這里直接使用push的方式

當然,除了push,我們還可以shift等各種方式。 

actions的內(nèi)容:

commit(ADD_KIND_NAME, state.items[index++].name);

這里,state.items[index++].name獲取到的是一個一個的字符串。

最后,看到數(shù)據(jù)如下:

注:同樣可以參考文檔 --- 細節(jié)與最佳實踐

以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • 結(jié)合Vue控制字符和字節(jié)的顯示個數(shù)的示例

    結(jié)合Vue控制字符和字節(jié)的顯示個數(shù)的示例

    這篇文章主要介紹了結(jié)合Vue控制字符和字節(jié)的顯示個數(shù)的示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-05-05
  • vue 使用 echarts 繪制中國地圖的實現(xiàn)代碼

    vue 使用 echarts 繪制中國地圖的實現(xiàn)代碼

    這篇文章主要介紹了vue 使用 echarts 繪制中國地圖,內(nèi)容包括插入echarts所需模塊及完整的代碼,代碼簡單易懂,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-01-01
  • rollup打包vue組件并發(fā)布到npm的方法

    rollup打包vue組件并發(fā)布到npm的方法

    這篇文章主要介紹了rollup打包vue組件并發(fā)布到npm,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-05-05
  • 前端自動化測試Vue中TDD和單元測試示例詳解

    前端自動化測試Vue中TDD和單元測試示例詳解

    這篇文章主要為大家介紹了前端自動化測試Vue中TDD和單元測試示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-02-02
  • vue?實現(xiàn)左滑圖片驗證功能

    vue?實現(xiàn)左滑圖片驗證功能

    網(wǎng)頁中滑動圖片驗證一直是各大網(wǎng)站、移動端的主流校驗方式,其主要作用是為了區(qū)分人和機器以及為了防止機器人程序暴力登錄或攻擊從而設(shè)置的一種安全保護方式,這篇文章主要介紹了vue?實現(xiàn)左滑圖片驗證,需要的朋友可以參考下
    2023-04-04
  • 前端框架Vue.js構(gòu)建大型應(yīng)用淺析

    前端框架Vue.js構(gòu)建大型應(yīng)用淺析

    這篇文章主要為大家詳細介紹了前端框架Vue.js構(gòu)建大型應(yīng)用的相關(guān)資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-09-09
  • vue如何實現(xiàn)點擊選中取消切換

    vue如何實現(xiàn)點擊選中取消切換

    這篇文章主要介紹了vue實現(xiàn)點擊選中取消切換,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-05-05
  • vue關(guān)于eslint空格縮進等的報錯問題及解決

    vue關(guān)于eslint空格縮進等的報錯問題及解決

    這篇文章主要介紹了vue關(guān)于eslint空格縮進等的報錯問題及解決,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-05-05
  • 詳細講解如何創(chuàng)建, 發(fā)布自己的 Vue UI 組件庫

    詳細講解如何創(chuàng)建, 發(fā)布自己的 Vue UI 組件庫

    當我們自己開發(fā)了一個 _UI Component_, 需要在多個項目中使用的時候呢? 我們首先想到的可能是直接復制一份過去對嗎?我們?yōu)槭裁床话l(fā)布一個 UI 組件庫給自己用呢?下面小編和大家來一起學習下吧
    2019-05-05
  • vue使用urlEncode問題

    vue使用urlEncode問題

    這篇文章主要介紹了vue使用urlEncode問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-03-03

最新評論