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