<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 知識點

          共 33308字,需瀏覽 67分鐘

           ·

          2021-09-27 15:00



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

          點擊上方 程序員成長指北,關(guān)注公眾號

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


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

          先推薦兩個vscode插件

          Volar

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

          特色功能

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

          多個根節(jié)點編輯器不會報錯

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

          image.png

          編輯器分隔

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

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

          image.png

          它就會自動給你分隔成三個頁面,分別對應(yīng)templatescriptstyle,這樣就太舒服了有沒有。

          image.png

          Vue 3 Snippets

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

          image.png

          然后它就給自動給我們寫了如下代碼

          image.png

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

          創(chuàng)建Vue3項目

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

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

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

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

          使用 Vite 創(chuàng)建

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

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

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

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

          然后看看根組件app.vue

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


          <script lang="ts">
          // 這里可以書寫TS代碼

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

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

          復(fù)制代碼

          Composition API

          接下來到了重頭戲,Vue3的招牌特性,Composition API

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

          那個忙了一夜的Vue3動畫很好,就是太短了

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

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

          setup

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

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

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

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

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

          由此可以推斷出setup執(zhí)行的時候,組件對象還沒有創(chuàng)建,組件實例對象this還不可用,此時thisundefined, 不能通過this來訪問data/computed/methods/props

          返回對象中的屬性會與data函數(shù)返回對象的屬性合并成為組件對象的屬性,返回對象中的方法會與methods中的方法合并成功組件對象的方法,如果有重名, setup優(yōu)先。因為在setupthis不可用,methods中可以訪問setup提供的屬性和方法, 但在setup方法中不能訪問datamethods里的內(nèi)容,所以還是不建議混合使用。

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

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

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

          注意:setup不能是一個async函數(shù): 因為返回值不再是return的對象, 而是promise, 模板中就不可以使用return中返回對象的數(shù)據(jù)了。

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

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

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

          • attrs: 獲取當(dāng)前組件標(biāo)簽上所有沒有通過props接收的屬性的對象, 相當(dāng)于 this.$attrs
          • slots: 包含所有傳入的插槽內(nèi)容的對象, 相當(dāng)于 this.$slots
          • emit: 用來分發(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

          作用

          定義一個響應(yīng)式的數(shù)據(jù)(一般用來定義一個基本類型的響應(yīng)式數(shù)據(jù)UndefinedNullBooleanNumberString)

          語法

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

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

          用一個例子來演示:實現(xiàn)一個按鈕,點擊可以增加數(shù)字

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

          在Vue2中

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

          在Vue3中

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

          Vue2中我們通過this.$refs來獲取dom節(jié)點,Vue3中我們通過ref來獲取節(jié)點

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

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

          注意:一定要在setupreturn中返回,不然會報錯。

          還是用一個例子來演示:讓輸入框自動獲取焦點

          <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)簽元素
          功能需求: 讓輸入框自動獲取焦點
          */

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

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

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

          reactive

          語法

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

          作用

          定義多個數(shù)據(jù)的響應(yīng)式,接收一個普通對象然后返回該普通對象的響應(yīng)式代理器對象(Proxy),響應(yīng)式轉(zhuǎn)換是“深層的”:會影響對象內(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ù)結(jié)構(gòu)'],
                },
              });
              const updateUser = () => {
                user.name = '小紅';
                user.age += 2;
                user.wife.books[0] = '金瓶梅';
              };
              return {
                user,
                updateUser,
              };
            },
          復(fù)制代碼

          computed函數(shù):

          Vue2中的computed配置功能一致,返回的是一個ref類型的對象

          計算屬性的函數(shù)中如果只傳入一個回調(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ù)制代碼

          計算屬性的函數(shù)中可以傳入一個對象,可以包含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)聽的數(shù)據(jù)
          • 參數(shù)2:回調(diào)函數(shù)
          • 參數(shù)3:配置

          作用

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

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

          通過配置deeptrue, 來指定深度監(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)聽多個數(shù)據(jù),使用數(shù)組

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

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

          watchEffect函數(shù):

          作用

          監(jiān)視數(shù)據(jù)發(fā)生變化時執(zhí)行回調(diào),不用直接指定要監(jiān)視的數(shù)據(jù), 回調(diào)函數(shù)中使用的哪些響應(yīng)式數(shù)據(jù)就監(jiān)視哪些響應(yīng)式數(shù)據(jù),默認(rèn)初始時就會執(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可以實現(xiàn)計算屬性set方法
          watchEffect(() => {
              const names = fullName3.value.split('_');
              user.firstName = names[0];
              user.lastName = names[1];
          });
          復(fù)制代碼

          生命周期對比:

          微信截圖_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

          作用

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

          應(yīng)用

          我們使用reactive創(chuàng)建的對象,如果想在模板中使用,就必須得使用xxx.xxx的形式,如果大量用到的話還是很麻煩的,但是使用es6解構(gòu)以后,會失去響應(yīng)式,那么toRefs的作用就體現(xiàn)在這,,利用toRefs可以將一個響應(yīng)式 reactive 對象的所有原始屬性轉(zhuǎn)換為響應(yīng)式的ref屬性。當(dāng)然小伙伴們可以自行開發(fā)更多應(yī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 {
                /
          /通過toRefs返回的對象,解構(gòu)出來的屬性也是響應(yīng)式的
                ...state2,
              };
            },
          });
          </
          script>
          復(fù)制代碼

          provide 與 inject

          作用

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

          代碼演示

          父組件

          <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)下插入顯示 換句話說就是可以把 子組件 或者 dom節(jié)點 插入到任何你想插入到的地方去。

          語法

          使用to屬性 引號內(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">
                點我打開對話框
              </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(不確定的)

          作用

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

          語法

           <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可以簡寫成#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ù)制代碼

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

          16.gif

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

          作用

          • isRef: 檢查一個值是否為一個 ref 對象
          • isReactive: 檢查一個對象是否是由 reactive 創(chuàng)建的響應(yīng)式代理
          • isReadonly: 檢查一個對象是否是由 readonly 創(chuàng)建的只讀代理
          • isProxy: 檢查一個對象是否是由 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ù)制代碼

          其他不常用特性

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

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

          語法糖

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

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

          好辦,Vue3官方提供了script setup語法糖

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

          但是這么過癮的語法糖,還是稍微添加了一點點心智負(fù)擔(dān),因為沒有了setup函數(shù),那么propsemitattrs怎么獲取呢,就要介紹一下新的語法了。

          setup script語法糖提供了三個新的API來供我們使用:definePropsdefineEmituseContext

          • defineProps 用來接收父組件傳來的值props
          • defineEmit 用來聲明觸發(fā)的事件表。
          • useContext 用來獲取組件上下文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ù)制代碼

          我們點擊一下子組件可以看到context被打印了出來,其中的attrsemitslotsexpose屬性和方法依然可以使用。props也可以輸出在頁面上,事件也成功派發(fā)。

          其他知識點

          接下來介紹一下我使用Vue3過程中遇到的問題或者小技巧,不全面,想起什么就寫什么吧

          script setup語法糖請注意

          如果在父組件中通過ref='xxx'的方法來獲取子組件實例,子組件使用了script setup語法糖,那么子組件的數(shù)據(jù)需要用expose的方式導(dǎo)出,否則會因為獲取不到數(shù)據(jù)而報錯。

          代碼演示

          父組件

          <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ù)制代碼

          子組件先不使用語法糖

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

          </template>

          <script >
          import { ref } from 'vue'

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

          可以看到是可以獲取到我們在子組件中定義的msg屬性的

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

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

          </template>

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

          復(fù)制代碼

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

          image.png

          我們可以看看尤大大怎么說

          image.png

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

          Emit派發(fā)事件可以對參數(shù)進(jì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ù)制代碼

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

          image.png

          跨組件通訊mitt.js

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

          代碼演示

          先安裝

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

          然后封裝一個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)聽事件,更新數(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'>點擊修改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)指令綁定在對應(yīng)元素時觸發(fā)。只會觸發(fā)一次。
          • inserted:當(dāng)對應(yīng)元素被插入到 DOM 的父元素時觸發(fā)。
          • update:當(dāng)元素更新時,這個鉤子會被觸發(fā)(此時元素的后代元素還沒有觸發(fā)更新)。
          • componentUpdated:當(dāng)整個組件(包括子組件)完成更新后,這個鉤子觸發(fā)。
          • unbind:當(dāng)指令被從元素上移除時,這個鉤子會被觸發(fā)。也只觸發(fā)一次。

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

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

          過渡動畫

          這個沒有什么大的改動,只是修改了兩個class名字,正是因為沒有什么大的改動,導(dǎo)致我曾經(jīng)在這里栽了大跟頭,寫完了怎么都不對,后來查官網(wǎng)才知道。

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

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

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

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

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

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

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

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

          其他小知識

          Vue3移除了filter

          獲取組件實例方法getCurrentInstance()

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

          我的開源項目:

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

          參考資料

          [1]

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


          作者:一尾流鶯

          https://juejin.cn/post/6977004323742220319

          Node 社群


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


             “分享、點贊在看” 支持一波??

          瀏覽 91
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

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

          手機(jī)掃一掃分享

          分享
          舉報
          <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>
                  福利视频免费看 | 欧美日本在线播放 | 91精品人妻无码 | 免费a级黄片 | www.俺去 |