今天的內容書接上回,同樣是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劫持到了,去做了其他解析模板等操作,這就叫資料劫持