初識vue3

1. 新建項目

vue create vue-study

2. 運行

yarn serve

語法

1. setup函數(shù)

可以取代data和method,相較于vue2,如果需要在template中使用的話,setup函數(shù)需要return。不需要再界面上暴露的變量就不需要return,精確控制導出的變量和方法

```javaScript
setup() {
    const girls = ref(["大腳", "劉英", "曉紅"]);
    const selectGirl = ref("");
    // 使用ref,在script中使用/獲取變量值需要加上value
    const selectGirlFun = (index: number) => {
        selectGirl.value = girls.value[index];
    };
    //因為在模板中這些變量和方法都需要調(diào)用,所以需要return出去。
    return {
        girls,
        selectGirl,
        selectGirlFun,
    };
}
```

2. ref函數(shù)

使用的話,需要引入`import { ref } from "vue";`,然后`ref(["大腳", "劉英", "曉紅"])`

ref函數(shù)接收一個內(nèi)部值,返回一個可響應且可變的對象,**在setup中,使用ref,要改變和讀取一個值的時候,還要加上value**

3. reactive函數(shù)

是一個接收Object(對象)參數(shù)的函數(shù),用于優(yōu)化上述使用ref函數(shù)之后,改變和讀取變量需要加上value的情況

和ref()函數(shù)一樣,都是生成響應式對象的方法
```HTML
<button
    v-for="(item, index) in data.girls"
    v-bind:key="index"
    @click="data.selectGirlFun(index)"
    >
    {{ index }} : {{ item }}
</button>
<!-- 需要加上data.來調(diào)用 -->
<div>你選擇了【{{ data.selectGirl }}】為你服務</div>
```

```JavaScript
// 記得加上類型注解
interface DataProps {
    girls: string[];
    selectGirl: string;
    selectGirlFun: (index: number) => void;
}

const data: DataProps = reactive({
    girls: ["大腳", "劉英", "曉紅"],
    selectGirl: '',
    selectGirlFun: (index: number) => {
        // 修改值不需要加value了
        data.selectGirl = data.girls[index]
    }
});

// 只需要返回一個data
return {
    data,
};
```

4. toRefs()函數(shù)

使用reactive函數(shù)后,現(xiàn)在template中,每次輸出變量前面都要加一個data,可以使用toRefs來優(yōu)化

Vue3 的一個新函數(shù)toRefs(),引入后就可以對data進行包裝,把 data 變成refData,這樣就可以使用擴展運算符的方式了,否則直接使用擴展運算符會導致變量不可響應
```HTML
<button
  v-for="(item, index) in girls"
  v-bind:key="index"
  @click="selectGirlFun(index)"
>
  {{ index }} : {{ item }}
</button>
<div>你選擇了【{{ selectGirl }}】為你服務</div>
```

```JavaScript
setup() {
    // const girls = ref(["大腳", "劉英", "曉紅"]);
    // const selectGirl = ref("");
    // const selectGirlFun = (index: number) => {
    //   selectGirl.value = girls.value[index];
    // };
    const data: DataProps = reactive({
        girls: ["大腳", "劉英", "曉紅"],
        selectGirl: "",
        selectGirlFun: (index: number) => {
            data.selectGirl = data.girls[index];
        },
    });
    const refData = toRefs(data);

    return {
        ...refData,
    };
},
```

5. 生命周期

1. setup函數(shù) -> 開始創(chuàng)建組件之前,在`beforeCreate`和`created`之前,創(chuàng)建的是data和method。

可以使用setup函數(shù)來代替beforeCreatecreated
2. onBeforeMount -> 組件掛載到節(jié)點之前
3. onMounted -> 組件掛載到節(jié)點之后
4. onBeforeUpdate => 組件更新之前
5. onUpdated -> 組件更新之后
6. onBeforeUnmount -> 組件卸載之前
7. onUnmounted -> 組件卸載之后
8. onActivated -> 激活<keep-alive>組件時
9. onDeactivated -> 離開<keep-alive>組件時
10. onErrorCaptured -> 當捕獲一個來自子孫組件的異常時激活鉤子函數(shù)

在使用鉤子函數(shù)之前,需要引入
```JavaScript
import {
    reactive,
    toRefs,
    onMounted,
    onBeforeMount,
    onBeforeUpdate,
    onUpdated,
} from "vue";

// 注意:vue3的這些鉤子函數(shù)寫在setup函數(shù)里面
setup() {
    console.log("1-開始創(chuàng)建組件-----setup()");
    const data: DataProps = reactive({
    girls: ["大腳", "劉英", "曉紅"],
    selectGirl: "",
    selectGirlFun: (index: number) => {
        data.selectGirl = data.girls[index];
    },
    });
    onBeforeMount(() => {
        console.log("2-組件掛載到頁面之前執(zhí)行-----onBeforeMount()");
    });

    onMounted(() => {
        console.log("3-組件掛載到頁面之后執(zhí)行-----onMounted()");
    });
    onBeforeUpdate(() => {
        console.log("4-組件更新之前-----onBeforeUpdate()");
    });

    onUpdated(() => {
    c   onsole.log("5-組件更新之后-----onUpdated()");
    });

    const refData = toRefs(data);

    return {
    ...refData,
    };
},
```

