vue面試二十問
這是我自己在準備面試的時候,上網收集彙總的一些知識點,不能說你會這些就能找到自己心儀的工作,但你要想找到心儀的工作就必須會這些!
一、什麼是MVVM?
MVVM是Model-View-ViewModel的縮寫。Model 層代表資料模型;View 代表DOM,ViewModel 是一個同步View 和 Model的對象。
View 和 Model 之間并沒有直接的聯系,而是通過ViewModel進行互動,Model 和 ViewModel 之間的互動是雙向的, 是以View 資料的變化會同步到Model中,而Model 資料的變化也會立即反應到View 上。
優點:需關注業務邏輯,不需要手動操作DOM, 不需要關注資料狀态的同步問題,複雜的資料狀态維護完全由 MVVM 來統一管理。
二、vue的優點是什麼?
- 低耦合。視圖(View)可以獨立于Model變化和修改,一個ViewModel可以綁定到不同的"View"上,當View變化的時候Model可以不變,當Model變化的時候View也可以不變。
- 元件化,實作html的封裝和重用
- 虛拟DOM,不在使用原生DOM操作
- 運作速度快
三、元件之間的傳值?
1.父元件向子元件傳值:
使用自定義屬性綁定(v-bind:)相應的父元件資料 ,把自定義屬性在子元件的props屬性裡定義一下。
<sonCom v-bind:parentmsg="msg"></sonCom>
//子元件props屬性
props:['parentmsg']
2.子元件調用父元件方法并傳參(變向的子元件向父元件傳值)
通過$emit
//父元件方法
methods:{
show(data){
console.log(data)
}
}
//DOM
<sonCom v-on:func = 'show'></sonCom>
//子元件
this.$emit('func',123)//123可以改成子元件data中的資料,完成子元件向父元件傳值
3.兄弟元件傳值
通過event bus ,大項目vuex
1.建立一個空vue執行個體,并将它釋出到全局中(bus.js檔案)
import Vue from 'vue'
const bus = new Vue()
export default bus
2.在子元件一中引用bus.js,用bus.$emit(‘參數name’,value)方法傳參
3.在子元件二中引用bus.js,用bus.$on(‘參數名字’,callback(value))方式接受參數并處理
四、為什麼元件中的data必須是function?
元件中的data寫成一個函數,資料以函數傳回值的形式定義,保證每個元件執行個體都有自己的私有資料空間,不會造成污染。要不然所有元件執行個體共用一個data,改一個其他全改
五、v-show、v-if 差別,使用場景
v-show:本質控制css的display:none,隻編譯一次。切換開銷小,初始開銷大
适用場景:頻繁切換某節點
v-if:本質動态向DOM樹添加或者删除DOM元素,不停銷毀和建立比較消耗性能。初始渲染開銷小,切換開銷大
适用場景:不需要頻繁切換節點
六、擷取DOM
ref=“domName”,this.$refs.domName
七、為什麼要使用key?
需要使用key來給每個節點做一個唯一辨別,Diff算法就可以正确的識别此節點。作用主要是為了高效的更新虛拟DOM
八、雙向資料綁定
(大緻)
vue.js 是采用資料劫持結合釋出者-訂閱者模式的方式,通過
Object.defineProperty()
來劫持各個屬性的
setter
,
getter
,在資料變動時釋出消息給訂閱者,觸發相應的監聽回調
核心:Object.defineProperty()(詳看紅寶書)
手寫一個簡單的雙向資料綁定
let input = document.getElementById("input");
let text = document.getElementById("text");
let data = { value: "" };
Object.defineProperty(data, "value", {
set: function (val) {
text.innerHTML = val;
input.value = val;
},
get: function () {
return input.value;
}
});
input.onkeyup = function (e) {
data.value = e.target.value;
};
九、computed和watch的差別
computed:
- 支援緩存,隻有依賴資料發生改變,才會重新進行計算.
- 不支援異步,當computed内有異步操作時無效,無法監聽資料的變化.
适用場景:一個屬性受多個屬性影響(購物車商品結算)
watch:
- 不支援緩存,資料變,直接會觸發相應的操作;
- watch支援異步;
- 監聽的函數接收兩個參數,第一個參數是最新的值;第二個參數是輸入之前的值;
适用場景:當需要在資料變化時執行異步或開銷較大的操作時(搜尋資料)
十、常用事件修飾符
- .stop():等同于JavaScript中的event.stopPropagation(),防止事件冒泡。
- .prevent:等同于JavaScript中的event.preventDefault(),防止執行預設的行為。
- .capture:與事件冒泡的方向相反,事件捕獲由外到内。
- .self:隻會觸發自己範圍内的事件,不包含子元素
- .once:隻會觸發一次
十一、vue-router中的導航鈎子
- 全局 鈎子
const router = new VueRouter({ ... }); router.beforeEach((to, from, next) => { // do someting }); //to: Route,代表要進入的目标,它是一個路由對象 //from: Route,代表目前正要離開的路由,同樣也是一個路由對象 //: Function,這是一個必須需要調用的方法,而具體的執行效果則依賴 next 方法調用的參數
- 路由獨享鈎子
cont router = new VueRouter({
routes: [
{
path: '/file',
component: File,
beforeEnter: (to, from ,next) => {
// do someting
}
}
]
});
- 元件内的導航鈎子
const File = {
template: `<div>This is file</div>`,
beforeRouteEnter(to, from, next) {
// do someting
// 在渲染該元件的對應路由被 confirm 前調用
},
beforeRouteUpdate(to, from, next) {
// do someting
// 在目前路由改變,但是依然渲染該元件是調用
},
beforeRouteLeave(to, from ,next) {
// do someting
// 導航離開該元件的對應路由時被調用
}
}
十二、vue的兩個核心
- 資料驅動
viewModel,保證資料和視圖的一緻性
-
元件系統
元件化開發,優點很多,可以很好的降低資料之間的耦合度。将常用的代碼封裝成元件之後,就能高度的複用,提高代碼的可重用性。一個頁面/子產品可以由多個元件所組成。
十三、Vue生命周期
/*建立階段*/
//1.第一個生命周期函數
beforeCreate() {//表示執行個體完全被建立出來之前,會執行它
// console.log(this.msg);
// this.show();
/*
在beforeCreate生命周期執行的時候,data和methods中的資料還沒有初始化
*/
},
//2.第二個生命周期函數
created() {
console.log(this.msg + '--->created');
this.show();
//在created中,data,和methods 已經被初始化了
},
//3.第三個生命周期函數
beforeMount() {
//表示 模闆已經在記憶體中編譯完成了,但是尚未把模闆渲染到頁面中
console.log(document.getElementById("me").innerHTML + '--->beforeMount')
//在beforeMount 執行的時候,頁面中元素還沒有被真正替換過來,隻是之前寫的一些模闆字元串
},
//4.第四個生命周期函數
mounted() {
//表示 模闆已經在記憶體中編譯完成了,但是已經把模闆渲染到頁面中
console.log(document.getElementById("me").innerHTML + '--->mounted')
//mounted 執行的時候,頁面中元素已經被真正替換過來
//隻要執行完mounted,就表示整個Vue執行個體已經初始化完畢了,此時元件已經脫離了建立階段,進入了運作階段。
},
/*運作階段*/
//1.第一個運作生命周期函數
beforeUpdate() { //這時候表示我們的界面還沒有被更新,【資料更新了】
console.log('頁面中msg的值' + document.getElementById("me").innerHTML + '--->beforeUpdate')
console.log("Data中msg值為:" + this.msg)
//資料是最新的,頁面沒有同步
},
//2.第二個運作生命周期函數
updated() {
console.log('頁面中msg的值' + document.getElementById("me").innerHTML + '--->updated')
console.log("Data中msg值為:" + this.msg)
//資料是最新的,頁面已經同步
},
/*銷毀階段*/
//1.第一個銷毀生命周期函數
beforeDestroy() { //Vue執行個體從運作到銷毀階段
//Vue執行個體上所有的Data和所有的methods,以及過濾器、指令。。。都處于可用狀态,此時還沒有真正執行銷毀過程
},
//1.第二個銷毀生命周期函數
destroyed() {
//Vue執行個體上所有的Data和所有的methods,以及過濾器、指令。。。都已經銷毀。
},
});
十四、vuex
1.Vuex是什麼
Vuex是實作元件全局狀态(資料)管理的一種機制,可以友善實作組價之間的資料的共享
[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-28jCMlgP-1599554454926)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1598779618877.png)]
- Vuex優點
- 能夠在Vuex中集中管理共享的資料,易于開發和後期維護
- 能夠高效的實作元件之間的資料共享,提高開發效率
- 儲存在vuex中的資料都是響應式的,能夠實時保持資料與頁面的同步
- Vuex四個核心概念
-
State
State提供唯一的公共資料源,所有共享的資料都要統一放到Store的State中進行存儲。state裡面存放的資料是響應式的,Vue元件從store中讀取資料,若是store中的資料發生改變,依賴這個資料的元件也會發生更新
元件中通路:
//方式一: this.$store.state.myDate //方式二: import { mapState } from 'vuex' computed:{ ...mapState(['myData']) }
-
Mutation
Mutation用于變更Store中的資料,可以集中監控資料變化(不能寫異步代碼)
//store.js中 mutation:{ func(state,argument){ fn() } } //元件中調用 this.$store.commit('func',argument) //第二種方法 import { mapMutations } from 'vuex' methods:{ ...mapMutations(['func']), myfunc(){ this.func(argument) } }
-
Action
如果通過異步操作變更資料,必須通過Action,而不能使用Mutation,但是在Action 中還是要通過觸發Mutation的方式間接變更資料
//store.js中 actions:{ func(context,argument){ setTimeout(()=>{ context.commit('mutation裡的function',argument ) },wait) } } //元件中 this.$store.dispatch('func',argument) //方式二: import { mapActions } from 'vuex' methods:{ ...mapActions(['func']), myfunc(){ this.func(argument) } }
-
Getter
用于對Store中的資料進行加工處理形成新的資料。Store資料改變,Getter的資料也會跟着變化(像vue裡的計算屬性)
getters:{ newData(state){ return `新值為${state.myData}` } } //方式一: this.$store.getters.newData //方式二: import { mapGetters } from 'vuex' computed:{ ...mapGetters(['newData']) }
-
modules
在Vue中State使用是單一狀态樹結構,應該的所有的狀态都放在state裡面,如果項目比較複雜,那state是一個很大的對象,store對象也将對變得非常大,難于管理。
module:可以讓每一個子產品擁有自己的state、mutation、action、getters,使得結構非常清晰,友善管理。
const moduleA = { state: { ... }, mutations: { ... }, actions: { ... }, getters: { ... } } const moduleB = { state: { ... }, mutations: { ... }, actions: { ... } } const store = new Vuex.Store({ modules: { a: moduleA, b: moduleB})
-
十五、單頁面應用(SPA)
SPA->就是隻有一個首頁面的應用,浏覽器一開始要加載所有必須的 html、js、css。互動時候由路由程式動态載入,單頁面的頁面跳轉僅重新整理局部資源,多用于pc端
優點:
- 良好的互動體驗:單頁應用的内容的改變不需要重新加載整個頁面。
- 減輕伺服器壓力:伺服器隻用出資料就可以,不用管展示邏輯和頁面合成,吞吐能力會提高幾倍。
- 良好的前後端分離:後端不用負責模闆渲染,隻需要進行資料的存儲與計算
缺點:
- 對SEO不太友好,不利于seo的搜尋
- 需要自行實作導航的前進後退;
- 頁面複雜度高、初次加載耗時多
十六、虛拟DOM
- 什麼是虛拟DOM?
虛拟 dom 是相對于浏覽器所渲染出來的真實 dom 的,在react,vue等技術出現之前,我們要改變頁面展示的内容隻能通過周遊查詢 dom 樹的方式找到需要修改的 dom 然後修改樣式行為或者結構,來達到更新 ui 的目的。
這種方式相當消耗計算資源,因為每次查詢 dom 幾乎都需要周遊整顆 dom 樹,如果建立一個與 dom 樹對應的虛拟 dom 對象( js 對象),以對象嵌套的方式來表示 dom 樹,那麼每次 dom 的更改就變成了 js 對象的屬性的更改,這樣一來就能查找 js 對象的屬性變化要比查詢 dom 樹的性能開銷小。
- 為什麼DOM性能開銷大?
其實并不是查詢 dom 樹性能開銷大而是 dom 樹的實作子產品和 js 子產品是分開的這些跨子產品的通訊增加了成本,以及 dom 操作引起的浏覽器的回流和重繪,使得性能開銷巨大,原本在 pc 端是沒有性能問題的,因為 pc 的計算能力強,但是随着移動端的發展,越來越多的網頁在智能手機上運作,而手機的性能參差不齊,會有性能問題。
- vue大緻解決方法
每次更新 dom 都盡量避免重新整理整個頁面,而是有針對性的去重新整理那被更改的一部分、也就是diff算法
- diff算法的大緻思路
我們先根據真實DOM生成一顆
virtual DOM
,當
virtual DOM
某個節點的資料改變後會生成一個新的
Vnode
,然後
Vnode
和
oldVnode
作對比,發現有不一樣的地方就直接修改在真實的DOM上,然後使
oldVnode
的值為
Vnode
。diff的過程就是調用名為
patch
的函數,比較新舊節點,一邊比較一邊給真實的DOM打更新檔。
具體實作可以參考https://www.cnblogs.com/wind-lanyan/p/9061684.html
十七、vue-router的兩種模式
1、hash ——即位址欄URL中的#符号(此hsah 不是密碼學裡的散列運算)。 比如這個URL:http://www.abc.com/#/hello, hash 的值為#/hello。它的特點在于:hash 雖然出現URL中,但不會被包含在HTTP請求中,對後端完全沒有影響,是以改變hash不會重新加載頁面。
2、history ——利用了HTML5 History Interface 中新增的pushState() 和replaceState() 方法。(需要特定浏覽器支援) 這兩個方法應用于浏覽器的曆史記錄站,在目前已有的back、forward、go 的基礎之上,它們提供了對曆史記錄進行修改的功能。隻是當它們執行修改是,雖然改變了目前的URL,但你浏覽器不會立即向後端發送請求。history模式,會出現404 的情況,需要背景配置。—>利于seo
十八、Keep-alive元件
元件切換的時,保持這些元件的狀态,以避免反複重渲染導緻的性能問題(Vue 會建立了一個新的執行個體)
十九、Slot插槽
插槽含義:就是引入子元件後,在插入子元件元素中添加資訊或者标簽,使得子元件的指定位置插入資訊或者标簽
插槽有三種:預設插槽、具名插槽、作用域插槽
二十、nextTick
在Vue生命周期的
created()
鈎子函數進行的DOM操作一定要放在
Vue.nextTick()
的回調函數中
changeMsg() {
this.msg = "Hello world."
this.msg1 = this.$refs.msgDiv.innerHTML //原來内容
this.$nextTick(() => {
this.msg2 = this.$refs.msgDiv.innerHTML //Hello world
})
this.msg3 = this.$refs.msgDiv.innerHTML//原來内容
}
//其根本原因是因為Vue中DOM更新是異步的
)
十九、Slot插槽
插槽含義:就是引入子元件後,在插入子元件元素中添加資訊或者标簽,使得子元件的指定位置插入資訊或者标簽
插槽有三種:預設插槽、具名插槽、作用域插槽
二十、nextTick
在Vue生命周期的
created()
鈎子函數進行的DOM操作一定要放在
Vue.nextTick()
的回調函數中
changeMsg() {
this.msg = "Hello world."
this.msg1 = this.$refs.msgDiv.innerHTML //原來内容
this.$nextTick(() => {
this.msg2 = this.$refs.msgDiv.innerHTML //Hello world
})
this.msg3 = this.$refs.msgDiv.innerHTML//原來内容
}
//其根本原因是因為Vue中DOM更新是異步的