- 1. 基本問題
- 1.1. Vue.js 的特點
- 1.2. Vue.js 雙向綁定的原理
- 1.3. Vue.js 3.0 放棄defineProperty, 使用Proxy的原因
- 1.4. Vue 2 中給 data 中的對象屬性添加一個新的屬性時會發生什么?如何解決?
- 1.5. Computed和Watch的區別
- 1.6. Computed 和 Methods 的區別
- 1.7. 虛擬DOM,diff算法
- 1.8. 為何需要Virtual DOM?
- 1.9. 過濾器 (Filter)
- 1.10. 常見的事件修飾符及其作用
- 1.11. v-show指令和v-if指令的區別是什么?
- 1.12. v-model 是如何實現的,語法糖實際是什么
- 1.13. data為什么是一個函數而不是對象
- 1.14. Vue template 到 render 的過程
- 1.15. Vue data 中某一個屬性的值發生改變后,視圖會立即同步執行重新渲染嗎?
- 1.16. axios是什么
- 1.17. sass是什么?如何在vue中安裝和使用?
- 1.18. Vue.js頁面閃爍
- 1.19. 如何解決數據層級結構太深的問題
- 1.20. 在 Vue. js開發環境下調用API接口,如何避免跨域
- 1.21. 批量異步更新策略
- 1.22. vue 的 nextTick 方法的實現原理
- 1.23. Vue 組件 data 為什么必須是函數 ?
- 1.24. v-if和v-for一起使用的弊端及解決辦法
- 1.25. vue常用指令
- 1.26. 組件傳值方式有哪些
- 1.27. vue-loader是什么?使用它的用途有哪些?
- 2. 組件 Component
- 3. Vuex
- 4. Router
1. 基本問題
1.1. Vue.js 的特點
- 易用: 簡單,易學,上手快
- 靈活: (漸進式)不斷繁榮的生態系統,可以在一個庫和一套完整框架之間自如伸縮。
- 高效: 20kB min+gzip 運行大小;超快虛擬 DOM;最省心的優化
- 雙向綁定:開發效率高
- 基於組件的代碼共享
- Web項目工程化,增加可讀性、可維護性
1.2. Vue.js 雙向綁定的原理
Vue.js 2.0 采用數據劫持(Proxy 模式)結合發布者-訂閱者模式(PubSub 模式)的方式,通過 Object.defineProperty()來劫持各個屬性的 setter,getter,在數據變動時發布消息給訂閱者,觸發相應的監聽回調。
每個組件實例都有相應的watcher程序實例,它會在組件渲染的過程中把屬性記錄為依賴,之后當依賴項的setter被調用時,會通知watcher重新計算,從而致使它關聯的組件得以更新。
Vue.js 3.0, 放棄了Object.defineProperty ,使用更快的ES6原生 Proxy (訪問對象攔截器, 也稱代理器)
步驟:
-
需要observe的數據對象進行遞歸遍歷,包括子屬性對象的屬性,都加上setter和getter這樣的話,給這個對象的某個值賦值,就會觸發setter,那么就能監聽到了數據變化
-
compile解析模板指令,將模板中的變量替換成數據,然后初始化渲染頁面視圖,並將每個指令對應的節點綁定更新函數,添加監聽數據的訂閱者,一旦數據有變動,收到通知,更新視圖
-
Watcher訂閱者是Observer和Compile之間通信的橋梁,主要做的事情是: ①在自身實例化時往屬性訂閱器(dep)里面添加自己 ②自身必須有一個update()方法 ③待屬性變動dep.notice()通知時,能調用自身的update()方法,並觸發Compile中綁定的回調,則功成身退。
-
MVVM作為數據綁定的入口,整合Observer、Compile和Watcher三者,通過Observer來監聽自己的model數據變化,通過Compile來解析編譯模板指令,最終利用Watcher搭起Observer和Compile之間的通信橋梁,達到數據變化 -> 視圖更新;視圖交互變化(input) -> 數據model變更的雙向綁定效果。
1.3. Vue.js 3.0 放棄defineProperty, 使用Proxy的原因
Object.defineProperty缺陷
- 監控到數組下標的變化時,開銷很大。所以Vue.js放棄了下標變化的檢測;
- Object.defineProperty只能劫持對象的屬性,而Proxy是直接代理對象。Object.defineProperty需要遍歷對象的每個屬性,如果屬性值也是對象,則需要深度遍歷。而 Proxy 直接代理對象,不需要遍歷操作。
- Object.defineProperty對新增屬性需要手動進行Observe。vue2時需要使用 vm.$set 才能保證新增的屬性也是響應式
- Proxy支持13種攔截操作,這是defineProperty所不具有的
- Proxy 作為新標准,長遠來看,JS引擎會繼續優化 Proxy,但 getter 和 setter 基本不會再有針對性優化
1.4. Vue 2 中給 data 中的對象屬性添加一個新的屬性時會發生什么?如何解決?
視圖並未刷新。這是因為在Vue實例創建時,新屬性並未聲明,因此就沒有被Vue轉換為響應式的屬性,自然就不會觸發視圖的更新,這時就需要使用Vue的全局 api $set():this.$set(this.obj, 'new_property', 'new_value')
1.5. Computed和Watch的區別
- computed 計算屬性 : 依賴其它屬性值,並且 computed 的值有緩存,只有它依賴的 屬性值發生改變,下一次獲取 computed 的值時才會重新計算 computed 的值。
- watch 偵聽器 : 更多的是觀察的作用,無緩存性,類似於某些數據的監聽回調,每 當監聽的數據變化時都會執行回調進行后續操作。
運用場景:
- 當我們需要進行數值計算,並且依賴於其它數據時,應該使用 computed,因為可以利用 computed 的緩存特性,避免每次獲取值時,都要重新計算。
- 當我們需要在數據變化時執行異步或開銷較大的操作時,應該使用 watch,使用 watch 選項允許我們執行異步操作 ( 訪問一個 API ),限制我們執行該操作的頻率, 並在我們得到最終結果前,設置中間狀態。這些都是計算屬性無法做到的。
- 多個因素影響一個顯示,用Computed;一個因素的變化影響多個其他因素、顯示,用Watch;
1.6. Computed 和 Methods 的區別
- computed: 計算屬性是基於它們的依賴進行緩存的,只有在它的相關依賴發生改變時才會重新求值對於 method ,只要發生重新渲染,
- method 調用總會執行該函數
1.7. 虛擬DOM,diff算法
(1)讓我們不用直接操作DOM元素,只操作數據便可以重新渲染頁面
(2)虛擬dom是為了解決瀏覽器性能問題而被設計出來的
當操作數據時,將改變的dom元素緩存起來,都計算完后再通過比較映射到真實的dom樹上
(3)diff算法比較新舊虛擬dom。如果節點類型相同,則比較數據,修改數據;如果節點不同,直接干掉節點及所有子節點,插入新的節點;如果給每個節點都設置了唯一的key,就可以准確的找到需要改變的內容,否則就會出現修改一個地方導致其他地方都改變的情況。比如A-B-C-D, 我要插入新節點A-B-M-C-D,實際上改變的了C和D。但是設置了key,就可以准確的找到B C並插入
1.8. 為何需要Virtual DOM?
- 具備跨平台的優勢
- 操作 DOM 慢,js運行效率高。我們可以將DOM對比操作放在JS層,提高效率。
- 提升渲染性能
1.9. 過濾器 (Filter)
在Vue中使用filters來過濾(格式化)數據,filters不會修改數據,而是過濾(格式化)數據,改變用戶看到的輸出(計算屬性 computed ,方法 methods 都是通過修改數據來處理數據格式的輸出顯示。
使用場景: 比如需要處理時間、數字等的的顯示格式;
1.10. 常見的事件修飾符及其作用
.stop
:等同於 JavaScript 中的 event.stopPropagation() ,防止事件冒泡;.prevent
:等同於 JavaScript 中的 event.preventDefault() ,防止執行預設的行為(如果事件可取消,則取消該事件,而不停止事件的進一步傳播);.capture
:當元素發生冒泡時,先觸發帶有該修飾符的元素。若有多個該修飾符,則由外而內觸發。如 div1中嵌套div2中嵌套div3.capture中嵌套div4,那么執行順序為:div3=》div4=》div2=》div1.self
:只會觸發自己范圍內的事件,不包含子元素;.once
:只會觸發一次。
1.11. v-show指令和v-if指令的區別是什么?
v-show 僅僅控制元素的顯示方式,將 display 屬性在 block 和 none 來回切換;而v-if會控制這個 DOM 節點的存在與否。當我們需要經常切換某個元素的顯示/隱藏時,使用v-show會更加節省性能上的開銷;當只需要一次顯示或隱藏時,使用v-if更加合理。
1.12. v-model 是如何實現的,語法糖實際是什么
- 作用在表單元素上
v-model="message"
等同於v-bind:value="message" v-on:input="message=$event.target.value"
- 作用在組件上, 本質是一個父子組件通信的語法糖,通過prop和$.emit實現, 等同於
:value="message" @input=" $emit('input', $event.target.value)"
1.13. data為什么是一個函數而不是對象
JavaScript中的對象是引用類型的數據,當多個實例引用同一個對象時,只要一個實例對這個對象進行操作,其他實例中的數據也會發生變化。
而在Vue中,我們更多的是想要復用組件,那就需要每個組件都有自己的數據,這樣組件之間才不會相互干擾。
所以組件的數據不能寫成對象的形式,而是要寫成函數的形式。數據以函數返回值的形式定義,這樣當我們每次復用組件的時候,就會返回一個新的data,也就是說每個組件都有自己的私有數據空間,它們各自維護自己的數據,不會干擾其他組件的正常運行。
1.14. Vue template 到 render 的過程
- 調用parse方法將template轉化為ast(抽象語法樹, abstract syntax tree)
- 對靜態節點做優化。如果為靜態節點,他們生成的DOM永遠不會改變,這對運行時模板更新起到了極大的優化作用。
- 生成渲染函數. 渲染的返回值是VNode,VNode是Vue的虛擬DOM節點,里面有(標簽名,子節點,文本等等)
1.15. Vue data 中某一個屬性的值發生改變后,視圖會立即同步執行重新渲染嗎?
不會立即同步執行重新渲染。
Vue 實現響應式並不是數據發生變化之后 DOM 立即變化,而是按一定的策略進行 DOM 的更新。
Vue 在更新 DOM 時是異步執行的。只要偵聽到數據變化, Vue 將開啟一個隊列,並緩沖在同一事件循環中發生的所有數據變更。
如果同一個watcher被多次觸發,只會被推入到隊列中一次。這種在緩沖時去除重復數據對於避免不必要的計算和 DOM 操作是非常重要的。
然后,在下一個的事件循環"tick"中,Vue 刷新隊列並執行實際(已去重的)工作。
1.16. axios是什么
易用、簡潔且高效的http庫, 支持node端和瀏覽器端,支持Promise,支持攔截器等高級配置。
1.17. sass是什么?如何在vue中安裝和使用?
sass是一種CSS預編譯語言安裝和使用步驟如下。
- 用npm安裝加載程序( sass-loader、 css-loader等加載程序)。
- 在 webpack.config.js中配置sass加載程序。
1.18. Vue.js頁面閃爍
Vue. js提供了一個v-cloak指令,該指令一直保持在元素上,直到關聯實例結束編譯。當和CSS一起使用時,這個指令可以隱藏未編譯的標簽,直到實例編譯結束。用法如下。
[v-cloak]{
display:none;
}
<div v-cloak>{{ title }}</div>
1.19. 如何解決數據層級結構太深的問題
在開發業務時,經常會岀現異步獲取數據的情況,有時數據層次比較深,如以下代碼: span 'v-text="a.b.c.d"></span>
, 可以使用vm.$set手動定義一層數據: vm.$set("demo",a.b.c.d)
1.20. 在 Vue. js開發環境下調用API接口,如何避免跨域
config/ index.js內對 proxyTable項配置代理。
1.21. 批量異步更新策略
Vue 在修改數據后,視圖不會立刻更新,而是等同一事件循環中的所有數據變化完成之后,再統一進行視圖更新。
換句話說,只要觀察到數據變化,就會自動開啟一個隊列,並緩沖在同一個事件循環中發生的所以數據改變。在緩沖時會去除重復數據,從而避免不必要的計算和 DOM 操作。
1.22. vue 的 nextTick 方法的實現原理
- vue 用異步隊列的方式來控制 DOM 更新和 nextTick 回調先后執行
- microtask 因為其高優先級特性,能確保隊列中的微任務在一次事件循環前被執行完畢
1.23. Vue 組件 data 為什么必須是函數 ?
因為組件是可以復用的,JS 里對象是引用關系,如果組件 data 是一個對象,那么子組件中的 data 屬性值會互相污染。
所以一個組件的 data 選項必須是一個函數,因此每個實例可以維護一份被返回對象的獨立的拷貝。
1.24. v-if和v-for一起使用的弊端及解決辦法
由於v-for的優先級比v-if高,所以導致每循環一次就會去v-if一次,而v-if是通過創建和銷毀dom元素來控制元素的顯示與隱藏,所以就會不停的去創建和銷毀元素,造成頁面卡頓,性能下降。
解決辦法:
- 在v-for的外層或內層包裹一個元素來使用v-if
- 用computed處理
1.25. vue常用指令
- v-model 多用於表單元素實現雙向數據綁定(同angular中的ng-model)
- v-bind 動態綁定 作用: 及時對頁面的數據進行更改
- v-on:click 給標簽綁定函數,可以縮寫為@,例如綁定一個點擊函數 函數必須寫在methods里面
- v-for 格式: v-for="字段名 in(of) 數組json" 循環數組或json(同angular中的ng-repeat)
- v-show 顯示內容 (同angular中的ng-show)
- v-hide 隱藏內容(同angular中的ng-hide)
- v-if 顯示與隱藏 (dom元素的刪除添加 同angular中的ng-if 默認值為false)
- v-else-if 必須和v-if連用
- v-else 必須和v-if連用 不能單獨使用 否則報錯 模板編譯錯誤
- v-text 解析文本
- v-html 解析html標簽
- v-bind:class 三種綁定方法 1、對象型 '{red:isred}' 2、三元型 'isred?"red":"blue"' 3、數組型 '[{red:"isred"},{blue:"isblue"}]'
- v-once 進入頁面時 只渲染一次 不在進行渲染
- v-cloak 防止閃爍
- v-pre 把標簽內部的元素原位輸出
1.26. 組件傳值方式有哪些
- 父傳子:子組件通過props['xx'] 來接收父組件傳遞的屬性 xx 的值
- 子傳父:子組件通過 this.$emit('fnName',value) 來傳遞,父組件通過接收 fnName 事件方法來接收回調
- 其他方式:通過創建一個bus,進行傳值
- 使用Vuex
1.27. vue-loader是什么?使用它的用途有哪些?
2. 組件 Component
2.1. vue中如何編寫可復用的組件 (編寫組件的原則)
- 以組件功能命名
- 只負責ui的展示和交互動畫,不要在組件里與服務器打交道(獲取異步數據等)
- 可復用組件不會因組件使用的位置、場景而變化。盡量減少對外部條件的依賴。
2.2. 如何讓CSS只在當前組件中起作用?
在每一個Vue.js組件中都可以定義各自的CSS、 JavaScript代碼。如果希望組件內寫的CSS只對當前組件起作用,只需要在Style標簽添加Scoped屬性,即。
2.3. keep-alive是什么?
如果需要在組件切換的時候,保存一些組件的狀態防止多次渲染,就可以使用 keep-alive 組件包裹需要保存的組件。
兩個重要屬性,include 緩存組件名稱,exclude 不需要緩存的組件名稱。
2.4. 如何在 Vue. js動態插入圖片
對“src”屬性插值將導致404請求錯誤。應使用 v-bind:src (簡寫:src
)格式代替。
2.5. 父子組件的生命周期順序
- 加載渲染過程:
父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted - 子組件更新過程:父beforeUpdate->子beforeUpdate->子updated->父updated
- 父組件更新過程:父beforeUpdate->父updated
- 銷毀過程:父beforeDestroy->子beforeDestroy->子destroyed->父destroyed
3. Vuex
3.1. vuex的核心概念
- state => 基本數據
- getters => 從基本數據派生的數據
- mutations => 修改數據,同步
- actions => 修改數據,異步 (Action 提交的是 mutation,而不是直接變更狀態)
- modules => 模塊化Vuex
3.2. vuex是什么?怎么使用?哪種功能場景使用它?
Vuex 是一個專為 Vue.js 應用程序開發的狀態管理器,采用集中式存儲管理應用的所有組件的狀態,主要是為了多頁面、多組件之間的通信。
Vuex有5個重要的屬性,分別是 State、Getter、Mutation、Action、Module,由 view 層發起一個 Action 給 Mutation,在 Mutation 中修改狀態,返回新的狀態,通過 Getter暴露給 view層的組件或者頁面,頁面監測到狀態改變於是更新頁面。如果你的項目很簡單,最好不要使用 Vuex,對於大型項目,Vuex 能夠更好的幫助我們管理組件外部的狀態,一般可以運用在購物車、登錄狀態、播放等場景中。
3.3. 多個組件之間如何拆分各自的state,每塊小的組件有自己的狀態,它們之間還有一些公共的狀態需要維護,如何思考這塊
- 公共的數據部分可以提升至和他們最近的父組件,由父組件派發
- 公共數據可以放到vuex中統一管理,各組件分別獲取
4. Router
4.1. vue-router路由的兩種模式
vue-router中默認使用的是hash模式
- hash模式, 帶#。如:http://localhost:8080/#/pageA。改變hash,瀏覽器本身不會有任何請求服務器動作的,但是頁面狀態和url已經關聯起來了。
- history模式,不帶#, 如:http://localhost:8080/ 正常的而路徑,並沒有#。基於HTML5的 pushState、replaceState實現
4.2. vue-router如何定義嵌套路由
通過children 數組:
const router = new VueRouter({
routes: [
{
path: "/parentPage",
component: testPage,
children: [
{
path: "/childrenA",
component: childrenComponentA,
},
{
path: "/childrenB",
component: childrenComponentB,
},
],
},
{
// 其他和parentPage平級的路由
},
],
});
4.3. vue-router有哪幾種導航鈎子?
- 全局導航鈎子:router.beforeEach(to,from,next)
- 組件內的鈎子beforeRouteEnter (to, from, next) beforeRouteUpdate (to, from, next) beforeRouteLeave (to, from, next)
- 單獨路由獨享組件 beforeEnter: (to, from, next)
4.4. $route和$router的區別
- $route是“路由信息對象”,包括path,params,hash,query,fullPath,matched,name等路由信息參數。
- $router是“路由實例”對象包括了路由的跳轉方法,鈎子函數等
4.5. 路由之間跳轉的方式
- 聲明式(標簽跳轉)
- 編程式( js跳轉)
4.6. active-class是哪個組件的屬性
vue-router 模塊 的router-link組件