Vuejs的簡(jiǎn)單使用方法

這篇文章主要介紹“Vuejs的簡(jiǎn)單使用方法”,在日常操作中,相信很多人在Vuejs的簡(jiǎn)單使用方法問題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”Vuejs的簡(jiǎn)單使用方法”的疑惑有所幫助!接下來,請(qǐng)跟著小編一起來學(xué)習(xí)吧!

創(chuàng)新互聯(lián)建站專注為客戶提供全方位的互聯(lián)網(wǎng)綜合服務(wù),包含不限于成都做網(wǎng)站、網(wǎng)站建設(shè)、海陵網(wǎng)絡(luò)推廣、成都微信小程序、海陵網(wǎng)絡(luò)營銷、海陵企業(yè)策劃、海陵品牌公關(guān)、搜索引擎seo、人物專訪、企業(yè)宣傳片、企業(yè)代運(yùn)營等,從售前售中售后,我們都將竭誠為您服務(wù),您的肯定,是我們最大的嘉獎(jiǎng);創(chuàng)新互聯(lián)建站為所有大學(xué)生創(chuàng)業(yè)者提供海陵建站搭建服務(wù),24小時(shí)服務(wù)熱線:18980820575,官方網(wǎng)址:muchs.cn

框架設(shè)計(jì)遠(yuǎn)沒有大家想的那么簡(jiǎn)單,并不是說只把功能開發(fā)完成,能用就算完事兒了,這里面還是有很多學(xué)問的。比如說,我們的框架應(yīng)該給用戶提供哪些構(gòu)建產(chǎn)物?產(chǎn)物的模塊格式如何?當(dāng)用戶沒有以預(yù)期的方式使用框架時(shí)是否應(yīng)該打印合適的警告信息從而提升更好的開發(fā)體驗(yàn),讓用戶快速定位問題?開發(fā)版本的構(gòu)建和生產(chǎn)版本的構(gòu)建有何區(qū)別?熱跟新(HMR:Hot Module Replacement)需要框架層面的支持才行,我們是否也應(yīng)該考慮?再有就是當(dāng)你的框架提供了多個(gè)功能,如果用戶只需要其中幾個(gè)功能,那么用戶是否可以選擇關(guān)閉其他功能從而減少資源的打包體積?所有以上這些問題我們都會(huì)在本節(jié)內(nèi)容進(jìn)行討論。

本節(jié)內(nèi)容需要大家對(duì)常用的模塊打包工具有一定的使用經(jīng)驗(yàn),尤其是 rollup.js 以及 webpack。如果你只用過或了解過其中一個(gè)也沒關(guān)系,因?yàn)樗鼈兒芏喔拍钇鋵?shí)是類似的。如果你沒有使用任何模塊打包工具那么需要你自行去了解一下,至少有了初步認(rèn)識(shí)之后再來看本節(jié)內(nèi)容會(huì)更好一些。

提升用戶的開發(fā)體驗(yàn)

衡量一個(gè)框架是否足夠優(yōu)秀的指標(biāo)之一就是看它的開發(fā)體驗(yàn)如何,我們拿 Vue3 舉個(gè)例子:

createApp(App).mount('#not-exist')

當(dāng)我們創(chuàng)建一個(gè) Vue 應(yīng)用并試圖將其掛載到一個(gè)不存在的 DOM 節(jié)點(diǎn)時(shí)就會(huì)得到一個(gè)警告信息:

Vuejs的簡(jiǎn)單使用方法

warn

從這條信息中我們得知掛載失敗了,并說明了失敗的原因:Vue 根據(jù)我們提供的選擇器無法找到相應(yīng)的 DOM 元素(返回 null),正式因?yàn)檫@條信息的存在使得我們能夠清晰且快速的了解并定位問題,可以試想一下如果 Vue 內(nèi)部不做任何處理,那么很可能得到的是一個(gè) JS 層面的錯(cuò)誤信息,例如:Uncaught TypeError: Cannot read property 'xxx' of null,但是根據(jù)此信息我們很難知道問題出在哪里。

所以在框架設(shè)計(jì)和開發(fā)的過程中,提供友好的警告信息是至關(guān)重要的,如果這一點(diǎn)做得不好那么很可能經(jīng)常收到用戶的抱怨。始終提供友好的警告信息不僅能夠快速幫助用戶定位問題,節(jié)省用戶的時(shí)間,還能夠?yàn)榭蚣苁斋@良好的口碑,讓用戶認(rèn)為你是非常專業(yè)的。

