<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Vue3中級指南-Compostition API詳解

          共 9204字,需瀏覽 19分鐘

           ·

          2023-04-28 09:25

          Compostition API集合,解決Vue2組件開發(fā)問題

          更好的TypeScript支持

          新的Api支持

          什么是reactive?

          • reactive是vue3中提供的實現(xiàn)響應(yīng)式數(shù)據(jù)的方法
          • 在vue2中響應(yīng)式數(shù)據(jù)是通過defineProperty來實現(xiàn)的
            • 因為有缺陷,在處理數(shù)組方面,所以vue3中響應(yīng)式數(shù)據(jù)是通過ES6的Proxy來實現(xiàn)的

          reactive注意點

          • reactive參數(shù)必須是對象(json/arr)
          • 如果給reactive傳遞了其他對象
            • 默認(rèn)情況下修改對象,界面不會自動更新。
            • 如果想更新,可以通過重新賦值的方式。

          什么是ref?

          • ref和reactive一樣,也用用來實現(xiàn)響應(yīng)式數(shù)據(jù)的方法
          • 由于reactive必須傳遞一個對象,所有導(dǎo)致在企業(yè)開發(fā)中如果我們只想讓某個變量實現(xiàn)響應(yīng)式的時候會非常麻煩,所有vue3就給我們提供了ref方法,實現(xiàn)對簡單之的監(jiān)聽

          ref本質(zhì)

          • ref底層的本質(zhì)還是reactive,系統(tǒng)會自動根據(jù)我們給ref傳入的值將它轉(zhuǎn)換成以下這樣

                        
                        ref(xxx)?=>?reactive({value:xxx})

          ref注意點

          • 在vue中使用ref聲明的變量在模版中不需要通過.value獲取,因為在template模版中,vue會自動給我們添加.value
          • 在js中使用ref的值或者更改ref的值必須通過.value獲取和更改

          遞歸監(jiān)聽

          • 默認(rèn)情況下,無論是通過ref還是reactive都是遞歸監(jiān)聽

          • 遞歸監(jiān)聽存在的問題,如果數(shù)據(jù)量較大,非常消耗性能

          • 非遞歸監(jiān)聽

          shallowReactive

                
                ????let?state?=?shallowReactive({
          ??????a:?"a",
          ??????b:?{
          ????????c:?"c",
          ????????d:?{
          ??????????e:?"e"
          ????????}
          ??????}
          ????})

          注意:shallowReactive用于創(chuàng)建非遞歸監(jiān)聽的屬性,只會監(jiān)聽第一層

          shallowRef

                
                ????let?state?=?shallowRef({
          ??????a:?"a",
          ??????b:?{
          ????????c:?"c",
          ????????d:?{
          ??????????e:?"e"
          ????????}
          ??????}
          ????})

          注意:shallowRef監(jiān)聽的是.value的變化。并不是shallowReactive第一層的變化。

          triggerRef

                
                ????let?state?=?shallowRef({
          ??????a:?"a",
          ??????b:?{
          ????????c:?"c",
          ????????d:?{
          ??????????e:?"e"
          ????????}
          ??????}
          ????})
          ????
          ????//?修改后頁面并不會更新視圖
          ????state.b.d.e?=?"ee"
          ????//?主動觸發(fā)視圖更新
          ????triggerRef(state)
          • 應(yīng)用場景

            一半情況下我們使用ref和reactive即可,只有在需要監(jiān)聽的數(shù)據(jù)量比較大的時候,我們才使用shallowRef/shallowReactive

          toRaw

          了解toRaw之前我們可以先看下以下的一個小列子來理解為啥需要用到toRaw

                
                <script?lang="ts">
          import?{?reactive?}?from?"vue";

          export?default?{
          ??name:?"App",
          ??setup()?{
          ????let?data?=?{
          ??????name:?"只會番茄炒蛋",
          ??????age:?18,
          ????};
          ????let?state?=?reactive(data);
          ????
          ????function?changeAge()?{
          ??????//?state.age?+=?1;
          ??????data.age?+=?1;
          ??????console.log(data);
          ??????console.log(state);
          ????}
          ????return?{
          ??????state,
          ??????changeAge,
          ????};
          ??},
          };
          </script>

          我們會發(fā)現(xiàn),數(shù)據(jù)改變了但是視圖并沒有更新。這里我們明白的一點就是data和state是引用關(guān)系。state的本質(zhì)是一個Proxy對象,在這個Proxy對象中引用了data

          如果直接修改data,數(shù)據(jù)是改變的,但是無法觸發(fā)頁面的更新

          只有通過包裝之后的對象來修改,才會觸發(fā)頁面的更新

          這個方法有啥作用場景就是, 當(dāng)我們只想修改數(shù)據(jù),但是不想視圖發(fā)生變化時使用。因為ref和reactive數(shù)據(jù)類型的特點就是每次修改數(shù)據(jù)都會被追蹤,都會更新ui界面。非常消耗性能。如果我們有一些操作不需要追蹤和更新頁面,那么這時候就可以通過toRaw方法拿到他的原始數(shù)據(jù)。這樣就能夠節(jié)省性能

          總結(jié):toRaw方法從響應(yīng)式數(shù)據(jù)獲取原始數(shù)據(jù)

          注意:當(dāng)我們通過toRaw獲取ref類型的原始數(shù)據(jù)時會發(fā)現(xiàn)獲取不到。

          ref本質(zhì):reactive

          Ref(obj) => reactive({value: obj})

          這也是為什么需要通過.value來獲取ref創(chuàng)建的數(shù)據(jù)

          總結(jié):如果想要通過toRaw拿到ref類型的原始數(shù)據(jù)(創(chuàng)建時傳入的那個數(shù)據(jù))那么久必須明確告訴toRaw方法,要獲取的時.value的值。因為經(jīng)過Vue處理之后,.value中保存的才是當(dāng)初的原始數(shù)據(jù)。

                
                <script?lang="ts">
          import?{?ref,?toRaw?}?from?"vue";

          export?default?{
          ??name:?"App",
          ??setup()?{
          ????let?data?=?{
          ??????name:?"只會番茄炒蛋",
          ??????age:?18,
          ????};
          ????let?state?=?ref(data);
          ????let?data2?=?toRaw(state.value);
          ????console.log(data2);

          ????function?changeAge()?{
          ??????//?state.age?+=?1;
          ??????data.age?+=?1;
          ??????console.log(data);
          ??????console.log(state);
          ????}
          ????return?{
          ??????state,
          ??????changeAge,
          ????};
          ??},
          };
          </script>

          Markrow

          永遠(yuǎn)不會被追蹤的數(shù)據(jù),被markrow聲明的變量永遠(yuǎn)不會被追蹤,即使被reactive或者ref聲明。修改數(shù)據(jù)也不會改變數(shù)據(jù),更不會觸發(fā)視圖更新

          ref和toRef的區(qū)別

          • ref 和toRef 修改響應(yīng)式數(shù)據(jù)都會會影響以前的數(shù)據(jù)
          • ref 數(shù)據(jù)發(fā)生改變,界面就會自動更新
          • toRef數(shù)據(jù)發(fā)生改變,界面也不會自動更新

          toRef應(yīng)用場景:如果想讓響應(yīng)式數(shù)據(jù)和以前的數(shù)據(jù)關(guān)聯(lián)起來,并且更新響應(yīng)式數(shù)據(jù)之后還不想更新UI,那么就可以使用。

          toRefs

          將響應(yīng)式對象轉(zhuǎn)換為普通對象,其中結(jié)果對象的每個 property 都是指向原始對象相應(yīng) property 的 ref。

          或者說將一個對象身上的所有屬性變?yōu)轫憫?yīng)式數(shù)據(jù)可以使用。以上這些方法都是為了提升性能。主要用的多的還是ref和reactive

          customRef

          創(chuàng)建一個自定義的 ref,并對其依賴項跟蹤和更新觸發(fā)進行顯式控制。它需要一個工廠函數(shù),該函數(shù)接收 tracktrigger 函數(shù)作為參數(shù),并且應(yīng)該返回一個帶有 getset 的對象。

          為什么要自定義ref我們下面再說。先說如何實現(xiàn)

                
                <script?lang="ts">
          import?{?customRef?}?from?"vue";

          function?myRef(value)?{
          ??return?customRef((track,?trigger)?=>?{
          ????return?{
          ??????get()?{
          ????????//?track()方法告訴vue這個數(shù)據(jù)是要被追蹤的
          ????????track();
          ????????console.log("get",?value);
          ????????return?value;
          ??????},
          ??????set(newValue)?{
          ????????value?=?newValue;
          ????????console.log("set",?value);
          ????????//?trigger()方法告訴vue更新視圖
          ????????trigger();
          ??????},
          ????};
          ??});
          }

          export?default?{
          ??name:?"App",
          ??setup()?{
          ????let?state?=?myRef(18);
          ????function?change()?{
          ??????state.value?=?20;
          ????}
          ????return?{
          ??????state,
          ??????change,
          ????};
          ??},
          };
          </script>

          為什么要自定義ref

          首先我們要知道一點的是setup函數(shù)只能是一個同步的函數(shù),不能是一個異步的函數(shù)。至于為什么不能是一個異步的函數(shù)大家在setup前面加上async讓后正常聲明變量在頁面中顯示就知道原因了。

          所以當(dāng)我們在業(yè)務(wù)中需要發(fā)起ajax請求獲取數(shù)據(jù)的時候,且想通過async await來獲取數(shù)據(jù)就行不通了。

          那么無法使用async await的時候就意味著我們的代碼中可能會出現(xiàn)大量的回調(diào)函數(shù)。

          那么我們還想按照以前同步代碼的方式來書寫 就可以考慮使用自定義ref。

                
                <script?lang="ts">
          import?{?customRef?}?from?"vue";

          function?myRef(value)?{
          ??return?customRef((track,?trigger)?=>?{
          ????fetch(value)
          ??????.then(async?(res)?=>?{
          ????????value?=?await?res.json();
          ????????console.log(value);
          ????????trigger();
          ??????})
          ??????.catch((reason)?=>?{
          ????????console.log(reason);
          ??????});

          ????return?{
          ??????get()?{
          ????????//?track()方法告訴vue這個數(shù)據(jù)是要被追蹤的
          ????????track();
          ????????console.log("get",?value);
          ????????return?value;
          ??????},
          ??????set(newValue)?{
          ????????value?=?newValue;
          ????????console.log("set",?value);
          ????????//?trigger()方法告訴vue更新視圖
          ????????trigger();
          ??????},
          ????};
          ??});
          }

          export?default?{
          ??name:?"App",
          ??setup()?{
          ????let?state?=?myRef("../public/data.json");
          ????function?change()?{
          ??????state.value?=?20;
          ????}
          ????return?{
          ??????state,
          ??????change,
          ????};
          ??},
          };
          </script>

          ref獲取元素

          vue3和vue2不同, vue3并沒有this.$屬性的那些東西了。想要獲取元素也很簡單

                
                <template>
          ??<div>
          ????<div?ref="box">我是box</div>
          ??</div>

          </template>

          <script?lang="ts">
          import?{?onMounted,?ref?}?from?"vue";

          export?default?{
          ??name:?"App",
          ??setup()?{
          ????let?box?=?ref(null);
          ????onMounted(()?=>?{
          ??????console.log(box.value);
          ????});
          ????return?{
          ??????box,
          ????};
          ??},
          };
          </
          script>

          這里注意為什么打印的是box.value 和上面ref聲明變量獲取的原因一致。

          為什么在onMounted中打印。這點生命周期和2是一致的。因為setup和created還有beforeC reated一樣,這這期間dom還沒有創(chuàng)建

          readonly家族

          • readonly

          接受一個對象 (響應(yīng)式或純對象) 或 ref 并返回原始對象的只讀代理。只讀代理是深層的:任何被訪問的嵌套 property 也是只讀的。

          用于創(chuàng)建一個只讀屬性,并且是遞歸只讀

          • shallowReadonly

          用于創(chuàng)建一個只讀的數(shù)據(jù),但是不是遞歸只讀。只有第一層只讀

          • isReadonly

          用于判斷屬性是否是一個readonly返回布爾值

          這里大家可能會有疑問那么我直接使用const聲明變量不就行了嗎。這里要注意。const通常用于聲明常量,且通常是聲明原始類型。但是如果聲明引用類型。隨便變量不可重新賦值。但是引用類型的屬性的值是可以更改的。

          關(guān)于響應(yīng)式數(shù)據(jù)本質(zhì)上的理解

          • 在vue2.x中是通過defineProperty來實現(xiàn)響應(yīng)式數(shù)據(jù)的。但是有部分缺陷,例如數(shù)組的處理

          • 在vue3.x中是通過Proxy來實現(xiàn)響應(yīng)式數(shù)據(jù)的

                
                //?簡單實現(xiàn)
          let?obj?=?{?name:?"番茄",?age:?18?}
          let?state?=?new?Proxy(obj,?{
          ????get(obj,?key)?{
          ????????console.log(obj,?key);?//?{name:?'番茄',?age:?18}?name
          ????},
          ????set(obj,?key,?value)?{
          ????????console.log(obj,?key,?value);?//?{name:?'番茄',?age:?18}?name?炒蛋
          ????????obj[key]?=?value
          ????????console.log("更新UI視圖");
          ???????return?true
          ????}
          })

          console.log(state.name);?//?番茄
          state.name?=?"炒蛋"
          console.log(state);?//?Proxy?{name:?'炒蛋',?age:?18}

          通過上述簡單的列子。我們就可以在獲取值和設(shè)置值的做很多事情了。

          注意點:set方法一定要給返回值告訴此次操作完成成功。因為在set操作中可能不止做一次修改例如數(shù)組

          proxy代理數(shù)組

                
                //?簡單實現(xiàn)
          let?arr?=?[1,?2,?3]
          let?state?=?new?Proxy(arr,?{
          ????get(obj,?key)?{
          ????????console.log(obj,?key);?//?[1,?2,?3]?1
          ????????return?obj[key]
          ????},
          ????set(obj,?key,?value)?{
          ????????/**
          ?????????*??[?1,?2,?3?]?push
          ????????????[?1,?2,?3?]?length
          ????????????[?1,?2,?3?]?3?4
          ????????????更新UI視圖
          ????????????[?1,?2,?3,?4?]?length?4
          ????????????更新UI視圖
          ????????????[?1,?2,?3,?4?]
          ?????????*/

          ????????console.log(obj,?key,?value);
          ????????obj[key]?=?value
          ????????console.log("更新UI視圖");
          ????????return?true
          ????}
          })

          //?console.log(state[1])?//?2
          state.push(4)
          console.log(state);

          通過上述代碼我們會發(fā)現(xiàn)set方法中執(zhí)行了兩次。一次是[ 1, 2, 3 ] 3 4, 一次是[ 1, 2, 3, 4 ] length 4

          set方法一定通過返回值告訴當(dāng)前的操作是否成功。如果將上面的return ture注視掉就會報錯

                
                state.push(4)
          ??????^

          TypeError:?'set'?on?proxy:?trap?returned?falsish?for?property?'3'
          ????at?Proxy.push?(<anonymous>)
          ????at?Object.<anonymous>?(/Users/cctvabu/vite-vue3-project/proxy.js:26:7)
          ????at?Module._compile?(internal/modules/cjs/loader.js:1063:30)
          ????at?Object.Module._extensions..js?(internal/modules/cjs/loader.js:1092:10)
          ????at?Module.load?(internal/modules/cjs/loader.js:928:32)
          ????at?Function.Module._load?(internal/modules/cjs/loader.js:769:14)
          ????at?Function.executeUserEntryPoint?[as?runMain]?(internal/modules/run_main.js:72:12)
          ????at?internal/main/run_main_module.js:17:47

          所以注意在set方法中一定要通過返回值告訴當(dāng)前操作是否成功


          以上呢就是我學(xué)習(xí)了解到的部分api知識。后續(xù)還在學(xué)習(xí)和補充中。當(dāng)然有不對的地方請評論指出,我查閱資料修改。

          找工作

          本人最近準(zhǔn)備跳槽找工作。有介紹工作的可以聯(lián)系我哈~


          瀏覽 103
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  欧美激情人妻少妇中文字幕视频在线 | 一级A片黃色A | 水多多成人视频 | 欧美一级成人网站 | 大胆国模免费视频 |