常见的前端vue面试题
常見(jiàn)的前端vue面試題
1、請(qǐng)講述下VUE的MVVM的理解?
MVVM 是 Model-View-ViewModel的縮寫(xiě),即將數(shù)據(jù)模型與數(shù)據(jù)表現(xiàn)層通過(guò)數(shù)據(jù)驅(qū)動(dòng)進(jìn)行分離,從而只需要關(guān)系數(shù)據(jù)模型的開(kāi)發(fā),而不需要考慮頁(yè)面的表現(xiàn),具體說(shuō)來(lái)如下:
Model 代表數(shù)據(jù)模型:主要用于定義數(shù)據(jù)和操作的業(yè)務(wù)邏輯。
View 代表頁(yè)面展示組件(即dom展現(xiàn)形式):負(fù)責(zé)將數(shù)據(jù)模型轉(zhuǎn)化成UI 展現(xiàn)出來(lái)。
ViewModel 為model和view之間的橋梁:監(jiān)聽(tīng)模型數(shù)據(jù)的改變和控制視圖行為、處理用戶交互。通過(guò)雙向數(shù)據(jù)綁定把 View 層和 Model 層連接了起來(lái),而View 和 Model 之間的同步工作完全是自動(dòng)的,無(wú)需人為干涉
在MVVM架構(gòu)下,View 和 Model 之間并沒(méi)有直接的聯(lián)系,而是通過(guò)ViewModel進(jìn)行交互,Model 和 ViewModel 之間的交互是雙向的, 因此View 數(shù)據(jù)的變化會(huì)同步到Model中,而Model 數(shù)據(jù)的變化也會(huì)立即反應(yīng)到View 上。
2、VUE的生命周期及理解?
答:總共分為8個(gè)階段,具體為:創(chuàng)建前/后,載入前/后,更新前/后,銷(xiāo)毀前/后。
創(chuàng)建前/后: 在beforeCreated階段:vue實(shí)例的掛載元素$el和數(shù)據(jù)對(duì)象data都為undefined,還未初始化;在created階段,vue實(shí)例的數(shù)據(jù)對(duì)象data有了, $el還沒(méi)有。
載入前/后: 在beforeMount階段,vue實(shí)例的$el和data都初始化了,但還是掛載之前為虛擬的dom節(jié)點(diǎn),data.message還未替換;在mounted階段,vue實(shí)例掛載完成,data.message成功渲染。
更新前/后: 當(dāng)data變化時(shí),會(huì)觸發(fā)beforeUpdate和updated方法。
銷(xiāo)毀前/后: 在執(zhí)行destroy方法后,對(duì)data的改變不會(huì)再觸發(fā)周期函數(shù),說(shuō)明此時(shí)vue實(shí)例已經(jīng)解除了事件監(jiān)聽(tīng)以及和dom的綁定,但是dom結(jié)構(gòu)依然存在。
具體講解及應(yīng)用
beforeCreate: 在new一個(gè)vue實(shí)例后,只有一些默認(rèn)的生命周期鉤子和默認(rèn)事件,其他的東西都還沒(méi)創(chuàng)建,data和methods中的數(shù)據(jù)都還沒(méi)有初始化。不能在這個(gè)階段使用data中的數(shù)據(jù)和methods中的方法
create: data 和 methods都已經(jīng)被初始化好了,如果要調(diào)用 methods 中的方法,或者操作 data 中的數(shù)據(jù),最早可以在這個(gè)階段中操作
beforeMount: 執(zhí)行到這個(gè)鉤子的時(shí)候,在內(nèi)存中已經(jīng)編譯好了模板了,但是還沒(méi)有掛載到頁(yè)面中,此時(shí),頁(yè)面還是舊的,不能直接操作頁(yè)面的dom和獲取dom對(duì)象
mounted: 執(zhí)行到這個(gè)鉤子的時(shí)候,就表示Vue實(shí)例已經(jīng)初始化完成了。此時(shí)組件脫離了創(chuàng)建階段,進(jìn)入到了運(yùn)行階段。如果我們想要通過(guò)插件操作頁(yè)面上的DOM節(jié)點(diǎn),最早可以在和這個(gè)階段中進(jìn)行
beforeUpdate: 當(dāng)執(zhí)行這個(gè)鉤子時(shí),頁(yè)面中的顯示的數(shù)據(jù)還是舊的,data中的數(shù)據(jù)是更新后的,頁(yè)面還沒(méi)有和最新的數(shù)據(jù)保持同步
updated: 頁(yè)面顯示的數(shù)據(jù)和data中的數(shù)據(jù)已經(jīng)保持同步了,都是最新的
beforeDestory: Vue實(shí)例從運(yùn)行階段進(jìn)入到了銷(xiāo)毀階段,這個(gè)時(shí)候上所有的data和 methods、指令、過(guò)濾器 ……都是處于可用狀態(tài)。還沒(méi)有真正被銷(xiāo)毀
destroyed: 這個(gè)時(shí)候上所有的data和methods、指令、過(guò)濾器 ……都是處于不可用狀態(tài)。組件已經(jīng)被銷(xiāo)毀了。
3、v-if和v-show的區(qū)別?
共同點(diǎn): 都能控制元素的顯示和隱藏;
不同點(diǎn): 實(shí)現(xiàn)本質(zhì)方法不同,v-show本質(zhì)就是通過(guò)控制css中的display設(shè)置為none,控制隱藏,只會(huì)編譯一次;v-if是動(dòng)態(tài)的向DOM樹(shù)內(nèi)添加或者刪除DOM元素,若初始值為false,就不會(huì)編譯了。而且v-if不停的銷(xiāo)毀和創(chuàng)建比較消耗性能。
如果要頻繁切換某節(jié)點(diǎn),使用v-show(切換開(kāi)銷(xiāo)比較小,初始開(kāi)銷(xiāo)較大)。如果不需要頻繁切換某節(jié)點(diǎn)使用v-if(初始渲染開(kāi)銷(xiāo)較小,切換開(kāi)銷(xiāo)比較大)。
4、v-if和v-for同時(shí)使用在同一個(gè)標(biāo)簽上的表現(xiàn)?
當(dāng)v-if與v-for一起使用時(shí),v-for具有比v-if更高的優(yōu)先級(jí),這意味著v-if將分別重復(fù)運(yùn)行于每個(gè)v-for循環(huán)中。
所以,不推薦v-if和v-for同時(shí)使用。如果v-if和v-for一起用的話,vue中的的會(huì)自動(dòng)提示v-if應(yīng)該放到外層去
5、v-for中的key的理解?
需要使用key來(lái)給每個(gè)節(jié)點(diǎn)做一個(gè)唯一標(biāo)識(shí),Diff算法就可以正確的識(shí)別此節(jié)點(diǎn)。主要是為了高效的更新虛擬DOM。
6、vue中transition的理解?
1)定義transition時(shí)需要設(shè)置對(duì)應(yīng)的name,具體語(yǔ)法為:< transition name=“fade”>需要?jiǎng)赢?huà)的內(nèi)容或者組件或者頁(yè)面< /transition>
2)過(guò)渡動(dòng)畫(huà)主要包含6個(gè)class,分別為:
v-enter:定義元素進(jìn)入過(guò)渡的初始狀態(tài),在元素插入前生效,插入后一幀刪除,
v-enter-active:在元素插入前生效,在動(dòng)畫(huà)完成后刪除,
v-enter-to:在元素插入后一幀生效,在動(dòng)畫(huà)完成后刪除,
v-leave:離開(kāi)過(guò)渡的初始狀態(tài),在元素離開(kāi)時(shí)生效,下一幀刪除
v-leave-active:在離開(kāi)過(guò)渡時(shí)生效,在動(dòng)畫(huà)完成后刪除
v-leave-to:離開(kāi)過(guò)渡結(jié)束狀態(tài),在離開(kāi)過(guò)渡下一幀生效,在動(dòng)畫(huà)完成后刪除
??:v會(huì)轉(zhuǎn)化為對(duì)應(yīng)的transition的name值
3)當(dāng)然我們也可以自定義這六個(gè)class 可以直接在transition中設(shè)置對(duì)應(yīng)的屬性為對(duì)應(yīng)的class名稱(chēng),屬性有:enter-class,enter-active-class,enter-to-class,leave-class,leave-active-class,leave-to-class
4)在同時(shí)使用過(guò)渡和css動(dòng)畫(huà)的時(shí)候 可以設(shè)置type屬性來(lái)制定vue內(nèi)部機(jī)制監(jiān)聽(tīng)transitioned或者animationed事件來(lái)完成過(guò)渡還是動(dòng)畫(huà)的監(jiān)聽(tīng)
5)如果需要設(shè)置對(duì)應(yīng)的過(guò)渡時(shí)間,可以直接設(shè)置屬性duration,可以直接接收一個(gè)數(shù)字(單位為毫秒),也可以接收一個(gè)對(duì)象{enter:1000,leave:300}
6)也可以設(shè)置過(guò)渡的鉤子函數(shù),具體有:before-enter,enter,after-enter,enter-cancelled,before-leave,leave,after-leave,leave-cancelled
7、vue的自定義指令?
自定義指令分為全局指令和組件指令,其中全局指令需要使用directive來(lái)進(jìn)行定義,組件指令需要使用directives來(lái)進(jìn)行定義,具體定義方法同過(guò)濾器filter或者其他生命周期,具體使用方法如下:
全局自定義指令 directive(name,{}),其中name表示定義的指令名稱(chēng)(定義指令的時(shí)候不需要帶v-,但是在調(diào)用的時(shí)候需要哦帶v-),第二個(gè)參數(shù)是一個(gè)對(duì)象,對(duì)象中包括五個(gè)自定義組件的鉤子函數(shù),具體包括:
1、bind函數(shù): 只調(diào)用一次,指令第一次綁定在元素上調(diào)用,即初始化調(diào)用一次,
2、inserted函數(shù): 并綁定元素插入父級(jí)元素(即new vue中el綁定的元素)時(shí)調(diào)用(此時(shí)父級(jí)元素不一定轉(zhuǎn)化為了dom)
3、update函數(shù): 在元素發(fā)生更新時(shí)就會(huì)調(diào)用,可以通過(guò)比較新舊的值來(lái)進(jìn)行邏輯處理
4、componentUpdated函數(shù): 元素更新完成后觸發(fā)一次
5、unbind函數(shù): 在元素所在的模板刪除的時(shí)候就觸發(fā)一次
鉤子函數(shù)對(duì)應(yīng)的參數(shù)el,binding,vnode,oldnode,具體參數(shù)講解如下:
a、el指令所綁定的元素 可以直接操組dom元素
b、binding一個(gè)對(duì)象,具體包括以下屬性:
1)name:定義的指令名稱(chēng) 不包括v-
2)value:指令的綁定值,如果綁定的是一個(gè)計(jì)算式,value為對(duì)應(yīng)計(jì)算結(jié)果
3)oldvalue:指令綁定元素的前一個(gè)值,只對(duì)update和componentUpdated鉤子函數(shù)有值
4)expression:指令綁定的原始值 不對(duì)值進(jìn)行任何加工
5)arg:傳遞給指令的參數(shù)
6)modifiers:指令修飾符,如:v-focus.show.async 則接收的modifiers為{show:true,async:true}
c、vnode:vue編譯生成的虛擬dom
d、oldVnode:上一個(gè)vnode,只在update和componentUpdated鉤子函數(shù)中有效
??:如果不需要其他鉤子函數(shù),可以直接簡(jiǎn)寫(xiě)為:directive(“focus”,function(el,binding){})
8、vue的實(shí)現(xiàn)原理?
vue.js 是采用數(shù)據(jù)劫持結(jié)合發(fā)布者-訂閱者模式的方式,通過(guò)Object.defineProperty()來(lái)劫持各個(gè)屬性的setter,getter,在數(shù)據(jù)變動(dòng)時(shí)發(fā)布消息給訂閱者,觸發(fā)相應(yīng)的監(jiān)聽(tīng)回調(diào)。
具體步驟:
第一步:需要observe的數(shù)據(jù)對(duì)象進(jìn)行遞歸遍歷, 包括子屬性對(duì)象的屬性,都加上setter和getter,這樣的話,給這個(gè)對(duì)象的某個(gè)值賦值,就會(huì)觸發(fā)setter,那么就能監(jiān)聽(tīng)到了數(shù)據(jù)變化
第二步:compile解析模板指令, 將模板中的變量替換成數(shù)據(jù),然后初始化渲染頁(yè)面視圖,并將每個(gè)指令對(duì)應(yīng)的節(jié)點(diǎn)綁定更新函數(shù),添加監(jiān)聽(tīng)數(shù)據(jù)的訂閱者,一旦數(shù)據(jù)有變動(dòng),收到通知,更新視圖
第三步:Watcher訂閱者是Observer和Compile之間通信的橋梁, 主要做的事情是:
1、在自身實(shí)例化時(shí)往屬性訂閱器(dep)里面添加自己
2、自身必須有一個(gè)update()方法
3、待屬性變動(dòng)dep.notice()通知時(shí),能調(diào)用自身的update()方法,并觸發(fā)Compile中綁定的回調(diào),則功成身退。
第四步:MVVM作為數(shù)據(jù)綁定的入口,整合Observer、Compile和Watcher三者,通過(guò)Observer來(lái)監(jiān)聽(tīng)自己的model數(shù)據(jù)變化,通過(guò)Compile來(lái)解析編譯模板指令,最終利用Watcher搭起Observer和Compile之間的通信橋梁,達(dá)到數(shù)據(jù)變化 -> 視圖更新;視圖交互變化(input) -> 數(shù)據(jù)model變更的雙向綁定效果。
9、vue的diff算法理解?
1)diff算法的作用:
用來(lái)修改dom的一小段,不會(huì)引起dom樹(shù)的重繪
2)diff算法的實(shí)現(xiàn)原理:
diff算法將virtual dom的某個(gè)節(jié)點(diǎn)數(shù)據(jù)改變后生成的新的vnode與舊節(jié)點(diǎn)進(jìn)行比較,并替換為新的節(jié)點(diǎn),具體過(guò)程就是調(diào)用patch方法,比較新舊節(jié)點(diǎn),一邊比較一邊給真實(shí)的dom打補(bǔ)丁進(jìn)行替換
3)具體過(guò)程詳解:
a、在采用diff算法進(jìn)行新舊節(jié)點(diǎn)進(jìn)行比較的時(shí)候,比較是按照在同級(jí)進(jìn)行比較的,不會(huì)進(jìn)行跨級(jí)比較:
b、當(dāng)數(shù)據(jù)發(fā)生改變的時(shí)候,set方法會(huì)調(diào)用dep.notify通知所有的訂閱者watcher,訂閱者會(huì)調(diào)用patch函數(shù)給響應(yīng)的dom進(jìn)行打補(bǔ)丁,從而更新真實(shí)的視圖
c、patch函數(shù)接受兩個(gè)參數(shù),第一個(gè)是舊節(jié)點(diǎn),第二個(gè)是新節(jié)點(diǎn),首先判斷兩個(gè)節(jié)點(diǎn)是否值得比較,值得比較則執(zhí)行patchVnode函數(shù),不值得比較則直接將舊節(jié)點(diǎn)替換為新節(jié)點(diǎn)。如果兩個(gè)節(jié)點(diǎn)一樣就直接檢查對(duì)應(yīng)的子節(jié)點(diǎn),如果子節(jié)點(diǎn)不一樣就說(shuō)明整個(gè)子節(jié)點(diǎn)全部改變不再往下對(duì)比直接進(jìn)行新舊節(jié)點(diǎn)的整體替換
d、patchVnode函數(shù):找到真實(shí)的dom元素;判斷新舊節(jié)點(diǎn)是否指向同一個(gè)對(duì)象,如果是就直接返回;如果新舊節(jié)點(diǎn)都有文本節(jié)點(diǎn),那么直接將新的文本節(jié)點(diǎn)賦值給dom元素并且更新舊的節(jié)點(diǎn)為新的節(jié)點(diǎn);如果舊節(jié)點(diǎn)有子節(jié)點(diǎn)而新節(jié)點(diǎn)沒(méi)有,則直接刪除dom元素中的子節(jié)點(diǎn);如果舊節(jié)點(diǎn)沒(méi)有子節(jié)點(diǎn),新節(jié)點(diǎn)有子節(jié)點(diǎn),那么直接將新節(jié)點(diǎn)中的子節(jié)點(diǎn)更新到dom中;如果兩者都有子節(jié)點(diǎn),那么繼續(xù)調(diào)用函數(shù)updateChildren
e、updateChildren函數(shù):抽離出新舊節(jié)點(diǎn)的所有子節(jié)點(diǎn),并且設(shè)置新舊節(jié)點(diǎn)的開(kāi)始指針和結(jié)束指針,然后進(jìn)行兩輛比較,從而更新dom(調(diào)整順序或者插入新的內(nèi)容 結(jié)束后刪掉多余的內(nèi)容)
10、vue組件的通信(父子組件和非父子組件)?
父子組件通信
傳遞參數(shù)可以使用props,傳遞函數(shù)可以直接在調(diào)用子組件的時(shí)候傳遞自定義事件,并使用$emit來(lái)調(diào)用,例如:
//父組件 <div classs="parent"><child @getinfo="myname" :userinfo="usermessage"></child><div>export default {data(){return {usermessage:'我是父親'}},methods:{myname(name){console.log('我的名字叫'+name)}}}//子組件 <div classs="child">來(lái)源:{{userinfo}}<button @click="getname">顯示我的名字</button><div>export default {props:['userinfo'],methods:{getname(){this.$emit('getinfo','bilibili')}}}兄弟組件通信
首先建立一個(gè)vue實(shí)例空白頁(yè)(js文件)
import Vue from 'vue'export default new Vue()組件a(數(shù)據(jù)發(fā)送方)通過(guò)使用 $emit 自定義事件把數(shù)據(jù)帶過(guò)去
<template><div><span>A組件->{{msg}}</span><input type="button" value="把a(bǔ)組件數(shù)據(jù)傳給b" @click ="send"></div> </template> <script> import vmson from "../../../util/emptyVue" export default {data(){return {msg:{a:'111',b:'222'}}},methods:{send:function(){vmson.$emit("aevent",this.msg)}} } </script>組件b(數(shù)據(jù)接收方)使用而通過(guò) $on監(jiān)聽(tīng)自定義事件的callback接收數(shù)據(jù)
<template><div><span>b組件,a傳的的數(shù)據(jù)為->{{msg}}</span></div> </template> <script>import vmson from "../../../util/emptyVue"export default {data(){return {msg:""}},mounted(){vmson.$on("aevent",(val)=>{//監(jiān)聽(tīng)事件aevent,回調(diào)函數(shù)要使用箭頭函數(shù);console.log(val);//打印結(jié)果:我是a組件的數(shù)據(jù)this.msg = val;})}} </script>11、vue的路由模式及區(qū)別?
hash模式在瀏覽器中符號(hào)“#”,#以及#后面的字符稱(chēng)之為hash,用window.location.hash讀取;
特點(diǎn):hash雖然在URL中,但不被包括在HTTP請(qǐng)求中;用來(lái)指導(dǎo)瀏覽器動(dòng)作,對(duì)服務(wù)端安全無(wú)用,hash不會(huì)重加載頁(yè)面。
history模式:history采用HTML5的新特性;
提供了兩個(gè)新方法:pushState(),replaceState()可以對(duì)瀏覽器歷史記錄棧進(jìn)行修改,以及popState事件的監(jiān)聽(tīng)到狀態(tài)變更。history 模式下,前端的 URL必須和實(shí)際向后端發(fā)起請(qǐng)求的URL一致,否則會(huì)報(bào)404錯(cuò)誤
12、vue與react、angular的比較?
Vue
輕量級(jí)框架:只關(guān)注視圖層,是一個(gè)構(gòu)建數(shù)據(jù)的視圖集合,大小只有幾十kb;
簡(jiǎn)單易學(xué):國(guó)人開(kāi)發(fā),中文文檔,不存在語(yǔ)言障礙 ,易于理解和學(xué)習(xí);
雙向數(shù)據(jù)綁定:保留了angular的特點(diǎn),在數(shù)據(jù)操作方面更為簡(jiǎn)單;
組件化:保留了react的優(yōu)點(diǎn),實(shí)現(xiàn)了html的封裝和重用,在構(gòu)建單頁(yè)面應(yīng)用方面有著獨(dú)特的優(yōu)勢(shì);
視圖,數(shù)據(jù),結(jié)構(gòu)分離:使數(shù)據(jù)的更改更為簡(jiǎn)單,不需要進(jìn)行邏輯代碼的修改,只需要操作數(shù)據(jù)就能完成相關(guān)操作;
虛擬DOM:dom操作是非常耗費(fèi)性能的, 不再使用原生的dom操作節(jié)點(diǎn),極大解放dom操作,但具體操作的還是dom不過(guò)是換了另一種方式;
運(yùn)行速度更快:相比較與react而言,同樣是操作虛擬dom,就性能而言,vue存在很大的優(yōu)勢(shì)。
React
相同點(diǎn):
React采用特殊的JSX語(yǔ)法,Vue.js在組件開(kāi)發(fā)中也推崇編寫(xiě).vue特殊文件格式,對(duì)文件內(nèi)容都有一些約定,兩者都需要編譯后使用;中心思想相同:一切都是組件,組件實(shí)例之間可以嵌套;都提供合理的鉤子函數(shù),可以讓開(kāi)發(fā)者定制化地去處理需求;都不內(nèi)置列數(shù)AJAX,Route等功能到核心包,而是以插件的方式加載;在組件開(kāi)發(fā)中都支持mixins的特性。
不同點(diǎn):
React采用的Virtual DOM會(huì)對(duì)渲染出來(lái)的結(jié)果做臟檢查;Vue.js在模板中提供了指令,過(guò)濾器等,可以非常方便,快捷地操作Virtual DOM。
Angular
相同點(diǎn):
都支持指令:內(nèi)置指令和自定義指令;都支持過(guò)濾器:內(nèi)置過(guò)濾器和自定義過(guò)濾器;都支持雙向數(shù)據(jù)綁定;都不支持低端瀏覽器。
不同點(diǎn):
AngularJS的學(xué)習(xí)成本高,比如增加了Dependency Injection特性,而Vue.js本身提供的API都比較簡(jiǎn)單、直觀;在性能上,AngularJS依賴(lài)對(duì)數(shù)據(jù)做臟檢查,所以Watcher越多越慢;Vue.js使用基于依賴(lài)追蹤的觀察并且使用異步隊(duì)列更新,所有的數(shù)據(jù)都是獨(dú)立觸發(fā)的。
13、vue-roter的鉤子函數(shù)?
vue路由鉤子大致可以分為三類(lèi):
全局鉤子
主要包括beforeEach和afterEach,beforeEach函數(shù)有三個(gè)參數(shù):
to:router即將進(jìn)入的路由對(duì)象
from:當(dāng)前導(dǎo)航即將離開(kāi)的路由
next:Function,進(jìn)行管道中的一個(gè)鉤子,如果執(zhí)行完了,則導(dǎo)航的狀態(tài)就是 confirmed (確認(rèn)的);否則為false,終止導(dǎo)航。
afterEach函數(shù)不用傳next()函數(shù)這類(lèi)鉤子主要作用于全局,一般用來(lái)判斷權(quán)限,以及以及頁(yè)面丟失時(shí)候需要執(zhí)行的操作,例如:
//使用鉤子函數(shù)對(duì)路由進(jìn)行權(quán)限跳轉(zhuǎn) router.beforeEach((to, from, next) => {const role = localStorage.getItem('ms_username');if(!role && to.path !== '/login'){next('/login');}else if(to.meta.permission){// 如果是管理員權(quán)限則可進(jìn)入,這里只是簡(jiǎn)單的模擬管理員權(quán)限而已role === 'admin' ? next() : next('/403');}else{// 簡(jiǎn)單的判斷IE10及以下不進(jìn)入富文本編輯器,該組件不兼容if(navigator.userAgent.indexOf('MSIE') > -1 && to.path === '/editor'){Vue.prototype.$alert('vue-quill-editor組件不兼容IE10及以下瀏覽器,請(qǐng)使用更高版本的瀏覽器查看', '瀏覽器不兼容通知', {confirmButtonText: '確定'});}else{next();}} })2)單個(gè)路由里面的鉤子
主要用于寫(xiě)某個(gè)指定路由跳轉(zhuǎn)時(shí)需要執(zhí)行的邏輯
3)組件路由
主要包括beforeRouteEnter和beforeRouteUpdate,beforeRouteLeave,這幾個(gè)鉤子都是寫(xiě)在組件里面也可以傳三個(gè)參數(shù)(to,from,next),作用與前面類(lèi)似.
beforeRouteEnter(to, from, next) {next(vm => {if (vm.$route.meta.hasOwnProperty('auth_key') &&vm.$route.meta.auth_key != '') {if (!vm.hasPermission(vm.$route.meta.auth_key)) {vm.$router.replace('/admin/noPermission')}}}) }14、vuex的使用?
Vuex 是一個(gè)專(zhuān)為 Vue.js 應(yīng)用程序開(kāi)發(fā)的狀態(tài)管理模式。它采用集中式存儲(chǔ)管理應(yīng)用的所有組件的狀態(tài),并以相應(yīng)的規(guī)則保證狀態(tài)以一種可預(yù)測(cè)的方式發(fā)生變化,具體包括:
1)state:Vuex 使用單一狀態(tài)樹(shù),即每個(gè)應(yīng)用將僅僅包含一個(gè)store 實(shí)例,但單一狀態(tài)樹(shù)和模塊化并不沖突。存放的數(shù)據(jù)狀態(tài),不可以直接修改里面的數(shù)據(jù)。
2)getter:state的計(jì)算屬性,類(lèi)似vue的計(jì)算屬性,主要用來(lái)過(guò)濾一些數(shù)據(jù)。
3)action:actions可以理解為通過(guò)將mutations里面處里數(shù)據(jù)的方法變成可異步的處理數(shù)據(jù)的方法,簡(jiǎn)單的說(shuō)就是異步操作數(shù)據(jù)。view 層通過(guò) store.dispath 來(lái)分發(fā) action。可以異步函數(shù)調(diào)用
4)mutation:mutations定義的方法動(dòng)態(tài)修改Vuex 的 store 中的狀態(tài)或數(shù)據(jù)
5)modules:項(xiàng)目特別復(fù)雜的時(shí)候,可以讓每一個(gè)模塊擁有自己的state、mutation、action、getters,使得結(jié)構(gòu)非常清晰,方便管理。
15、vue的filter的理解與用法?
1)全局過(guò)濾器必須寫(xiě)在vue實(shí)例創(chuàng)建之前
Vue.filter('testfilter', function (value,text) { // 返回處理后的值return value+text})2)局部寫(xiě)法:在組件實(shí)例對(duì)象里掛載。
filters: {changemsg:(val,text)\=>{ return val + text} }3)使用方式:只能使用在{{}}和:v-bind中,定義時(shí)第一個(gè)參數(shù)固定為預(yù)處理的數(shù),后面的數(shù)為調(diào)用時(shí)傳入的參數(shù),調(diào)用時(shí)參數(shù)第一個(gè)對(duì)應(yīng)定義時(shí)第二個(gè)參數(shù),依次往后類(lèi)推
<h3 :title="test|changemsg(1234)">{{test|changemsg(4567)}}</h3> //多個(gè)過(guò)濾器也可以串行使用 <h2>{{name|filter1|filter2|filter3}}</h2>4)vue-cli項(xiàng)目中注冊(cè)多個(gè)全局過(guò)濾器寫(xiě)法:
//1.創(chuàng)建一個(gè)單獨(dú)的文件定義并暴露函數(shù)對(duì)象 const filter1 = function (val) {return val + '--1' } const filter2 = function (val) {return val + '--2' } const filter3 = function (val) {return val + '--3' }export default {filter1,filter2,filter3 }//2.導(dǎo)入main.js(在vue實(shí)例之前) import filters from './filter/filter.js'//3.循環(huán)注冊(cè)過(guò)濾器 Object.keys(filters).forEach(key=>{Vue.filter(key,filters[key]) })16、vue的keep-alive的理解?
keep-alive 是Vue內(nèi)置的一個(gè)組件,可以使被包含的組件保留狀態(tài),或避免重新渲染,頁(yè)面第一次進(jìn)入,鉤子的觸發(fā)順序:created-> mounted-> activated,退出時(shí)觸發(fā) deactivated ,當(dāng)再次進(jìn)入(前進(jìn)或者后退)時(shí),只觸發(fā)activated事件掛載的方法等,只執(zhí)行一次的放在 mounted 中;組件每次進(jìn)去執(zhí)行的方法放在 activated 中;其有幾個(gè)屬性如下:
1)include - 字符串或正則表達(dá)式,只有名稱(chēng)匹配的組件會(huì)被緩存
2)exclude - 字符串或正則表達(dá)式,任何名稱(chēng)匹配的組件都不會(huì)被緩存
3)include 和 exclude 的屬性允許組件有條件地緩存。二者都可以用“,”分隔字符串、正則表達(dá)式、數(shù)組。當(dāng)使用正則或者是數(shù)組時(shí),要記得使用v-bind 。
<!-- 逗號(hào)分隔字符串,只有組件a與b被緩存。--> <keep-alive include="a,b"><component></component> </keep-alive><!-- 正則表達(dá)式 (需要使用 v-bind,符合匹配規(guī)則的都會(huì)被緩存) --> <keep-alive :include="/a|b/"><component></component> </keep-alive><!-- Array (需要使用 v-bind,被包含的都會(huì)被緩存) --> <keep-alive :include="['a', 'b']"><component></component> </keep-alive>17、如何封裝一個(gè)vue組件?
根據(jù)業(yè)務(wù)需求,建立組件的模板,先把架子搭起來(lái),寫(xiě)寫(xiě)樣式,考慮好組件的基本邏輯。
1、準(zhǔn)備好組件的數(shù)據(jù)輸入。即分析好邏輯,定好 props 里面的數(shù)據(jù)、類(lèi)型。
2、準(zhǔn)備好組件的數(shù)據(jù)輸出。即根據(jù)組件邏輯,做好要暴露出來(lái)的方法。
3、封裝完畢了,直接調(diào)用即可
18、vue首屏白屏如何解決?
1)路由懶加載
2)vue-cli開(kāi)啟打包壓縮 和后臺(tái)配合 gzip訪問(wèn)
3)進(jìn)行cdn加速
4)開(kāi)啟vue服務(wù)渲染模式
5)用webpack的externals屬性把不需要打包的庫(kù)文件分離出去,減少打包后文件的大小
6)在生產(chǎn)環(huán)境中刪除掉不必要的console.log
plugins: [new webpack.optimize.UglifyJsPlugin({ //添加-刪除console.logcompress: {warnings: false,drop_debugger: true,drop_console: true},sourceMap: true}),7)開(kāi)啟nginx的gzip ,在nginx.conf配置文件中配置
http { //在 http中配置如下代碼,gzip on;gzip_disable "msie6"; gzip_vary on; gzip_proxied any;gzip_comp_level 8; #壓縮級(jí)別gzip_buffers 16 8k;#gzip_http_version 1.1;gzip_min_length 100; #不壓縮臨界值gzip_types text/plain application/javascript application/x-javascript text/cssapplication/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png;}8)添加loading效果,給用戶一種進(jìn)度感受
19、vue中的v-cloak的理解?
使用 v-cloak 指令設(shè)置樣式,這些樣式會(huì)在 Vue 實(shí)例編譯結(jié)束時(shí),從綁定的 HTML 元素上被移除。
一般用于解決網(wǎng)頁(yè)閃屏的問(wèn)題,在對(duì)一個(gè)的標(biāo)簽中使用v-cloak,然后在樣式中設(shè)置[v-cloak]樣式,[v-cloak]需寫(xiě)在 link 引入的css中,或者寫(xiě)一個(gè)內(nèi)聯(lián)css樣式,寫(xiě)在import引入的css中不起作用。
20、vue中template編譯的理解?
答:就是先轉(zhuǎn)化成AST樹(shù),再得到的render函數(shù)返回VNode(Vue的虛擬DOM節(jié)點(diǎn)),具體為:
首先,通過(guò)compile編譯器把template編譯成AST語(yǔ)法樹(shù)(abstract syntax tree 即 源代碼的抽象語(yǔ)法結(jié)構(gòu)的樹(shù)狀表現(xiàn)形式),compile是createCompiler的返回值,createCompiler是用以創(chuàng)建編譯器的。
另外compile還負(fù)責(zé)合并option。
然后,AST會(huì)經(jīng)過(guò)generate(將AST語(yǔ)法樹(shù)轉(zhuǎn)化成render funtion字符串的過(guò)程)得到render函數(shù),render的返回值是VNode,VNode是Vue的虛擬DOM節(jié)點(diǎn),里面有(標(biāo)簽名、子節(jié)點(diǎn)、文本等等)
21、v-model的理解?
答:v-model用于表單數(shù)據(jù)的雙向綁定,其實(shí)它就是一個(gè)語(yǔ)法糖,這個(gè)背后就做了兩個(gè)操作:
1)v-bind綁定一個(gè)value屬性;
2)v-on指令給當(dāng)前元素綁定input事件
22、computed和watch的用法和區(qū)別?
computed
1)變量不在 data中定義,而是定義在computed中,寫(xiě)法跟寫(xiě)方法一樣,有返回值。函數(shù)名直接在頁(yè)面模板中渲染,不加小括號(hào) 。
2)根據(jù)傳入的變量的變化 進(jìn)行結(jié)果的更新。
3)計(jì)算屬性基于響應(yīng)式依賴(lài)進(jìn)行緩存。如其中的任意一個(gè)值未發(fā)生變化,它調(diào)用的就是上一次計(jì)算緩存的數(shù)據(jù),因此提高了程序的性能。而methods中每調(diào)用一次就會(huì)重新計(jì)算一次,為了進(jìn)行不必要的資源消耗,選擇用計(jì)算屬性。
watch
1)計(jì)算屬性的時(shí)候 初始化的時(shí)候就可以被監(jiān)聽(tīng)到并且計(jì)算 但是watch是發(fā)生改變的時(shí)候才會(huì)觸發(fā)。
2)當(dāng)有一些數(shù)據(jù)需要隨著其它數(shù)據(jù)變動(dòng)而變動(dòng)時(shí),或者當(dāng)需要在數(shù)據(jù)變化時(shí)執(zhí)行異步或開(kāi)銷(xiāo)較大的操作時(shí),使用 watch。
總結(jié):
1)計(jì)算屬性變量在computed中定義,屬性監(jiān)聽(tīng)在data中定義。
2)計(jì)算屬性是聲明式的描述一個(gè)值依賴(lài)了其他值,依賴(lài)的值改變后重新計(jì)算結(jié)果更新DOM。屬性監(jiān)聽(tīng)的是定義的變量,當(dāng)定義的值發(fā)生變化時(shí),執(zhí)行相對(duì)應(yīng)的函數(shù)。
23、$nextTick的使用?
答:在vue中理解修改數(shù)據(jù)后,對(duì)應(yīng)的dom需要一定的時(shí)間進(jìn)行更新,因此為了能夠準(zhǔn)確的后去更新后的dom,可以采用延遲回調(diào)的方法進(jìn)行更新dom的獲取,所以出現(xiàn)了$nextTick來(lái)進(jìn)行延遲回調(diào)。即:在下次 DOM 更新循環(huán)結(jié)束之后執(zhí)行延遲回調(diào)。在修改數(shù)據(jù)之后立即使用這個(gè)方法,獲取更新后的 DOM。
24、data為什么是一個(gè)函數(shù)?
答:這是有JavaScript的特性所導(dǎo)致,在component中,data必須以函數(shù)的形式存在,不可以是對(duì)象。
組建中的data寫(xiě)成一個(gè)函數(shù),數(shù)據(jù)以函數(shù)返回值的形式定義,這樣每次復(fù)用組件的時(shí)候,都會(huì)返回一份新的data,相當(dāng)于每個(gè)組件實(shí)例都有自己私有的數(shù)據(jù)空間,它們只負(fù)責(zé)各自維護(hù)的數(shù)據(jù),不會(huì)造成混亂。而單純的寫(xiě)成對(duì)象形式,就是所有的組件實(shí)例共用了一個(gè)data,這樣改一個(gè)全都改了。
25、vue單頁(yè)面和傳統(tǒng)的多頁(yè)面區(qū)別?
單頁(yè)面應(yīng)用(SPA)
通俗一點(diǎn)說(shuō)就是指只有一個(gè)主頁(yè)面的應(yīng)用,瀏覽器一開(kāi)始要加載所有必須的 html, js, css。所有的頁(yè)面內(nèi)容都包含在這個(gè)所謂的主頁(yè)面中。但在寫(xiě)的時(shí)候,還是會(huì)分開(kāi)寫(xiě)(頁(yè)面片段),然后在交互的時(shí)候由路由程序動(dòng)態(tài)載入,單頁(yè)面的頁(yè)面跳轉(zhuǎn),僅刷新局部資源。多應(yīng)用于pc端。
多頁(yè)面(MPA)
指一個(gè)應(yīng)用中有多個(gè)頁(yè)面,頁(yè)面跳轉(zhuǎn)時(shí)是整頁(yè)刷新
單頁(yè)面的優(yōu)點(diǎn):
用戶體驗(yàn)好,快,內(nèi)容的改變不需要重新加載整個(gè)頁(yè)面,基于這一點(diǎn)spa對(duì)服務(wù)器壓力較小;前后端分離;頁(yè)面效果會(huì)比較炫酷(比如切換頁(yè)面內(nèi)容時(shí)的專(zhuān)場(chǎng)動(dòng)畫(huà))。
單頁(yè)面缺點(diǎn):
不利于seo;導(dǎo)航不可用,如果一定要導(dǎo)航需要自行實(shí)現(xiàn)前進(jìn)、后退。(由于是單頁(yè)面不能用瀏覽器的前進(jìn)后退功能,所以需要自己建立堆棧管理);初次加載時(shí)耗時(shí)多;頁(yè)面復(fù)雜度提高很多。
26、vue常用的修飾符?
.stop: 等同于JavaScript中的event.stopPropagation(),防止事件冒泡;
.prevent: 等同于JavaScript中的event.preventDefault(),防止執(zhí)行預(yù)設(shè)的行為(如果事件可取消,則取消該事件,而不停止事件的進(jìn)一步傳播);
.capture: 與事件冒泡的方向相反,事件捕獲由外到內(nèi);
.self: 只會(huì)觸發(fā)自己范圍內(nèi)的事件,不包含子元素;
.once: 只會(huì)觸發(fā)一次。
27、vue更新數(shù)組時(shí)觸發(fā)視圖更新的方法?
答:push();pop();shift();unshift();splice();sort();reverse()
28、route和router的區(qū)別?
$router
router是VueRouter的一個(gè)對(duì)象,通過(guò)Vue.use(VueRouter)和VueRouter構(gòu)造函數(shù)得到一個(gè)router的實(shí)例對(duì)象,這個(gè)對(duì)象中是一個(gè)全局的對(duì)象,他包含了所有的路由包含了許多關(guān)鍵的對(duì)象和屬性,常見(jiàn)的有:
1)push:向 history 棧添加一個(gè)新的記錄,當(dāng)我們點(diǎn)擊瀏覽器的返回按鈕時(shí)可以看到之前的頁(yè)面
// 字符串this.$router.push('home') // 對(duì)象this.$router.push({ path: 'home' }) // 命名的路由this.$router.push({ name: 'user', params: { userId: 123 }}) // 帶查詢(xún)參數(shù),變成 /register?plan=123this.$router.push({ path: 'register', query: { plan: '123' }})2)go:頁(yè)面路由跳轉(zhuǎn) 前進(jìn)或者后退
// 頁(yè)面路由跳轉(zhuǎn) 前進(jìn)或者后退 this.$router.go(-1) // 后退3)replace:push方法會(huì)向 history 棧添加一個(gè)新的記錄,而replace方法是替換當(dāng)前的頁(yè)面,不會(huì)向 history 棧添加一個(gè)新的記錄
$route
$route對(duì)象表示當(dāng)前的路由信息,包含了當(dāng)前URL解析得到的信息。包含當(dāng)前的路徑、參數(shù)、query對(duì)象等。
$route.path:字符串,對(duì)應(yīng)當(dāng)前路由的路徑,總是解析為絕對(duì)路徑,如 “/foo/bar”。
$route.params:一個(gè) key/value 對(duì)象,包含了 動(dòng)態(tài)片段 和 全匹配片段,如果沒(méi)有路由參數(shù),就是一個(gè)空對(duì)象。
$route.query:一個(gè) key/value 對(duì)象,表示 URL 查詢(xún)參數(shù)。例如,對(duì)于路徑 /foo?user=1,則有 $route.query.user == 1,如果沒(méi)有查詢(xún)參數(shù),則是個(gè)空對(duì)象。
$route.hash:當(dāng)前路由的 hash 值 (不帶#) ,如果沒(méi)有 hash 值,則為空字符串。
$route.fullPath:完成解析后的 URL,包含查詢(xún)參數(shù)和 hash 的完整路徑。
$route.matched:數(shù)組,包含當(dāng)前匹配的路徑中所包含的所有片段所對(duì)應(yīng)的配置參數(shù)對(duì)象。
$route.name:當(dāng)前路徑名字
$route.meta:路由元信息
29、vue-router實(shí)現(xiàn)懶加載的方式?
vue異步組件
vue異步組件技術(shù) ==== 異步加載
vue-router配置路由 , 使用vue的異步組件技術(shù) , 可以實(shí)現(xiàn)按需加載 。但是,這種情況下一個(gè)組件生成一個(gè)js文件
es提案的import()
路由懶加載(使用import)
// 下面2行代碼,沒(méi)有指定webpackChunkName,每個(gè)組件打包成一個(gè)js文件。 /* const Home = () => import('@/components/home') const Index = () => import('@/components/index') const About = () => import('@/components/about') */ // 下面2行代碼,指定了相同的webpackChunkName,會(huì)合并打包成一個(gè)js文件。把組件按組分塊 const Home = () => import(/* webpackChunkName: 'ImportFuncDemo' */ '@/components/home') const Index = () => import(/* webpackChunkName: 'ImportFuncDemo' */ '@/components/index') const About = () => import(/* webpackChunkName: 'ImportFuncDemo' */ '@/components/about') {path: '/about',component: About }, {path: '/index',component: Index }, {path: '/home',component: Home }webpack的require,ensure()
vue-router配置路由,使用webpack的require.ensure技術(shù),也可以實(shí)現(xiàn)按需加載。這種情況下,多個(gè)路由指定相同的chunkName,會(huì)合并打包成一個(gè)js文件。
/* 組件懶加載方案三: webpack提供的require.ensure() */ {path: '/home',name: 'home',component: r => require.ensure([], () => r(require('@/components/home')), 'demo') }, {path: '/index',name: 'Index',component: r => require.ensure([], () => r(require('@/components/index')), 'demo') }, {path: '/about',name: 'about',component: r => require.ensure([], () => r(require('@/components/about')), 'demo-01') }30、delete和Vue.delete刪除數(shù)組的區(qū)別?
答:delete只是被刪除的元素變成了 empty/undefined 其他的元素的鍵值還是不變。Vue.delete 直接刪除了數(shù)組 改變了數(shù)組的鍵值。
31、路由跳轉(zhuǎn)和location.href的區(qū)別?
使用location.href=’/url’來(lái)跳轉(zhuǎn),簡(jiǎn)單方便,但是刷新了頁(yè)面;
使用路由方式跳轉(zhuǎn),無(wú)刷新頁(yè)面,靜態(tài)跳轉(zhuǎn);
32、vue的solt的用法?
在子組件內(nèi)使用特殊的<slot>元素就可以為這個(gè)子組件開(kāi)啟一個(gè)slot(插槽),在父組件模板里,插入在子組件標(biāo)簽內(nèi)的所有內(nèi)容將替代子組件的<slot> 標(biāo)簽及它的內(nèi)容。
簡(jiǎn)單說(shuō)來(lái)就是:在子組件內(nèi)部用 < slot></ slot>標(biāo)簽占位,當(dāng)在父組件中使用子組件的時(shí)候,我們可以在子組件中插入內(nèi)容,而這些插入的內(nèi)容則會(huì)替換 < slot>< /slot>標(biāo)簽的位置。
當(dāng)然:單個(gè)solt的時(shí)候可以不對(duì)solt進(jìn)行命名,如果存在多個(gè) 則一個(gè)可以不命名,其他必須命名,在調(diào)用的時(shí)候指定名稱(chēng)的對(duì)應(yīng)替換slot,沒(méi)有指定的則直接默認(rèn)無(wú)名稱(chēng)的solt
33、$ emit 、$ on 、$ once 、$off理解?
$emit
觸發(fā)當(dāng)前實(shí)例上的自定義事件(并將附加參數(shù)都傳給監(jiān)聽(tīng)器回調(diào))
$on
監(jiān)聽(tīng)實(shí)例上自定義事件并調(diào)用回調(diào)函數(shù),監(jiān)聽(tīng)emit觸發(fā)的事件
$once
監(jiān)聽(tīng)一個(gè)自定義事件,但是只觸發(fā)一次,在第一次觸發(fā)之后移除監(jiān)聽(tīng)器。
$off
用來(lái)移除自定義事件監(jiān)聽(tīng)器。如果沒(méi)有提供參數(shù),則移除所有的事件監(jiān)聽(tīng)器;如果只提供了事件,則移除該事件所有的監(jiān)聽(tīng)器;如果同時(shí)提供了事件與回調(diào),則只移除這個(gè)回調(diào)的監(jiān)聽(tīng)器。
這四個(gè)方法的實(shí)現(xiàn)原理是:通過(guò)對(duì)vue實(shí)例掛載,然后分別使用對(duì)象存儲(chǔ)數(shù)組對(duì)應(yīng)的函數(shù)事件,其中emit通過(guò)循環(huán)查找存儲(chǔ)的數(shù)組中對(duì)應(yīng)的函數(shù)進(jìn)行調(diào)用,once只匹配一次就就結(jié)束,on是將對(duì)應(yīng)的函數(shù)存儲(chǔ)到數(shù)組中,off是刪除數(shù)組中指定的元素或者所有的元素事件。具體可以參考文章:VUE emit實(shí)現(xiàn)
34、 $ root 、$ refs、$ parent的使用?
$root
可以用來(lái)獲取vue的根實(shí)例,比如在簡(jiǎn)單的項(xiàng)目中將公共數(shù)據(jù)放再vue根實(shí)例上(可以理解為一個(gè)全局 store ),因此可以代替vuex實(shí)現(xiàn)狀態(tài)管理;
$refs
在子組件上使用ref特性后,this.屬性可以直接訪問(wèn)該子組件。可以代替事件emit 和$on 的作用。
使用方式是通過(guò)ref特性為這個(gè)子組件賦予一個(gè)ID引用,再通過(guò)this.$refs.testId獲取指定元素。
注意:$refs只會(huì)在組件渲染完成之后生效,并且它們不是響應(yīng)式的。這僅作為一個(gè)用于直接操作子組件的“逃生艙”——你應(yīng)該避免在模板或計(jì)算屬性中訪問(wèn) $refs。
$parent
$parent屬性可以用來(lái)從一個(gè)子組件訪問(wèn)父組件的實(shí)例,可以替代將數(shù)據(jù)以 prop 的方式傳入子組件的方式;當(dāng)變更父級(jí)組件的數(shù)據(jù)的時(shí)候,容易造成調(diào)試和理解難度增加;
35、vue開(kāi)發(fā)遇到的問(wèn)題?
1)樣式污染
答:在編寫(xiě)樣式中,如果需要防止樣式的污染,可以使用兩種方式,一種是在組件的根元素上增加一個(gè)唯一的class或者id,然后在編寫(xiě)組件的樣式時(shí)候在根元素對(duì)應(yīng)的class或者id下進(jìn)行編寫(xiě);另一種方式是在對(duì)應(yīng)的style上添加scoped關(guān)鍵字,不過(guò)該關(guān)鍵字對(duì)引用的框架UI無(wú)效
2)router-link在安卓上不起作用
答:不起作用的原因是因?yàn)檗D(zhuǎn)碼編譯的問(wèn)題,可以使用babel來(lái)進(jìn)行處理,安裝babel polypill插件解決
3)初始化頁(yè)面出現(xiàn)閃屏亂碼的問(wèn)題
答:這是因?yàn)関ue還沒(méi)有解析的情況下會(huì)容易出現(xiàn)花屏現(xiàn)象,看到類(lèi)似于{{data}}的字樣,可以使用兩種方式來(lái)進(jìn)行處理,一種為:在設(shè)置index.html的根元素的元素的樣式為display:none,然后在mounted中的$nextTick函數(shù)中display:block展示;另一種方式是使用vue的內(nèi)置指令:v-cloak,并且在css中設(shè)置樣式
[v-cloak] { display: none; }4)router-link上事件無(wú)效解決方法
答:使用@click.native來(lái)進(jìn)行調(diào)用原生的js事件。原因:router-link會(huì)阻止click事件,.native指直接監(jiān)聽(tīng)一個(gè)原生事件。
總結(jié)
以上是生活随笔為你收集整理的常见的前端vue面试题的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 常见JavaScript基础面试题上(附
- 下一篇: JavaScript数组的API