在 Vue 的源碼中,你經(jīng)常能夠看到 warn() 函數(shù)的調(diào)用,例如上面圖片中的信息就是由這句 warn() 函數(shù)調(diào)用打印的:

warn(    `Failed to mount app: mount target selector "${container}" returned null.`  )

對(duì)于 warn() 函數(shù)來說,由于它需要盡可能的提供有用的信息,因此它需要收集當(dāng)前發(fā)生錯(cuò)誤的組件的組件棧信息,所以如果你去看源碼你會(huì)發(fā)現(xiàn)有些復(fù)雜,但其實(shí)最終就是調(diào)用了 console.warn() 函數(shù)。

對(duì)于開發(fā)體驗(yàn)來說,除了提供必要的警告信息,還有很多其他方面可以作為切入口,可以進(jìn)一步提升用戶的開發(fā)體驗(yàn)。例如在 Vue3 中當(dāng)我們?cè)诳刂婆_(tái)打印一個(gè) Ref 數(shù)據(jù)時(shí):

const count = ref(0)  console.log(count)

打開控制臺(tái)查看輸出,如下圖所示:

Vuejs的簡(jiǎn)單使用方法

沒有任何處理的輸出

可以發(fā)現(xiàn)非常的不直觀,當(dāng)然我們可以直接打印 count.value ,這樣就只會(huì)輸出 0,但是有沒有辦法在打印 count 的時(shí)候讓輸出的信息更有好呢?當(dāng)然可以,瀏覽允許我們編寫自定義的 formatter,從而自定義輸出的形式。在 Vue 的源碼中你可以搜索到名為 initCustomFormatter 的函數(shù),這個(gè)函數(shù)就是用來在開發(fā)環(huán)境下初始化自定義 formatter 的,以 chrome 為例我們可以打開 devtool 的設(shè)置,然后勾選 Console \-> Enable custom formatters:

Vuejs的簡(jiǎn)單使用方法

然后刷新瀏覽器后查看控制臺(tái),會(huì)發(fā)現(xiàn)輸出的內(nèi)容變得非常直觀:

Vuejs的簡(jiǎn)單使用方法

控制框架代碼的體積

框架的大小也是衡量框架的標(biāo)準(zhǔn)之一,在實(shí)現(xiàn)同樣功能的情況下當(dāng)然是用越少的代碼越好,這樣體積就會(huì)越小,最后瀏覽器加載資源的時(shí)間也就越少。這時(shí)我們不禁會(huì)想,提供越完善的警告信息就意味著我們要編寫更多的代碼,這不是與控制代碼體積相駁嗎?沒錯(cuò),所以我們要想辦法解決這個(gè)問題。

如果我們?nèi)タ?Vue 的源碼會(huì)發(fā)現(xiàn),每一個(gè) warn() 函數(shù)的調(diào)用都會(huì)配合 __DEV__ 常量的檢查,例如:

if (__DEV__ && !res) {    warn(      `Failed to mount app: mount target selector "${container}" returned null.`    )  }

可以看到,打印警告信息的前提是:__DEV__這個(gè)常量一定要為真,這里的 __DEV__ 常量就是達(dá)到目的的關(guān)鍵。

Vue 使用的是 rollup.js 對(duì)項(xiàng)目進(jìn)行構(gòu)建的,這里的 __DEV__ 常量實(shí)際上是通過 rollup 的配置來預(yù)定義的,其功能類似于 webpack 中的 DefinePlugin 插件。

Vue 在輸出資源的時(shí)候,會(huì)輸出兩個(gè)版本的資源,其中一個(gè)資源用于開發(fā)環(huán)境,如 vue.global.js ;另一個(gè)與其對(duì)應(yīng)的用于生產(chǎn)環(huán)境,如:vue.global.prod.js ,通過文件名稱我們也能夠區(qū)分。

當(dāng) Vue 構(gòu)建用于開發(fā)環(huán)境的資源時(shí),會(huì)把 __DEV__ 常量設(shè)置為 true,這時(shí)上面那段輸出警告信息的代碼就等價(jià)于:

if (true && !res) {    warn(      `Failed to mount app: mount target selector "${container}" returned null.`    )  }

可以看到這里的 __DEV__ 被替換成了字面量 true ,所以這段代碼在開發(fā)環(huán)境是肯定存在的。

當(dāng) Vue 構(gòu)建用于生產(chǎn)環(huán)境的資源時(shí),會(huì)把 __DEV__ 常量設(shè)置為 false,這時(shí)上面那段輸出警告信息的代碼就等價(jià)于:

