Vue中級面試題彙總

Vue在created和mounted這兩個生命週期中請求數據有什麼區別呢?

參考答案 在created中,頁面視圖未出現,若是請求信息過多,頁面會長時間處於白屏狀態,DOM節點沒出來,沒法操做DOM節點。在mounted不會這樣,比較好。

v-model的原理是什麼?

參考答案
<template>
    <div>
        <my-component v-model="value"></my-component>
        <!-- 等同 -->
        <my-component :value="value" @input="value=$event"></my-component>
        <button @click="value=true">顯示</button>
    </div>
</template>
<script>
    export default{
        data(){
            return{
                value:false,
            }
        },
        components:{
            myComponent:resolve =>require(['./my_component'],resolve),
        }
    }
</script>
複製代碼
<template>
    <div v-show="value">
        <span>個人組件</span>
        <button @click="$emit('input',false)">隱藏</button>
    </div>
</template>
<script>
    export default{
        props:{
            value:{
                type:Boolean,
                default:false,
            }
        },
        data(){
            return{}
        },
    }
</script>
複製代碼

說說你對keep-alive的理解

參考答案 keep-alive是一個抽象組件:它自身不會渲染一個DOM元素,也不會出如今父組件鏈中;使用keep-alive包裹動態組件時,會緩存不活動的組件實例,而不是銷燬它們。

其有三個參數css

  • include定義緩存白名單,會緩存的組件;
  • exclude定義緩存黑名單,不會緩存的組件;
  • 以上兩個參數能夠是逗號分隔字符串、正則表達式或一個數組,include="a,b":include="/a|b/":include="['a', 'b']"
  • 匹配首先檢查組件自身的 name 選項,若是 name 選項不可用,則匹配它的局部註冊名稱 (父組件 components 選項的鍵值)。匿名組件不能被匹配;
  • max最多能夠緩存多少組件實例。一旦這個數字達到了,在新實例被建立以前,已緩存組件中最久沒有被訪問的實例會被銷燬掉;
  • 不會在函數式組件中正常工做,由於它們沒有緩存實例;
  • 當組件在內被切換,它的activated和deactivated這兩個生命週期鉤子函數將會被對應執行。

v-if和v-for的優先級是什麼?若是這兩個同時出現時,那應該怎麼優化才能獲得更好的性能?

參考答案

當它們處於同一節點,v-for的優先級比v-if更高,這意味着v-if將分別重複運行於每一個v-for循環中。當你只想爲部分項渲染節點時,這種優先級的機制會十分有用。html

<ul>
    <li v-for="item in items" v-if="item.show">{{item}}</li>
</ul>
複製代碼

若是你的目的是有條件地跳過循環的執行,那麼能夠將 v-if 置於外層元素 (或<template>)上。vue

<ul v-if="items.length">
    <li v-for="item in items">{{item}}</li>
</ul>
複製代碼

使用v-for遍歷對象時,是按什麼順序遍歷的?如何保證順序?

參考答案 按Object.keys()的順序的遍歷,轉成數組保證順序。

在v-for中使用key,會提高性能嗎,爲何?

參考答案

