看完后完全了解 Vue 2.0 和 Vue 3.0 的區別

1.數據的雙向綁定

Vue2.0使用Object.defineProperty

原理:通過使用 Object.defineProperty 來劫持對象屬性的 geter 和 seter 操作,當數據發生改變發出通知

代碼:

 1 <!DOCTYPE html>2 <html lang="en">3 <head>4     <meta charset="UTF-8">5     <meta name="yingaxiang" content="width=device-width, initial-scale=1.0">6     <title>vue2.x數據雙向綁定</title>7 </head>8 <body>9     <div>
10         <input type="text" id="input">
11         <span id="text"></span>
12     </div>
13 </body>
14 </html>
15 <script>
16     var obj = {};
17     Object.defineProperty(obj, 'prop', {
18         get: function () {
19             return val;
20         },
21         set: function (newVal) {
22             val = newVal;
23             document.getElementById('text').innerHTML = val;
24         }
25     });
26     document.addEventListener('keyup', function (e) {
27         obj.prop = e.target.value;
28     });
29 </script>

Vue 3.0使用ES6的新特性porxy

原理:通過ES6的新特性proxy來劫持數據,當數據改變時發出通知

代碼:

 1 <!DOCTYPE html>2 <html lang="en">3 <head>4     <meta charset="UTF-8">5     <meta name="yingaxiang" content="width=device-width, initial-scale=1.0">6     <title>vue3.0數據雙向綁定</title>7 </head>8 <body>9     <div>
10         <input type="text" id="input">
11         <span id="text"></span>
12     </div>
13 </body>
14 </html>
15 <script>
16     var obj = {};
17     var obj1 = new Proxy(obj, {
18         // target就是第一個參數obj, receive就是返回的obj(返回的proxy對象)
19         get: function (target, key, receive) {
20             // 返回該屬性值
21             return target[key];
22         },
23         set: function (target, key, newVal, receive) {
24             // 執行賦值操作
25             target[key] = newVal;
26             document.getElementById('text').innerHTML = target[key];
27         }
28     })
29     document.addEventListener('keyup', function (e) {
30         obj1[0] = e.target.value;
31     });
32 </script>

總結:
Vue2.x版本中的雙向綁定不能檢測到下標的變化
proxy可以劫持整個對象,并返回一個新對象

2. vue3的亮點

性能比2.x快1.2~2倍

diff算法的優化

在vue2中,虛擬dom是全量比較的。

在vue3中,增加了靜態標記PatchFlag。在創建vnode的時候,會根據vnode的內容是否可以變化,為其添加靜態標記PatchFlag。diff的時候,只會比較有PatchFlag的節點。PatchFlag是有類型的,比如一個可變化文本節點,會將其添加PatchFlag枚舉值為TEXT的靜態標記。這樣在diff的時候,只需比對文本內容。需要比對的內容更少了。PatchFlag還有動態class、動態style、動態屬性、動態key屬性等枚舉值。

render階段的靜態提升(render階段指生成虛擬dom樹的階段)

在vue2中,一旦檢查到數據變化,就會re-render組件,所有的vnode都會重新創建一遍,形成新的vdom樹。

在vue3中,對于不參與更新的vnode,會做靜態提升,只會被創建一次,在re-render時直接復用。

靜態提升可以理解為第一次render不參與更新的vnode節點的時候,保存它們的引用。re-render新vdom樹時,直接拿它們的引用過來即可,無需重新創建。

事件偵聽緩存

在vue2中,我們寫的@click="onClick"也是被當作動態屬性,diff的時候也要對比。但我們知道它不會變化,比如變成@click=“onClick2”,綁定別的值。

在vue3中,如果事件是不會變化的,會將onClick緩存起來(跟靜態提升達到的效果類似),該節點也不會被標記上PatchFlag(也就是無需更新的節點)。這樣在render和diff兩個階段,事件偵聽屬性都節約了不必要的性能消耗。

我曾經維護過一個擁有很龐大dom樹的頁面。由于節點非常多,無需參與更新的節點也很多,使用vue2的情況下,在render和diff兩個階段,消費了很多性能,如果當時有vue3的話,我想性能會被優化很多。

減少創建組件實例的開銷

vue2.x每創建一個實例,在this上要暴露data、props、computed這些,都是靠Object.defineProperty去定義的。這部分操作還是挺費時的。

vue3.0中基于Proxy,減少了創建組件實例的性能開銷。

按需編譯,體積比Vue2.x更小(Tree shaking)