if (false && !res) {    warn(      `Failed to mount app: mount target selector "${container}" returned null.`    )  }

可以看到 __DEV__ 常量被替換為字面量 false ,這時(shí)我們發(fā)現(xiàn)這段分支代碼永遠(yuǎn)都不會(huì)執(zhí)行,因?yàn)榕袛鄺l件始終為假,這段永遠(yuǎn)不會(huì)執(zhí)行的代碼被稱為 Dead Code,它不會(huì)出現(xiàn)在最終的產(chǎn)物中,在構(gòu)建資源的時(shí)候就會(huì)被移除,因此在 vue.global.prod.js 中是不會(huì)存在這段代碼的。

這樣我們就做到了在開發(fā)環(huán)境為用戶提供友好的警告信息的同時(shí),還不會(huì)增加生產(chǎn)環(huán)境代碼的體積。

框架要做到良好的 Tree-Shaking

上文中我們提到通過構(gòu)建工具設(shè)置預(yù)定義的常量 __DEV__,就能夠做到在生產(chǎn)環(huán)境使得框架不包含打印警告信息的代碼,從而使得框架自身的代碼量變少。但是從用戶的角度來看,這么做仍然不夠,還是拿 Vue 來舉個(gè)例子,我們知道 Vue 提供了內(nèi)置的組件例如 <Transition> ,如果我們的項(xiàng)目中根本就沒有使用到該組件,那么 <Transition> 組件的代碼需要包含在我們項(xiàng)目最終的構(gòu)建資源中嗎?答案是當(dāng)然不需要,那如何做到這一點(diǎn)呢?這就不得不提到本節(jié)的主角 Tree-Shaking。

那什么是 Tree-Shaking 呢?在前端領(lǐng)域這個(gè)概念因 rollup 而普及,簡(jiǎn)單的說所謂 Tree-Shaking 指的就是消除哪些永遠(yuǎn)不會(huì)執(zhí)行的代碼,也就是排除 dead-code,現(xiàn)在無論是 rollup 還是 webpack 都支持 Tree-Shaking。

想要實(shí)現(xiàn) Tree-Shaking 必須滿足一個(gè)條件,即模塊必須是 ES Module,因?yàn)?Tree-Shaking 依賴 ESM 的靜態(tài)結(jié)構(gòu)。我們使用 rollup 通過一個(gè)簡(jiǎn)單的例子看看 Tree-Shaking 如何工作,我們 demo 的目錄結(jié)構(gòu)如下:

├── demo  │   └── package.json  │   └── input.js │   └── utils.js

首先安裝 rollup:

yarn add rollup \-D # 或者 npm install rollup \-D

下面是 input.js 和 utils.js 文件的內(nèi)容:

// input.js  import { foo } from './utils.js'  foo()  // utils.js  export function foo(obj) {    obj && obj.foo  }  export function bar(obj) {    obj && obj.bar  }

代碼很簡(jiǎn)單,我們?cè)?utils.js 文件中定義并導(dǎo)出了兩個(gè)函數(shù),分別是 foo 和 bar,然后在 input.js 中導(dǎo)入了 foo 函數(shù)并執(zhí)行,注意我們并沒有導(dǎo)入 bar 函數(shù)。

接著我們執(zhí)行如下命令使用 rollup 構(gòu)建:

npx rollup input.js -f esm -o bundle.js

這句命令的意思是以 input.js 文件問入口,輸出 ESM 模塊,輸出的文件名叫做 bundle.js 。命令執(zhí)行成功后,我們打開 bundle.js 來查看一下它的內(nèi)容:

// bundle.js  function foo(obj) {    obj && obj.foo  }  foo();

可以看到,其中并不包含 bar 函數(shù),這說明 Tree-Shaking 起了作用,由于我們并沒有使用 bar 函數(shù),因此它作為 dead-code 被刪除了。但是如果我們仔細(xì)觀察會(huì)發(fā)現(xiàn),foo 函數(shù)的執(zhí)行也沒啥意義呀,就是讀取了對(duì)象的值,所以它執(zhí)行還是不執(zhí)行也沒有本質(zhì)的區(qū)別呀,所以即使把這段代碼刪了,也對(duì)我們的應(yīng)用沒啥影響,那為什么 rollup 不把這段代碼也作為 dead-code 移除呢?

