Vue2中檢測數組變化的限制和解決方法
vue2用下標設置數組沒效果
- arr = [1,2] arr[0] = 0,頁面上顯示的arr并沒有修改(如果對應下標是原始值;若是引用值)
- 解決1:Vue.Set
- 解決2:arr.splice (Vue會劫持splice方法) Vue2對對象是循環defineProperty(遞歸、深度)set時通知dep.notify();對于數組則是重寫數組7個方法(push、pop、shift、unshift、splice、sort、reverse)時通知dep.notify();
<div id="app">{{ arr[0].a }}{{ arr[1].a }}</div><script>var app = new Vue({el: '#app',data: {arr: [{ a: 2 }, { a: 600 }]},mounted() {setTimeout(() => {this.arr[1] = [{ a: 400 }] // 這樣看不到400this.arr[1].a = 800 // 這樣能看到變成800}, 3000)}})</script>
vue2設置數組長度沒效果
- arr.length-- ,頁面上顯示的arr并沒有修改
- 解決1:Vue.Delete
- 解決2:arr.splice
Vue nextTick
Vue渲染是異步渲染,添加元素時不會馬上渲染,而是到下一個tick才渲染。 nextTick的回調會在dom異步渲染完畢后執行(vue是組件級的,若一有數據就更新性能肯定不好)。并且vue是批量做渲染的 在外部添加3個 在nextTick里獲取個數 只會打印一次
nextTick的實現
- 如果支持promise,將回調放在then方法里
- 若不,若支持MutationObserver,就xxx也是異步執行的
- 若不,若支持setImmediate
- 再不,setTimeout
computed method watch區別
- method用在視圖上,每次都去執行,開銷大,而computed是具備緩存的,若依賴的屬性無變化,不計算
Vue Plugin
- 全局方法 Vue.xx訪問
- 全局指令
- mixin
- 原型上綁定方法 Vue實例this訪問
- 導出插件,在main.js里use
Vue組件data返回函數
- Vue組件可能存在多個實例,如果使用對象形式定義data,會導致他們共用一個data對象,那么狀態變更將會影響所有組件實例;采用函數形式定義,在initData時會將其作為工廠函數返回全新的data對象,有效規避多實例之間狀態污染問題。而Vue根實例只能有一個,不會有次問題。
加key 高效更新dom
- key的作用主要是為了高效更新虛擬DOM,其原理是vue在patch(打補丁)過程中通過key可以精準判斷兩個節點是都是同一個,從而避免頻繁更新不同元素,是patch過程更高效,減少dom操作量,提高性能
- 若不設置key還可能在列表更新時引發一些隱蔽的bug
- vue中在使用相同標簽名元素的過渡切換時,也會使用到key屬性,目的是為了讓vue可以區分他們,否則vue只會替換其內部屬性而不會觸發過渡效果
- 不使用key,更新時不知道每個元素的位置,所以在A更新A,B更新B,C更新為F,以此類推,實際更新了3次,從F開始FCD + 創建插入E (源碼中,每次循環認為這5對是sameVnode,只能每次都去更新。而加了key能精準判斷是否是相同節點)
- 使用key,只做了一次創建F并插入到C前面的操作(比較時,比較首位元素是否相同)
源碼
-
沒有設置key時,key的值是undefined,兩個未設置key的標簽值被判斷為相同
-
diff算法不是最優,增加key優化了diff,降低復雜度
-
加key
index作為key
- 在數據會增減時可能會產生問題,在頭部插入,在中間刪除(數量變化,index是在變的)
- random作為key,隨機數還是有可能是一樣的
vue-router的原理
- vue-router通過hash與History interface兩種方式實現前端路由,更新視圖但不重新請求頁面”是前端路由原理的核心
- history模式則會將URL修改得就和正常請求后端的URL一樣,如后端沒有配置對應/user/id的路由處理,則會返回404錯誤
- 它提供mode參數
- hash帶# new HashHistory 是基于location.hash來實現的。Location.hash的值就是URL中#后面的內容。當hash改變時,頁面不會因此刷新,瀏覽器也不會請求服務器。
- history更像url new HTML5History
update beforeUpdate
總結:
- 不能籠統地說能修改或不能修改數據
- 修改的數據未渲染到視圖不會觸發這2個鉤子
- this.msg = this.msg + 1是有可能引起死循環的操作
- beforeUpdate修改視圖數據不會再次觸發beforeUpdate 即使++也沒關系
- updated修改視圖數據為常量,會再觸發一輪beforeUpdate → update;因此,若在此生命周期++會死循環