主要看v-for渲染的是什麼。node

  • 若是渲染是一個簡單的列表,如不依賴子組件狀態或臨時DOM狀態(例如:表單輸入值)的列表渲染輸出,不用key性能會更好,由於不用key採用的是「就地更新」的策略。若是數據項的順序被改變, Vue將不會移動DOM元素來匹配數據項的順序,而是就地更新每一個元素。
    <template>
        <div>
            <span v-for="item in lists">{{item}}</span>
        </div>
    </template>
    <script>
    export default {
        data() {
            return {
                lists: [1, 2, 3, 4, 5]
            }
        },
    }
    </script>
    複製代碼
    以上的例子,v-for的內容會生成如下的DOM節點數組,咱們給每個節點標記一個身份id,以辨別節點的位置:
    [
        '<span>1</span>', // id: A
        '<span>2</span>', // id:  B
        '<span>3</span>', // id:  C
        '<span>4</span>', // id:  D
        '<span>5</span>'  // id:  E
    ]
    複製代碼
    將lists中的數據進行位置調換,變成[2,4,3,1,5],在沒有key的情景下,節點位置不變,可是節點的內容更新了,這就是「就地更新」
    [
        '<span>2</span>', // id: A
        '<span>4</span>', // id:  B
        '<span>3</span>', // id:  C
        '<span>1</span>', // id:  D
        '<span>5</span>'  // id:  E
    ]
    複製代碼
    可是在有key的情景下,節點位置進行了交換,可是內容沒有更新
    [
        '<span>2</span>', // id: B
        '<span>4</span>', // id:  D
        '<span>3</span>', // id:  C
        '<span>1</span>', // id:  A
        '<span>5</span>'  // id:  E
    ]
    複製代碼
  • 若是渲染不是一個簡單的列表,用key性能會更好一點,由於vue是採用diff算法來對比新舊虛擬節點來更新節點,在diff算法中,當新節點跟舊節點頭尾交叉對比沒有結果時,先處理舊節點生成一個健爲key,值爲節點下標index的map映射,若是新節點有key,會經過map映射找到對應的舊節點,若是新節點沒有key,會採用遍歷查找的方式去找到對應的舊節點,一種一個map映射,另外一種是遍歷查找。相比而言。map映射的速度更快。
    // vue源碼 src/core/vdom/patch.js 488行
    // 如下是爲了閱讀性進行格式化後的代碼
    // oldCh 是一箇舊虛擬節點數組
    // oldKeyToIdx map映射對象
    // idxInOld 對比後獲得舊節點下標
    if (isUndef(oldKeyToIdx)) {
        oldKeyToIdx = createKeyToOldIdx(oldCh, oldStartIdx, oldEndIdx)
    }
    if (isDef(newStartVnode.key)) {
        // map 方式獲取
        idxInOld = oldKeyToIdx[newStartVnode.key]
    } else {
        // 遍歷方式獲取
        idxInOld = findIdxInOld(newStartVnode, oldCh, oldStartIdx, oldEndIdx)
    }
    複製代碼
    建立map函數
    function createKeyToOldIdx(children, beginIdx, endIdx) {
        let i, key
        const map = {}
        for (i = beginIdx; i <= endIdx; ++i) {
            key = children[i].key
            if (isDef(key)) map[key] = i
        }
        return map
    }
    複製代碼
    遍歷尋找函數
    // sameVnode 是對比新舊節點是否相同的函數
    function findIdxInOld(node, oldCh, start, end) {
        for (let i = start; i < end; i++) {
            const c = oldCh[i];
            if (isDef(c) && sameVnode(node, c)) return i
        }
    }
    複製代碼

key除了在v-for中使用,還有什麼做用?

參考答案

還能夠強制替換元素/組件而不是重複使用它。在如下場景可使用正則表達式

  • 完整地觸發組件的生命週期鉤子
  • 觸發過渡
<transition>
  <span :key="text">{{ text }}</span>
</transition>
複製代碼

當 text 發生改變時,<span>會隨時被更新,所以會觸發過渡。算法

使用key要什麼要注意的嗎?

參考答案
  • 不要使用對象或數組之類的非基本類型值做爲key,請用字符串或數值類型的值;npm

  • 不要使用數組的index做爲key值,由於在刪除數組某一項,index也會隨之變化,致使key變化,渲染會出錯。json

    例:在渲染[a,b,c]用 index 做爲 key,那麼在刪除第二項的時候,index 就會從 0 1 2 變成 0 1(而不是 0 2),隨之第三項的key變成1了,就會誤把第三項刪除了。後端

說說組件的命名規範

參考答案

給組件命名有兩種方式,一種是使用鏈式命名my-component,一種是使用大駝峯命名MyComponent,數組

  • 在字符串模板中<my-component></my-component><MyComponent></MyComponent>均可以使用,

  • 在非字符串模板中最好使用<MyComponent></MyComponent>,由於要遵循W3C規範中的自定義組件名 (字母全小寫且必須包含一個連字符),避免和當前以及將來的 HTML 元素相沖突。

爲何組件中data必須用函數返回一個對象?

參考答案 對象爲引用類型,當重用組件時,因爲數據對象都指向同一個data對象,當在一個組件中修改data時,其餘重用的組件中的data會同時被修改;而使用返回對象的函數,因爲每次返回的都是一個新對象(Object的實例),引用地址不一樣,則不會出現這個問題。

Vue父子組件雙向綁定的方法有哪些?

