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ù)來代替beforeCreate和created
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 {};
},
};