這就涉及到 Tree-Shaking 中的第二個(gè)關(guān)鍵點(diǎn),即副作用。如果一個(gè)函數(shù)調(diào)用會(huì)產(chǎn)生副作用,那么就不能將其移除。什么是副作用?簡(jiǎn)單地說副作用的意思是當(dāng)調(diào)用函數(shù)的時(shí)候,會(huì)對(duì)外部產(chǎn)生影響,例如修改了全局變量。這時(shí)你可能會(huì)說,上面的代碼明顯是讀取對(duì)象的值怎么會(huì)產(chǎn)生副作用呢?其實(shí)是有可能的,想想一下如果 obj 對(duì)象是一個(gè)通過 Proxy 創(chuàng)建的代理對(duì)象那么當(dāng)我們讀取對(duì)象屬性時(shí)就會(huì)觸發(fā) Getter ,在 Getter 中是可能產(chǎn)生副作用的,例如我們?cè)?Getter 中修改了某個(gè)全局變量。而到底會(huì)不會(huì)產(chǎn)生副作用,這個(gè)只有代碼真正運(yùn)行的時(shí)候才能知道, JS 本身是動(dòng)態(tài)語言,想要靜態(tài)的分析哪些代碼是 dead-code 是一件很有難度的事兒,上面只是舉了一個(gè)簡(jiǎn)單的例子。

正因?yàn)殪o態(tài)分析 JS 代碼很困難,所以諸如 rollup 等這類工具都會(huì)給我提供一個(gè)機(jī)制,讓我們有能力明確的告訴 rollup :”放心吧,這段代碼不會(huì)產(chǎn)生副作用,你可以放心移除它“,那具體怎么做呢?如下代碼所示,我們修改 input.js 文件:

import {foo} from './utils'  /*#__PURE__*/ foo()

注意這段注釋代碼 /*#__PURE_*_/,該注釋的作用就是用來告訴 rollup 對(duì)于 foo() 函數(shù)的調(diào)用不會(huì)產(chǎn)生副作用,你可以放心的對(duì)其進(jìn)行 Tree-Shaking,此時(shí)再次執(zhí)行構(gòu)建命令并查看 bundle.js 文件你會(huì)發(fā)現(xiàn)它的內(nèi)容是空的,這說明 Tree-Shaking 生效了。

基于這個(gè)案例大家應(yīng)該明白的是,在編寫框架的時(shí)候我們需要合理的使用/*#__PURE_*_/ 注釋,如果你去搜索 Vue 的源碼會(huì)發(fā)現(xiàn)它大量的使用了該注釋,例如下面這句:

export const isHTMLTag = /*#__PURE__*/ makeMap(HTML_TAGS)

也許你會(huì)覺得這會(huì)不會(huì)對(duì)編寫代碼帶來很大的心智負(fù)擔(dān)?其實(shí)不會(huì),這是因?yàn)橥ǔ.a(chǎn)生副作用的代碼都是模塊內(nèi)函數(shù)的頂級(jí)調(diào)用,什么是頂級(jí)調(diào)用呢?如下代碼所示:

foo() // 頂級(jí)調(diào)用  function bar() {    foo() // 函數(shù)內(nèi)調(diào)用  }

可以看到對(duì)于頂級(jí)調(diào)用來說是可能產(chǎn)生副作用的,但對(duì)于函數(shù)內(nèi)調(diào)用來說只要函數(shù) bar 沒有被調(diào)用,那么 foo 函數(shù)的調(diào)用當(dāng)然不會(huì)產(chǎn)生副作用。因此你會(huì)發(fā)現(xiàn)在 Vue 的源碼中,基本都是在一些頂級(jí)調(diào)用的函數(shù)上使用 /*#__PURE__*/ 注釋的。當(dāng)然該注釋不僅僅作用與函數(shù),它可以使用在任何語句上,這個(gè)注釋也不是只有 rollup 才能識(shí)別,webpack 以及壓縮工具如 terser 都能識(shí)別它。

框架應(yīng)該輸出怎樣的構(gòu)建產(chǎn)物

上文中我們提到 Vue 會(huì)為開發(fā)環(huán)境和生產(chǎn)環(huán)境輸出不同的包,例如 vue.global.js 用于開發(fā)環(huán)境,它包含了必要的警告信息,而 vue.global.prod.js 用于生產(chǎn)環(huán)境,不包含警告信息。實(shí)際上 Vue 的構(gòu)建產(chǎn)物除了有環(huán)境上的區(qū)分之外,還會(huì)根據(jù)使用場(chǎng)景的不同而輸出其他形式的產(chǎn)物,這一節(jié)我們將討論這些產(chǎn)物的用途以及在構(gòu)建階段如何輸出這些產(chǎn)物。

