這篇文章主要介紹了vue2和Vue3對(duì)比分析的相關(guān)知識(shí),內(nèi)容詳細(xì)易懂,操作簡(jiǎn)單快捷,具有一定借鑒價(jià)值,相信大家閱讀完這篇vue2和Vue3對(duì)比分析文章都會(huì)有所收獲,下面我們一起來看看吧。
目前創(chuàng)新互聯(lián)建站已為上千的企業(yè)提供了網(wǎng)站建設(shè)、域名、雅安服務(wù)器托管、網(wǎng)站改版維護(hù)、企業(yè)網(wǎng)站設(shè)計(jì)、高安網(wǎng)站維護(hù)等服務(wù),公司將堅(jiān)持客戶導(dǎo)向、應(yīng)用為本的策略,正道將秉承"和諧、參與、激情"的文化,與客戶和合作伙伴齊心協(xié)力一起成長(zhǎng),共同發(fā)展。
Vue2只支持單節(jié)點(diǎn)
,Vue3 template支持多節(jié)點(diǎn)
,類似react fragments
變化
基本都在script中(Option api -> Composition api)不會(huì)再看見滿屏的this了?。。?/p>
style支持v-bind
Proxy代替defineProperty
defineProperty無法實(shí)現(xiàn)對(duì)數(shù)組對(duì)象的深層監(jiān)聽,Proxy
是瀏覽器最新api,功能更加強(qiáng)大。
不再支持IE,Vue2想享受Vue3帶來的部分更新,可考慮升級(jí)Vue2.7
版本
TypeScript的支持
Vue2采用的是Facebook的Flow
,沒法完美支持TypeScript
(所以項(xiàng)目初期技術(shù)選型很重要)
Vue3 TypeScript完全重寫
,提供和React一樣的TS支持
全新生態(tài)
基本還是vue周邊伴隨Vue3升級(jí)那一套,但是狀態(tài)管理推薦,由原來的Vuex變?yōu)?code>Pina
全新的vite
支持,包括vitest
等,官方提供周邊工具更多了
其它優(yōu)化
性能更好,體積更小
就不用說了
事件監(jiān)聽緩存
,類似@click綁定的函數(shù),無需多次創(chuàng)建,放在了cacheHandler緩存中
SSR
:Vue 3.0 會(huì)將靜態(tài)標(biāo)簽直接轉(zhuǎn)化為文本,相比 React 先將 JSX 轉(zhuǎn)化為虛擬 DOM,再將虛擬 DOM 轉(zhuǎn)化為 HTML,這一點(diǎn)Vue3的速度要快很多
Use Hooks
放棄過去的mixins,使用Hooks解決過去mixins的一些缺點(diǎn)
不再和vue2一樣,完全對(duì)比兩棵虛擬DOM樹,Vue3采用動(dòng)靜結(jié)合
的方法,優(yōu)化diff性能
通過編譯階段對(duì)靜態(tài)模板進(jìn)行分析,編譯生成 Block tree。更新性能由 模版整體大小相關(guān)
=》與動(dòng)態(tài)內(nèi)容的數(shù)量相關(guān)
,這是一個(gè)非常大的性能突破。將代碼提升到渲染函數(shù)之外,這樣可以避免在每次渲染時(shí)重新創(chuàng)建這些對(duì)象,從而大大提高內(nèi)存使用率并減少垃圾回收的頻率。
vue2 poly-repo
vue2.x的源碼托管在src目錄中,然后依據(jù)功能拆分出了complier(模板編譯的相關(guān)代碼),core(與平臺(tái)無關(guān)的通用運(yùn)行時(shí)代碼),platforms(平臺(tái)專有代碼),server(服務(wù)端渲染的相關(guān)代碼)、sfc(.vue 單文件解析相關(guān)代碼)、shared(共享工具代碼) 等目錄
vue3 mono-repo
package可以獨(dú)立于
vue.js去使用,這樣例如用戶想要使用vue3.0的響應(yīng)式,可以單獨(dú)依賴reactive
,而不必依賴整個(gè)vue.js,減少引用包的體積,而vue2.x卻做不到這一點(diǎn)。
源碼結(jié)構(gòu)對(duì)比
什么是組合式 API?- Vue官方
解決了過去組件過長(zhǎng)時(shí),optionsApi帶來的難以維護(hù)的問題
邏輯可以整塊復(fù)用
所有API都是import引入的,對(duì)Tree- shaking很友好,沒用到功能,打包的時(shí)候會(huì)被清理掉,減小包的大小
新的 setup
選項(xiàng)在組件被創(chuàng)建之前執(zhí)行,一旦 props
被解析完成,它就將被作為組合式 API 的入口。
可以當(dāng)做Vue2的beforeCreate和create生命周期用
可直接寫await語(yǔ)法
SFC單文件組件中直接使用即可,或者也可以結(jié)合
export default
使用
// or export default { setup(props, context) { // Attribute (非響應(yīng)式對(duì)象,等同于 $attrs) console.log(context.attrs) // 插槽 (非響應(yīng)式對(duì)象,等同于 $slots) console.log(context.slots) // 觸發(fā)事件 (方法,等同于 $emit) console.log(context.emit) // 暴露公共 property (函數(shù)) console.log(context.expose) } }
ref 用來創(chuàng)建基礎(chǔ)類型
的響應(yīng)式數(shù)據(jù)
template中默認(rèn)調(diào)用value顯示數(shù)據(jù),script中需要使用.value
調(diào)用
和react ref差不多,react是.current獲取值,vue3是.value。
Ref的本質(zhì)是通過Reactive創(chuàng)建的,Ref(10)=>Reactive({value:10})
有一定的心智負(fù)擔(dān),尤大也明確說了不會(huì)支持script中直接訪問。究其原因,還是基礎(chǔ)類型無法攔截它的變化,當(dāng)然也有大哥提出用new String('foo')類似的語(yǔ)法對(duì)基礎(chǔ)類型進(jìn)行包裝。個(gè)人感覺直接拿已支持的reactive來搞也不錯(cuò)
Ref
ts定義 import { type Ref } from 'vue';
isRef
判斷是否為ref對(duì)象。一般是ref,toRef,toRefs創(chuàng)建的變量
toRefs
將reactive對(duì)象
解構(gòu)為單個(gè)響應(yīng)式對(duì)象
shallowRef
創(chuàng)建一個(gè)跟蹤自身 .value 變化的 ref,但不會(huì)使其值也變成響應(yīng)式的,簡(jiǎn)單理解為創(chuàng)建一個(gè)和ref相同結(jié)構(gòu)的非響應(yīng)式變量
triggerRef
強(qiáng)制更新頁(yè)面DOM。即使創(chuàng)建的ref沒有變,想更新dom可以用
customRef
提供類似于computed的get和set,可自定義ref行為
reactive 用來創(chuàng)建引用類型
的響應(yīng)式數(shù)據(jù)
reactive的本質(zhì)是將每一層的數(shù)據(jù)都解析成proxy對(duì)象
reactive 的響應(yīng)式默認(rèn)都是遞歸的
,改變某一層的值都會(huì)遞歸的調(diào)用一遍,重新渲染dom。
直接解構(gòu)
,響應(yīng)性會(huì)丟失,需要用toRefs
包裹。引用類型直接改變引用地址也會(huì)導(dǎo)致響應(yīng)式丟失
readonly
將reactive的值更改為只讀
shallowReactive
只能對(duì)淺層的數(shù)據(jù)響應(yīng) 如果是深層的數(shù)據(jù)只會(huì)改變值 不會(huì)改變視圖
import { reactive, toRefs } from 'vue' const book = reactive({ author: 'Vue Team', year: '2020', title: 'Vue 3 Guide', description: 'You are reading this book right now ;)', price: 'free' }) let { author, title } = toRefs(book) title.value = 'Vue 3 Detailed Guide' // 我們需要使用 .value 作為標(biāo)題,現(xiàn)在是 ref console.log(book.title) // 'Vue 3 Detailed Guide'
區(qū)別不大,把setup當(dāng)created用,其它就當(dāng)改了個(gè)名
功能和vue2一致
watch(監(jiān)聽參數(shù),變化回調(diào),配置參數(shù))
注意監(jiān)聽對(duì)象的單個(gè)屬性:watch(() => articleInfo.author, (newVal) => {})
,第一個(gè)參數(shù)為箭頭函數(shù)返回要監(jiān)聽的目標(biāo)屬性
import { ref, reactive, watch } from 'vue' const counter1 = ref(0) const counter2 = ref(0) // 監(jiān)聽多個(gè) watch([counter1, counter2], (newValue, oldValue) => { console.log('The new counter1 value is: ' + counter1.value) console.log('The new counter2 value is: ' + counter2.value) }) const obj = reactive({ name: 'JJ', age: 18 }) // 深度監(jiān)聽對(duì)象 watch(obj, (newValue, oldValue) => { console.log('The new obj value is: ' + obj.value) }, { deep: true, immediate: true }) // watch監(jiān)聽單個(gè)屬性 watch(() => obj.name, (newValue, oldValue) => { console.log('The new obj value is: ' + obj.value) }, { deep: true, immediate: true })
類似React useEffect,但是不需要寫依賴項(xiàng),只要我們回調(diào)中引用了 響應(yīng)式的屬性
和watch的區(qū)別:
同一個(gè)功能的兩種不同形態(tài),底層的實(shí)現(xiàn)是一樣的
watch 可以獲取到新值與舊值(更新前的值),而 watchEffect
是拿不到的。
watch - 顯式
指定依賴源,watchEffect - 自動(dòng)
收集依賴源
watchEffect 在組件初始化的時(shí)候就會(huì)執(zhí)行一次用以收集依賴,watch指定了依賴,所以不需要。
可以理解為watchEffect 就是配置了{(lán) immediate: true } 的watch
使用場(chǎng)景:antfu小哥
:推薦在大部分時(shí)候用 watch 顯式的指定依賴以避免不必要的重復(fù)觸發(fā),也避免在后續(xù)代碼修改或重構(gòu)時(shí)不小心引入新的依賴。watchEffect 適用于一些邏輯相對(duì)簡(jiǎn)單,依賴源和邏輯強(qiáng)相關(guān)的場(chǎng)景(或者懶惰的場(chǎng)景 )。
const stopWatch = watchEffect( (oninvalidate): void => { oninvalidate(() => { console.log("前置校驗(yàn)函數(shù)"); }); // 引用了響應(yīng)式的屬性 count console.log("watchEffect count變化", count.value); }, { // 副作用刷新時(shí)機(jī) flush 一般使用post // 可選:pre(組件更新前執(zhí)行)/sync(強(qiáng)制效果始終同步觸發(fā))/post(組件更新后執(zhí)行) flush: "post", // 開發(fā)調(diào)試 onTrigger() { console.log("開發(fā)調(diào)試"); }, } );
更加靈活,可以在定義響應(yīng)式變量時(shí)聲明
作用和vue2無差異
import { ref, computed } from 'vue' const counter = ref(0) const twiceTheCounter = computed(() => counter.value * 2) // get set寫法 const plusOne = computed({ get: () => counter.value + 1, set: (val) => { counter.value = val - 1 }, }) plusOne.value = 1 console.log(counter.value) // 0 counter.value++ console.log(counter.value) // 1 console.log(twiceTheCounter.value) // 2
通過進(jìn)行引入defineAsyncComponent
可配合Suspense 進(jìn)行更多操作,可用于loading和骨架屏相關(guān),和react Suspense基本一致。不過react Suspense基本一致這個(gè)屬性都不太好用,vue的不清楚實(shí)際場(chǎng)景咋樣
// template// script const AsyncComponent = defineAsyncComponent(() => import('./asyncComponent.vue')) loading...
Teleport 是一種能夠?qū)⑽覀兊哪0邃秩局林付―OM節(jié)點(diǎn),不受父級(jí)style、v-show等屬性影響,但data、prop數(shù)據(jù)依舊能夠共用的技術(shù);類似于 React 的 Portal
。之前寫react是不怎么用這個(gè)屬性,vue3這個(gè)估計(jì)也沒多大用。
主要解決的問題 因?yàn)門eleport節(jié)點(diǎn)掛載在其他指定的DOM節(jié)點(diǎn)下,完全不受父級(jí)style樣式影響
to 屬性 插入指定元素位置,body,html,自定義className等等
作用和vue2還是一樣的,生命周期名稱變了
初次進(jìn)入時(shí):onMounted> onActivated
退出后觸發(fā) deactivated
再次進(jìn)入:只會(huì)觸發(fā) onActivated
defineXxxx 無需import即可直接使用
defineProps 代替過去的props
defineEmits 代替過去的$emit
defineOptions 自定義一些組件屬性,比如組件名稱(需要插件支持)
defineComponent 用于render函數(shù)、TSX、IDE提醒等
defineExpose 子組件聲明的數(shù)據(jù),暴露給父組件直接用
和vue2一致
兩者用法,除了pina沒有Mutations,差別不大。但是官方推薦的東西,自然有它的各種優(yōu)點(diǎn)
Vuex: State、Gettes、Mutations(同步)、Actions(異步)
Pinia: State、Gettes、Actions(同步異步都支持)
Vuex4 用于 Vue3 ,Vuex3 用于 Vue2
Pinia2.x 即支持 Vue2 也支持 Vue3
可以讓寫react的兄弟,快速上手寫vue3
react中 {{}} => {}
兼容的指令:v-model,v-if,v-show
import { ref } from 'vue' let v = ref('') const renderDom = () => { return ( <> {v.value}> ) } export default renderDom
無需導(dǎo)入xxx,import { reactive,ref } from "vue";
,只需要用即可
自定義組件名稱,需要引入插件unplugin-vue-define-options
,并在vite中配置
import { defineConfig } from 'vite'; import vue from '@vitejs/plugin-vue'; import DefineOptions from 'unplugin-vue-define-options/vite'; export default defineConfig({ plugins: [vue(), DefineOptions()], });
不使用插件,也可以通過多寫一個(gè)script標(biāo)簽來單獨(dú)寫options
vetur只支持vue2,volar只支持vue3,兩者沖突。
建議禁用vetur,格式化代碼使用prettier,本地使用volar做代碼高亮。
或者通過項(xiàng)目配置,指定相關(guān)插件配置
底層語(yǔ)法糖時(shí)間改變,之前vue2是update:input,vue3 是update:modelValue
支持多個(gè)v-model
支持自定義修飾符
棄用.sync等
created 元素初始化的時(shí)候
beforeMount 指令綁定到元素后調(diào)用 只調(diào)用一次
mounted 元素插入父級(jí)dom調(diào)用
beforeUpdate 元素被更新之前調(diào)用
update 這個(gè)周期方法被移除 改用updated
beforeUnmount 在元素被移除前調(diào)用
unmounted 指令被移除后調(diào)用 只調(diào)用一次
比如這個(gè)v-move 封裝自定義拖拽指令
import { Directive } from "vue"; const vMove: Directive = { mounted(el: HTMLElement) { let moveEl = el.firstElementChild as HTMLElement; const mouseDown = (e: MouseEvent) => { //鼠標(biāo)點(diǎn)擊物體那一刻相對(duì)于物體左側(cè)邊框的距離=點(diǎn)擊時(shí)的位置相對(duì)于瀏覽器最左邊的距離-物體左邊框相對(duì)于瀏覽器最左邊的距離 console.log(e.clientX, e.clientY, "-----起始", el.offsetLeft); let X = e.clientX - el.offsetLeft; let Y = e.clientY - el.offsetTop; const move = (e: MouseEvent) => { el.style.left = e.clientX - X + "px"; el.style.top = e.clientY - Y + "px"; console.log(e.clientX, e.clientY, "---改變"); }; document.addEventListener("mousemove", move); document.addEventListener("mouseup", () => { document.removeEventListener("mousemove", move); }); }; moveEl.addEventListener("mousedown", mouseDown); }, };
用了react hook的人都知道很香,vue3支持這個(gè)相當(dāng)不錯(cuò),能解決很多業(yè)務(wù)場(chǎng)景的封裝
可以當(dāng)做mixins寫
// useWindowResize import { onMounted, onUnmounted, ref } from "vue"; function useWindowResize() { const width = ref(0); const height = ref(0); function onResize() { width.value = window.innerWidth; height.value = window.innerHeight; } onMounted(() => { window.addEventListener("resize", onResize); onResize(); }); onUnmounted(() => { window.removeEventListener("resize", onResize); }); return { width, height }; } export default useWindowResize;
vueuse 官方,感謝評(píng)論區(qū)@rogepi 小哥的提醒
ahooks-vue
v3hooks
Vue3 究竟好在哪里?(和 React Hook 的詳細(xì)對(duì)比)
關(guān)于“vue2和Vue3對(duì)比分析”這篇文章的內(nèi)容就介紹到這里,感謝各位的閱讀!相信大家對(duì)“vue2和Vue3對(duì)比分析”知識(shí)都有一定的了解,大家如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。