Vue2的生命周期函數(shù)依然可以使用,可以寫在setup函數(shù)后面
```JavaScript
setup() {
    ...
}
beforeCreate() {
    console.log("1-組件創(chuàng)建之前-----beforeCreate()");
},
beforeMount() {
    console.log("2-組件掛載到頁面之前執(zhí)行-----BeforeMount()");
},
mounted() {
    console.log("3-組件掛載到頁面之后執(zhí)行-----Mounted()");
},
beforeUpdate() {
    console.log("4-組件更新之前-----BeforeUpdate()");
},
updated() {
    console.log("5-組件更新之后-----Updated()");
},


// 以下是兩個版本生命周期的對比
// 除了beforeDestroy -> onBeforeUnmount、destroyed -> onUnmounted,其他只是加了on
Vue2--------------vue3
beforeCreate  -> setup()
created       -> setup()
beforeMount   -> onBeforeMount
mounted       -> onMounted
beforeUpdate  -> onBeforeUpdate
updated       -> onUpdated
beforeDestroy -> onBeforeUnmount
destroyed     -> onUnmounted
activated     -> onActivated
deactivated   -> onDeactivated
errorCaptured -> onErrorCaptured
````

6. onRenderTracked()和onRenderTrigger()函數(shù)

用來調(diào)試使用的兩個鉤子函數(shù)。使用前需要引入
`import { onRenderTriggered ,onRenderTracked,} from "vue";`

onRenderTracked函數(shù)——狀態(tài)追蹤

它會追蹤頁面上**所有**響應式變量和方法的狀態(tài),即我們在setup中return出去的值,一旦頁面有更新,他都會進行追蹤,然后生成一個event對象,我們通過event對象來查找程序的問題所在

onRenderTriggered函數(shù)——狀態(tài)觸發(fā)

它不像onRenderTracked函數(shù),這個函數(shù)不會跟蹤所有值的變化,而是給你變化值的信息,并且新值和舊值都會給你明確的展示出來

```JavaScript
onRenderTracked((event) => {
    console.log("狀態(tài)跟蹤組件----------->");
    console.log(event);
});

onRenderTriggered((event) => {
    console.log("狀態(tài)跟蹤組件----------->");
    console.log(event);
});
```

其中`event`對象屬性:
```
- key 那邊變量發(fā)生了變化
- newValue 更新后變量的值
- oldValue 更新前變量的值
- target 目前頁面中的響應變量和函數(shù)
```

7. watch函數(shù)

使用之前需要先導入 `import {... , watch} from "vue"`

以下是監(jiān)聽一個數(shù)和多個數(shù)的使用方式
```JavaScript
watch(overText, (newValue, oldValue) => {
    document.title = newValue;
});

// 注意:
// 當我們想監(jiān)聽data.selectGirl這個reactive里邊的值時,可以使用一個函數(shù)來解決,() => data.selectGirl
// 監(jiān)聽多個數(shù)的變化,返回的newValue也是一個數(shù)組
watch([overText, () => data.selectGirl], (newValue, oldValue) => {
    console.log(`new--->${newValue}`);
    console.log(`old--->${oldValue}`);
    document.title = newValue[0]; // 返回的newValue也是一個數(shù)組
});
```

8. Vue3模塊化

如果需要將一個功能進行模塊化和復用化,可以在src目錄下,新建一個文件夾hooks(所有抽離出來的功能模塊都可以放到這個文件夾里),然后再新建一個文件useNowTime.ts,這里使用use開頭是一個使用習慣,代表是一個抽離出來的模塊。

```JavaScript
// 注意需要引入ref
import { ref } from "vue";

const nowTime = ref("00:00:00");
const getNowTime = () => {
    const now = new Date();
    const hour = now.getHours() < 10 ? "0" + now.getHours() : now.getHours();
    const minu =
        now.getMinutes() < 10 ? "0" + now.getMinutes() : now.getMinutes();
    const sec =
        now.getSeconds() < 10 ? "0" + now.getSeconds() : now.getSeconds();
    nowTime.value = hour + ":" + minu + ":" + sec;

    setTimeout(getNowTime, 1000);
};

// 最后export
export { nowTime, getNowTime }

// 引入和使用
import { nowTime, getNowTime } from "./hooks/useNowTime";
// 注意: 需要在setup中return,才可以在template中使用
setup() {
    return {nowTime,getNowTime};
}

