# Vue3的改進(jìn)及特點(diǎn)
1.性能的提升:打包大小減少 41%效诅,初次渲染快 55%师脂,更新快 133%澳腹,內(nèi)存使用減少 54%。
2.新推出的Composition API 使組件更易維護(hù)闻牡,減少無(wú)用數(shù)據(jù)綁定頁(yè)面更流暢。
4.更好TypeScript支持绳矩,可以在創(chuàng)建命令里直接配置罩润,頁(yè)面集成暢通無(wú)阻。
5.Teleport(瞬移組件)翼馆、Suspense(解決異步加載組件問(wèn)題)和全局 API 的修改和優(yōu)化割以。
6.Vue3兼容大部分Vue2的特性,用Vue2代碼開(kāi)發(fā)Vue3都可以应媚。
# 安裝
vue --version # 查看版本
注意:如果以前安裝過(guò)严沥,需要檢查一下版本,因?yàn)橹挥凶钚掳姹?V4.5.4 以上版本)才有創(chuàng)建 Vue3 的選項(xiàng)中姜。
npm install -g @vue/cli
使用 vue-cli 命令行創(chuàng)建項(xiàng)目
vue create vue3-1 // 根據(jù)提示自己選擇配置
啟動(dòng)命令
yarn serve 或 npm run serve
打包命令
yarn build 或 npm run build
# 新語(yǔ)法 setup(),ref(),reactive()
// 注:setup是為了優(yōu)化性能讓程序按需引入全局統(tǒng)一
1.用法一
<template>
? <div class="home">
? ? <div>名字:{{ name }}</div>
? ? <ul>
? ? ? <li v-for="item in list" :key="item" @click="show(item)">{{ item }}</li>
? ? </ul>
? </div>
</template>
<script lang="ts">
import { defineComponent, ref } from "vue";
// 注:defineComponent 在TypeScript下消玄,給予了組件正確的參數(shù)類型推斷
export default defineComponent({
? name: "Home",
? components: {},
? props:['msg'],
? setup(props,context) {
? ? // 注:setup函數(shù)是處于生命周期函數(shù) beforeCreate 和 Created 兩個(gè)鉤子函數(shù)之間的函數(shù) 也就說(shuō)在 setup 函數(shù)中是無(wú)法使用 data 和 methods 中的數(shù)據(jù)和方法跟伏,而methods等可以使用setup中return出去的數(shù)據(jù)。
? ? /*
? ? 一.函數(shù)的第一個(gè)參數(shù)是 props 用于接收 props.msg
? ? ? 這個(gè)props是一個(gè)響應(yīng)式的Proxy對(duì)象翩瓜,不可以解構(gòu)受扳,解構(gòu)后會(huì)失去響應(yīng),如果要用解構(gòu)的方式兔跌,要用toRefs
? ? ? let { msg } = toRefs(props) //但是解析成ref了要用msg.value,所以直接用props.msg更簡(jiǎn)單
? ? 二.context對(duì)象在setup()中暴露三個(gè)屬性 attrs 勘高、slots 和?emit 因?yàn)樵趕etup函數(shù)中還沒(méi)有創(chuàng)建Vue實(shí)例,是無(wú)法使用vm.$attrs坟桅、vm.$slots和vm.$emit的华望,所以這三個(gè)屬性充當(dāng)了這樣的作用,使用方法相同桦卒。
? ? 注意:
? ? ? context.attrs和vm.$attrts包含的是在實(shí)例vm.props中沒(méi)有被聲明識(shí)別的attribute(class和style除外)立美。所以setup()中參數(shù)props中暴露的變量,就不會(huì)在context.attrs中暴露方灾。
? ? ? context.slots和vm.$slots只能訪問(wèn)具名插槽建蹄,沒(méi)有命名的插槽或者v-slot:default的是沒(méi)有暴露的。
? ? ? context的attrs和slots是有狀態(tài)的裕偿,當(dāng)組件更新時(shí)也會(huì)實(shí)時(shí)更新洞慎,所以也不要解構(gòu)。但與props不同的是嘿棘,它們不是響應(yīng)式的劲腿,在setup()中的使用應(yīng)保持只讀的狀態(tài),如果要改變可以在onUpdated的周期函數(shù)中進(jìn)行鸟妙。
? ? ? context.emit和vm.$emit可以觸發(fā)實(shí)例上的監(jiān)聽(tīng)事件焦人。
? ? */
? ? const list = ref(["深圳", "北京", "上海"]);
? ? const name = ref("");
? ? //注:用ref是為了轉(zhuǎn)換成引用類型,讓全局引用保持一致重父,而之前原始類型是不行的花椭,所以要name.value的方示賦值
? ? const show = (index: string) => {
? ? ? ? name.value = index;
? ? };
? ? // 注:不return出去的數(shù)據(jù),模板是無(wú)法使用的房午。
? ? return {
? ? ? ? list,
? ? ? ? name,
? ? ? ? show
? ? };
? },
});
</script>
2.用法二 reactive() 優(yōu)化
<template>
? <div class="home">
? ? <div>名字:{{ data.name }}</div>
? ? <ul>
? ? ? <li v-for="item in data.list" :key="item" @click="data.show(item)">{{ item }}</li>
? ? </ul>
? </div>
</template>
<script lang="ts">
import { defineComponent, reactive } from "vue";
export default defineComponent({
? name: "Home",
? components: {},
? setup() {
? ? const data = reactive({
? ? ? list: ["深圳", "北京", "上海"],
? ? ? name: "",
? ? ? show: (index: string) => {
? ? ? ? data.name = index;
? ? ? },
? ? });
? ? return {
? ? ? data
? ? };
? },
});
</script>
2.用法三 toRefs() 優(yōu)化
<template>
? <div class="home">
? ? <div>名字:{{ name }}</div>
? ? <ul>
? ? ? <li v-for="item in list" :key="item" @click="show(item)">{{ item }}</li>
? ? </ul>
? </div>
</template>
<script lang="ts">
import { defineComponent,reactive,toRefs } from "vue";
export default defineComponent({
? name: "Home",
? components: {},
? setup() {
? ? const data = reactive({
? ? ? list: ["深圳", "北京", "上海"],
? ? ? name: "",
? ? ? show: (index: string) => {
? ? ? ? data.name = index;
? ? ? },
? ? });
? ? const refData = toRefs(data);
? ? //不能直接解析 ...data 必須用 toRefs()
? ? return {
? ? ? ...refData
? ? };
? },
});
</script>
# Vue3 生命周期函數(shù)用法, 需要引入 (注:vue2 生命周期函數(shù)不影響)
<script lang="ts">
import { defineComponent,ref,reactive,toRefs,
onBeforeMount,
onMounted,
onBeforeUpdate,
onUpdated,
onBeforeUnmount,
onUnmounted,
onActivated,
onDeactivated,
onErrorCaptured,
onRenderTracked,
onRenderTriggered
} from "vue";
export default defineComponent({
? name: "Home",
? components: {},
? setup() {
? ? //setup() 開(kāi)始創(chuàng)建組件之前矿辽,在beforeCreate和created之前執(zhí)行。
? ? const data = reactive({
? ? ? list: ["深圳", "北京", "上海"]
? ? });
? ? onBeforeMount(()=>{
? ? ? //組件掛載到節(jié)點(diǎn)上之前執(zhí)行的函數(shù)郭厌。
? ? })
? ? onMounted(()=>{
? ? ? //組件掛載完成后執(zhí)行的函數(shù)袋倔。
? ? })
? ? onBeforeUpdate(()=>{
? ? ? //組件更新之前執(zhí)行的函數(shù)
? ? })
? ? onUpdated(()=>{
? ? ? //組件更新完成之后執(zhí)行的函數(shù)。
? ? })
? ? onBeforeUnmount(()=>{
? ? ? //組件卸載之前執(zhí)行的函數(shù)折柠。
? ? })
? ? onUnmounted(()=>{
? ? ? //組件卸載完成后執(zhí)行的函數(shù)宾娜。
? ? })
? ? onActivated(()=>{
? ? ? //被包含在<keep-alive>中的組件,會(huì)多出兩個(gè)生命周期鉤子函數(shù)扇售。被激活時(shí)執(zhí)行碳默。
? ? })
? ? onDeactivated(()=>{
? ? ? //比如從 A 組件贾陷,切換到 B 組件缘眶,A 組件消失時(shí)執(zhí)行嘱根。
? ? })
? ? onErrorCaptured(()=>{
? ? ? //當(dāng)捕獲一個(gè)來(lái)自子孫組件的異常時(shí)激活鉤子函數(shù)。
? ? })
? ? //< 調(diào)試用生命函數(shù)
? ? onRenderTracked((event)=>{
? ? ? //跟蹤所有狀態(tài)觸發(fā)
? ? ? console.log(event);
? ? });
? ? onRenderTriggered((event) => {
? ? ? //跟蹤當(dāng)前狀態(tài)觸發(fā)
? ? ? console.log(event);
? ? ? //key 那邊變量發(fā)生了變化
? ? ? //newValue 更新后變量的值
? ? ? //oldValue 更新前變量的值
? ? ? //target 目前頁(yè)面中的響應(yīng)變量和函數(shù)
? ? });
? ? // 調(diào)試用生命函數(shù) />
? ? const refData = toRefs(data);
? ? return {
? ? ? ...refData
? ? };
? },
? mounted(){
? ? console.log("vue2 生命周期");
? }
});
</script>
# Vue3 watch用法
<script lang="ts">
import { defineComponent, ref, reactive, toRefs, watch } from "vue";
export default defineComponent({
? name: "Home",
? components: {},
? setup() {
? ? const text = ref("測(cè)試單個(gè)值");
? ? const data = reactive({
? ? ? list: ["深圳", "北京", "上海"],
? ? ? name: "",
? ? ? show: (index: string) => {
? ? ? ? data.name = index;
? ? ? },
? ? });
? ? //watch(text, 單個(gè)用法巷懈,watch([text,()=>data.name], 多個(gè)用法该抒,注:()=>data.name 為了兼容vue2
? ? watch([text,()=>data.name], (newValue, oldValue) => {
? ? ? console.log(`new--->${newValue}`);
? ? ? console.log(`old--->${oldValue}`);
? ? });
? ? const refData = toRefs(data);
? ? return {
? ? ? ...refData,
? ? };
? },
});
</script>
# Vue3 模塊化重用功能 (優(yōu)化 mixins)
1.新建useTime.ts文件
import { ref } from "vue";
const time = ref("00:00:00");
const getTime = () => {
? ? const now = new Date();
? ? const h= now.getHours() < 10 ? "0" + now.getHours() : now.getHours();
? ? const m = now.getMinutes() < 10 ? "0" + now.getMinutes() : now.getMinutes();
? ? const s= now.getSeconds() < 10 ? "0" + now.getSeconds() : now.getSeconds();
? ? time.value = h + ":" + m + ":" + s;
? ? setTimeout(getTime, 1000);
};
export { time, getTime }
2.引入
<template>
? <div class="home">
? ? <div>時(shí)間:{{time}} <button @click="startTime">開(kāi)始</button></div>
? </div>
</template>
<script lang="ts">
import { defineComponent, ref } from "vue";
import { time, getTime } from './useTime';
export default defineComponent({
? name: "Home",
? components: {},
? setup() {
? ? const startTime = () => {
? ? ? getTime();
? ? };
? ? return {
? ? ? startTime,
? ? ? time
? ? };
? },
});
</script>
# teleport 獨(dú)立掛載組件(解決樣式等沖突問(wèn)題不掛載到app下)
1. index.html 頁(yè)面新加插入點(diǎn)(會(huì)掛載到 #headTitie DOM下)
<div id="headTitie"></div>
<div id="app"></div>
2. 在components目錄下新建 headTitle.vue
<template>
? <teleport to="#headTitie">
? ? <div class="head">
? ? ? <h1>{{ title }}</h1>
? ? </div>
? </teleport>
</template>
<script lang="ts">
import { defineComponent, ref } from "vue";
export default defineComponent({
? name: "headTitie",
? setup() {
? ? const title = ref("Vue3 新特性示例");
? ? return {
? ? ? title,
? ? };
? },
});
</script>
3. 在 App.vue 加
<template>
? <headTitle />
? <router-view />
</template>
<script lang="ts">
import headTitle from "./components/headTitle.vue";
export default {
? name: "App",
? components: {
? ? headTitle,
? },
};
</script>
# Suspense 異步請(qǐng)求組件
1. 新建Demo.vue
<template>
? <div class="Demo">
? ? <div>名字:{{ name }}</div>
? </div>
</template>
<script lang="ts">
import { defineComponent } from "vue";
export default defineComponent({
? name: "Demo",
? components: {},
? setup() {
? ? return new Promise((resolve, reject) => {
? ? ? setTimeout(() => {
? ? ? ? return resolve({ name: "我是 Suspense 異步請(qǐng)求組件" });
? ? ? }, 2100);
? ? });
? },
});
</script>
2. 使用引入 home.vue
<template>
? <div class="home">
? ? <Suspense>
? ? ? <template #default>
? ? ? ? <Demo />
? ? ? </template>
? ? ? <template #fallback>
? ? ? ? <p>加載中...</p>
? ? ? </template>
? ? </Suspense>
? </div>
</template>
<script lang="ts">
import { defineComponent } from "vue";
import Demo from "./Demo.vue";
export default defineComponent({
? name: "Home",
? components: {Demo}
});
</script>