js更新數組對象_7 種Vue 數據已更新而頁面沒有更新的情況及深化總結(收藏)

作者:前端1943

鏈接:https://segmentfault.com/a/1190000022772025

如果你發現你自己需要在 Vue 中做一次強制更新,99.9% 的情況,是你在某個地方做錯了事。

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

原因:由于 Vue 會在初始化實例時對 property 執行 getter/setter 轉化,所以 property 必須在 data 對象上存在才能讓 Vue 將它轉換為響應式的。

場景:

var vm = new Vue({  data:{},  // 頁面不會變化  template: '
{{message}}
'})vm.message = 'Hello!' // `vm.message` 不是響應式的

解決辦法:

var vm = new Vue({  data: {    // 聲明 a、b 為一個空值字符串    message: '',  },  template: '
{{ message }}
'})vm.message = 'Hello!'

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

原因:官方 - 由于 JavaScript(ES5) 的限制,Vue.js 不能檢測到對象屬性的添加或刪除。因為 Vue.js 在初始化實例時將屬性轉為 getter/setter,所以屬性必須在 data 對象上才能讓 Vue.js 轉換它,才能讓它是響應的。

場景:

var vm = new Vue({  data:{    obj: {      id: 001    }  },  // 頁面不會變化  template: '
{{ obj.message }}
'})vm.obj.message = 'hello' // 不是響應式的delete vm.obj.id // 不是響應式的

解決辦法:

// 動態添加 - Vue.setVue.set(vm.obj, propertyName, newValue)// 動態添加 - vm.$setvm.$set(vm.obj, propertyName, newValue)// 動態添加多個// 代替 Object.assign(this.obj, { a: 1, b: 2 })this.obj = Object.assign({}, this.obj, { a: 1, b: 2 })// 動態移除 - Vue.deleteVue.delete(vm.obj, propertyName)// 動態移除 - vm.$deletevm.$delete(vm.obj, propertyName)

3. Vue 不能檢測通過數組索引直接修改一個數組項

原因:官方 - 由于 JavaScript 的限制,Vue 不能檢測數組和對象的變化;尤雨溪 - 性能代價和獲得用戶體驗不成正比。

場景:

var vm = new Vue({  data: {    items: ['a', 'b', 'c']  }})vm.items[1] = 'x' // 不是響應性的

解決辦法:

// Vue.setVue.set(vm.items, indexOfItem, newValue)// vm.$setvm.$set(vm.items, indexOfItem, newValue)// Array.prototype.splicevm.items.splice(indexOfItem, 1, newValue)

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

Object.defineProperty() 可以監測數組的變化。但對數組新增一個屬性(index)不會監測到數據變化,因為無法監測到新增數組的下標(index),刪除一個屬性(index)也是。

場景:

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'  // 觸發 setterarr[1]          // 觸發 getter 返回值為 "123"arr[5] = 5      // 不會觸發 setter 和 getter

4. Vue 不能監測直接修改數組長度的變化

原因:官方 - 由于 JavaScript 的限制,Vue 不能檢測數組和對象的變化;尤雨溪 - 性能代價和獲得用戶體驗不成正比。

場景:

var vm = new Vue({  data: {    items: ['a', 'b', 'c']  }})vm.items.length = 2 // 不是響應性的

解決辦法:

vm.items.splice(newLength)

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

原因:Vue 在更新 DOM 時是異步執行的。只要偵聽到數據變化,Vue 將開啟一個隊列,并緩沖在同一事件循環中發生的所有數據變更。如果同一個 watcher 被多次觸發,只會被推入到隊列中一次。這種在緩沖時去除重復數據對于避免不必要的計算和 DOM 操作是非常重要的。然后,在下一個的事件循環“tick”中,Vue 刷新隊列并執行實際 (已去重的) 工作。Vue 在內部對異步隊列嘗試使用原生的 Promise.then、MutationObserver 和 setImmediate,如果執行環境不支持,則會采用 setTimeout(fn, 0) 代替。

場景:

{{message}}
var vm = new Vue({  el: '#example',  data: {    message: '123'  }})vm.message = 'new message' // 更改數據vm.$el.textContent === 'new message' // falsevm.$el.style.color = 'red' // 頁面沒有變化

解決辦法:

var vm = new Vue({  el: '#example',  data: {    message: '123'  }})vm.message = 'new message' // 更改數據//使用 Vue.nextTick(callback) callback 將在 DOM 更新完成后被調用Vue.nextTick(function () {  vm.$el.textContent === 'new message' // true  vm.$el.style.color = 'red' // 文字顏色變成紅色})

拓展:異步更新帶來的數據響應的誤解

{{message.text}}
var vm = new Vue({  el: '#example',  data: {    message: {},  }})vm.$nextTick(function () {  this.message = {}  this.message.text = '我更新啦!'})

上段代碼中,我們在 data 對象中聲明了一個 message 空對象,然后在下次 DOM 更新循環結束之后觸發的異步回調中,執行了如下兩段代碼:

this.message = {};this.message.text = '我更新啦!'

到這里,模版更新了,頁面最后會顯示 我更新啦!。

模板更新了,應該具有響應式特性,如果這么想那么你就已經走入了誤區。

一開始我們在 data 對象中只是聲明了一個 message 空對象,并不具有 text 屬性,所以該 text 屬性是不具有響應式特性的。

但模板切切實實已經更新了,這又是怎么回事呢?

那是因為 Vue.js 的 DOM 更新是異步的,即當 setter 操作發生后,指令并不會立馬更新,指令的更新操作會有一個延遲,當指令更新真正執行的時候,此時 text 屬性已經賦值,所以指令更新模板時得到的是新值。

模板中每個指令/數據綁定都有一個對應的 watcher 對象,在計算過程中它把屬性記錄為依賴。之后當依賴的 setter 被調用時,會觸發 watcher 重新計算 ,也就會導致它的關聯指令更新 DOM。

730ad1abc71eb29bb25ea3fa15e7ca3b.png

具體流程如下所示:

  • 執行 this.message = {}; 時, setter 被調用。
  • Vue.js 追蹤到 message 依賴的 setter 被調用后,會觸發 watcher 重新計算。
  • this.message.text = '我更新啦!'; 對 text 屬性進行賦值。
  • 異步回調邏輯執行結束之后,就會導致它的關聯指令更新 DOM,指令更新開始執行。

所以真正的觸發模版更新的操作是 this.message = {};這一句引起的,因為觸發了 setter,所以單看上述例子,具有響應式特性的數據只有 message 這一層,它的動態添加的屬性是不具備的。

對應上述第二點 - Vue 無法檢測對象 property 的添加或移除

6. 循環嵌套層級太深,視圖不更新?

看到網上有些人說數據更新的層級太深,導致數據不更新或者更新緩慢從而導致試圖不更新?

由于我沒有遇到過這種情況,在我試圖重現這種場景的情況下,發現并沒有上述情況的發生,所以對于這一點不進行過多描述(如果有人在真實場景下遇到這種情況留個言吧)。

針對上述情況有人給出的解決方案是使用強制更新:

如果你發現你自己需要在 Vue 中做一次強制更新,99.9% 的情況,是你在某個地方做錯了事。

vm.$forceUpdate()

7. 拓展:路由參數變化時,頁面不更新(數據不更新)

拓展一個因為路由參數變化,而導致頁面不更新的問題,頁面不更新本質上就是數據沒有更新。

原因:路由視圖組件引用了相同組件時,當路由參會變化時,會導致該組件無法更新,也就是我們常說中的頁面無法更新的問題。

場景:

To Foo To Baz To Bar
const Home = {  template: `
{{message}}
`, data() { return { message: 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})

上段代碼中,我們在路由構建選項 routes 中配置了一個動態路由 '/home/:name',它們共用一個路由組件 Home,這代表他們復用 RouterView 。

當進行路由切換時,頁面只會渲染第一次路由匹配到的參數,之后再進行路由切換時,message 是沒有變化的。

解決辦法:

解決的辦法有很多種,這里只列舉我常用到幾種方法。

  1. 通過 watch 監聽 $route 的變化。const Home = { template: `
    {{message}}
    `, data() { return { message: this.$route.params.name } }, watch: { '$route': function() { this.message = this.$route.params.name } } } ... new Vue({ el: '#app', router })
  2. 給 綁定 key 屬性,這樣 Vue 就會認為這是不同的 。弊端:如果從 /home 跳轉到 /user 等其他路由下,我們是不用擔心組件更新問題的,所以這個時候 key 屬性是多余的。
    ...

參考:

  • 對 Vue 響應式數據更新的誤解 -:https://github.com/xiaofuzi/deep-in-vue/issues/11
  • [小丸子的城堡] -:https://www.cnblogs.com/youhong/p/12173354.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/454579.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/454579.shtml
英文地址,請注明出處:http://en.pswp.cn/news/454579.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

從P560小型機B181201B故障代碼識別手把手詳解

背景:生產小型機發生宕機事件,現場發現液晶面板存在B181201B代碼,可是查看網絡,未見有權威的參考文章,通過管理口登錄HMC管理界面,發現錯誤代碼B181201B,同時提示可能是電源故障,后登…

Java反射中method.isBridge() 橋接方法

橋接方法是 JDK 1.5 引入泛型后&#xff0c;為了使Java的泛型方法生成的字節碼和 1.5 版本前的字節碼相兼容&#xff0c;由編譯器自動生成的方法。我們可以通過Method.isBridge()方法來判斷一個方法是否是橋接方法。 假定接口 public interface SuperClass<T> {void met…

python 利用pexpect進行多機遠程命令執行

在安裝之前&#xff0c;確認你的機器安裝了python,和easy_install.通常python是自動安裝的&#xff0c;如果沒有安裝easy_install&#xff0c;那么wget -q http://peak.telecommunity.com/dist/ez_setup.py 獲取一下python ez_setup.pypexpect是python一個模塊&#xff0c;可以…

Python 之 線程

進程 之前我們已經了解了操作系統中進程的概念&#xff0c;程序并不能單獨運行&#xff0c;只有將程序裝載到內存中&#xff0c;系統為它分配資源才能運行&#xff0c;而這種執行的程序就稱之為進程。程序和進程的區別就在于&#xff1a;程序是指令的集合&#xff0c;它是進程…

flymcu無法打開串口_西門子1200與其他PLC/組態軟件無線串口通訊(自由口)

一、控制系統原理圖1:控制系統原理二、硬件需求S7-1200 PLC目前有3種類型的CPU&#xff1a;1)S7-1211C CPU2)S7-1212C CPU3)S7-1214C CPU這三種類型的CPU都可以連接三個串口通信模版本例中使用的PLC硬件為&#xff1a;1)PM1207電源(6EP1 332-1SH71)2)S7-1214C(6ES7 214-1BE30-0…

android按鈕固定尺寸,如何在android中保持按鈕的固定寬高比

我正在改進你的XML.我沒有測試它,但它應該工作.建議的更改是,而不是將圖像設置為背景,將其設置為ImageButtons的src.此外,如果您堅持使用Button,則可以使用其他布局包裝每個按鈕,并將其重力屬性設置為“center”.看一下下面的XML.android:layout_width"fill_parent"a…

橫空出世,席卷互聯網--評微軟等公司數據結構和算法面試100題

橫空出世&#xff0c;席卷互聯網 ---評微軟數據結構算法面試100題 作者&#xff1a;July。 時間&#xff1a;2010年10月-11月。版權所有&#xff0c;侵權必究。 出處&#xff1a;http://blog.csdn.net/v_JULY_v。 說明&#xff1a;本文原題為&#xff1a;“橫空出世&#xff0c…

收銀管理系統怎樣幫助商家很好地經營服裝門店

收銀管理系統對于服裝門店的經營可以提供多方面的幫助&#xff0c;以下是一些具體的優勢和功能&#xff1a; 1. 快速準確的收銀&#xff1a;收銀管理系統可以實現快速、準確的收銀操作&#xff0c;通過條碼掃描或手動輸入商品信息&#xff0c;自動計算價格并生成收據。這樣可以…

BZOJ 1567: [JSOI2008]Blue Mary的戰役地圖

二次聯通門 : BZOJ 1567: [JSOI2008]Blue Mary的戰役地圖 /*BZOJ 1567: [JSOI2008]Blue Mary的戰役地圖社會我棟哥人慫P話多暴力能A題正解能WA0*/ #include <cstdio> #include <iostream>#define rg register inline void read (int &n) {rg char c getchar (…

python模擬輸入回車鍵_用Python模擬鍵盤輸入

import win32apiimport win32conwin32api.keybd_event(17,0,0,0) #ctrl鍵位碼是17win32api.keybd_event(86,0,0,0) #v鍵位碼是86win32api.keybd_event(86,0,win32con.KEYEVENTF_KEYUP,0) #釋放按鍵win32api.keybd_event(17,0,win32con.KEYEVENTF_KEYUP,0)附個鍵位碼表&#xff…

Python 之 進程

目錄 理論知識 操作系統背景知識 進程 什么是進程 進程調度 進程的并行與并發 同步異步阻塞非阻塞 同步和異步 阻塞與非阻塞 同步/異步與阻塞/非阻塞 組合 進程的創建與結束 進程的創建 進程的結束 在python程序中的進程操作 multiprocess&#xff08;multiproc…

從全息投影到全息平臺,必須克服7個障礙

“每個科幻愛好者和癡迷技術的人兒都希望能擁有一個全息成像臺。不幸的是&#xff0c;制造全息平臺的技術還尚未被人類掌握。據說我們離這項技術可用之時還有大約10到15年的時間——這是 AMD 的專業人士 Phil Rogers 說的&#xff0c;他專攻 3D 技術工作已超過20年。在《今日宇…

android fragment fragmenttransaction,Android FragmentTransaction 常用方法總結

FragmentManage&#xff1a;FragmentManager能夠實現管理activity中fragment. 通過調用activity的getFragmentManager()取得它的實例.FragmentManager可以做如下一些事情:1、使用findFragmentById() (用于在activity ...public class Toolkit { /** * * Role:Telec…

IBM總架構師寇衛東:話說程序員的職業生涯-IT程序人生-職業生涯規劃

初級程序員和高級程序員時期&#xff0c;都屬于職業生涯發展的第一階段&#xff0c;我們可以稱之為黃金時期。這階段程序員的年齡在20~35歲之間&#xff0c;因為年輕&#xff0c;所以更善于學習&#xff0c;而且體力充沛&#xff0c;很多走過這個階段的程序員有過通宵工作的經歷…

metric learning -- 馬氏距離與歐氏距離

一 基本概念 方差&#xff1a;&#xff08;variance&#xff09;是在概率論和統計方差衡量隨機變量或一組數據時離散程度的度量。概率論中方差用來度量隨機變量和其數學期望&#xff08;即均值&#xff09;之間的偏離程度。統計中的方差&#xff08;樣本方差&#xff09;是每個…

深入理解 C# 協變和逆變

msdn 解釋如下&#xff1a; “協變”是指能夠使用與原始指定的派生類型相比&#xff0c;派生程度更大的類型。 “逆變”則是指能夠使用派生程度更小的類型。 解釋的很正確&#xff0c;大致就是這樣&#xff0c;不過不夠直白。 直白的理解&#xff1a; “協變”->”和諧的變”…

華為mate20能用鴻蒙嗎,華為mate20可以用5g網絡嗎

華為mate20不可以用5g網絡&#xff0c;它是4g手機在2018年上市&#xff0c;當時5g并沒有開始流行&#xff0c;因此mate20是不支持5G的。不過在后來的2019年秋季&#xff0c;華為發布了mate20 x的5g版本&#xff0c;這也是mate20系列里唯一支持5G的&#xff0c;除此之外mate20、…

基本農田衛星地圖查詢_#重慶朝天門#谷歌百度騰訊高德“衛星地圖”PK,谷歌更勝一籌...

截圖自便民查詢網&#xff0c;各家衛星地圖PK&#xff0c;各有千秋~谷歌精確度最高&#xff1a;5m&#xff0c;來福士修建中&#xff0c;嘉陵江是綠的&#xff0c;長江是黃的。兩江交匯處有一條分明的界線。谷歌 5m:20ft谷歌 50m:100ft谷歌 200m:500ft谷歌 300m:1000ft谷歌 500…

軟件開發者面試百問答案,老紫竹研究室出品(已經有64個)

當然&#xff0c;全部是我個人的答案&#xff0c;不代表別人。地址 www.laozizhu.com/program.jsp?typeId104 老紫竹研究室&#xff0c;分享軟件開發的快樂與收獲 ‘ 我這里貼上已經寫好的答案連接。 軟件開發者面試百問答案 - 你需要哪些東西幫助你判斷項目是否符合時間要求…

Python 第三方庫之 Celery 分布式任務隊列

一、Celery介紹和使用&#xff1a; Celery 是一個 基于python開發的分布式異步消息任務隊列&#xff0c;通過它可以輕松的實現任務的異步處理&#xff0c; 如果你的業務場景中需要用到異步任務&#xff0c;就可以考慮使用celery&#xff0c; 舉幾個實例場景中可用的例子: 你想…