```

遠程調(diào)用API組件也可以這樣子封裝

9. Teleport瞬間移動組件的使用

它可以把你寫的組件掛載到任何你想掛載的DOM上,在vue2中,所有dom都是掛載在#app下的,如果想改變節(jié)點這是非常的困難的。vue3的Teleport組件可以幫助解決這個問題。

Teleport方法,可以把Dialog組件渲染到你任意想渲染的外部Dom上,不必嵌套再#app里了,這樣就不會互相干擾了??梢园裈eleport看成一個傳送門,把你的組件傳送到你需要的地方。 teleport組件和其它組件沒有任何其它的差異,用起來都是一樣的。

使用方法如下:
```JavaScript
// Model.vue,自定義組件
// 將編寫的組件用<teleport>標簽進行包裹,在組件上有一個to屬性,這個就是要寫你需要渲染的DOMID了。
<template>
    <teleport to="#modal">
        <div id="center">
        <h2>JSPang11</h2>
        </div>
    </teleport>
</template>

// /public/index.html,在其中增加一個#model節(jié)點
<div id="app"></div>
<div id="modal"></div>

// App.vue,正常使用即可
<Modal></Modal>
```
這時候在瀏覽器中預覽,就會發(fā)現(xiàn),現(xiàn)在組件已經(jīng)掛載到model節(jié)點上了,這就是teleport組件的使用了。

10. 初識Suspense組件

在Vue2.x時代,判斷異步請求的狀態(tài)是一件必須的事情,但是這些狀態(tài)都要自己處理,根據(jù)請求是否完畢展示不同的界面,Vue3提供了Suspense組件來解決異步請求,頁面渲染的問題

Suspense提供兩個template的位置,一個是沒有請求回來時顯示的內(nèi)容,一個是全部請求完畢的內(nèi)容。這樣進行異步內(nèi)容的渲染就會非常簡單。

**注意點:如果你要使用Suspense的話,要返回一個promise對象,而不是原來的那種JSON對象。**

以下為使用辦法:
```JavaScript
// AsyncShow.vue,異步請求組件
// 2s之后頁面出現(xiàn)JSPang文字
<template>
    <h1>{{ result }}</h1>
</template>
<script lang="ts">
    import { defineComponent } from "vue";
    // defineComponent是用來解決TypeScript情況下,傳統(tǒng)的Vue.extends無法對組件給出正確的參數(shù)類型推斷的。也就是說在TypeScript環(huán)境中如果參數(shù)類型推斷不正常時,用defineComponent()組件來進行包裝函數(shù)。
    export default defineComponent({
        setup() {
            return new Promise((resolve, reject) => {
                setTimeout(() => {
                    return resolve({ result: "JSPang" });
                }, 2000);
            });
        },
    });
</script>

// App.vue
// 可以看到Suspense是有兩個template插槽的,第一個default代表異步請求完成后,顯示的模板內(nèi)容。fallback代表在加載中時,顯示的模板內(nèi)容。
<template>
    <div>
        <Suspense>
            <template #default>
                <AsyncShow />
            </template>
            <template #fallback>
                <h1>Loading...</h1>
            </template>
        </Suspense>
    </div>
</template>
```

運行之后,如果一切正常,你可以看到,當我們打開頁面時,首先顯示的是Loading,然后才會顯示JSPang。也就是promise返回的結果


- 在編寫異步請求組件的時候,還可以通過 `async...await`的寫法,它是`promise`的語法糖
```JavaScript
// AsyncShow.vue,異步請求組件
export default defineComponent({
    async setup() {  //promise 語法糖  返回之后也是promise對象
        const rawData = await  axios.get('https://apiblog.jspang.com/default/getGirl')
        return {result:rawData.data}
    }
})

```

Suspense組件加載多個異步組件的場景:

```JavaScript
<Suspense>
    <template #default>
        // 警告:是一個實驗性的特性,它的API很可能會改變slots,除非只有一個根節(jié)點
        // 直接在Suspense組件下寫兩個異步組件會導致頁面不顯示
        <AsyncShow></AsyncShow>
        <AsyncShow2></AsyncShow2>
    </template>
    <template #fallback>
        <div>
        Loading... ---- 異步加載中
        </div>
    </template>
</Suspense>

// 解決辦法
  <template #default>
    // 使用一個根節(jié)點包裹住,擴展一下,在<transition-group>組件中也是可以這樣子解決
    <div>
        <AsyncShow></AsyncShow>
        <AsyncShow2></AsyncShow2>
    </div>
</template>
```

11. 處理異步請求錯誤

在異步請求中必須要作的一件事情,就是要捕獲錯誤,因為我們沒辦法后端給我們返回的結果,也有可能服務不通,所以一定要進行捕獲異常和進行處理。

在vue3.x的版本中,可以使用onErrorCaptured這個鉤子函數(shù)來捕獲異常。在使用這個鉤子函數(shù)前,需要先進行引入
import { onErrorCaptured} from "vue";

有了onErrorCaptured就可以直接在setup()函數(shù)中直接使用了。鉤子函數(shù)要求我們返回一個布爾值,代表錯誤是否向上傳遞,我們這里返回了true。

const app = {
  name: "App",
  components: { AsyncShow, GirlShow },
  setup() {
    onErrorCaptured((error) => {
      console.log(`error====>`,error)
      return true  
    })
    return {};
  },
};

參考

技術胖的vue3教程

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容