今天的內容書接上回,同樣是vue的核心基礎部分,今天偏向於理論性,特別是vue對於數據對象的監測那一塊,剛開始琢磨了半天,這股勁一過,現在好理解多了 10.watch和computed對比 計算屬性案例(watch來做) 在增加一條需求輸入姓後要反應一秒後再響應 computed 區別 : comp ...
今天的內容書接上回,同樣是vue的核心基礎部分,今天偏向於理論性,特別是vue對於數據對象的監測那一塊,剛開始琢磨了半天,這股勁一過,現在好理解多了
10.watch和computed對比
計算屬性案例(watch來做)
在增加一條需求輸入姓後要反應一秒後再響應
computed
區別 :
- computed能完成的功能,watch都可以完成
- watch可以完成的功能,computed不一定能完成,就比如watch這裡可以非同步操作,computed就不行,因為computed裡面我們靠的就是那個返回值讓他的getter返回值就會等於fullname這個計算屬性,所以如果返回值給了定時器,那麼我的fullname就沒有得到返回值,但是watch不一樣,watch是對值做操作,在定時器裡面就已經完成了賦值的操作,不需要你返回給我
註意 :
- 前面都說被vue所管理的函數最好別寫箭頭函數,但是這裡的定時器必須寫為箭頭函數,因為如果是普通函數那麼他的this就為window,定時器的this本身就是為window,但是如果這裡是箭頭函數,都知道,箭頭函數的this是定義它位置的地方的this,所以就是監視這個屬性裡面的this就是vm實例
- 被vue所管理的函數最好寫成普通函數,不被vue所管理的函數(定時器、ajax回調、promise的回調)最好寫成箭頭函數
11.綁定class樣式
-
字元串寫法,適用於:樣式類名不確定,需要動態指定
註意一下這裡的生成隨機整數是怎麼的寫法
-
數組寫法:適用於:個數不確定,類名也不確定的時候,個數我以後 可能有一百個可能有幾個,名字可能叫這個可能叫那個
-
對象寫法:適用於個數確定,類名也確定,我只有這兩個,也只叫這個名字
-
綁定style樣式(瞭解)這是對象寫法,同樣也有數組寫法,就是fontsize寫在這個對象,background寫在那個對象,數組寫法就是將兩個對象結合起來【obj1,obj2】
12.條件渲染
控制元素的隱藏顯示
全新指令語法:v-show、v-if他們兩個都可以實現顯示隱藏,v-show底層實現是display:none,v-if直接把元素都刪沒了,所以當我們需要頻繁切換顯示隱藏的時候建議v-show
案例:
v-else-if跟v-if是一組的判斷,如果前面達成條件後面就不再做判斷
v-else 註意v-else後面就不跟條件了直接寫上v-else,出了條件外的都顯示他
註意v-if判斷是一個整體,包括else if、else,中間不能寫其他的來打斷
v-if與template配合使用
我要完成這麼一個界面當點擊達到1的時候顯示出來
這種做法是不是有點冗餘,每個都要去判斷一下,所以就有一個標簽template,只能配合v-if使用,它最大的好處就是不會影響頁面標簽佈局
13.列表渲染
全新指令語法v-for
- 遍曆數組
首先用了v-for我們有多少數據,就自動會遍歷出多少li,然後v-for每個li是必須配置一個:key的動態屬性的,我們的遍歷可以寫多個參數,寫多少個的時候前面表示這個對象,後面表示這個對象在數組裡面的索引號,而我們的key就可以配置為p.id或者是index這個索引號
-
遍歷對象
遍歷對象要註意,遍歷的值和我們的數據是反的,前面是我們的數據,後面變成了值,而且遍歷對象,key就為這個屬性名,
v-for除了可以用in 用 of也是一樣的效果
-
遍歷字元串
字元串就是可以把每一個字元遍歷出來,前面是值,後面是下標
-
遍歷指定次數(不常用)
13.1 key作用與原理(面試)
首先要知道我們動態生成的key並不是拿在頁面上來呈現的,可以看到最終生成的真實DOM是沒有這個屬性的,它是用來vue拿來用的
當我們用index作為key的值會出現的問題:
有一個需求當我們點擊按鈕會在上面新增條數據老六
是不是就出現問題了,分析一下下麵這個圖就知道問題在哪了
這個就是我們前面所說的vue的一大優點,虛擬DOM加Diff演算法,就在這裡體現了。首先我們初始化的數據,打開網頁vue會先在記憶體生成虛擬DOM,同時key是我們的index,然後正常將虛擬DOM轉為真實DOM,轉到頁面上來了,我們正常在input框輸入內容,這個時候我們去點擊新增老六這個按鈕,相當於讓數據變成了我們的新數據樣式,然後又會在記憶體生成虛擬DOM,這個時候由於是第二次生成了,所以Diff演算法就來了,vue會拿我們新的虛擬dom和舊的虛擬dom進行比較,而比較的依據就是key,當我們比較第一條數據的時候,key對上了之後,先去比較文本發現文本不一樣,那麼就不能復用,就會以新的虛擬dom為準,接著回去比較input標簽,註意這個時候比較input標簽會發現是一樣的,為什麼,因為都是input標簽,都是text格式,我們在裡面輸入的內容實在真實dom輸入的跟虛擬dom沒有關係,所以比較出來是一樣的,既然一樣我就可以去key=0,以前已經生成過真實dom了吧,那我就直接去拿來複用了,所以最終形成的結果就是,新增的文本就上我們舊的input,以此類推,所以就導致了我們最終呈現的效果有問題
這是用index作為key的問題一,還有一個問題就是效率變低了,為什麼,因為我們原來本來可以復用的數據,他給我重新生成了真實dom肯定效率低了
當我們用id作為key時
首先比較key=004發現沒有,沒有那就直接新增,後面的都發現有,而且數據也對的上那就直接復用
開發中如何選擇key
- 最好是用每條數據的唯一標識(id、手機號、身份證號、學號等)
- 如果不存在對數據的逆序添加、逆序刪除等破壞順序的操作,或者渲染列表僅用於展示(沒有新增刪除),使用index作為key還是沒問題的,順序添加刪除使用它還是可以的
13.2 列表過濾
也就是模糊搜索,先完成能過濾的功能(註意數組和字元串的方法)
這麼做的話就會損壞原數據,我們的原數據是不能動的,因為要確保,不搜索了還能回去
定義一個新數組,讓新數組去接收搜索出來的值,同時原數組也沒有改動所以可以一直搜索,不會像原來一樣越搜數據越少的情況,同時要把遍歷的v-for修改為新數組,但是現在就有一個問題新數組為空,那我們剛開始的時候就看不到列表了
這裡有一個很重要的概念,字元串的indexOf方法對於空字元串的查找是找得到的,意思就是任何字元串.indexOf('')都不會返回-1,都是有值的
所以只需要開啟初始化就監視一下即可,這個時候keyword為空字元串,那麼數據裡面的每條數據都有空字元串,那就會把全部數據輸出出來
計算屬性實現
計算屬性能實現的,watch肯定能實現,watch能實現的只要不涉及到非同步任務,計算屬性一般也能實現
就這一段代碼即可實現,為什麼直接就能渲染,以為watch預設是要先搜索再去執行handler,這裡一來就會執行,一來就是空字元串,為什麼不用自定義一個新的數組,因為計算屬性就相當於一個新的數組了
13.3 列表排序
關鍵點在於利用計算屬性裡面的任何一個依賴數據發生變動都會重新運算計算節點
- 數組排序參數是誰
- 排序和過濾是密不可分的,我還需要在過濾出來的基礎上排序,不是一點排序就回到了原數據列表
- 之所以點擊原順序可以回去,關鍵點就在於計算屬性裡面每一個依賴數據發生變動,都會重新計算重新渲染,所以一點擊原順序sortType就變動了,重新根據關鍵字去過濾數組,得出來的滿足不了排序的if就直接輸出arr了
13.4 vue監測數據改變的原理
先看到一個數據更新時的問題
點擊後沒反應,vue管理工具也沒有數據更新
13.4.1 vue對象監測原理
先看一張圖,這裡有點繞,有點難以理解,我在那裡捋了四五十分鐘接近一個小時,vue的一個對象檢測原理就是,我們說過我們的data數據最終會呈現在vm實例的_data上,vue對於對象數據的檢測就是定義了一個構造函數,這個構造函數會把我們的數據的屬性名全部拿過來然後做一個遍歷,在遍歷裡面,是最重要的邏輯,用對象定義屬性的方法,**對象為this,這裡的this指的就是這個構造函數的實例,同時給他上面定義屬性,當訪問到這個構造函數實例的這個屬性的時候就把obj對應的屬性的值給到他(也就是data上面對應的值),其實這裡就是做了一個數據代理,我們讀取和寫入雖然是在這個實例上面我就說_data上面吧,插值語法之所以能夠直接寫name是因為後面又給vm做了一個數據代理,其實vue的讀寫都是基於這個_data的,讀通過_data來讀,修改雖然是修改的_data但是會把val給到data數據本身。總結就是:vue對於對象數據的監測就是通過一個構造函數,目的是加工data來給_data賦值,真正的邏輯在於裡面的defineProperty這個方法,真正的監測原理就是通過這裡面的getter和setter來讀和寫我們的data,然後再setter作進一步的邏輯,既然是setter那就是值變化了,就回去重新解析模板,diff比較虛擬DOM看哪些能復用,再把我們修改的值渲染上去 **
一句話總結:vue監測原理就靠這個setter
13.4.2 vue.set()的使用
這個案例首先要註意一點,在vue裡面如果值為undefined,並不會報錯,只是沒有文字顯示出來而已,這裡的age沒有賦值,所以undefined,在頁面上並不會報錯,只是一片空白沒有數據
一個需求,我如果想通過將它直接賦值讓頁面出現他的性別:
可以看到頁面並沒有顯示,而且我們的數據也有,但是是寫死的並不是響應式的,我們之前研究過vue的監測原理靠的就是那個setter,這裡沒有給她做setter所以自然也不會映射到頁面上來
-
Vue.set()vue提供的的api,可以讓我們在後面添加的數據,也能夠完成響應式數據,也有屬於自己的getter和setter
三個參數:第一個參數往哪裡添加這個屬性,第二個參數屬性名,第三個參數值
-
第二種寫法:vm.$set(參數跟上面一樣三個)
-
局限性
該方法不能直接給data和vm添加屬性
13.4.3 vue數組監測原理
vue裡面不能直接以數組索引去修改值
可以看到我們數組的值都變了,但是vue監測不到,所以頁面不會變,不能直接通過數組索引去修改值
在vue裡面數組能被監測到的只能是可以修改數組本身的七種方法
所以現在就可以對我們13.4那裡的案例做出回應了
問題:為什麼vue知道我們使用了這些方法
因為vue對這些方法做出了包裝,不是Array原來的那七個方法了,實現邏輯肯定還是原來那種只是添加了一些邏輯(方法完成後會去重新解析模板,重新diff虛擬DOM)
讓數組被監測到方法二:
Vue.set這個api也可以
13.4.4 總結vue數據監測
看下總結案例(如何實現性別在未添加之前為隱藏、修改數組裡面的對象不需要數組的方法)
-
vue會監視data中所有層次的數據
-
對象中通過setter實現監視,且要在定義data時就傳入數據,如果是在之後添加的數據,需要Vue.set或者是vm.$set來實現監視
-
數組中的數據通過包裹數組的七種方法實現
-
vue數組中修改元素大多數要通過七種方法或者set兩個api
七種方法為變更方法,但是也有非變更方法如(filter、concat、slice這些會返回新數組的方法,可以讓返回的新數組替換掉舊數組,同樣可以受到監視,頁面同樣會被更改)
-
最後註意一下set兩個api不能給vm和data跟數據對象添加屬性
-
數據劫持:就是前面說的對象監測原理,把一個完好的data數據變成了setter的方式,我如果要修改student的值,瞬間就被setter劫持到了,去做了其他解析模板等操作,這就叫數據劫持
-