1. 不依賴vue-cli腳手架創建vue項目
我們一般創建vue項目都是通過vue-cli腳手架去創建,這次我嘗試了通過文檔完成所有項目配置包括webpack、ant-design-vue、vue-router、vuex等
項目源碼: https://github.com/wzp123321/myVueJSProByMySelf.git
1.新建項目
2.使用vscode打開項目
3.初始化
4.安裝基本的 npm 包
5.創建文件夾以及文件
6.配置webpack.config.js
在這之前先安裝一些依賴
模板解析依賴:
樣式依賴:
css-loader: https://webpack.docschina.org/loaders/css-loader/
文件載入依賴
解析es6語法依賴: https://github.com/babel/babel-loader
這是一個webpack插件,可簡化HTML文件的創建以服務您的webpack捆綁軟體
現在就可以配置webpack.config.js,如果有什麼不清楚的可以參考官網 https://webpack.docschina.org/configuration/
7.安裝解析依賴 https://github.com/webpack/webpack-dev-server
8.修改package.json文件
9.配置babel,創建.babelrc文件
修改webpack.config.js
如果編譯時報錯的話可能是因為你沒有安裝依賴:
10.主要文件:
app.vue:
index.js:
html文件:
Vue項目文件夾大致參考
1.混入 (mixins) 是一種分發 Vue 組件中可復用功能的非常靈活的方式。混入對象可以包含任意組件選項。當組件使用混入對象時,所有混入對象的選項將被混入該組件本身的選項。
mixins文件夾下可以寫各種調用ajax請求方法的方法,然後在需要調用這些方法請求數據的文件中:
這里的getCourseList文件中有請求需要的參數以及請求完成之後獲取的數據 直接在文件類似this.getAllDemoClass();就能調用方法
2.components通用組件存放文件夾:
在這個文件夾下封裝了項目需要的組件 然後在components下的index.js中向外暴露即可 然後在使用組件的文件中引用components即可
後續:
1.引入ant-design-vue:
具體引入操作可見官網 https://vue.ant.design/docs/vue/introce-cn/
2.引入Vue Router https://router.vuejs.org/zh/installation.html
路由配置文件:router/index.js
3.引入vuex
新建store/index.js
news/index.vue
4.頁面頂部進度條插件Nprogress
使用:
2. 【面試題解析】從 Vue 源碼分析 key 的作用
最近看了面試題中有一個這樣的題, v-for 為什麼要綁定 key?
Vue 中 key 很多人都弄不清楚有什麼作用,甚至還有些人認為不綁定 key 就會報錯。
其實沒綁定 key 的話,Vue 還是可以正常運行的,報警告是因為沒通過 Eslint 的檢查。
接下來將通過源碼一步步分析這個 key 的作用。
Virtual DOM 最主要保留了 DOM 元素的層級關系和一些基本屬性,本質上就是一個 JS 對象。相對於真實的 DOM,Virtual DOM 更簡單,操作起來速度更快。
如果需要改變 DOM,則會通過新舊 Virtual DOM 對比,找出需要修改的節點進行真實的 DOM 操作,從而減小性能消耗。
傳統的 Diff 演算法需要遍歷一個樹的每個節點,與另一棵樹的每個節點對比,時間復雜度為 O(n²)。
Vue 採用的 Diff 演算法則通過逐級對比,大大降低了復雜性,時間復雜度為 O(n)。
VNode 更新首先會經過 patch 函數, patch 函數源碼如下:
vnode 表示更新後的節點,oldVnode 表示更新前的節點,通過對比新舊節點進行操作。
1、vnode 未定義,oldVnode 存在則觸發 destroy 的鉤子函數
2、oldVnode 未定義,則根據 vnode 創建新的元素
3、oldVnode 不為真實元素並且 oldVnode 與 vnode 為同一節點,則會調用 patchVnode 觸發更新
4、oldVnode 為真實元素或者 oldVnode 與 vnode 不是同一節點,另做處理
接下來會進入 patchVnode 函數,源碼如下:
1、vnode 的 text 不存在,則會比對 oldVnode 與 vnode 的 children 節點進行更新操作
2、vnode 的 text 存在,則會修改 DOM 節點的 text
接下來在 updateChildren 函數內就可以看到 key 的用處。
key 的作用主要是給 VNode 添加唯一標識,通過這個 key,可以更快找到新舊 VNode 的變化,從而進一步操作。
key 的作用主要表現在以下這段源碼中。
updateChildren 過程為:
1、分別用兩個指針(startIndex, endIndex)表示 oldCh 和 newCh 的頭尾節點
2、對指針所對應的節點做一個兩兩比較,判斷是否屬於同一節點
3、如果4種比較都沒有匹配,那麼判斷是否有 key,有 key 就會用 key 去做一個比較;無 key 則會通過遍歷的形式進行比較
4、比較的過程中,指針往中間靠,當有一個 startIndex > endIndex,則表示有一個已經遍歷完了,比較結束
從 VNode 的渲染過程可以得知,Vue 的 Diff 演算法先進行的是同級比較,然後再比較子節點。
子節點比較會通過 startIndex、endIndex 兩個指針進行兩兩比較,再通過 key 比對子節點。如果沒設置 key,則會通過遍歷的方式匹配節點,增加性能消耗。
所以不綁定 key 並不會有問題,綁定 key 之後在性能上有一定的提升。
綜上,key 主要是應用在 Diff 演算法中,作用是為了更快速定位出相同的新舊節點,盡量減少 DOM 的創建和銷毀的操作。
希望以上內容能夠對各位小夥伴有所幫助,祝大家面試順利。
Vue 的文檔中對 key 的說明如下:
關於就地修改,關鍵在於 sameVnode 的實現,源碼如下:
可以看出,當 key 未綁定時,主要通過元素的標簽等進行判斷,在 updateChildren 內會將 oldStartVnode 與 newStartVnode 判斷為同一節點。
如果 VNode 中只包含了文本節點,在 patchVnode 中可以直接替換文本節點,而不需要移動節點的位置,確實在不綁定 key 的情況下效率要高一丟丟。
某些情況下不綁定 key 的效率更高,那為什麼大部分Eslint的規則還是要求綁定 key 呢?
因為在實際項目中,大多數情況下 v-for 的節點內並不只有文本節點,那麼 VNode 的位元組點就要進行銷毀和創建的操作。
相比替換文本帶來的一丟丟提升,這部分會消耗更多的性能,得不償失。
了解了就地修改,那麼我們在一些簡單節點上可以選擇不綁定 key,從而提高性能。
如果你喜歡我的文章,希望可以關注一下我的公眾號【前端develop】
3. vue-lazyload 源碼解析
/src/lazy.js
定義變數接收實例化參數。
lazy.js 默認導出一個函數,該函數返回一個 Lazy 類,形成閉包,保持對 Vue 的引用。
判斷是否支持Webp圖片
/src/listener.js
定義變數接收實例化參數。
filter 方法將配置的 filter 對象中的方法執行,接收兩個參數,一個為 ReactiveListener 實例,一個為 options 參數對象。
initState 方法給元素添加 data-set 屬性,值為圖片地址 src,並且定義了圖片狀態對象 state 。在 Lazy 中已經根據像素比選擇了最適配屏幕的圖片,顧這里不需要考慮 srcset 屬性。另外,我們自定義指令是 v-lazy,到目前為止,還沒有給圖片的 src 屬性賦值。
render 方法,是在 Lazy 中實例化 ReactiveListener 時傳遞過來的參數。
回過頭再來結合 lazy.js 中的 lazyLoadHandler 方法與 ReactiveListener 暴露的方法來看。
/src/lazy-container.js
LazyContainer 的核心是 container 下的選擇器selector(默認 img 標簽)遍歷後調用 lazy 的 add 方法進行綁定,自定義指令 v-lazyload-container。
/src/lazy-component.js
上述實現元素綁定主要是通過自定義指令 v-lazy , v-lazy-container 。那麼 LazyComponent 則是通過注冊的 lazy-component 組件,完成綁定,默認渲染成為 div 標簽,作為 img 的容器。
/src/lazy-image.js
通 LazyComponent 組件,只不過 LazyImage 注冊的 lazy-image 組件,渲染成的是 img 標簽,多了 src 屬性。
通過自定義指令 v-lazy 將設置背景圖的元素或者 img元素,通過 _addListenerTarget 方法收集與數組 TargetQueue 中,並遍歷觸發懶載入的方法, addEventListener 綁定在該元素上,觸發的事件為 lazyLoadHandler ;
在需要懶載入的元素上設置屬性 data-src ,這是期望的圖片地址(filter 配置項可以預先過濾賦值),元素上自定義 lazyLoad 表示圖片狀態(狀態變更後,adapter 中觸發回調);
ListenerQueue 數組中收集的是 ReactiveListener 類的實例,主要是用於懶載入不同狀態下的圖片載入,loading - loaded - error;
當觸發 EventListener 了,執行 lazyLoadHandler 方法,根據演算法,進入 viewport 後, ReactiveListener 元素如果與觸發元素匹配,則進行圖片的載入及渲染。