1. 程式人生 > >關於Vue的常見面試題

關於Vue的常見面試題

什麼是 mvvm?

MVVM 是 Model-View-ViewModel 的縮寫。mvvm 是一種設計思想。Model 層代表資料模型,也可以在 Model 中定義資料修改和操作的業務邏輯;View 代表 UI 元件,它負責將資料模型轉化成 UI 展現出來,ViewModel 是一個同步 View 和 Model 的物件。

在 MVVM 架構下,View 和 Model 之間並沒有直接的聯絡,而是通過 ViewModel 進行互動,Model 和 ViewModel 之間的互動是雙向的, 因此 View 資料的變化會同步到 Model 中,而 Model 資料的變化也會立即反應到 View 上。

ViewModel 通過雙向資料繫結把 View 層和 Model 層連線了起來,而 View 和 Model 之間的同步工作完全是自動的,無需人為干涉,因此開發者只需關注業務邏輯,不需要手動操作 DOM, 不需要關注資料狀態的同步問題,複雜的資料狀態維護完全由 MVVM 來統一管理。

mvvm 和 mvc 區別?

mvc 和 mvvm 其實區別並不大。都是一種設計思想。主要就是 mvc 中 Controller 演變成 mvvm 中的 viewModel。mvvm 主要解決了 mvc 中大量的 DOM 操作使頁面渲染效能降低,載入速度變慢,影響使用者體驗。和當 Model 頻繁發生變化,開發者需要主動更新到 View 。

vue 的優點是什麼?

  • 低耦合。檢視(View)可以獨立於 Model 變化和修改,一個 ViewModel 可以繫結到不同的"View"上,當 View 變化的時候 Model 可以不變,當 Model 變化的時候 View 也可以不變。

  • 可重用性。你可以把一些檢視邏輯放在一個 ViewModel 裡面,讓很多 view 重用這段檢視邏輯。

  • 獨立開發。開發人員可以專注於業務邏輯和資料的開發(ViewModel),設計人員可以專注於頁面設計,使用 Expression Blend 可以很容易設計介面並生成 xml 程式碼。

  • 可測試。介面素來是比較難於測試的,而現在測試可以針對 ViewModel 來寫。

vue生命週期的理解?

答:總共分為 8 個階段建立前/後,載入前/後,更新前/後,銷燬前/後。

  • 建立前/後: 在 beforeCreate 階段,vue 例項的掛載元素 el 還沒有。

  • 載入前/後:在 beforeMount 階段,vue 例項的$el 和 data 都初始化了,但還是掛載之前為虛擬的 dom 節點,data.message 還未替換。在 mounted 階段,vue 例項掛載完成,data.message 成功渲染。

  • 更新前/後:當 data 變化時,會觸發 beforeUpdate 和 updated 方法。

  • 銷燬前/後:在執行 destroy 方法後,對 data 的改變不會再觸發周期函式,說明此時 vue 例項已經解除了事件監聽以及和 dom 的繫結,但是 dom 結構依然存在

元件之間的傳值?

  1. 父元件與子元件傳值

//父元件通過標籤上面定義傳值
<template>
    <Main :obj="data"></Main>
</template>
<script>
    //引入子元件
    import Main form "./main"

    exprot default{
        name:"parent",
        data(){
            return {
                data:"我要向子元件傳遞資料"
            }
        },
        //初始化元件
        components:{
            Main
        }
    }
</script>


//子元件通過props方法接受資料
<template>
    <div>{{data}}</div>
</template>
<script>
    exprot default{
        name:"son",
        //接受父元件傳值
        props:["data"]
    }
</script>
  1. 子元件向父元件傳遞資料

//子元件通過$emit方法傳遞引數
<template>
   <div v-on:click="events"></div>
</template>
<script>
    //引入子元件
    import Main form "./main"

    exprot default{
        methods:{
            events:function(){

            }
        }
    }
</script>


//

<template>
    <div>{{data}}</div>
</template>
<script>
    exprot default{
        name:"son",
        //接受父元件傳值
        props:["data"]
    }
</script>

active-class 是哪個元件的屬性?

vue-router 模組的 router-link 元件。

巢狀路由怎麼定義?

