目錄
- 總體來說
- 性能提升
- 樹搖(Tree shaking)
- 碎片化節點(Fragment)
- 傳送門 (Teleport)
- Suspense
- 更好的TypeScript支持
- Composition API
- 回應式原理
- 開發時差異
- 0. setup
- 1. 生命周期呼叫
- 2. 回應式(資料)API
- 3.計算屬性computed
- 4.偵聽器watch
- 5. 獲取DOM元素refs
- 6. 路由使用, VUEX ,VUE掛載
- 7. 自定義指令處理技巧
總體來說
性能提升
- 重寫了虛擬DOM的實作(跳過靜態節點,只處理動態節點)
- update性能提高1.3~2倍
- 服務端渲染速度提高了2~3倍
樹搖(Tree shaking)
可以將無用模塊“剪輯”掉,僅打包需要的
原理:
- ES6 Module引入進行靜態分析,故而編譯的時候正確判斷到底加載了那些模塊
- 靜態分析程式流,判斷那些模塊和變數未被使用或者參考,進而洗掉對應代碼
參考:介紹一下 tree shaking 及其作業原理
碎片化節點(Fragment)
在 vue2.x 中,每個組件只能有一個根,所以,寫每個組件模板時都要套一個父元素,
在 vue3 中,為了更方便的書寫組件模板,新增了一個類似 dom 的標簽元素
這樣做的好處在于:減少標簽層級, 減小記憶體占用,
傳送門 (Teleport)
可以將一個組件內部的一部分模板“傳送”到該組件的 DOM 結構外層的位置去,
Suspense
用于協調對組件樹中嵌套的異步依賴的處理,
如果在渲染時遇到異步依賴項 (異步組件和具有 async setup() 的組件),它將等到所有異步依賴項決議完成時再顯示默認插槽,
https://cn.vuejs.org/api/built-in-components.html#suspense
更好的TypeScript支持
Composition API
組合式API,替換原有的 Options API
根據邏輯相關性組織代碼,提高可讀性和可維護性
更好的重用邏輯代碼(避免mixins混入時命名沖突的問題)
兼容了VUE2中的寫法,原有Options API依然可以延用
回應式原理
不再基于 Object.defineProperty而是基于ES6中的Proxy
開發時差異

