Vue3 新特性

# Vue3的改進及特點

1.性能的提升:打包大小減少 41%,初次渲染快 55%,更新快 133%,內存使用減少 54%。

2.新推出的Composition API 使組件更易維護,減少無用數據綁定頁面更流暢。

4.更好TypeScript支持,可以在創建命令里直接配置,頁面集成暢通無阻。

5.Teleport(瞬移組件)、Suspense(解決異步加載組件問題)和全局 API 的修改和優化。

6.Vue3兼容大部分Vue2的特性,用Vue2代碼開發Vue3都可以。

# 安裝

vue --version # 查看版本

注意:如果以前安裝過,需要檢查一下版本,因為只有最新版本(V4.5.4 以上版本)才有創建 Vue3 的選項。

npm install -g @vue/cli

使用 vue-cli 命令行創建項目

vue create vue3-1 // 根據提示自己選擇配置

啟動命令

yarn serve 或 npm run serve

打包命令

yarn build 或 npm run build

# 新語法 setup(),ref(),reactive()

// 注:setup是為了優化性能讓程序按需引入全局統一

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下,給予了組件正確的參數類型推斷

export default defineComponent({

? name: "Home",

? components: {},

? props:['msg'],

? setup(props,context) {

? ? // 注:setup函數是處于生命周期函數 beforeCreate 和 Created 兩個鉤子函數之間的函數 也就說在 setup 函數中是無法使用 data 和 methods 中的數據和方法,而methods等可以使用setup中return出去的數據。

? ? /*

? ? 一.函數的第一個參數是 props 用于接收 props.msg

? ? ? 這個props是一個響應式的Proxy對象,不可以解構,解構后會失去響應,如果要用解構的方式,要用toRefs

? ? ? let { msg } = toRefs(props) //但是解析成ref了要用msg.value,所以直接用props.msg更簡單

? ? 二.context對象在setup()中暴露三個屬性 attrs 、slots 和?emit 因為在setup函數中還沒有創建Vue實例,是無法使用vm.$attrs、vm.$slots和vm.$emit的,所以這三個屬性充當了這樣的作用,使用方法相同。

? ? 注意:

? ? ? context.attrs和vm.$attrts包含的是在實例vm.props中沒有被聲明識別的attribute(class和style除外)。所以setup()中參數props中暴露的變量,就不會在context.attrs中暴露。

? ? ? context.slots和vm.$slots只能訪問具名插槽,沒有命名的插槽或者v-slot:default的是沒有暴露的。

? ? ? context的attrs和slots是有狀態的,當組件更新時也會實時更新,所以也不要解構。但與props不同的是,它們不是響應式的,在setup()中的使用應保持只讀的狀態,如果要改變可以在onUpdated的周期函數中進行。

? ? ? context.emit和vm.$emit可以觸發實例上的監聽事件。

? ? */

? ? const list = ref(["深圳", "北京", "上海"]);

? ? const name = ref("");

? ? //注:用ref是為了轉換成引用類型,讓全局引用保持一致,而之前原始類型是不行的,所以要name.value的方示賦值

? ? const show = (index: string) => {

? ? ? ? name.value = index;

? ? };

? ? // 注:不return出去的數據,模板是無法使用的。

? ? return {

? ? ? ? list,

? ? ? ? name,

? ? ? ? show

? ? };

? },

});

</script>

2.用法二 reactive() 優化

<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() 優化

<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 生命周期函數用法, 需要引入 (注:vue2 生命周期函數不影響)

<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() 開始創建組件之前,在beforeCreate和created之前執行。

? ? const data = reactive({

? ? ? list: ["深圳", "北京", "上海"]

? ? });

? ? onBeforeMount(()=>{

? ? ? //組件掛載到節點上之前執行的函數。

? ? })

? ? onMounted(()=>{

? ? ? //組件掛載完成后執行的函數。

? ? })

? ? onBeforeUpdate(()=>{

? ? ? //組件更新之前執行的函數

? ? })

? ? onUpdated(()=>{

? ? ? //組件更新完成之后執行的函數。

? ? })

? ? onBeforeUnmount(()=>{

? ? ? //組件卸載之前執行的函數。

? ? })

? ? onUnmounted(()=>{

? ? ? //組件卸載完成后執行的函數。

? ? })

? ? onActivated(()=>{

? ? ? //被包含在<keep-alive>中的組件,會多出兩個生命周期鉤子函數。被激活時執行。

? ? })

? ? onDeactivated(()=>{

? ? ? //比如從 A 組件,切換到 B 組件,A 組件消失時執行。

? ? })

? ? onErrorCaptured(()=>{

? ? ? //當捕獲一個來自子孫組件的異常時激活鉤子函數。

? ? })

? ? //< 調試用生命函數

? ? onRenderTracked((event)=>{

? ? ? //跟蹤所有狀態觸發

? ? ? console.log(event);

? ? });

? ? onRenderTriggered((event) => {

? ? ? //跟蹤當前狀態觸發

? ? ? console.log(event);

? ? ? //key 那邊變量發生了變化

? ? ? //newValue 更新后變量的值

? ? ? //oldValue 更新前變量的值

? ? ? //target 目前頁面中的響應變量和函數

? ? });

? ? // 調試用生命函數 />

? ? 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("測試單個值");

? ? const data = reactive({

? ? ? list: ["深圳", "北京", "上海"],

? ? ? name: "",

? ? ? show: (index: string) => {

? ? ? ? data.name = index;

? ? ? },

? ? });

? ? //watch(text, 單個用法,watch([text,()=>data.name], 多個用法,注:()=>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 模塊化重用功能 (優化 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>時間:{{time}} <button @click="startTime">開始</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 獨立掛載組件(解決樣式等沖突問題不掛載到app下)

1. index.html 頁面新加插入點(會掛載到 #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 異步請求組件

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 異步請求組件" });

? ? ? }, 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>

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容