天天看點

35道常見的前端vue面試題

35道常見的前端vue面試題

今天這篇文章給大家分享一些常見的前端vue面試題。有一定的參考價值,有需要的朋友可以參考一下,希望對大家有所幫助。

對于前端來說,盡管css、html、js是主要的基礎知識,但是随着技術的不斷發展,出現了很多優秀的mv*架構以及小程式架構。是以,對于前端開發者而言,需要對一些前端架構進行熟練掌握。這篇文章我們一起來聊一聊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-),第二個參數是一個對象,對象中包括五個自定義元件的鈎子函數,具體包括:

  1. bind函數:隻調用一次,指令第一次綁定在元素上調用,即初始化調用一次,
  2. inserted函數:并綁定元素插入父級元素(即new vue中el綁定的元素)時調用(此時父級元素不一定轉化為了dom)
  3. update函數:在元素發生更新時就會調用,可以通過比較新舊的值來進行邏輯處理
  4. componentUpdated函數:元素更新完成後觸發一次
  5. unbind函數:在元素所在的模闆删除的時候就觸發一次

鈎子函數對應的參數el,binding,vnode,oldnode,具體參數講解如下:

a、el指令所綁定的元素 可以直接操組dom元素

b、binding一個對象,具體包括以下屬性:

  1. 1)name:定義的指令名稱 不包括v-
  2. 2)value:指令的綁定值,如果綁定的是一個計算式,value為對應計算結果
  3. 3)oldvalue:指令綁定元素的前一個值,隻對update和componentUpdated鈎子函數有值
  4. 4)expression:指令綁定的原始值 不對值進行任何加工
  5. 5)arg:傳遞給指令的參數
  6. 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. 1、在自身執行個體化時往屬性訂閱器(dep)裡面添加自己
  2. 2、自身必須有一個update()方法
  3. 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算法進行新舊節點進行比較的時候,比較是按照在同級進行比較的,不會進行跨級比較:

35道常見的前端vue面試題

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

&dollar;route對象表示目前的路由資訊,包含了目前URL解析得到的資訊。包含目前的路徑、參數、query對象等。

1)&dollar;route.path:字元串,對應目前路由的路徑,總是解析為絕對路徑,如 "/foo/bar"。

2)&dollar;route.params:一個 key/value 對象,包含了 動态片段 和 全比對片段,如果沒有路由參數,就是一個空對象。

3)&dollar;route.query:一個 key/value 對象,表示 URL 查詢參數。例如,對于路徑 /foo?user=1,則有 $route.query.user == 1,如果沒有查詢參數,則是個空對象。

4)&dollar;route.hash:目前路由的 hash 值 (不帶#) ,如果沒有 hash 值,則為空字元串。

5.&dollar;route.fullPath:完成解析後的 URL,包含查詢參數和 hash 的完整路徑。

6&dollar;route.matched:數組,包含目前比對的路徑中所包含的所有片段所對應的配置參數對象。

7.&dollar;route.name:目前路徑名字

8.&dollar;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指直接監聽一個原生事件。

本文完〜

35道常見的前端vue面試題