在實際專案中我們會碰到多層巢狀的元件組合而成,但是我們如何實現巢狀路由呢?因此我們需要在 VueRouter 的引數中使用 children 配置,這樣就可以很好的實現路由巢狀。
index.html,只有一個路由出口

<div id="app">
    <!-- router-view 路由出口, 路由匹配到的元件將渲染在這裡 -->
    <router-view></router-view>
</div>

main.js,路由的重定向,就會在頁面一載入的時候,就會將 home 元件顯示出來,因為重定向指向了 home 元件,redirect 的指向與 path 的必須一致。children 裡面是子路由,當然子路由裡面還可以繼續巢狀子路由。

import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)

//引入兩個元件

import home from "./home.vue"
import game from "./game.vue"
//定義路由
const routes = [
    { path: "/", redirect: "/home" },//重定向,指向了home元件
    {
        path: "/home", component: home,
        children: [
            { path: "/home/game", component: game }
        ]
    }
]
//建立路由例項
const router = new VueRouter({routes})

new Vue({
    el: '#app',
    data: {
    },
    methods: {
    },
    router
})

home.vue,點選顯示就會將子路由顯示在出來,子路由的出口必須在父路由裡面,否則子路由無法顯示。

路由之間跳轉?

  • 宣告式(標籤跳轉)

  • 程式設計式( js 跳轉) router.push('index')

懶載入(按需載入路由)(常考)

webpack 中提供了 require.ensure()來實現按需載入。以前引入路由是通過 import 這樣的方式引入,改為 const 定義的方式進行引入。

  • 不進行頁面按需載入引入方式:

import  home   from '../../common/home.vue'
  • 進行頁面按需載入的引入方式:

const  home = r => require.ensure( [], () => r (require('../../common/home.vue')))

vuex 是什麼?怎麼使用?哪種功能場景使用它?

vue 框架中狀態管理。在 main.js 引入 store,注入。新建了一個目錄 store,….. export 。場景有:單頁應用中,元件之間的狀態。音樂播放、登入狀態、加入購物車

// 新建 store.js
import vue from 'vue'
import vuex form 'vuex'
vue.use(vuex)
export default new vuex.store({
    //...code
})

//main.js
import store from './store'
...

vue-router 有哪幾種導航鉤子?

三種

  • 全域性導航鉤子

  • router.beforeEach(to, from, next),

  • router.beforeResolve(to, from, next),

  • router.afterEach(to, from ,next)

  • 元件內鉤子

  • beforeRouteEnter,

  • beforeRouteUpdate,

  • beforeRouteLeave

  • 單獨路由獨享元件

  • beforeEnter

自定義指令(v-check, v-focus) 的方法有哪些? 它有哪些鉤子函式? 還有哪些鉤子函式引數

  • 全域性定義指令:在 vue 物件的 directive 方法裡面有兩個引數, 一個是指令名稱, 另一個是函式。

  • 元件內定義指令:directives

  • 鉤子函式: bind(繫結事件出發)、inserted(節點插入時候觸發)、update(元件內相關更新)

  • 鉤子函式引數: el、binding

說出至少 4 種 vue 當中的指令和它的用法

v-if(判斷是否隱藏)、v-for(把資料遍歷出來)、v-bind(繫結屬性)、v-model(實現雙向繫結)

vue 的雙向繫結的原理是什麼(常考)

vue.js 是採用資料劫持結合釋出者-訂閱者模式的方式,通過 Object.defineProperty()來劫持各個屬性的 setter,getter,在資料變動時釋出訊息給訂閱者,觸發相應的監聽回撥。

具體步驟:
第一步:需要 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 變更的雙向繫結效果。

vuex 有哪幾種屬性

有 5 種,分別是 state、getter、mutation、action、module

vuex 的 store 特性是什麼

  • vuex 就是一個倉庫,倉庫裡放了很多物件。其中 state 就是資料來源存放地,對應於一般 vue 物件裡面的 data

  • state 裡面存放的資料是響應式的,vue 元件從 store 讀取資料,若是 store 中的資料發生改變,依賴這相資料的元件也會發生更新

  • 它通過 mapState 把全域性的 state 和 getters 對映到當前元件的 computed 計算屬性