在vue3中,可以如下面這樣引用vue的功能函數,如果你的項目沒有用到watch,那編譯時就會把tree shaking掉。

import { computed, watch, nextTick } from "vue";

利用的就是 ES6 模塊系統import/export。

Compostion API: 組合API/注入API

這里要說到代碼的組織方式,傳統的網頁是html/css/javascript(結構/樣式/邏輯)分離。vue/react通過組件化的方式,將聯系緊密的結構/樣式/邏輯放在一起,有利于代碼的維護。

compostion api更進一步,著力于JavaScript(邏輯)部分,將邏輯相關的代碼放在一起,近而有利于代碼的維護。

在vue2的組件內,使用的是Option API風格(data/methods/mounted)來組織的代碼,這樣會讓邏輯分散,舉個例子就是我們完成一個計數器功能,要在data里聲明變量,在methods定義響應函數,在mounted里初始化變量,如果在一個功能比較多、代碼量比較大的組件里,你要維護這樣一個功能,就需要在data/methods/mounted反復的切換到對應位置,然后進行代碼的更改。

在vue3中,使用setup函數。如下所示跟count相關的邏輯,都放到counter.js文件里,跟todo相關的邏輯放到todos.js里。

import useCounter from './counter'
import useTodo from './todos'setup(){let { val, todos, addTodo } = useTodo()let {count,add} = useCounter() return {val, todos, addTodo,count,add,}
}

在我看來這就是Compostion API最大的特點,以功能為單位的代碼組織方式。同時它可以讓代碼更易重用。

說到重用,Compostion API的方式也比mixin的方式好很多,你可以清楚的看到組件使用的數據和方法來自哪個模塊,而mixin進組件的功能,常常會讓我們困惑此功能來自哪個mixin。

更好的TS支持

vue2不適合使用ts,原因在于vue2的Option API風格。options是個簡單對象,而ts是一種類型系統、面向對象的語法。兩者有點不匹配。

在vue2結合ts的具體實踐中,要用 vue-class-component 強化 vue 組件,讓 Script 支持 TypeScript 裝飾器,用 vue-property-decorator 來增加更多結合 Vue 特性的裝飾器,最終搞的ts的組件寫法和js的組件寫法差別挺大。

在vue3中,量身打造了defineComponent函數,使組件在ts下,更好的利用參數類型推斷 。Composition API 代碼風格中,比較有代表性的api就是 ref 和 reactive,也很好的支持了類型聲明。