參考答案
  • 經過在父組件上自定義一個監聽事件<myComponent@diy="handleDiy"></myComponent>,在子組件用this.$emit('diy',data)來觸發這個diy事件,其中data爲子組件向父組件通訊的數據,在父組件中監聽diy個事件時,能夠經過$event訪問data這個值。
  • 經過在父組件上用修飾符.sync綁定一個數據<myComponent :show.sync="show"></myComponent>,在子組件用this.$emit('updata:show',data)來改變父組件中show的值。
  • 經過v-model

組件的name選項有什麼做用?

參考答案
  • 遞歸組件時,組件調用自身使用;
  • is特殊特性和component內置組件標籤時使用;
  • keep-alive內置組件標籤中includeexclude屬性中使用。

什麼是遞歸組件?舉個例子說明下?

參考答案

遞歸引用能夠理解爲組件調用自身,在開發多級菜單組件時就會用到,調用前要先設置組件的name選項, 注意必定要配合v-if使用,避免造成死循環,用element-vue組件庫中NavMenu導航菜單組件開發多級菜單爲例:

<template>
    <el-submenu :index="menu.id" popper-class="layout-sider-submenu" :key="menu.id">
        <template slot="title">
            <Icon :type="menu.icon" v-if="menu.icon"/>
            <span>{{menu.title}}</span>
        </template>
        <template v-for="(child,i) in menu.menus">
            <side-menu-item v-if="Array.isArray(child.menus) && child.menus.length" :menu="child"></side-menu-item>
            <el-menu-item :index="child.id" :key="child.id" v-else>
                <Icon :type="child.icon" v-if="child.icon"/>
                <span>{{child.title}}</span>
            </el-menu-item>
        </template>
    </el-submenu>
</template>
<script>
    export default{
        name: 'sideMenuItem',
        props: {
            menu: {
                type: Object,
                default(){
                    return {};
                }
            }
        }
    }
</script>
複製代碼

說說你對slot的理解?slot使用場景有哪些?

參考答案

組件的插槽功能

說下$attrs$listeners的使用場景?

參考答案
  • $attrs: 包含了父做用域中(組件標籤)不做爲 prop 被識別 (且獲取) 的特性綁定 (class 和 style 除外)。 在建立基礎組件時候常用,能夠和組件選項inheritAttrs:false和配合使用在組件內部標籤上用v-bind="$attrs"將非prop特性綁定上去;
  • $listeners: 包含了父做用域中(組件標籤)的 (不含.native) v-on 事件監聽器。 在組件上監聽一些特定的事件,好比focus事件時,若是組件的根元素不是表單元素的,則監聽不到,那麼能夠用v-on="$listeners"綁定到表單元素標籤上解決。

說說你對provide和inject的理解

參考答案

組件的依賴注入

EventBus註冊在全局上時,路由切換時會重複觸發事件,如何解決呢?

參考答案

在有使用$on的組件中要在beforeDestroy鉤子函數中用$off銷燬。

Vue組件裏寫的原生addEventListeners監聽事件,要手動去銷燬嗎?爲何?

參考答案

要,否則會形成屢次綁定和內存泄露。關於移除事件監聽的坑

Vue組件裏的定時器要怎麼銷燬?

參考答案
  • 若是頁面上有不少定時器,能夠在data選項中建立一個對象timer,給每一個定時器取個名字一一映射在對象timer中, 在beforeDestroy構造函數中for(let k in this.timer){clearInterval(k)}
  • 若是頁面只有單個定時器,能夠這麼作。
    const timer = setInterval(() =>{}, 500);
    this.$once('hook:beforeDestroy', () => {
       clearInterval(timer);
    })
    複製代碼

Vue中能監聽到數組變化的方法有哪些?爲何這些方法能監聽到呢?

參考答案
  • push()pop()shift()unshift()splice()sort()reverse(),這些方法在Vue中被從新定義了,故能夠監聽到數組變化;
  • filter()concat()slice(),這些方法會返回一個新數組,也能夠監聽到數組的變化。

在Vue中那些數組變化沒法監聽,爲何,怎麼解決?

參考答案
  • 利用索引直接設置一個數組項時;

  • 修改數組的長度時。

    • 第一個狀況,利用已有索引直接設置一個數組項時Object.defineProperty()能夠監聽到,利用不存在的索引直接設置一個數組項時Object.defineProperty()不能夠監聽到,可是官方給出的解釋是因爲JavaScript的限制,Vue不能檢測以上數組的變更,其實根本緣由是性能問題,性能代價和得到的用戶體驗收益不成正比。
    • 第二個狀況,緣由是Object.defineProperty()不能監聽到數組的length屬性。
  • this.$set(this.items, indexOfItem, newValue)this.items.splice(indexOfItem, 1, newValue)來解決第一種狀況;

  • this.items.splice(newLength)來解決第二種狀況。