vuex 的 getter 特性是什麼

  • getter 可以對 state 進行計算操作,它就是 store 的計算屬性

  • 雖然在元件內也可以做計算屬性,但是 getters 可以在多給件之間複用

  • 如果一個狀態只在一個元件內使用,是可以不用 getters

vuex 的 mutation 特性是什麼

  • action 類似於 muation, 不同在於:action 提交的是 mutation,而不是直接變更狀態

  • action 可以包含任意非同步操作

vue 中 ajax 請求程式碼應該寫在元件的 methods 中還是 vuex 的 action 中

如果請求來的資料不是要被其他元件公用,僅僅在請求的元件內使用,就不需要放入 vuex 的 state 裡

如果被其他地方複用,請將請求放入 action 裡,方便複用,幷包裝成 promise 返回

不用 vuex 會帶來什麼問題

  • 可維護性會下降,你要修改資料,你得維護 3 個地方

  • 可讀性下降,因為一個元件裡的資料,你根本就看不出來是從哪裡來的

  • 增加耦合,大量的上傳派發,會讓耦合性大大的增加,本來 Vue 用 Component 就是為了減少耦合,現在這麼用,和元件化的初衷相背

vuex 原理

vuex 僅僅是作為 vue 的一個外掛而存在,不像 Redux,MobX 等庫可以應用於所有框架,vuex 只能使用在 vue 上,很大的程度是因為其高度依賴於 vue 的 computed 依賴檢測系統以及其外掛系統,

vuex 整體思想誕生於 flux,可其的實現方式完完全全的使用了 vue 自身的響應式設計,依賴監聽、依賴收集都屬於 vue 對物件 Property set get 方法的代理劫持。最後一句話結束 vuex 工作原理,vuex 中的 store 本質就是沒有 template 的隱藏著的 vue 元件;

使用 Vuex 只需執行 Vue.use(Vuex),並在 Vue 的配置中傳入一個 store 物件的示例,store 是如何實現注入的?美團

Vue.use(Vuex) 方法執行的是 install 方法,它實現了 Vue 例項物件的 init 方法封裝和注入,使傳入的 store 物件被設定到 Vue 上下文環境的store中。因此在VueComponent任意地方都能夠通過this.store 訪問到該 store。

state 內部支援模組配置和模組巢狀,如何實現的?美團

在 store 構造方法中有 makeLocalContext 方法,所有 module 都會有一個 local context,根據配置時的 path 進行匹配。所以執行如 dispatch('submitOrder', payload)這類 action 時,預設的拿到都是 module 的 local state,如果要訪問最外層或者是其他 module 的 state,只能從 rootState 按照 path 路徑逐步進行訪問。

在執行 dispatch 觸發 action(commit 同理)的時候,只需傳入(type, payload),action 執行函式中第一個引數 store 從哪裡獲取的?美團

store 初始化時,所有配置的 action 和 mutation 以及 getters 均被封裝過。在執行如 dispatch('submitOrder', payload)的時候,actions 中 type 為 submitOrder 的所有處理方法都是被封裝後的,其第一個引數為當前的 store 物件,所以能夠獲取到 { dispatch, commit, state, rootState } 等資料。

Vuex 如何區分 state 是外部直接修改,還是通過 mutation 方法修改的?美團

Vuex 中修改 state 的唯一渠道就是執行 commit('xx', payload) 方法,其底層通過執行 this._withCommit(fn) 設定_committing 標誌變數為 true,然後才能修改 state,修改完畢還需要還原_committing 變數。外部修改雖然能夠直接修改 state,但是並沒有修改_committing 標誌位,所以只要 watch 一下 state,state change 時判斷是否_committing 值為 true,即可判斷修改的合法性。

除錯時的"時空穿梭"功能是如何實現的?美團

devtoolPlugin 中提供了此功能。因為 dev 模式下所有的 state change 都會被記錄下來,'時空穿梭' 功能其實就是將當前的 state 替換為記錄中某個時刻的 state 狀態,利用 store.replaceState(targetState) 方法將執行 this._vm.state = state 實現。

axios 是什麼?怎麼使用?描述使用它實現登入功能的流程

axios 是請求後臺資源的模組。 npm i axios -S

如果傳送的是跨域請求,需在配置檔案中 config/index.js 進行配置