import { defineComponent, ref } from 'vue'const Component = defineComponent({props: {success: { type: String },student: {type: Object as PropType<Student>,required: true}},setup() {const year = ref(2020)const month = ref<string | number>('9')month.value = 9 // OKconst result = year.value.split('') // => Property 'split' does not exist on type 'number'}

自定義渲染API(Custom Renderer API)

vue2.x架構問題
vue2.x最開始支持運行在瀏覽器中,渲染到瀏覽器的dom上,隨著vue的流行,出現了weex和myvue。

  • weex:移動端跨平臺方案,需要渲染到移動設備。weex被寫在vue原項目里,缺點是這使vue原項目更大了,也不是通用解決方案。
  • myvue:小程序上使用,需要渲染到小程序框架上。myvue是單獨fork一份源代碼進行更改,缺點也非常明顯,myvue中vue的版本跟官方版本從fork的那一刻開始,就要開始不一致了。

vue2.x項目架構對于這種渲染到不同平臺不太友好,vue3.0推出了自定義渲染API解決了該問題。

下面我們先看vue2和vue3的入口寫法有所不同:

// vue2
import Vue from 'vue'
import App from './App.vue'
new Vue({ => h(App)}).$mount('#app')// vue3
const { createApp }  from 'vue'
import App from "./src/App"
createApp(App).mount(('#app')

vue官方實現的 createApp 會給我們的 template 映射生成 html 代碼,但是要是你不想渲染生成到 html ,而是要渲染生成到 canvas 之類的不是html的代碼的時候,那就需要用到 Custom Renderer API 來定義自己的 render 渲染生成函數了。

// 你自己實現一個createApp,比如是渲染到canvas的。
import { createApp } from "./runtime-render";
import App from "./src/App"; // 根組件createApp(App).mount('#app');

有了Custom Renderer API,如weex和myvue這類方案的問題就得到了完美解決。只需重寫createApp即可。

更先進的組件

Fragment組件
// vue2是不允許這樣寫的,組件必須有一個跟節點,現在可以這樣寫,vue將為我們創建一個虛擬的Fragment節點。

<template><div>Hello</div><div>World</div>
</template>

這樣寫有何好處呢?一是如果根節點不是必要的,無需創建了,減少了節點數。二是Fragment節點是虛擬的,不會DOM樹中呈現。

Suspense組件

<Suspense><template ><Suspended-component /></template><template #fallback>Loading...</template>
</Suspense>

在Suspended-component完全渲染之前,備用內容會被顯示出來。如果是異步組件,Suspense可以等待組件被下載,或者在設置函數中執行一些異步操作。

更快的開發體驗(vite開發構建工具)

在使用webpack作為開發構建工具時,npm run dev都要等一會,項目越大等的時間越長。熱重載頁有幾秒的延遲,但是如果用vite來做vue3的開發構建工具,npm run dev 秒開,熱重載也很快。這種開發體驗真是很爽,拒絕等待。

vite的原理還是用了瀏覽器支持import關鍵字了,啟動項目不用webpack構建工具先構建了,瀏覽器直接請求路由對應的代碼文件,代理服務器針對單個文件進行編譯并返回。如果請求的文件里還import了其他文件,同理瀏覽器繼續發請求,代理服務器返回。就這樣實現了npm run dev時無需編譯,實時請求實時編譯。

其他的,數據監聽方式變成了Proxy,消除了Object.defineProperty現有的限制(例如無法檢測新的屬性添加),并提供更好的性能。

vue3解決了vue2的一些問題,大型應用的性能問題、ts支持不友好問題,自定義渲染API解決體系架構存在的問題,如果在vue3的基礎上實現weex框架會好很多。也做出了很多優化,Compostion API讓代碼的組織形式更好。vite開發構建工具讓開發體驗更好,Tree shaking讓包更小、性能更優。

總的來說vue3還是非常棒的,帶來了很多非常好的新特性。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/248739.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/248739.shtml
英文地址,請注明出處:http://en.pswp.cn/news/248739.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

channels2.X 學習筆記

- No module named asgiref.sync 報錯解決&#xff1a; # 報錯原因&#xff1a; """ django版本過低&#xff0c; 卸載最新版本的 channels 使用2.x 版本的 """ pip3 uninstall channels - 安裝&#xff1a; """ Django 1.11.15 …

風格遷移學習筆記

風格遷移大作業 學習規劃 跑通一份代碼&#xff01;&#xff01;&#xff01;&#xff08;done&#xff09;對照代碼、Blog和論文理解相應的算法過程規劃下一步&#xff0c;修改代碼&#xff08;done&#xff09;&#xff0c;實現預計功能&#xff08;done&#xff09;調參&…

Netty源碼分析第5章(ByteBuf)----第5節: directArena分配緩沖區概述

Netty源碼分析第5章(ByteBuf)---->第5節: directArena分配緩沖區概述 Netty源碼分析第五章: ByteBuf 第五節: directArena分配緩沖區概述 上一小節簡單分析了PooledByteBufAllocator中, 線程局部緩存和arean的相關邏輯, 這一小節簡單分析下directArena分配緩沖區的相關過程 …

uni-app(從零開始)

uni-app&#xff08;從零開始&#xff09; uni-app 是什么&#xff1f; uniapp 就是使用Vue.js技術開發所有前端框架的跨端框架uniapp 就是可以將一套代碼 發布到多個平臺 uniapp 和 Vue 的關系&#xff1f; uniapp是基于vue進行開發&#xff0c;繼承了Vue的特性和語法在開…

Remote desktop manager共享賬號

因為多個遠程機器&#xff0c;是會用了域賬號進行登錄的。而域賬號的密碼&#xff0c;三個月之后&#xff0c;密碼強制過期 添加一個新的entry&#xff0c;類型是Credential Entry&#xff0c;然后選擇用戶名/密碼 在remote desktop編輯的頁面&#xff0c;Credentials選擇Crede…

bzoj4403:序列統計

我好傻啊 題目 先來看看長度只能為\(n\)的情況 那么答案非常顯然是\(\binom{mn-1}{n}\) 其中\(mR-L1\) 因為我們要構造一個非降序列&#xff0c;顯然可能一個數會被選擇多次&#xff0c;組合非常不好做&#xff0c;于是我們可以把每一個數的下標加上其對應的下標那么現在的值域…

Mui常用的方法

中對話框 語法&#xff1a;mui.confirm 用法 mui.confirm("確認要切換角色&#xff1f;", "提示", btnArray, function(e) {if(e.index 1) {} else {}});組件名作用alert警告框confirm確認框prompt輸入對話框toast消息提示框&#xff08;自動消失&#x…

sudo: pip:找不到命令

https://blog.csdn.net/fcku_88/article/details/84191288轉載于:https://www.cnblogs.com/xxswkl/p/11012709.html

java ListMapString,Object遍歷的方法

java List<Map<String,Object>遍歷的方法 public class Test {public static void main(String[] args) {List<Map<String, Object>> listMaps new ArrayList<Map<String, Object>>();Map<String, Object> map1 new HashMap<Strin…

vue如何更換網頁標簽的logo

Vue2 版本更換圖標 在我們項目的根目錄下面去添加或者替換 favicon.icon文件 找到我們的 build 文件夾下面的這兩個文件 進行如下配置 favicon: resolveApp(’./favicon.ico’) 刷新后發現并沒有什么效果 莫慌 最后一步 重啟項目 改變端口 如果重啟后還沒有起到作用的話就…

Java并發編程的藝術(十)——Java中的鎖(5)

1. LockSupport工具 1.1 LockSupport的作用 當需要阻塞或喚醒一個線程的時候&#xff0c;都會使用LockSupport工具類來完成相應工作。LockSupport定義了一組公共的靜態方法&#xff0c;這些方法提供了做基本的線程阻塞和喚醒功能。 1.2 LockSupport提供的阻塞和喚醒方法 方法描…

運動-模擬返回頂部

第一步&#xff1a;獲取底部的那個按鈕對象&#xff0c;默認的情況下那個按鈕對象是不可見的。可見的條件的是滾輪距離頂部有距離。 var oBtndocument.getElementById(btn1); 第二步&#xff1a;添加滾輪事件。 (1). 獲取滾輪距離頂部的距離。如果距離大于0&#xff0c;就將按鈕…

《JavaScript高級程序設計》筆記總結

在北京上班的我每天在上下班路上的時間總共是兩個半小時&#xff0c;為了充實這兩個多小時的時間&#xff0c;我便花了銀子換得了下面這個寶貝 本書內容&#xff08;引用書中前言&#xff09; 本書提供了JavaScript開發人員必須掌握的內容&#xff0c;全面涵蓋了JavaScript的…

Task執行多次

項目中&#xff0c;曾經出現過啟動時數據庫連接數瞬間增大&#xff0c;當時并沒有注意該問題。 后期&#xff0c;由于Task任務多次執行&#xff0c;才著手查看這個問題&#xff0c;經排查&#xff0c;由于tomcat中webapp配置多次&#xff0c;導致webapp被掃描多次&#xff08;配…

ES6 的新特性總結

ES6 的新特性總結 關于聲明變量 由 var 變成 let 和 const 區別&#xff1a; var聲明的變量會掛載到window上&#xff0c;let和const聲明的變量不會var聲明的變量存在變量提升&#xff0c;而let和const聲明的變量不存在變量提升let和const聲明的變量形成塊級作用域在同一作…

遞推(一):遞推法的基本思想

所謂遞推&#xff0c;是指從已知的初始條件出發&#xff0c;依據某種遞推關系&#xff0c;逐次推出所要求的各中間結果及最后結果。其中初始條件或是問題本身已經給定&#xff0c;或是通過對問題的分析與化簡后確定。 利用遞推算法求問題規模為n的解的基本思想是&#xff1a;當…

在vue中methods互相調用的方法

在vue中methods互相調用的方法 轉載于:https://www.cnblogs.com/macT/p/10212878.html

MUI H5+ 開發app基礎

加載子頁面(防止手機性能差,出現上下滑動卡頓) 其中 url 就是子頁面的路徑 id 為自定義 通常和頁面名稱一致頁面的跳轉和傳值 切記 如果使用mui組件內的底部導航跳轉的方式只能使用document獲取元素的id 頁面跳轉傳值 新頁面接收參數 頁面初始化 H5加載完畢 判斷某個元素中是…

對象

一、對象 <!DOCTYPE html> <html><head><meta charset"UTF-8"><title></title><script type"text/javascript">/** JS中數據類型* String 字符串* Number 數值* Boolean 布爾值* Null 空值* Undefine…

uni-app 組件傳值

uni-app中的組件之間的傳值 我們將compontents中的test文件作為子組件 引入到index中使用 引入并使用 效果如下 父傳子 首先我們在父組件中使用子組件的標簽中去自定義title 在子組件中 通過props去接收并處理 效果如下&#xff1a; 子傳父 子組件中 設置一個按鈕…