天天看點

vue面試二十問

vue面試二十問

這是我自己在準備面試的時候,上網收集彙總的一些知識點,不能說你會這些就能找到自己心儀的工作,但你要想找到心儀的工作就必須會這些!

一、什麼是MVVM?

MVVM是Model-View-ViewModel的縮寫。Model 層代表資料模型;View 代表DOM,ViewModel 是一個同步View 和 Model的對象。

View 和 Model 之間并沒有直接的聯系,而是通過ViewModel進行互動,Model 和 ViewModel 之間的互動是雙向的, 是以View 資料的變化會同步到Model中,而Model 資料的變化也會立即反應到View 上。

優點:需關注業務邏輯,不需要手動操作DOM, 不需要關注資料狀态的同步問題,複雜的資料狀态維護完全由 MVVM 來統一管理。

二、vue的優點是什麼?

  1. 低耦合。視圖(View)可以獨立于Model變化和修改,一個ViewModel可以綁定到不同的"View"上,當View變化的時候Model可以不變,當Model變化的時候View也可以不變。
  2. 元件化,實作html的封裝和重用
  3. 虛拟DOM,不在使用原生DOM操作
  4. 運作速度快

三、元件之間的傳值?

1.父元件向子元件傳值:

使用自定義屬性綁定(v-bind:)相應的父元件資料 ,把自定義屬性在子元件的props屬性裡定義一下。

<sonCom v-bind:parentmsg="msg"></sonCom>
//子元件props屬性
props:['parentmsg']
           

2.子元件調用父元件方法并傳參(變向的子元件向父元件傳值)

通過$emit

//父元件方法
methods:{
    show(data){
        console.log(data)
    }
}

//DOM
<sonCom v-on:func = 'show'></sonCom>

//子元件
this.$emit('func',123)//123可以改成子元件data中的資料,完成子元件向父元件傳值
           

3.兄弟元件傳值

通過event bus ,大項目vuex

1.建立一個空vue執行個體,并将它釋出到全局中(bus.js檔案)

import Vue from 'vue'
const bus = new Vue()
export default bus
           

2.在子元件一中引用bus.js,用bus.$emit(‘參數name’,value)方法傳參

3.在子元件二中引用bus.js,用bus.$on(‘參數名字’,callback(value))方式接受參數并處理

四、為什麼元件中的data必須是function?

元件中的data寫成一個函數,資料以函數傳回值的形式定義,保證每個元件執行個體都有自己的私有資料空間,不會造成污染。要不然所有元件執行個體共用一個data,改一個其他全改

五、v-show、v-if 差別,使用場景

v-show:本質控制css的display:none,隻編譯一次。切換開銷小,初始開銷大

适用場景:頻繁切換某節點

v-if:本質動态向DOM樹添加或者删除DOM元素,不停銷毀和建立比較消耗性能。初始渲染開銷小,切換開銷大

适用場景:不需要頻繁切換節點

六、擷取DOM

ref=“domName”,this.$refs.domName

七、為什麼要使用key?

需要使用key來給每個節點做一個唯一辨別,Diff算法就可以正确的識别此節點。作用主要是為了高效的更新虛拟DOM

八、雙向資料綁定

(大緻)

vue.js 是采用資料劫持結合釋出者-訂閱者模式的方式,通過

Object.defineProperty()

來劫持各個屬性的

setter

getter

,在資料變動時釋出消息給訂閱者,觸發相應的監聽回調

核心:Object.defineProperty()(詳看紅寶書)

手寫一個簡單的雙向資料綁定

let input = document.getElementById("input");
  let text = document.getElementById("text");
  let data = { value: "" };
  Object.defineProperty(data, "value", {
    set: function (val) {
      text.innerHTML = val;
      input.value = val;
    },
    get: function () {
      return input.value;
    }
  });
  input.onkeyup = function (e) {
    data.value = e.target.value;
  };
           

九、computed和watch的差別

computed:

  1. 支援緩存,隻有依賴資料發生改變,才會重新進行計算.
  2. 不支援異步,當computed内有異步操作時無效,無法監聽資料的變化.

适用場景:一個屬性受多個屬性影響(購物車商品結算)

watch:

  1. 不支援緩存,資料變,直接會觸發相應的操作;
  2. watch支援異步;
  3. 監聽的函數接收兩個參數,第一個參數是最新的值;第二個參數是輸入之前的值;