0. setup
組合式API以setup函式作為組件的入口
<script setup> 是在單檔案組件 (SFC) 中使用組合式 API 的編譯時語法糖,當同時使用 SFC 與組合式 API 時該語法是默認推薦,相比于普通的 <script> 語法,它具有更多優勢:
- 更少的樣板內容,更簡潔的代碼,
- 能夠使用純 TypeScript 宣告 props 和自定義事件,
- 更好的運行時性能 (其模板會被編譯成同一作用域內的渲染函式,避免了渲染背景關系代理物件),
- 更好的 IDE 型別推導性能 (減少了語言服務器從代碼中抽取型別的作業),
// setup 函式的第一個引數是組件的 props
// 沒有vue2.x中的this指向vue物件了
export default {
props: {
title: String
},
setup(props) {
console.log(props.title)
}
}
1. 生命周期呼叫
<script setup>
// 在vue中解構出方法
import { onMounted, onUpdated } from 'vue'
onMounted(() => {
...
})
onUpdated(() => {
...
})
</script>
beforeCreate -> 使用 setup()
created -> 使用 setup()
beforeMount -> onBeforeMount
mounted -> onMounted
beforeUpdate -> onBeforeUpdate
updated -> onUpdated
beforeDestroy -> onBeforeUnmount
destroyed -> onUnmounted
errorCaptured -> one rrorCaptured
2. 回應式(資料)API
ref
接受一個引數值并回傳一個回應式且可改變的 ref 物件
- ref 物件擁有一個指向內部值的單一屬性 .value
- 當ref在模板中使用的時候,它會自動解套,無需在模板內額外書寫 .value
import { ref } from "vue";
export default {
setup() {
let Num = ref(0),
isShow = ref(false);
return {
Num,
isShow
};
}
};
reactive
- 接收一個普通物件然后回傳該普通物件的回應式代理等同于 2.x 的 Vue.observable()
- 回應式轉換是“深層的”:會影響物件內部所有嵌套的屬性
使用toRefs(state)可將其創建的傳為Refs型別,方便在模板中直接取值,而不用.value
import { ref, reactive } from "vue";
export default {
props: { title: String },
setup() {
let state = reactive({
Num: 0,
arr: [1, 2]
});
let change = () => {
state.arr[0] = state.arr[0] + 1;
state.name = "flytree";
};
return {
state,
change
};
}
};
相關的一些方法:
unref / toRef / toRefs / isRef / isProxy / isReactive / isReadonly
3.計算屬性computed
傳入一個 getter 函式,回傳一個默認不可手動修改的 ref 物件
const count = ref(1);
const plusOne = computed(() => count.value + 1);
console.log(plusOne.value); //2
plusOne.value++; //錯誤!
或者傳入一個擁有 get 和 set 函式的物件,創建一個可手動修改的計算狀態
const count = ref(1);
const plusOne = computed({
get: () => count.value + 1,
set: val => {
count.value = https://www.cnblogs.com/flytree/archive/2022/08/24/val - 1;
}
});
plusOne.value = 1;
console.log(count.value); //0
4.偵聽器watch
watchEffect
立即執行傳入的一個函式,并回應式追蹤其依賴,并在其依賴變更時重新運行該函式
export default {
props: {
title: String,
},
setup(props) {
watchEffect(() => {
console.log(`title is: ` + props.title);
});
}
};
watch
- watch API 完全等效于 2.x this.$watch
- watch 需要偵聽特定的資料源,并在回呼函式中執行副作用
- 默認情況是懶執行的,也就是說僅在偵聽的源變更時才執行回呼偵聽單個資料源
點擊查看代碼
// 偵聽器的資料源可以是一個擁有回傳值的 getter 函式,也可以是 ref
const state = reactive({ count: 0 })
watch(
() => state.count,
(count, prevCount) => {
/* ... */
}
);
const count = ref(0)
watch(count, (count, prevCount) => {
/* ... */
});
import { ref, reactive, toRefs, computed, watch } from "vue";
export default {
setup() {
....
let ratio = ref("--");
watch(state, (state, preState) => {
let total = state.supNum + state.oppNum;
ratio.value =
https://www.cnblogs.com/flytree/archive/2022/08/24/total === 0 ?"--" : ((state.supNum / total) * 100).toFixed(2) + "%";
});
return {
...,
ratio
};
}
};
5. 獲取DOM元素refs
模板的Refs
當使用組合式 API 時,reactive refs 和 template refs 的概念已經是統一的
點擊查看代碼
<template>
<div ref="root"></div>
</template>
<script>
import { ref, onMounted } from 'vue';
export default {
setup() {
const root = ref(null);
onMounted(() => {
console.log(root.value);
});
return {
root
};
}
}
</script>
6. 路由使用, VUEX ,VUE掛載
先要解構出方法,再去創建對應路由,store或vue物件,其它一樣
Vue Router 4.x
import { createRouter, createWebHashHistory } from 'vue-router';
import routes from './routes';
const router = createRouter({
history: createWebHashHistory(),
routes
});
router.beforeEach(async (to, from, next) => { ... })
export default router;
Vue Router 3.x
import VueRouter from 'vue-router'
import routes from './routes';
const router = new VueRouter({
routes
})
export default router;
VUEX 4.x
import { createStore, createLogger } from 'vuex';
export default createStore({
state: {},
mutations: {},
actions: {},
plugins: [createLogger()]
})
VUEX 3.x
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {},
state: {},
mutations: {},
actions: {},
})
export default store
實體創建
VUE 3.x
import { createApp } from 'vue';
const app = createApp(App);
app.use(store);
app.use(router);
app.mount('#app');
VUE 2.x
import Vue from 'vue'
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
7. 自定義指令處理技巧
export default function directive(app) {
app.directive('xxx', {
// 指令首次系結到元素且在安裝父組件之前...「等同于bind」
beforeMount(el, binding, vnode, prevVnode) {
// binding:資料物件
// + arg:傳給指令的引數 v-xxx:n -> arg:"n"
// + modifiers:修飾符物件 v-xxx.stop -> modifiers:{stop:true}
// + value:指令系結的值 v-xxx="1+1" -> value:2
// + oldValue:之前系結的值
},
// 安裝系結元素的父組件時...「等同于inserted」
mounted() {},
// 在包含組件的VNode更新之前...
beforeUpdate() {},
// 在包含組件的VNode及其子VNode更新后...「等同于componentUpdated」
updated() {},
// 在卸載系結元素的父組件之前...
beforeUnmount() {},
// 指令與元素解除系結且父組件已卸載時...「等同于unbind」
unmounted() {}
});
};
// main.js
import {
createApp
} from 'vue';
import App from './App.vue';
import directive from './directive';
const app = createApp(App);
directive(app);
app.mount('#app');
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/502602.html
標籤:其他