不同類型的產(chǎn)物一定是有對(duì)應(yīng)的需求背景的,因此我們從需求講起。首先我們希望用戶可以直接在 html 頁面中使用 <script>標(biāo)簽引入框架并使用:

<body>    <script src="/path/to/vue.js"></script>    <script>    const { createApp } = Vue    // ...    </script>  </body>

為了能夠?qū)崿F(xiàn)這個(gè)需求,我們就需要輸出一種叫做 IIFE 格式的資源,IIFE 的全稱是 Immediately Invoked Function Expression ,即”立即調(diào)用的函數(shù)表達(dá)式“,可以很容易的用 JS 來表達(dá):

(function () {    // ...  }())  如上代碼所示,這就是一個(gè)立即執(zhí)行的函數(shù)表達(dá)式。實(shí)際上 vue.globale.js 文件就是 IIFE 形式的資源,大家可以看一下它的代碼結(jié)構(gòu):  var Vue = (function(exports){    // ...   exports.createApp = createApp;    // ...    return exports  }({}))

這樣當(dāng)我們使用 <script> 標(biāo)簽直接引入 vue.global.js 文件后,那么全局變量 Vue 就是可用的了。

在 rollup 中我們可以通過配置 format: 'iife' 來實(shí)現(xiàn)輸出這種形式的資源:

// rollup.config.js  const config = {    input: 'input.js',    output: {      file: 'output.js',      format: 'iife' // 指定模塊形式    }  }  export default config

不過隨著技術(shù)的發(fā)展和瀏覽器的支持,現(xiàn)在主流瀏覽器對(duì)原生 ESM 模塊的支持都不錯(cuò),所以用戶除了能夠使用 <script> 標(biāo)簽引用 IIFE 格式的資源外,還可以直接引如 ESM 格式的資源,例如 Vue3 會(huì)輸出 vue.esm-browser.js 文件,用戶可以直接用 <script> 標(biāo)簽引入:

<script type="module" src="/path/to/vue.esm-browser.js"></script>

為了輸出 ESM 格式的資源就需要我們配置 rollup 的輸出格式為:format: 'esm'。

你可能已經(jīng)注意到了,為什么 vue.esm-browser.js 文件中會(huì)有 -browser 字樣,其實(shí)對(duì)于 ESM 格式的資源來說,Vue 還會(huì)輸出一個(gè) vue.esm-bundler.js 文件,其中 -browser 變成了 -bundler。為什么這么做呢?我們知道無論是 rollup 還是 webpack 在尋找資源時(shí),如果 package.json 中存在 module 字段,那么會(huì)優(yōu)先使用 module 字段指向的資源來代替 main 字段所指向的資源。我們可以打開 Vue 源碼中的 packages/vue/package.json 文件看一下:

{   "main": "index.js",    "module": "dist/vue.runtime.esm-bundler.js",  }

其中 module 字段指向的是 vue.runtime.esm-bundler.js 文件,意思就是說如果你的項(xiàng)目是使用 webpack 構(gòu)建的,那你使用的 Vue 資源就是 vue.runtime.esm-bundler.js ,也就是說帶有 -bundler 字樣的 ESM 資源是給 rollup 或 webpack 等打包工具使用的,而帶有 -browser 字樣的 ESM 資源是直接給 <script type="module"> 去使用的。

那他們之間的區(qū)別是什么呢?那這就不得不提到上文中的 __DEV__ 常量,當(dāng)構(gòu)建用于 <script> c標(biāo)簽的 ESM 資源時(shí),如果是用于開發(fā)環(huán)境,那么 __DEV__ 會(huì)設(shè)置為 true;如果是用于生產(chǎn)環(huán)境,那么 __DEV__ 常量會(huì)被設(shè)置為 false ,從而被 Tree-Shaking 移除。但是當(dāng)我們構(gòu)建提供給打包工具的 ESM 格式的資源時(shí),我們不能直接把 __DEV__ 設(shè)置為 true 或 false,而是使用(process.env.NODE_ENV !== 'production')替換掉 _DEV__常量。例如下面的源碼:

if (__DEV__) {   warn(`useCssModule() is not supported in the global build.`)  }

在帶有 -bundler 字樣的資源中會(huì)變成:

if ((process.env.NODE_ENV !== 'production')) {    warn(`useCssModule() is not supported in the global build.`)  }

這樣用戶側(cè)的 webpack 配置可以自己決定構(gòu)建資源的目標(biāo)環(huán)境,但是最終的效果其實(shí)是一樣的,這段代碼也只會(huì)出現(xiàn)在開發(fā)環(huán)境。

用戶除了可以直接使用 <script> 標(biāo)簽引入資源,我們還希望用戶可以在 Node.js 中通過 require 語句引用資源,例如:

const Vue = require('vue')

為什么會(huì)有這種需求呢?答案是服務(wù)端渲染,當(dāng)服務(wù)端渲染時(shí) Vue 的代碼是運(yùn)行在 Node.js 環(huán)境的,而非瀏覽器環(huán)境,在 Node.js 環(huán)境下資源的模塊格式應(yīng)該是 CommonJS ,簡(jiǎn)稱 cjs。為了能夠輸出 cjs 模塊的資源,我們可以修改 rollup 的配置:format: 'cjs' 來實(shí)現(xiàn):

// rollup.config.js  const config = {    input: 'input.js',    output: {      file: 'output.js',      format: 'cjs' // 指定模塊形式    }  }  export default config

特性開關(guān)

在設(shè)計(jì)框架時(shí),框架會(huì)提供諸多特性(或功能)給用戶,例如我們提供 A、B、C 三個(gè)特性給用戶,同時(shí)呢我們還提供了 a、b、c 三個(gè)對(duì)應(yīng)的特性開關(guān),用戶可以通過設(shè)置 a、b、c 為 true 和 false 來代表開啟和關(guān)閉,那么將會(huì)帶來很多收益:

對(duì)于用戶關(guān)閉的特性,我們可以利用 Tree-Shaking 機(jī)制讓其不包含在最終的資源中。

該機(jī)制為框架設(shè)計(jì)帶來了靈活性,可以通過特性開關(guān)任意為框架添加新的特性而不用擔(dān)心用不到這些特性的用戶側(cè)資源體積變大,同時(shí)當(dāng)框架升級(jí)時(shí),我們也可以通過特性開關(guān)來支持遺留的 API,這樣新的用戶可以選擇不適用遺留的 API,從而做到用戶側(cè)資源最小化。

那怎么實(shí)現(xiàn)特性開關(guān)呢?其實(shí)很簡(jiǎn)單,原理和上文提到的 __DEV__ 常量一樣,本質(zhì)是利用 rollup 的預(yù)定義常量插件來實(shí)現(xiàn),那一段 Vue3 的 rollup 配置來看:

{   __FEATURE_OPTIONS_API__: isBundlerESMBuild ? `__VUE_OPTIONS_API__` : true,  }

其中 __FEATURE_OPTIONS_API__ 類似于 __DEV__,我們可以在 Vue3 的源碼中搜索,可以找到很多類似如下代碼這樣的判斷分支:

// support for 2.x options  if (__FEATURE_OPTIONS_API__) {    currentInstance = instance    pauseTracking()    applyOptions(instance, Component)    resetTracking()    currentInstance = null  }

當(dāng) Vue 構(gòu)建資源時(shí),如果構(gòu)建的資源是用于給打包工具使用的話(即帶有 -bundler 字樣的資源),那么上面代碼在資源中會(huì)變成:

// support for 2.x options  if (__VUE_OPTIONS_API__) { // 這一這里    currentInstance = instance    pauseTracking()    applyOptions(instance, Component)    resetTracking()    currentInstance = null  }

其中 __VUE_OPTIONS_API__ 就是一個(gè)特性開關(guān),用戶側(cè)就可以通過設(shè)置 __VUE_OPTIONS_API__ 來控制是否包含這段代碼。通常用戶可以使用 webpack.DefinePlugin 插件實(shí)現(xiàn):

// webpack.DefinePlugin 插件配置  new webpack.DefinePlugin({    __VUE_OPTIONS_API__: JSON.stringify(true) // 開啟特性  })

最后再來詳細(xì)解釋一下 __VUE_OPTIONS_API__ 開關(guān)是干嘛用的,在 Vue2 中我們編寫的組件叫做組件選項(xiàng) API:

export default {   data() {}, // data 選項(xiàng)    computed: {}, // computed 選項(xiàng)   //  其他選項(xiàng)...  }

但是在 Vue3 中,更推薦使用 Composition API 來編寫代碼,例如:

export default {   setup() {    const count = ref(0)      const doubleCount = computed(() => count.value * 2) // 相當(dāng)于 Vue2 中的 computed 選項(xiàng)   }  }

但是為了兼容 Vue2,在 Vue3 中仍然可以使用選項(xiàng) API 的方式編寫代碼,但是對(duì)于明確知道自己不會(huì)使用選項(xiàng) API 的用戶來說,它們就可以選擇使用 __VUE_OPTIONS_API__ 開關(guān)來關(guān)閉該特性,這樣在打包的時(shí)候 Vue 的這部分代碼就不會(huì)包含在最終的資源中,從而減小資源體積。

錯(cuò)誤處理

錯(cuò)誤處理是開發(fā)框架的過程中非常重要的環(huán)節(jié),框架的錯(cuò)誤處理做的好壞能夠直接決定用戶應(yīng)用程序的健壯性,同時(shí)還決定了用戶開發(fā)應(yīng)用時(shí)處理錯(cuò)誤的心智負(fù)擔(dān)。

為了讓大家對(duì)錯(cuò)誤處理的重要性有更加直觀的感受,我們從一個(gè)小例子說起。假設(shè)我們開發(fā)了一個(gè)工具模塊,代碼如下:

// utils.js  export default {    foo(fn) {      fn && fn()    }  }

該模塊導(dǎo)出一個(gè)對(duì)象,其中 foo 屬性是一個(gè)函數(shù),接收一個(gè)回調(diào)函數(shù)作為參數(shù),調(diào)用 foo 函數(shù)時(shí)會(huì)執(zhí)行回調(diào)函數(shù),在用戶側(cè)使用時(shí):

import utils from 'utils.js'  utils.foo(() => {    // ...  })

大家思考一下如果用戶提供的回調(diào)函數(shù)在執(zhí)行的時(shí)候出錯(cuò)了怎么辦?此時(shí)有兩個(gè)辦法,其一是讓用戶自行處理,這需要用戶自己去 try...catch:

import utils from 'utils.js'  utils.foo(() => {    try {     // ...    } catch (e) {     // ...  }  })

但是這對(duì)用戶來說是增加了負(fù)擔(dān),試想一下如果 utils.js 不是僅僅提供了一個(gè) foo 函數(shù),而是提供了幾十上百個(gè)類似的函數(shù),那么用戶在使用的時(shí)候就需要逐一添加錯(cuò)誤處理程序。

第二種辦法是我們代替用戶統(tǒng)一處理錯(cuò)誤,如下代碼所示:

// utils.js  export default {    foo(fn) {      try {        fn && fn()      } catch(e) {/* ... */}    },    bar(fn) {      try {        fn && fn()       } catch(e) {/* ... */}    },  }

這種辦法其實(shí)就是我們代替用戶編寫錯(cuò)誤處理程序,實(shí)際上我們可以進(jìn)一步封裝錯(cuò)誤處理程序?yàn)橐粋€(gè)函數(shù),假設(shè)叫它 &middot;callWithErrorHandling&middot;:

// utils.js  export default {    foo(fn) {      callWithErrorHandling(fn)    },   bar(fn) {      callWithErrorHandling(fn)    },  }  function callWithErrorHandling(fn) {    try {      fn && fn()    } catch (e) {      console.log(e)    }  }

可以看到代碼變得簡(jiǎn)潔多了,但簡(jiǎn)潔不是目的,這么做真正的好處是,我們有機(jī)會(huì)為用戶提供統(tǒng)一的錯(cuò)誤處理接口,如下代碼所示:

// utils.js  let handleError = null  export default {    foo(fn) {      callWithErrorHandling(fn)    },    // 用戶可以調(diào)用該函數(shù)注冊(cè)統(tǒng)一的錯(cuò)誤處理函數(shù)    resigterErrorHandler(fn) {      handleError = fn    } }  function callWithErrorHandling(fn) {    try {      fn && fn()    } catch (e) {      // 捕獲到的錯(cuò)誤傳遞給用戶的錯(cuò)誤處理程序      handleError(e)    }  }

我們提供了 resigterErrorHandler 函數(shù),用戶可以使用它注冊(cè)錯(cuò)誤處理程序,然后在 callWithErrorHandling 函數(shù)內(nèi)部捕獲到錯(cuò)誤時(shí),把錯(cuò)誤對(duì)象傳遞給用戶注冊(cè)的錯(cuò)誤處理程序。

這樣在用戶側(cè)的代碼就會(huì)非常簡(jiǎn)潔且健壯:

import utils from 'utils.js'  // 注冊(cè)錯(cuò)誤處理程序  utils.resigterErrorHandler((e) => {    console.log(e)  }) utils.foo(() => {/*...*/})  utils.bar(() => {/*...*/})

這時(shí)錯(cuò)誤處理的能力完全由用戶控制,用戶既可以選擇忽略錯(cuò)誤,也可以調(diào)用上報(bào)程序?qū)㈠e(cuò)誤上報(bào)到監(jiān)控系統(tǒng)。

實(shí)際上這就是 Vue 錯(cuò)誤處理的原理,你可以在源碼中搜索到 callWithErrorHandling 函數(shù),另外在 Vue 中我們也可以注冊(cè)統(tǒng)一的錯(cuò)誤處理函數(shù):

import App from 'App.vue'  const app = createApp(App)  app.config.errorHandler = () => {    // 錯(cuò)誤處理程序  }

良好的 Typescript 類型支持

Typescript 是微軟開源的編程語言,簡(jiǎn)稱 TS,它是 JS 的超集能夠?yàn)?JS 提供類型支持。現(xiàn)在越來越多的人和團(tuán)隊(duì)在他們的項(xiàng)目中使用 TS 語言,使用 TS 的好處很多,如代碼即文檔、編輯器的自動(dòng)提示、一定程度上能夠避免低級(jí) bug、讓代碼的可維護(hù)性更強(qiáng)等等。因此對(duì) TS 類型支持的是否完善也成為評(píng)價(jià)一個(gè)框架的重要指標(biāo)。

那如何衡量一個(gè)框架對(duì) TS 類型支持的好壞呢?這里有一個(gè)常見的誤區(qū),很多同學(xué)以為只要是使用 TS 編寫就是對(duì) TS 類型支持的友好,其實(shí)使用 TS 編寫框架和框架對(duì) TS 類型支持的友好是兩件關(guān)系不大的事兒??紤]到有的同學(xué)可能沒有接觸過 TS,所以這里不會(huì)做深入討論,我們只舉一個(gè)簡(jiǎn)單的例子,如下是使用 TS 編寫的函數(shù):

function foo(val: any) {    return val  }

這個(gè)函數(shù)很簡(jiǎn)單,它接受一個(gè)參數(shù) val 并且參數(shù)可以是任意類型(any),該函數(shù)直接將參數(shù)作為返回值,這說明返回值的類型是由參數(shù)決定的,參數(shù)如果是 number 類型那么返回值也是 number 類型,然后我們可以嘗試使用一下這個(gè)函數(shù),如下圖所示:

Vuejs的簡(jiǎn)單使用方法

類型支持不友好

在調(diào)用 foo 函數(shù)時(shí)我們傳遞了一個(gè)字符串類型的參數(shù) 'str',按照之前的分析,我們得到的結(jié)果 res 的類型應(yīng)該也是字符串類型,然而當(dāng)我們把鼠標(biāo) hover 到 res 常量上時(shí)可以看到其類型是 any,這并不是我們想要的結(jié)果,為了達(dá)到理想狀態(tài)我們只需要對(duì) foo 函數(shù)做簡(jiǎn)單的修改即可:

function foo<T extends any>(val: T): T {    return val  }

大家不需要理解這段代碼,我們直接來看一下現(xiàn)在的表現(xiàn):

Vuejs的簡(jiǎn)單使用方法

圖片類型友好

可以看到 res 的類型是字符字面量 'str' 而不是 any 了,這說明我們的代碼生效了。

通過這個(gè)簡(jiǎn)單的例子我們認(rèn)識(shí)到,使用 TS 編寫代碼與對(duì) TS 類型支持友好是兩件事,在編寫大型框架時(shí)想要做到完美的 TS 類型支持是一件很不容易的事情,大家可以查看 Vue 源碼中的 runtime-core/src/apiDefineComponent.ts 文件,整個(gè)文件里真正會(huì)在瀏覽器運(yùn)行的代碼其實(shí)只有 3 行,但是當(dāng)你打開這個(gè)文件的時(shí)候你會(huì)發(fā)現(xiàn)它整整有接近 200 行的代碼,其實(shí)這些代碼都是在做類型支持方面的事情,由此可見框架想要做到完善的類型支持是需要付出相當(dāng)大的努力的。

到此,關(guān)于“Vuejs的簡(jiǎn)單使用方法”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)砀鄬?shí)用的文章!

當(dāng)前題目:Vuejs的簡(jiǎn)單使用方法
當(dāng)前網(wǎng)址:http://muchs.cn/article30/jopcso.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站策劃、網(wǎng)頁設(shè)計(jì)公司、品牌網(wǎng)站制作、網(wǎng)站排名移動(dòng)網(wǎng)站建設(shè)、電子商務(wù)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

成都做網(wǎng)站