适用場景:當需要在資料變化時執行異步或開銷較大的操作時(搜尋資料)

十、常用事件修飾符

  • .stop():等同于JavaScript中的event.stopPropagation(),防止事件冒泡。
  • .prevent:等同于JavaScript中的event.preventDefault(),防止執行預設的行為。
  • .capture:與事件冒泡的方向相反,事件捕獲由外到内。
  • .self:隻會觸發自己範圍内的事件,不包含子元素
  • .once:隻會觸發一次

十一、vue-router中的導航鈎子

  • 全局 鈎子
    const router = new VueRouter({ ... });
    router.beforeEach((to, from, next) => {
        // do someting
    });
    //to: Route,代表要進入的目标,它是一個路由對象
    
    //from: Route,代表目前正要離開的路由,同樣也是一個路由對象
    
    //: Function,這是一個必須需要調用的方法,而具體的執行效果則依賴 next 方法調用的參數
               
  • 路由獨享鈎子
cont router = new VueRouter({
    routes: [
        {
            path: '/file',
            component: File,
            beforeEnter: (to, from ,next) => {
                // do someting
            }
        }
    ]
});
           
  • 元件内的導航鈎子
const File = {
    template: `<div>This is file</div>`,
    beforeRouteEnter(to, from, next) {
        // do someting
        // 在渲染該元件的對應路由被 confirm 前調用
    },
    beforeRouteUpdate(to, from, next) {
        // do someting
        // 在目前路由改變,但是依然渲染該元件是調用
    },
    beforeRouteLeave(to, from ,next) {
        // do someting
        // 導航離開該元件的對應路由時被調用
    }
}
           

十二、vue的兩個核心

  1. 資料驅動

​ viewModel,保證資料和視圖的一緻性

  1. 元件系統

    元件化開發,優點很多,可以很好的降低資料之間的耦合度。将常用的代碼封裝成元件之後,就能高度的複用,提高代碼的可重用性。一個頁面/子產品可以由多個元件所組成。

十三、Vue生命周期

vue面試二十問
/*建立階段*/

      //1.第一個生命周期函數
      beforeCreate() {//表示執行個體完全被建立出來之前,會執行它
        // console.log(this.msg);
        // this.show();

        /*
          在beforeCreate生命周期執行的時候,data和methods中的資料還沒有初始化
        */

      },
      //2.第二個生命周期函數
      created() {
        console.log(this.msg + '--->created');
        this.show();
        //在created中,data,和methods 已經被初始化了
      },
      //3.第三個生命周期函數
      beforeMount() {
        //表示 模闆已經在記憶體中編譯完成了,但是尚未把模闆渲染到頁面中
        console.log(document.getElementById("me").innerHTML + '--->beforeMount')
        //在beforeMount 執行的時候,頁面中元素還沒有被真正替換過來,隻是之前寫的一些模闆字元串
      },
      //4.第四個生命周期函數
      mounted() {
        //表示 模闆已經在記憶體中編譯完成了,但是已經把模闆渲染到頁面中
        console.log(document.getElementById("me").innerHTML + '--->mounted')
        //mounted 執行的時候,頁面中元素已經被真正替換過來
        //隻要執行完mounted,就表示整個Vue執行個體已經初始化完畢了,此時元件已經脫離了建立階段,進入了運作階段。
      },


      /*運作階段*/

      //1.第一個運作生命周期函數
      beforeUpdate() { //這時候表示我們的界面還沒有被更新,【資料更新了】

        console.log('頁面中msg的值' + document.getElementById("me").innerHTML + '--->beforeUpdate')
        console.log("Data中msg值為:" + this.msg)

        //資料是最新的,頁面沒有同步
      },

      //2.第二個運作生命周期函數
      updated() {

        console.log('頁面中msg的值' + document.getElementById("me").innerHTML + '--->updated')
        console.log("Data中msg值為:" + this.msg)
        //資料是最新的,頁面已經同步
      },


      /*銷毀階段*/
      //1.第一個銷毀生命周期函數
      beforeDestroy() {  //Vue執行個體從運作到銷毀階段
        //Vue執行個體上所有的Data和所有的methods,以及過濾器、指令。。。都處于可用狀态,此時還沒有真正執行銷毀過程
      },

      //1.第二個銷毀生命周期函數
      destroyed() {
        //Vue執行個體上所有的Data和所有的methods,以及過濾器、指令。。。都已經銷毀。
      },

    });
           

