這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 背景 最近心血來潮,想要在本地開發時,也用CDN的方式引入 Vue,想著既然通過CDN引入了,那麼在項目中就沒必要再 import Vue,然後把項目中引入 Vue 的地方都刪掉,結果改完後,界面看似正常運行,但數據變更後,界面沒有重新渲 ...
這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助
背景
最近心血來潮,想要在本地開發時,也用CDN的方式引入 Vue,想著既然通過CDN引入了,那麼在項目中就沒必要再 import Vue,然後把項目中引入 Vue 的地方都刪掉,結果改完後,界面看似正常運行,但數據變更後,界面沒有重新渲染。經過一番折騰,終於定位到問題。
vue版本:Vue2.7+;打包工具:Vite;核心插件:@vitejs/plugin-vue2;
在解決這個問題之前,我們需要先搞清楚兩個事情:1)@vitejs/plugin-vue2的作用;2)@vitejs/plugin-vue2的工作原理。
@vitejs/plugin-vue2的作用
vite不做贅述,具體內容看官網。
在聊@vitejs/plugin-vue2的作用之前,我們必須搞清楚什麼是單文件組件?
Vue 的單文件組件 (即
*.vue
文件,英文 Single-File Component,簡稱 SFC) 是一種特殊的文件格式,使我們能夠將一個 Vue 組件的模板、邏輯與樣式封裝在單個文件中。
很明顯,這是 Vue 自己定義並實現的組件模板,不能直接在瀏覽器中運行,在實際項目中,我們一般會使用集成了 SFC 編譯器的構建工具,比如 Vite 或者 Vue CLI (基於 webpack)。本文只討論使用 Vite 的情況。
@vitejs/plugin-vue2 就是提供對 Vue 2.7 的單文件組件支持。如果大家的Vue項目是使用 Vite ,下麵這段代碼應該不陌生:
// vite.config.js import vue from '@vitejs/plugin-vue2' export default { plugins: [vue()] }
想要*.vue
文件能正常在瀏覽器中運行,我們就需要做以上配置。
@vitejs/plugin-vue2的工作原理
扒了一下這個插件的源碼,發現一行至關重要的代碼,如下圖:
這個插件在工作時,要依賴 Vue,上面紅色框標註的部分,就是它如何去查找 Vue 的邏輯。如果我們在配置文件中,配置了 Vue alias,則會使用配置的alias,否則預設使用本地安裝的 Vue。如何使用alias,參加vite文檔alias。
這裡可以先記住這個邏輯,後面有用。
問題分析
我們先看看復現問題的路徑:1. 在 index.html 直接引入 Vue CDN;2. 刪除項目中import Vue 的代碼。
然後本地Run起來,界面看起來很正常,但是,修改數據後,發現界面沒有重新渲染。為什麼呢?
我們先看經過 @vitejs/plugin-vue2 處理之後生成的代碼是什麼樣的,如下圖:
因為我在項目中,沒有為 Vue 配置 alias,所以**@vitejs/plugin-vue2直接使用了我本地安裝的 Vue**。原因見@vitejs/plugin-vue2的工作原理
但問題是,我在項目中刪除了 import Vue 的代碼,這個時候界面之所以能正常運行,是因為我在index.html引入的 Vue 有正常初始化,這裡就產生了一個衝突:
最後@vitejs/plugin-vue2處理的產物中,是使用本地 Vue 導出的 Ref 來處理響應式變數,但真正執行 Vue 初始化動作依賴的卻是 CDN。這會帶來什麼問題?
也就是說,數據變化後,能正常執行響應式邏輯,但是 notify 的時候,卻找不到可通知對象(此時,是觸發了 本地安裝 Vue 的代碼邏輯),因為初始化的時候,收集依賴關係時,執行的是 CDN 導入的 Vue 代碼邏輯,這兩者之間沒有正確建立聯繫,導致數據變了,但是界面沒有重新渲染。
如果看不懂,可能需要瞭解一下 Vue 初始化時 幹了啥,主要是要知道如何收集依賴,並觸發DOM更新,要理解Watcher是如何工作的。
如何解決
很簡單,我們只要保證初始化 和 最後數據變化執行 的代碼邏輯 來自同一個源就可以,而不是一個來自 本地安裝的 Vue,一個來自CDN。
最簡單的方法,就是在項目中手動import Vue,這個時候,初始化的時候,就會走 本地安裝的 Vue 的代碼邏輯。
不過這樣的話,還是會載入兩次 Vue,不是特別優雅。也可以使用 CDN 載入的 Vue,也得在項目中 import Vue,只不過引入的 路徑要變化。
import Vue from '具體的 Vue 路徑'
可以通過配置 alias,簡化 from 後面的路徑,變成 import Vue from 'Vue'。