在Vue中那些對象變化沒法監聽,爲何,怎麼解決?

參考答案
  • 對象屬性的添加
  • 對象屬性的刪除

由於Vue是經過Object.defineProperty來將對象的key轉成getter/setter的形式來追蹤變化,但getter/setter只能追蹤一個數據是否被修改,沒法追蹤新增屬性和刪除屬性,因此纔會致使上面對象變化沒法監聽。

  • this.$set(this.obj,"key","newValue")來解決第一種狀況;
  • Object.assign來解決第二種狀況。

刪除對象用delete和Vue.delete有什麼區別?

參考答案
  • delete:只是被刪除對象成員變爲' 'undefined,其餘元素鍵值不變;
  • Vue.delete:直接刪了對象成員,若是對象是響應式的,確保刪除能觸發更新視圖,這個方法主要用於避開 Vue 不能檢測到屬性被刪除的限制。

watch和計算屬性有什麼區別?

參考答案
  • watch:一個數據影響多個數據,當須要在數據變化時執行異步或開銷較大的操做時;
  • 計算屬性:一個數據受多個數據影響。

計算屬性和方法有什麼區別?

參考答案
  • 計算屬性:是基於它們的響應式依賴進行緩存的,只在相關響應式依賴發生改變時它們纔會從新求值。
  • 方法:每當觸發從新渲染時,調用方法將總會再次執行函數。當咱們不但願有緩存,可使用方法,可是若是求值開銷大時建議用計算屬性。

過渡動畫實現的方式有哪些?

參考答案

你有寫過自定義指令嗎?自定義指令的生命週期(鉤子函數)有哪些?

參考答案

自定義指令的鉤子函數

手寫一個自定義指令及寫出如何調用

參考答案

註冊一個讓字體顏色閃爍的指令v-color

Vue怎麼定義全局方法

參考答案

有三種

  • 掛載在Vue的prototype上

    // base.js
    const install = function (Vue, opts) {
        Vue.prototype.demo = function () {
            console.log('我已經在Vue原型鏈上')
        }
    }
    export default {
        install
    }
    複製代碼
    //main.js
    //註冊全局函數
    import base from 'service/base';
    Vue.use(base);
    複製代碼
  • 利用全局混入mixin

  • this.$root.$on綁定方法,用this.$root.$off解綁方法,用this.$root.$emit全局調用。

    this.$root.$on('demo',function(){
        console.log('test');
    })
    this.$root.$emit('demo');
    this.$root.$off('demo');
    複製代碼

說說你對DOM選項el、template、render的理解?