十四、vuex

1.Vuex是什麼

Vuex是實作元件全局狀态(資料)管理的一種機制,可以友善實作組價之間的資料的共享

[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-28jCMlgP-1599554454926)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1598779618877.png)]

  1. Vuex優點
  • 能夠在Vuex中集中管理共享的資料,易于開發和後期維護
  • 能夠高效的實作元件之間的資料共享,提高開發效率
  • 儲存在vuex中的資料都是響應式的,能夠實時保持資料與頁面的同步
  1. Vuex四個核心概念
    • State

      State提供唯一的公共資料源,所有共享的資料都要統一放到Store的State中進行存儲。state裡面存放的資料是響應式的,Vue元件從store中讀取資料,若是store中的資料發生改變,依賴這個資料的元件也會發生更新

      元件中通路:

      //方式一:
      this.$store.state.myDate
      //方式二:
      import { mapState } from 'vuex'
      
      computed:{
          ...mapState(['myData'])
      }
                 
    • Mutation

      Mutation用于變更Store中的資料,可以集中監控資料變化(不能寫異步代碼)

      //store.js中
      mutation:{
          func(state,argument){
              fn()
          }
      }
      //元件中調用
       this.$store.commit('func',argument)
      
      
      //第二種方法
      import { mapMutations } from 'vuex'
      methods:{
          ...mapMutations(['func']),
              myfunc(){
              this.func(argument)
          }
      }
                 
    • Action

      如果通過異步操作變更資料,必須通過Action,而不能使用Mutation,但是在Action 中還是要通過觸發Mutation的方式間接變更資料

      //store.js中
      actions:{
          func(context,argument){
              setTimeout(()=>{
                  context.commit('mutation裡的function',argument )
              },wait)
          }
      }
      
      //元件中
      this.$store.dispatch('func',argument)
      
      //方式二:
      import { mapActions } from 'vuex'
      methods:{
          ...mapActions(['func']),
              myfunc(){
              this.func(argument)
          }
      }
                 
    • Getter

      用于對Store中的資料進行加工處理形成新的資料。Store資料改變,Getter的資料也會跟着變化(像vue裡的計算屬性)

      getters:{
          newData(state){
              return `新值為${state.myData}`
          }
      }
      //方式一:
      this.$store.getters.newData
      
      //方式二:
      import { mapGetters } from 'vuex'
      
      computed:{
          ...mapGetters(['newData'])
      }
                 
    • modules

      在Vue中State使用是單一狀态樹結構,應該的所有的狀态都放在state裡面,如果項目比較複雜,那state是一個很大的對象,store對象也将對變得非常大,難于管理。

      module:可以讓每一個子產品擁有自己的state、mutation、action、getters,使得結構非常清晰,友善管理。

      const moduleA = {
       state: { ... },
       mutations: { ... },
       actions: { ... },
       getters: { ... }
       }
      const moduleB = {
       state: { ... },
       mutations: { ... },
       actions: { ... }
       }
       
      const store = new Vuex.Store({
       modules: {
        a: moduleA,
        b: moduleB})
                 

十五、單頁面應用(SPA)

SPA->就是隻有一個首頁面的應用,浏覽器一開始要加載所有必須的 html、js、css。互動時候由路由程式動态載入,單頁面的頁面跳轉僅重新整理局部資源,多用于pc端

優點:

  • 良好的互動體驗:單頁應用的内容的改變不需要重新加載整個頁面。
  • 減輕伺服器壓力:伺服器隻用出資料就可以,不用管展示邏輯和頁面合成,吞吐能力會提高幾倍。
  • 良好的前後端分離:後端不用負責模闆渲染,隻需要進行資料的存儲與計算

缺點:

  • 對SEO不太友好,不利于seo的搜尋
  • 需要自行實作導航的前進後退;
  • 頁面複雜度高、初次加載耗時多

十六、虛拟DOM

  1. 什麼是虛拟DOM?

​ 虛拟 dom 是相對于浏覽器所渲染出來的真實 dom 的,在react,vue等技術出現之前,我們要改變頁面展示的内容隻能通過周遊查詢 dom 樹的方式找到需要修改的 dom 然後修改樣式行為或者結構,來達到更新 ui 的目的。

​ 這種方式相當消耗計算資源,因為每次查詢 dom 幾乎都需要周遊整顆 dom 樹,如果建立一個與 dom 樹對應的虛拟 dom 對象( js 對象),以對象嵌套的方式來表示 dom 樹,那麼每次 dom 的更改就變成了 js 對象的屬性的更改,這樣一來就能查找 js 對象的屬性變化要比查詢 dom 樹的性能開銷小。

  1. 為什麼DOM性能開銷大?

​ 其實并不是查詢 dom 樹性能開銷大而是 dom 樹的實作子產品和 js 子產品是分開的這些跨子產品的通訊增加了成本,以及 dom 操作引起的浏覽器的回流和重繪,使得性能開銷巨大,原本在 pc 端是沒有性能問題的,因為 pc 的計算能力強,但是随着移動端的發展,越來越多的網頁在智能手機上運作,而手機的性能參差不齊,會有性能問題。

  1. vue大緻解決方法

​ 每次更新 dom 都盡量避免重新整理整個頁面,而是有針對性的去重新整理那被更改的一部分、也就是diff算法

  1. diff算法的大緻思路

​ 我們先根據真實DOM生成一顆

virtual DOM

,當

virtual DOM

某個節點的資料改變後會生成一個新的

Vnode

,然後

Vnode

oldVnode

作對比,發現有不一樣的地方就直接修改在真實的DOM上,然後使

oldVnode

的值為

Vnode

。diff的過程就是調用名為

patch

的函數,比較新舊節點,一邊比較一邊給真實的DOM打更新檔。

具體實作可以參考https://www.cnblogs.com/wind-lanyan/p/9061684.html

十七、vue-router的兩種模式

1、hash ——即位址欄URL中的#符号(此hsah 不是密碼學裡的散列運算)。 比如這個URL:http://www.abc.com/#/hello, hash 的值為#/hello。它的特點在于:hash 雖然出現URL中,但不會被包含在HTTP請求中,對後端完全沒有影響,是以改變hash不會重新加載頁面。

2、history ——利用了HTML5 History Interface 中新增的pushState() 和replaceState() 方法。(需要特定浏覽器支援) 這兩個方法應用于浏覽器的曆史記錄站,在目前已有的back、forward、go 的基礎之上,它們提供了對曆史記錄進行修改的功能。隻是當它們執行修改是,雖然改變了目前的URL,但你浏覽器不會立即向後端發送請求。history模式,會出現404 的情況,需要背景配置。—>利于seo

十八、Keep-alive元件

元件切換的時,保持這些元件的狀态,以避免反複重渲染導緻的性能問題(Vue 會建立了一個新的執行個體)

十九、Slot插槽

插槽含義:就是引入子元件後,在插入子元件元素中添加資訊或者标簽,使得子元件的指定位置插入資訊或者标簽

插槽有三種:預設插槽、具名插槽、作用域插槽

二十、nextTick

在Vue生命周期的

created()

鈎子函數進行的DOM操作一定要放在

Vue.nextTick()

的回調函數中

changeMsg() {
      this.msg = "Hello world."
      this.msg1 = this.$refs.msgDiv.innerHTML //原來内容
      this.$nextTick(() => {
        this.msg2 = this.$refs.msgDiv.innerHTML //Hello world
      })
      this.msg3 = this.$refs.msgDiv.innerHTML//原來内容
    }

//其根本原因是因為Vue中DOM更新是異步的
           

十九、Slot插槽

插槽含義:就是引入子元件後,在插入子元件元素中添加資訊或者标簽,使得子元件的指定位置插入資訊或者标簽

插槽有三種:預設插槽、具名插槽、作用域插槽

二十、nextTick

在Vue生命周期的

created()

鈎子函數進行的DOM操作一定要放在

Vue.nextTick()

的回調函數中

changeMsg() {
      this.msg = "Hello world."
      this.msg1 = this.$refs.msgDiv.innerHTML //原來内容
      this.$nextTick(() => {
        this.msg2 = this.$refs.msgDiv.innerHTML //Hello world
      })
      this.msg3 = this.$refs.msgDiv.innerHTML//原來内容
    }

//其根本原因是因為Vue中DOM更新是異步的
           

繼續閱讀