1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        整理的一些 Vue3 知識(shí)點(diǎn)

        共 33308字,需瀏覽 67分鐘

         ·

        2021-09-27 15:00



        大廠技術(shù)  高級(jí)前端  Node進(jìn)階

        點(diǎn)擊上方 程序員成長(zhǎng)指北,關(guān)注公眾號(hào)

        回復(fù)1,加入高級(jí)Node交流群


        看完你就基本可以上手搞開(kāi)發(fā)了,本文適合Vue初學(xué)者,或者Vue2遷移者,當(dāng)然還是建議Vue3官網(wǎng)完全過(guò)一遍。不適合精通原理,源碼的大佬們。

        先推薦兩個(gè)vscode插件

        Volar

        首先推薦Volar,使用vscode開(kāi)發(fā)Vue項(xiàng)目的小伙伴肯定都認(rèn)識(shí)Vetur這個(gè)神級(jí)插件,有了它可以讓我們得開(kāi)發(fā)如魚(yú)得水。那么Volar可以理解為Vue3版本的Vetur,代碼高亮,語(yǔ)法提示,基本上Vetur有的它都有。

        特色功能

        當(dāng)然作為新的插件出山,肯定有它獨(dú)有的功能。

        多個(gè)根節(jié)點(diǎn)編輯器不會(huì)報(bào)錯(cuò)

        Vue3是允許我們有多個(gè)根節(jié)點(diǎn)的,但是我們?nèi)绻褂肰etur就會(huì)報(bào)錯(cuò),不會(huì)影響運(yùn)行,但是看起來(lái)就很煩。所以當(dāng)我們轉(zhuǎn)向Volar那么就不會(huì)出現(xiàn)這個(gè)問(wèn)題了。

        image.png

        編輯器分隔

        即便Vue的組件化開(kāi)發(fā),可以將單文件的代碼長(zhǎng)度大幅縮短,但還是動(dòng)輒幾百行甚是上千行。那么我們切換template,scriptstyle的時(shí)候就要頻繁上下翻,雖然有的插件可以直接定位到css,但是你回不去??!所以這個(gè)功能簡(jiǎn)直是太人性化了。

        安裝完Volar以后,打開(kāi)一個(gè).vue文件,看vscode的右上角,有這么一個(gè)圖標(biāo),點(diǎn)一下。

        image.png

        它就會(huì)自動(dòng)給你分隔成三個(gè)頁(yè)面,分別對(duì)應(yīng)templatescriptstyle,這樣就太舒服了有沒(méi)有。

        image.png

        Vue 3 Snippets

        推薦的第二個(gè)插件叫做Vue 3 Snippets,同樣的,他也有自己的Vue2版本。它是干什么的呢,可以看一下下面這張圖,我只輸入了“v3”,它有很多提示,我們就先選擇v3computed,選中回車即可。

        image.png

        然后它就給自動(dòng)給我們寫(xiě)了如下代碼

        image.png

        是不是超級(jí)省事,摸魚(yú)的時(shí)間又增加了!還有更多有趣的使用方式,小伙伴們自行探索吧。

        創(chuàng)建Vue3項(xiàng)目

        那么正式開(kāi)始學(xué)習(xí)我們的Vue3,先從創(chuàng)建項(xiàng)目開(kāi)始。

        使用 vue-cli 創(chuàng)建

        輸入下面的命令然后選擇配置項(xiàng)進(jìn)行安裝即可,這里注意vue-cli的版本一定要在4.5.0以上

        // 安裝或者升級(jí)
        npm install -g @vue/cli
        //查看版本 保證 vue cli 版本在 4.5.0 以上
        vue --version
        // 創(chuàng)建項(xiàng)目
        vue create my-project
        //然后根據(jù)提示一步一步傻瓜式操作就行了
        ...
        復(fù)制代碼

        使用 Vite 創(chuàng)建

        都說(shuō)Vue3.0Vite2更配,各種優(yōu)化,各種快,但都不屬于本文的內(nèi)容,本文的目的我們只需要知道它特別好用,怎么用就行了。我這里是多選擇了TS,每行都有注釋,一目了然。

        // 初始化viete項(xiàng)目
        npm init vite-app <project-name>
        // 進(jìn)入項(xiàng)目文件夾
        cd <project-name>
        // 安裝依賴
        npm install
        //啟動(dòng)項(xiàng)目
        npm run dev
        復(fù)制代碼

        創(chuàng)建完以后我們先來(lái)看看入口文件main.ts

        // 引入createApp函數(shù),創(chuàng)建對(duì)應(yīng)的應(yīng)用,產(chǎn)生應(yīng)用的實(shí)例對(duì)象
        import { createApp } from 'vue';
        // 引入app組件(所有組件的父級(jí)組件)
        import App from './App.vue';
        // 創(chuàng)建app應(yīng)用返回對(duì)應(yīng)的實(shí)例對(duì)象,調(diào)用mount方法進(jìn)行掛載  掛載到#app節(jié)點(diǎn)上去
        createApp(App).mount('#app');
        復(fù)制代碼

        然后看看根組件app.vue

        //Vue2組件中的html模板中必須要有一對(duì)根標(biāo)簽,Vue3組件的html模板中可以沒(méi)有根標(biāo)簽
        <template>
          <img alt="Vue logo" src="./assets/logo.png">
          <!-- 使用子級(jí)組件 -->
          <HelloWorld msg="Welcome to Your Vue.js + TypeScript App" />
        </template>


        <script lang="ts">
        // 這里可以書(shū)寫(xiě)TS代碼

        // defineComponent函數(shù),目的是定義一個(gè)組件 內(nèi)部可以傳入一個(gè)配置對(duì)象
        import { defineComponent } from 'vue';
        //引入子級(jí)組件
        import HelloWorld from './components/HelloWorld.vue';

        // 暴露出去一個(gè)定義好的組件
        export default defineComponent({
          // 當(dāng)前組件的名字
          name'App',
          // 注冊(cè)組件
          components: {
            // 注冊(cè)一個(gè)子級(jí)組件
            HelloWorld,
          },
        });
        </script>

        復(fù)制代碼

        Composition API

        接下來(lái)到了重頭戲,Vue3的招牌特性,Composition API

        關(guān)于Composition API這里有大佬做的動(dòng)畫(huà)演示,極力推薦。

        那個(gè)忙了一夜的Vue3動(dòng)畫(huà)很好,就是太短了

        Composition API可以更方便的抽取共通邏輯,但是不要過(guò)于在意邏輯代碼復(fù)用,以功能提取代碼也是一種思路。

        順便提一句,Vue3兼容大部分Vue2語(yǔ)法,所以在Vue3中書(shū)寫(xiě)Vue2語(yǔ)法是沒(méi)有問(wèn)題的(廢除的除外),但是既然我們已經(jīng)升級(jí)Vue3了,不建議混合使用,除非一些大型特殊項(xiàng)目需要兼容兩個(gè)版本。

        setup

        setup是組合Composition API中的入口函數(shù),也是第一個(gè)要使用的函數(shù)。

        setup只在初始化時(shí)執(zhí)行一次,所有的Composition API函數(shù)都在此使用。

        setup() {
          console.log('我執(zhí)行了'//我執(zhí)行了
        },
        復(fù)制代碼

        可以通過(guò)console.log看到setup是在beforeCreate生命周期之前執(zhí)行的(只執(zhí)行一次)

          beforeCreate() {
            console.log('beforeCreate執(zhí)行了');
          },
          setup() {
            console.log('setup執(zhí)行了');
            return {};
          },
          //setup執(zhí)行了
          //beforeCreate執(zhí)行了
        復(fù)制代碼

        由此可以推斷出setup執(zhí)行的時(shí)候,組件對(duì)象還沒(méi)有創(chuàng)建,組件實(shí)例對(duì)象this還不可用,此時(shí)thisundefined, 不能通過(guò)this來(lái)訪問(wèn)data/computed/methods/props。

        返回對(duì)象中的屬性會(huì)與data函數(shù)返回對(duì)象的屬性合并成為組件對(duì)象的屬性,返回對(duì)象中的方法會(huì)與methods中的方法合并成功組件對(duì)象的方法,如果有重名, setup優(yōu)先。因?yàn)樵?code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;outline: 0px;font-size: 14px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;border-radius: 4px;color: rgb(233, 105, 0);background-color: rgb(248, 248, 248);">setup中this不可用,methods中可以訪問(wèn)setup提供的屬性和方法, 但在setup方法中不能訪問(wèn)datamethods里的內(nèi)容,所以還是不建議混合使用。

        setup函數(shù)如果返回對(duì)象, 對(duì)象中的 屬性 或 方法 , 模板 中可以直接使用

        //templete
        <div>{{number}}</div>

        /
        /JS
        setup() {
          const number = 18;
          return {
            number,
          };
        },
        復(fù)制代碼

        注意:setup不能是一個(gè)async函數(shù): 因?yàn)榉祷刂挡辉偈?code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;outline: 0px;font-size: 14px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;border-radius: 4px;color: rgb(233, 105, 0);background-color: rgb(248, 248, 248);">return的對(duì)象, 而是promise, 模板中就不可以使用return中返回對(duì)象的數(shù)據(jù)了。

        setup的參數(shù)(props,context)`

        props: 是一個(gè)對(duì)象,里面有父級(jí)組件向子級(jí)組件傳遞的數(shù)據(jù),并且是在子級(jí)組件中使用props接收到的所有的屬性

        context:上下文對(duì)象,可以通過(guò)es6語(yǔ)法解構(gòu) setup(props, {attrs, slots, emit})

        • attrs: 獲取當(dāng)前組件標(biāo)簽上所有沒(méi)有通過(guò)props接收的屬性的對(duì)象, 相當(dāng)于 this.$attrs
        • slots: 包含所有傳入的插槽內(nèi)容的對(duì)象, 相當(dāng)于 this.$slots
        • emit: 用來(lái)分發(fā)自定義事件的函數(shù), 相當(dāng)于 this.$emit

        演示attrsprops

        //父組件
        <template>
          <child :msg="msg" msg2='哈哈哈' />
        </template>
        <script lang='ts'>
        import { defineComponent, ref } from 'vue';
        /
        / 引入子組件
        import Child from './
        components/Child.vue';
        export default defineComponent({
          name: '
        App',
          components: {
            Child,
          },
          setup() {
            const msg = ref('
        hello,vue3');
            return {
              msg,
            };
          },
        });
        </script>

        //子組件
        <template>
          <h2>子組件</h2>
          <h3>msg:{{ msg }}</h3>
        </template>

        <script lang='
        ts'>
        import { defineComponent } from '
        vue';
        export default defineComponent({
          name: '
        Child',
          props: ['
        msg'],
          setup(props, {attrs, slots, emit}) {
            console.log('
        props:', props);//msg: "hello,vue3"
            console.log('
        attrs:', attrs);//msg2: "哈哈哈"
            return {};
          },
        });
        </script>
        復(fù)制代碼

        演示emit

        //父組件
        <template>
          <child @show="show" />
        </template>

        <script lang='ts'>
          setup() {
            const show = () => {
              console.log('name:', 'hzw');
            };
            return {
              show,
            };
          },
        </
        script>

        //子組件
        <template>
          <button @click='emitFn'>事件分發(fā)</button>
        </template>

        <script lang='ts'>
        import { defineComponent } from 'vue';

        export default defineComponent({
          name'Child',
          setup(props, { emit }) {
            const emitFn = () => {
              emit('show');
            };
            return {
              emitFn,
            };
          },
        });
        </script>

        復(fù)制代碼

        ref

        作用

        定義一個(gè)響應(yīng)式的數(shù)據(jù)(一般用來(lái)定義一個(gè)基本類型的響應(yīng)式數(shù)據(jù)Undefined、Null、Boolean、NumberString)

        語(yǔ)法

        const xxx = ref(initValue):
        復(fù)制代碼

        注意script中操作數(shù)據(jù)需要使用xxx.value的形式,而模板中不需要添加.value

        用一個(gè)例子來(lái)演示:實(shí)現(xiàn)一個(gè)按鈕,點(diǎn)擊可以增加數(shù)字

        <template>
          <div>{{count}}</div>
          <button @click='updateCount'>增加</button>
        </template>
        復(fù)制代碼

        在Vue2中

        data() {
          return {
            conunt0,
          };
        },
        methods: {
          updateCount() {
            this.conunt++;
          },
        },
        復(fù)制代碼

        在Vue3中

         setup() {
            // ref用于定義一個(gè)響應(yīng)式的數(shù)據(jù),返回的是一個(gè)Ref對(duì)象,對(duì)象中有一個(gè)value屬性
            //如果需要對(duì)數(shù)據(jù)進(jìn)行操作,需要使用該Ref對(duì)象的value屬性
            const count = ref(0);
            function updateCount({
              count.value++;
            }
            return {
              count,
              updateCount,
            };
          },
        復(fù)制代碼

        Vue2中我們通過(guò)this.$refs來(lái)獲取dom節(jié)點(diǎn),Vue3中我們通過(guò)ref來(lái)獲取節(jié)點(diǎn)

        首先需要在標(biāo)簽上添加ref='xxx',然后再setup中定義一個(gè)初始值為nullref類型,名字要和標(biāo)簽的ref屬性一致

        const xxx = ref(null)
        復(fù)制代碼

        注意:一定要在setupreturn中返回,不然會(huì)報(bào)錯(cuò)。

        還是用一個(gè)例子來(lái)演示:讓輸入框自動(dòng)獲取焦點(diǎn)

        <template>
          <h2>App</h2>
          <input type="text">---
          <input type="text" ref="inputRef">
        </
        template>

        <script lang="ts">
        import { onMounted, ref } from 'vue'
        /* 
        ref獲取元素: 利用ref函數(shù)獲取組件中的標(biāo)簽元素
        功能需求: 讓輸入框自動(dòng)獲取焦點(diǎn)
        */

        export default {
          setup() {
            const inputRef = ref<HTMLElement|null>(null)

            onMounted(() => {
              inputRef.value && inputRef.value.focus()
            })

            return {
              inputRef
            }
          },
        }
        </script>
        復(fù)制代碼

        reactive

        語(yǔ)法

        const proxy = reactive(obj)
        復(fù)制代碼

        作用

        定義多個(gè)數(shù)據(jù)的響應(yīng)式,接收一個(gè)普通對(duì)象然后返回該普通對(duì)象的響應(yīng)式代理器對(duì)象(Proxy),響應(yīng)式轉(zhuǎn)換是“深層的”:會(huì)影響對(duì)象內(nèi)部所有嵌套的屬性,所有的數(shù)據(jù)都是響應(yīng)式的。

        代碼演示

        <template>
          <h3>姓名:{{user.name}}</h3>
          <h3>年齡:{{user.age}}</h3>
          <h3>wife:{{user.wife}}</h3>
          <button @click="updateUser">更新</button>
        </template>

         setup() {
            const user = reactive({
              name: 'hzw',
              age: 18,
              wife: {
                name: 'xioaohong',
                age: 18,
                books: ['紅寶書(shū)', '設(shè)計(jì)模式', '算法與數(shù)據(jù)結(jié)構(gòu)'],
              },
            });
            const updateUser = () => {
              user.name = '小紅';
              user.age += 2;
              user.wife.books[0] = '金瓶梅';
            };
            return {
              user,
              updateUser,
            };
          },
        復(fù)制代碼

        computed函數(shù):

        Vue2中的computed配置功能一致,返回的是一個(gè)ref類型的對(duì)象

        計(jì)算屬性的函數(shù)中如果只傳入一個(gè)回調(diào)函數(shù) 表示的是get操作

        import { computed } from 'vue';
        const user = reactive({
          firstName: '韓',
          lastName: '志偉',
        });
        const fullName1 = computed(() => {
          return user.firstName + user.lastName;
        });
        return {
          user,
          fullName1,
        };
        復(fù)制代碼

        計(jì)算屬性的函數(shù)中可以傳入一個(gè)對(duì)象,可以包含setget函數(shù),進(jìn)行讀取和修改的操作

        const fullName2 = computed({
          get() {
            return user.firstName + '_' + user.lastName;
          },
          set(val: string) {
            const names = val.split('_');
            user.firstName = names[0];
            user.lastName = names[1];
          },
        });
        return {
          user,
          fullName2,
        };
        復(fù)制代碼

        watch函數(shù):

        Vue2中的watch配置功能一致,

        • 參數(shù)1:要監(jiān)聽(tīng)的數(shù)據(jù)
        • 參數(shù)2:回調(diào)函數(shù)
        • 參數(shù)3:配置

        作用

        監(jiān)視指定的一個(gè)或多個(gè)響應(yīng)式數(shù)據(jù), 一旦數(shù)據(jù)變化, 就自動(dòng)執(zhí)行監(jiān)視回調(diào)

        默認(rèn)初始時(shí)不執(zhí)行回調(diào), 但可以通過(guò)配置immediatetrue, 來(lái)指定初始時(shí)立即執(zhí)行第一次

        通過(guò)配置deeptrue, 來(lái)指定深度監(jiān)視

        import { watch, ref } from 'vue';
        const user = reactive({
          firstName'韓',
          lastName'志偉',
        });
        const fullName3 = ref('');
        watch(
          user,
          ({ firstName, lastName }) => {
            fullName3.value = firstName + '_' + lastName;
          },
          { immediatetruedeeptrue }
        );
        return {
          user,
          fullName3,
        };
        復(fù)制代碼

        watch監(jiān)聽(tīng)多個(gè)數(shù)據(jù),使用數(shù)組

        watch監(jiān)聽(tīng)非響應(yīng)式數(shù)據(jù)的時(shí)候需要使用回調(diào)函數(shù)的形式

        watch([()=>user.firstName,()=>user.lastName,fullName3],()=>{console.log('我執(zhí)行了')})
        復(fù)制代碼

        watchEffect函數(shù):

        作用

        監(jiān)視數(shù)據(jù)發(fā)生變化時(shí)執(zhí)行回調(diào),不用直接指定要監(jiān)視的數(shù)據(jù), 回調(diào)函數(shù)中使用的哪些響應(yīng)式數(shù)據(jù)就監(jiān)視哪些響應(yīng)式數(shù)據(jù),默認(rèn)初始時(shí)就會(huì)執(zhí)行第一次, 從而可以收集需要監(jiān)視的數(shù)據(jù)。

        import { watchEffect, ref } from 'vue';
        const user = reactive({
          firstName'韓',
          lastName'志偉',
        });
        const fullName4 = ref('');
        watchEffect(() => {
          fullName4.value = user.firstName + '_' + user.lastName;
        });
        return {
          user,
          fullName4,
        };
        watchEffect可以實(shí)現(xiàn)計(jì)算屬性set方法
        watchEffect(() => {
            const names = fullName3.value.split('_');
            user.firstName = names[0];
            user.lastName = names[1];
        });
        復(fù)制代碼

        生命周期對(duì)比:

        微信截圖_20210623104108.png

        注意:3.0中的生命周期鉤子要比2.X中相同生命周期的鉤子要快

        Composition API還新增了以下調(diào)試鉤子函數(shù):但是不怎么常用

        • onRenderTracked
        • onRenderTriggered

        代碼演示

        setup() {

          onBeforeMount(() => {
            console.log('--onBeforeMount')
          })

          onMounted(() => {
            console.log('--onMounted')
          })

          onBeforeUpdate(() => {
            console.log('--onBeforeUpdate')
          })

          onUpdated(() => {
            console.log('--onUpdated')
          })

          onBeforeUnmount(() => {
            console.log('--onBeforeUnmount')
          })

          onUnmounted(() => {
            console.log('--onUnmounted')
          })
        }
        復(fù)制代碼

        toRefs

        作用

        把一個(gè)響應(yīng)式對(duì)象轉(zhuǎn)換成普通對(duì)象,該普通對(duì)象的每個(gè)屬性都是一個(gè) ref

        應(yīng)用

        我們使用reactive創(chuàng)建的對(duì)象,如果想在模板中使用,就必須得使用xxx.xxx的形式,如果大量用到的話還是很麻煩的,但是使用es6解構(gòu)以后,會(huì)失去響應(yīng)式,那么toRefs的作用就體現(xiàn)在這,,利用toRefs可以將一個(gè)響應(yīng)式 reactive 對(duì)象的所有原始屬性轉(zhuǎn)換為響應(yīng)式的ref屬性。當(dāng)然小伙伴們可以自行開(kāi)發(fā)更多應(yīng)用場(chǎng)景。

        代碼演示

        <template>
          <div>
            name:{{name}}
          </div>

        </template>

        <script lang='ts'>
        import { defineComponent, reactive, toRefs } from 'vue';

        export default defineComponent({
          name: '',
          setup() {
            const state = reactive({
              name: 'hzw',
            });
            const state2 = toRefs(state);
            setInterval(() => {
              state.name += '===';
            }, 1000);
            return {
              /
        /通過(guò)toRefs返回的對(duì)象,解構(gòu)出來(lái)的屬性也是響應(yīng)式的
              ...state2,
            };
          },
        });
        </
        script>
        復(fù)制代碼

        provide 與 inject

        作用

        實(shí)現(xiàn)跨層級(jí)組件(祖孫)間通信

        代碼演示

        父組件

        <template>
          <h1>父組件</h1>
          <p>當(dāng)前顏色: {{color}}</p>
          <button @click="color='red'"></button>
          <button @click="color='yellow'"></button>
          <button @click="color='blue'">藍(lán)</button>
          <hr>
          <Son />
        </template>

        <script lang="ts">
        import { provide, ref } from 'vue'
        import Son from './Son.vue'
        export default {
          name'ProvideInject',
          components: {
            Son
          },
          setup() {
            const color = ref('red')
            provide('color', color)
            return {
              color
            }
          }
        }
        </script>

        復(fù)制代碼

        子組件

        <template>
          <div>
            <h2>子組件</h2>
            <hr>
            <GrandSon />
          </div>
        </template>


        <script lang="ts">
        import GrandSon from './GrandSon.vue'
        export default {
          components: {
            GrandSon
          },
        }
        </script>

        復(fù)制代碼

        孫子組件

        <template>
          <h3 :style="{color}">孫子組件: {{color}}</h3>
        </template>

        <script lang="ts">
        import { inject } from 'vue'
        export default {
          setup() {
            const color = inject('color')
            return {
              color
            }
          }
        }
        </
        script>
        復(fù)制代碼

        其他特性

        Teleport(瞬移)

        作用

        Teleport 提供了一種干凈的方法, 讓組件的html在父組件界面外的特定標(biāo)簽(很可能是body)下插入顯示 換句話說(shuō)就是可以把 子組件 或者 dom節(jié)點(diǎn) 插入到任何你想插入到的地方去。

        語(yǔ)法

        使用to屬性 引號(hào)內(nèi)使用選擇器

          <teleport to="body">
          </teleport>
        復(fù)制代碼

        代碼演示

        //父組件

        <template>
          <div class="father">
            <h2>App</h2>
            <modal-button></modal-button>
          </div>

        </template>

        <script lang="ts">
        import ModalButton from './
        components/ModalButton.vue'
        export default {
          setup() {
            return {}
          },
          components: {
            ModalButton,
          },
        }
        </script>


        //子組件
        <template>
          <div class="son">
            <button @click="modalOpen = true">
              點(diǎn)我打開(kāi)對(duì)話框
            </button>

            <teleport to="body">
              <div v-if="modalOpen"
                   class="looklook">
                看看我出現(xiàn)在了哪里
                <button @click="modalOpen = false">
                  Close
                </button>
              </div>
            </teleport>
          </div>
        </template>

        <script>
        import { ref } from '
        vue'
        export default {
          name: '
        modal-button',
          setup() {
            const modalOpen = ref(false)
            return {
              modalOpen,
            }
          },
        }
        </script>
        復(fù)制代碼

        可以看到在子組件中的looklook元素跑到了body下面,而之前的位置默認(rèn)出現(xiàn)了兩行注釋

        微信截圖_20210623170701.png

        Suspense(不確定的)

        作用

        它們?cè)试S我們的應(yīng)用程序在等待異步組件時(shí)渲染一些后備內(nèi)容,可以讓我們創(chuàng)建一個(gè)平滑的用戶體驗(yàn)

        語(yǔ)法

         <Suspense>
            <template v-slot:default>
              <!-- 異步組件 -->
              <AsyncComp />
            </template>


            <template v-slot:fallback>
              <!-- 后備內(nèi)容 -->
              <h1>LOADING...</h1>
            </template>

          </Suspense>
        復(fù)制代碼

        vue3中引入異步組件的方式

        const AsyncComp = defineAsyncComponent(() => import('./AsyncComp.vue'))
        復(fù)制代碼

        代碼演示

        父組件

        <template>
          <Suspense>
             <!-- v-slot:defaul可以簡(jiǎn)寫(xiě)成#defaul -->
            <template v-slot:default>
              <AsyncComp/>
            </template>

            <template v-slot:fallback>
              <h1>LOADING...</h1>
            </template>
          </Suspense>

        </template>

        <script lang="ts">
        import { defineAsyncComponent } from 'vue'
        const AsyncComp = defineAsyncComponent(() => import('./
        AsyncComp.vue'))
        export default {
          setup() {
            return {
            }
          },

          components: {
            AsyncComp,
          }
        }
        </script>
        復(fù)制代碼

        子組件

        <template>
          <h2>AsyncComp22</h2>
          <p>{{msg}}</p>
        </template>

        <script lang="ts">
        export default {
          name: 'AsyncComp',
          setup () {
             return new Promise((resolve, reject) => {
               setTimeout(() => {
                 resolve({
                   msg: 'abc'
                 })
               }, 2000)
             })
          }
        }
        </
        script>

        復(fù)制代碼

        通過(guò)下圖可以看到在異步組件加載出來(lái)之前,顯示的是fallback中的內(nèi)容

        16.gif

        響應(yīng)式數(shù)據(jù)的判斷

        作用

        • isRef: 檢查一個(gè)值是否為一個(gè) ref 對(duì)象
        • isReactive: 檢查一個(gè)對(duì)象是否是由 reactive 創(chuàng)建的響應(yīng)式代理
        • isReadonly: 檢查一個(gè)對(duì)象是否是由 readonly 創(chuàng)建的只讀代理
        • isProxy: 檢查一個(gè)對(duì)象是否是由 reactive 或者 readonly 方法創(chuàng)建的代理

        代碼演示

        setup() {
            const state1 = ref(1);
            console.log('isref:', isRef(state1));//isref: true
            const state2 = reactive({});
            console.log('isReactive:', isReactive(state2));//isReactive: true
            const state3 = readonly({});
            console.log('isReadonly:', isReadonly(state3));//isReadonly: true
            const state4 = reactive({});
            console.log('isProxy:', isProxy(state2));//isProxy: true
            console.log('isProxy:', isProxy(state4));//isProxy: true
            return {};
          },
        復(fù)制代碼

        其他不常用特性

        還有很多很多不常用的新特性,我在日常開(kāi)發(fā)中是沒(méi)有用到的,很多都是用來(lái)做優(yōu)化的,感興趣的小伙伴們自行去官網(wǎng)查看,或者大佬們可以介紹一下應(yīng)用場(chǎng)景。

        • shallowReactive
        • shallowRef
        • readonly
        • shallowReadonly
        • markRaw
        • customRef
        • ...

        語(yǔ)法糖

        雖然Composition API用起來(lái)已經(jīng)非常方便了,但是我們還是有很煩的地方,比如

        • 組件引入了還要注冊(cè)
        • 屬性和方法都要在setup函數(shù)中返回,有的時(shí)候僅一個(gè)return就十幾行甚至幾十行
        • ...
        • 不想寫(xiě)啊怎么辦

        好辦,Vue3官方提供了script setup語(yǔ)法糖

        只需要在script標(biāo)簽中添加setup,組件只需引入不用注冊(cè),屬性和方法也不用返回,setup函數(shù)也不需要,甚至export default都不用寫(xiě)了,不僅是數(shù)據(jù),計(jì)算屬性和方法,甚至是自定義指令也可以在我們的template中自動(dòng)獲得。

        但是這么過(guò)癮的語(yǔ)法糖,還是稍微添加了一點(diǎn)點(diǎn)心智負(fù)擔(dān),因?yàn)闆](méi)有了setup函數(shù),那么props,emit,attrs怎么獲取呢,就要介紹一下新的語(yǔ)法了。

        setup script語(yǔ)法糖提供了三個(gè)新的API來(lái)供我們使用:defineProps、defineEmituseContext

        • defineProps 用來(lái)接收父組件傳來(lái)的值props。
        • defineEmit 用來(lái)聲明觸發(fā)的事件表。
        • useContext 用來(lái)獲取組件上下文context

        代碼演示

        父組件

        <template>
          <div>
            <h2>我是父組件!</h2>
            <Child msg="hello"
                   @child-click="handleClick" />

          </div>

        </template>

        <script setup>
        import Child from './
        components/Child.vue'

        const handleClick = (ctx) => {
          console.log(ctx)
        }
        </script>
        復(fù)制代碼

        子組件

        <template>
          <span @click="sonClick">msg: {{ props.msg }}</span>
        </template>

        <script setup>
        import { useContext, defineProps, defineEmit } from 'vue'

        const emit = defineEmit(['child-click'])
        const ctx = useContext()
        const props = defineProps({
          msg: String,
        })

        const sonClick = () => {
          emit('child-click', ctx)
        }
        </
        script>

        復(fù)制代碼

        我們點(diǎn)擊一下子組件可以看到context被打印了出來(lái),其中的attrsemit、slots、expose屬性和方法依然可以使用。props也可以輸出在頁(yè)面上,事件也成功派發(fā)。

        其他知識(shí)點(diǎn)

        接下來(lái)介紹一下我使用Vue3過(guò)程中遇到的問(wèn)題或者小技巧,不全面,想起什么就寫(xiě)什么吧

        script setup語(yǔ)法糖請(qǐng)注意

        如果在父組件中通過(guò)ref='xxx'的方法來(lái)獲取子組件實(shí)例,子組件使用了script setup語(yǔ)法糖,那么子組件的數(shù)據(jù)需要用expose的方式導(dǎo)出,否則會(huì)因?yàn)楂@取不到數(shù)據(jù)而報(bào)錯(cuò)。

        代碼演示

        父組件

        <template>
          <div>
            <h2>我是父組件!</h2>
            <Child ref='son' />
          </div>

        </template>

        <script setup>
        import Child from './
        components/Child.vue'
        import { ref } from '
        vue'
        const son = ref(null)
        console.log('
        ????~ son:', son)
        </script>
        復(fù)制代碼

        子組件先不使用語(yǔ)法糖

        <template>
          <div>
            我是子組件{{msg}}
          </div>

        </template>

        <script >
        import { ref } from 'vue'

        export default {
          setup() {
            const msg = ref('hello')
            return {
              msg,
            }
          },
        }
        復(fù)制代碼

        可以看到是可以獲取到我們?cè)谧咏M件中定義的msg屬性的

        現(xiàn)在把子組件換成script setup語(yǔ)法糖再來(lái)試一試

        <template>
          <div>
            我是子組件{{msg}}
          </div>

        </template>

        <script setup>
        import { ref } from 'vue'
        const msg = ref('hello')
        </
        script>

        復(fù)制代碼

        可以看到現(xiàn)在是獲取不到子組件定義的msg屬性的

        image.png

        我們可以看看尤大大怎么說(shuō)

        image.png

        補(bǔ)充自評(píng)論區(qū) 用戶2150817567886 setup語(yǔ)法糖定義的組件默認(rèn)情況下是不對(duì)外開(kāi)發(fā)內(nèi)部調(diào)用的,它需要用expose()函數(shù)來(lái)定義哪些數(shù)據(jù)允許對(duì)外開(kāi)放,具體內(nèi)容參考[1]

        Emit派發(fā)事件可以對(duì)參數(shù)進(jìn)行驗(yàn)證

        父組件

        <template>
          <div>
            <h2>我是父組件!</h2>
            <Child @sonClick='sonClick' />
          </div>

        </template>

        <script setup>
        import Child from './
        components/Child.vue'
        import { ref } from '
        vue'
        const sonClick = (value) => {
          console.log(value)
        }
        </script>
        復(fù)制代碼

        子組件



        <template>
          <div>
            我是子組件{{ msg }}
          </div>

          <button @click="handleClick(1)">我是按鈕1</button>
          <button @click="handleClick(2)">我是按鈕2</button>
        </template>

        <script>
        import { ref } from 'vue'
        export default {
          name: '',
          emits: {
            sonClick: (value) => {
              if (value === 1) {
                return true
              } else {
                return false
              }
            },
          },
          setup(props, { emit }) {
            const msg = ref('hello')
            const handleClick = (value) => {
              emit('sonClick', value)
            }
            return {
              msg,
              handleClick,
            }
          },
        }
        </
        script>
        復(fù)制代碼

        我們分別點(diǎn)一下按鈕1和按鈕2,可以看到當(dāng)我們點(diǎn)了按鈕2的時(shí)候,控制臺(tái)會(huì)發(fā)出警告,但是程序會(huì)繼續(xù)執(zhí)行,還沒(méi)想到什么適合的應(yīng)用場(chǎng)景,但是要知道這個(gè)知識(shí)點(diǎn),小伙伴們可以在這搞事情。

        image.png

        跨組件通訊mitt.js

        Vue2中怎么實(shí)現(xiàn)跨組件通訊呢,很多人第一想法就是event bus。但是Vue3移除了$on,$once,$off導(dǎo)致不能使用這個(gè)方法。但是Vue官方給大家推薦了mitt.js,它的原理就是event bus。

        代碼演示

        先安裝

        npm i mitt -s
        復(fù)制代碼

        然后封裝一個(gè)hook

        //mitt.js
        import mitt from 'mitt'
        const emitter = mitt();

        export default emitter;
        復(fù)制代碼

        父組件

        <template>
          <div>
            <h2>我是父組件!</h2>
            <Child1 />
            <Child2 />

          </div>

        </template>

        <script setup>
        import Child1 from './
        components/Child1.vue'
        import Child2 from '
        ./components/Child2.vue'
        </script>
        復(fù)制代碼

        子組件1

        <template>
          <div>
            我是子組件1
            <h1>{{msg}}</h1>
          </div>

        </template>

        <script>
        import { ref, onUnmounted } from 'vue'
        import emitter from '../mi
        tt'
        export default {
          name: '
        ',

          setup() {
            //初始化
            const msg = ref('
        hello')
            const changeMsg = () => {
              msg.value = '
        world'
            }
            // 監(jiān)聽(tīng)事件,更新數(shù)據(jù)
            emitter.on('
        change-msg', changeMsg)
            // 顯式卸載
            onUnmounted(() => {
              emitter.off('
        change-msg', changeMsg)
            })
            return {
              msg,
              changeMsg,
            }
          },
        }
        </script>
        復(fù)制代碼

        子組件2

        <template>
          <div>
            我是子組件2
          </div>

          <button @click='changeMsg'>點(diǎn)擊修改msg</button>
        </template>

        <script>
        import { ref } from 'vue'
        import emitter from '../mi
        tt'

        export default {
          name: '
        ',

          setup() {
            const changeMsg = () => {
              emitter.emit('
        change-msg')
            }
            return {
              changeMsg,
            }
          },
        }
        </script>
        復(fù)制代碼

        演示

        1.gif

        自定義指令

        先看看Vue2自定義指令的鉤子

        • bind:當(dāng)指令綁定在對(duì)應(yīng)元素時(shí)觸發(fā)。只會(huì)觸發(fā)一次。
        • inserted:當(dāng)對(duì)應(yīng)元素被插入到 DOM 的父元素時(shí)觸發(fā)。
        • update:當(dāng)元素更新時(shí),這個(gè)鉤子會(huì)被觸發(fā)(此時(shí)元素的后代元素還沒(méi)有觸發(fā)更新)。
        • componentUpdated:當(dāng)整個(gè)組件(包括子組件)完成更新后,這個(gè)鉤子觸發(fā)。
        • unbind:當(dāng)指令被從元素上移除時(shí),這個(gè)鉤子會(huì)被觸發(fā)。也只觸發(fā)一次。

        在 Vue3 中,官方為了更有助于代碼的可讀性和風(fēng)格統(tǒng)一,把自定義指令的鉤子名稱改的更像是組件生命周期,盡管他們是兩回事

        • bind => beforeMount
        • inserted => mounted
        • beforeUpdate新的鉤子,會(huì)在元素自身更新前觸發(fā)
        • update => 移除!
        • componentUpdated => updated
        • beforeUnmount新的鉤子,當(dāng)元素自身被卸載前觸發(fā)
        • unbind => unmounted

        過(guò)渡動(dòng)畫(huà)

        這個(gè)沒(méi)有什么大的改動(dòng),只是修改了兩個(gè)class名字,正是因?yàn)闆](méi)有什么大的改動(dòng),導(dǎo)致我曾經(jīng)在這里栽了大跟頭,寫(xiě)完了怎么都不對(duì),后來(lái)查官網(wǎng)才知道。

        以下是直接引用 官網(wǎng)的原文

        • v-enter-from:定義進(jìn)入過(guò)渡的開(kāi)始狀態(tài)。在元素被插入之前生效,在元素被插入之后的下一幀移除。

        • v-enter-active:定義進(jìn)入過(guò)渡生效時(shí)的狀態(tài)。在整個(gè)進(jìn)入過(guò)渡的階段中應(yīng)用,在元素被插入之前生效,在過(guò)渡/動(dòng)畫(huà)完成之后移除。這個(gè)類可以被用來(lái)定義進(jìn)入過(guò)渡的過(guò)程時(shí)間,延遲和曲線函數(shù)。

        • v-enter-to:定義進(jìn)入過(guò)渡的結(jié)束狀態(tài)。在元素被插入之后下一幀生效 (與此同時(shí) v-enter-from 被移除),在過(guò)渡/動(dòng)畫(huà)完成之后移除。

        • v-leave-from:定義離開(kāi)過(guò)渡的開(kāi)始狀態(tài)。在離開(kāi)過(guò)渡被觸發(fā)時(shí)立刻生效,下一幀被移除。

        • v-leave-active:定義離開(kāi)過(guò)渡生效時(shí)的狀態(tài)。在整個(gè)離開(kāi)過(guò)渡的階段中應(yīng)用,在離開(kāi)過(guò)渡被觸發(fā)時(shí)立刻生效,在過(guò)渡/動(dòng)畫(huà)完成之后移除。這個(gè)類可以被用來(lái)定義離開(kāi)過(guò)渡的過(guò)程時(shí)間,延遲和曲線函數(shù)。

        • v-leave-to:離開(kāi)過(guò)渡的結(jié)束狀態(tài)。在離開(kāi)過(guò)渡被觸發(fā)之后下一幀生效 (與此同時(shí) v-leave-from 被刪除),在過(guò)渡/動(dòng)畫(huà)完成之后移除。

        特別注意的是v-enter改成了v-enter-form,v-leave改成了v-leave-from

        其他小知識(shí)

        Vue3移除了filter

        獲取組件實(shí)例方法getCurrentInstance()

        這個(gè)方法可以獲取到當(dāng)前組件的實(shí)例,相當(dāng)于Vue2中的this最后,畢竟是個(gè)人總結(jié),難免會(huì)出現(xiàn)紕漏和錯(cuò)誤,期待各路大神的補(bǔ)充和糾正。

        我的開(kāi)源項(xiàng)目:

        https://juejin.cn/post/6963945204965441550"

        參考資料

        [1]

        https://github.com/vuejs/rfcs/pull/210


        作者:一尾流鶯

        https://juejin.cn/post/6977004323742220319

        Node 社群


        我組建了一個(gè)氛圍特別好的 Node.js 社群,里面有很多 Node.js小伙伴,如果你對(duì)Node.js學(xué)習(xí)感興趣的話(后續(xù)有計(jì)劃也可以),我們可以一起進(jìn)行Node.js相關(guān)的交流、學(xué)習(xí)、共建。下方加 考拉 好友回復(fù)「Node」即可。


           “分享、點(diǎn)贊、在看” 支持一波??

        瀏覽 91
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            一本大道久久a久久精品综合1 | 三级片久久 | 波多野结衣高清视频 | 午夜激情91 | 日本护士多人吞精囗交视频 | 狼人久久| 操逼视频免费观看网站 | 日日干天天干 | 久久人人爽人人爽人人片亞洲 | 妹子色综合|