參考答案
  • el:提供一個在頁面上已存在的DOM元素做爲Vue實例的掛載目標。能夠是CSS選擇器,也能夠是一個HTMLElement實例。
    • 由於全部的掛載元素會被Vue生成的DOM替換。所以不推薦掛載Vue實例到或者上。
    • 若是在const vm = new Vue({})中存在這個選項,實例將當即進入編譯過程,不然,須要顯式調用vm.$mount()手動開啓編譯。
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
    </head>
    <body>
        <div id="app">我是el掛載的內容:小明今年{{age}}歲了</div>
    </body>
    <script>
        const vm= new Vue({
            el:'#app',
            data:{
                age:17
            },
        }
    </script>
</html>
複製代碼
<script>
    const vm= new Vue({
        data:{
            age:17
        },
    })
    vm.$mount('#app')
</script>
複製代碼

  • template:一個字符串模板做爲Vue實例的標識使用。若是el存在,模板將會替換掛載的元素。掛載元素的內容都將被忽略,除非模板的內容有分發插槽。
    • 若是值以 # 開始,則它將被用做選擇符,並使用匹配元素的 innerHTML 做爲模板。
<script>
    const vm= new Vue({
        el:'#app',
        data:{
            age:17
        },
        template:'<div>我是template的內容:小明今年{{age}}歲了</div>',
    })
</script>
複製代碼
<script type="x-template" id="mb">
	<div>我是template的內容:小明今年{{age}}歲了</div>
</script>
<script>
    const vm= new Vue({
        el:'#app',
        data:{
            age:17
        },
        template:'#mb',
    })
</script>
複製代碼
<body>
    <div id="app">
        我是el掛載的內容:小明今年{{age}}歲了
    </div>
    <template id="mb">
        <div>我是template的內容:小明今年{{age}}歲了</div>
    </template>
</body>
<script>
    const vm= new Vue({
        el:'#app',
        data:{
            age:17
        },
        template:'#mb',
    })
</script>
複製代碼

  • render :Vue 選項中的 render 函數若存在,則 Vue 構造函數不會從 template 選項或經過 el 選項指定的掛載元素中提取出的 HTML 模板編譯渲染函數。
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
    </head>
    <body>
        <div id="app">
            我是el掛載的內容:小明今年{{age}}歲了
        </div>
    </body>
    <script>
        const vm= new Vue({
            el:'#app',
            data:{
                age:17
            },
            template:'<div>我是template的內容:小明今年{{age}}歲了</div>',
            render(h){
                return h('div',`我是render的內容:小明今年${this.age}歲了`)
            }
        })
    </script>
</html>
複製代碼

<template></template>有什麼用?

參考答案 當作一個不可見的包裹元素,減小沒必要要的DOM元素,整個結構會更加清晰。

Vue怎麼改變插入模板的分隔符?

參考答案

delimiters選項,其默認是["{{", "}}"]

// 將分隔符變成ES6模板字符串的風格
new Vue({
  delimiters: ['${', '}']
})
複製代碼

Vue變量名若是以_、$開頭的屬性會發生什麼問題?怎麼訪問到它們的值?

參考答案

_$ 開頭的屬性 不會 被 Vue 實例代理,由於它們可能和 Vue 內置的屬性、API 方法衝突,你可使用例如 vm.$data._property 的方式訪問這些屬性。

怎麼捕獲Vue組件的錯誤信息?

參考答案
  • errorCaptured是組件內部鉤子,當捕獲一個來自子孫組件的錯誤時被調用,接收errorvminfo三個參數,return false後能夠阻止錯誤繼續向上拋出。
  • errorHandler爲全局鉤子,使用Vue.config.errorHandler配置,接收參數與errorCaptured一致,2.6後可捕捉v-onpromise鏈的錯誤,可用於統一錯誤處理與錯誤兜底。

Vue.observable你有了解過嗎?說說看

參考答案 讓一個對象可響應。能夠做爲最小化的跨組件狀態存儲器。

Vue項目中如何配置favicon?

參考答案
  • 靜態配置 <link rel="icon" href="<%= BASE_URL %>favicon.ico">, 其中<%= BASE_URL %>等同vue.config.js中publicPath的配置;
  • 動態配置<link rel="icon" type="image/png" href="">
    import browserImg from 'images/kong.png';//爲favicon的默認圖片
    const imgurl ='後端傳回來的favicon.ico的線上地址'
    let link = document.querySelector('link[type="image/png"]');
    if (imgurl) {
        link.setAttribute('href', imgurl);
    } else {
        link.setAttribute('href', browserImg);
    }
    複製代碼

怎麼修改Vue項目打包後生成文件路徑?

參考答案
  • 在Vue CLI2中修改config/index.js文件中的build.assetsPublicPath的值;
  • 在Vue CLI3中配置publicPath的值。

怎麼解決Vue項目打包後靜態資源圖片失效的問題?

參考答案

在項目中通常經過配置alias路徑別名的方式解決,下面是Vue CLI3的配置。

configureWebpack: {
    resolve: {
        extensions: ['.js', '.vue', '.json'],
        alias: {
            '@': resolve('src'),
            'assets': resolve('src/assets'),
            'css': resolve('src/assets/css'),
            'images': resolve('src/assets/images'),
        }
    },
},
複製代碼

怎麼解決Vue中動態設置img的src不生效的問題?

參考答案

由於動態添加src被當作靜態資源處理了,沒有進行編譯,因此要加上require。

<template>
    <img class="logo" :src="logo" alt="公司logo">
</template>
<script>
export default {
    data() {
        return {
            logo:require("assets/images/logo.png"),
        };
    }
};
</script>
複製代碼

在Vue項目中如何引入第三方庫(好比jQuery)?有哪些方法能夠作到?

參考答案
相關文章
相關標籤/搜索