Vue面試總結(jié)

Vue優(yōu)點(diǎn)

數(shù)據(jù)驅(qū)動(dòng)和組件化

  • 數(shù)據(jù)驅(qū)動(dòng):自動(dòng)計(jì)算屬性和追蹤依賴的模板表達(dá)
  • 組件化:可復(fù)用,解耦的組件來構(gòu)造頁面

Vue生命周期

  • beforeCreated:創(chuàng)建前。數(shù)據(jù)觀測和初始化事件未開始。
  • created:創(chuàng)建后。完成數(shù)據(jù)觀測、屬性和方法的處理。以及初始化事件。
  • beforeMounted:掛載前。掛載開始前被調(diào)用,render函數(shù)被首次調(diào)用。完成編譯模板,data里的數(shù)據(jù)和模板生成HTML
  • mounted:掛在后。el屬性被新創(chuàng)建出來的vm.$el代替,并掛載到實(shí)例上之后被調(diào)用。
  • beforeUpdate:虛擬DOM重新渲染之前
  • update:虛擬DOM重新渲染之后
  • beforeDestory:實(shí)例被摧毀之前調(diào)用,實(shí)例仍然可用。
  • destoryed:實(shí)例被摧毀之后調(diào)用;調(diào)用時(shí),所有的監(jiān)聽器都會(huì)被移除。

Vue的指令有哪些

v-if/v-else/v-else-if/v-bind(:)/v-on(@)/v-show/v-html/v-text/v-model/v-for/v-once;

Vue常用修飾符

.prevent: 提交事件不再重載頁面
.stop: 阻止單擊事件冒泡
.self: 當(dāng)事件發(fā)生在該元素本身而不是子元素的時(shí)候會(huì)觸發(fā)
.capture: 事件偵聽,事件發(fā)生的時(shí)候會(huì)調(diào)用
.once: 跟v-once作用類似,只渲染一次,第二次不會(huì)執(zhí)行

watch和computed的區(qū)別

  • computed:計(jì)算屬性。通過其他變量來獲取另一個(gè)屬性,具有緩存。計(jì)算屬性只有在他們依賴的屬性改變的時(shí)候才會(huì)重新計(jì)算求值
  • watch:監(jiān)聽某一屬性。回調(diào)里面可以傳入新舊值。

watch詳解

watch:可以用來監(jiān)測VUE實(shí)例上數(shù)據(jù)的變動(dòng);

  1. 簡單運(yùn)用:
    watch: function(newVal,OldVal) {};
  2. 復(fù)雜運(yùn)用:
    1.immediate: 由于watch有一個(gè)特點(diǎn),就是最初綁定的時(shí)候 不會(huì)去執(zhí)行,只有當(dāng)值發(fā)生改變的時(shí)候 才會(huì)去執(zhí)行監(jiān)聽計(jì)算。如果我們想要在最初綁定的時(shí)候就去執(zhí)行監(jiān)聽計(jì)算的話,就需要在watch中設(shè)置immediate屬性值為true;
    2.deep: 比如說我們data里面監(jiān)聽的是一個(gè)對象,但是我們想要監(jiān)聽的是object.a的值的變化,就監(jiān)聽不到的。由于handler只監(jiān)聽data里的obj的變化。這時(shí)候我們就需要這是deep屬性為true。deep就是指深度觀察,監(jiān)聽器會(huì)逐一的遍歷下去,給obj的每一屬性都加上監(jiān)聽器,但是這樣是非常耗性能的。
watch: {
   handler:functio(newVal,OldVal) {},
   immediate:true,
}

Vue中如何獲取DOM

只有在mounted階段之后才能獲取dom

  1. ref:ref被用來給元素或者是子組件注冊引用信息,引用信息將會(huì)注冊在父組件的$refs對象上。如果是在普通的DOM上用,那么指向的就是普通的元素,如果是在子組件上使用,指向的就是子組件實(shí)例;
  2. 選擇器獲取:比如docment.querySelector("#id");

組件之間的傳值

  1. 父組件傳給子組件:子組件通過props接收傳遞的數(shù)據(jù)
  2. 子組件傳遞給父組件:通過$emit傳遞參數(shù)
  3. 同級之間傳遞:eventBus,創(chuàng)建一個(gè)事件中心,相當(dāng)于一個(gè)中轉(zhuǎn)站,可以用它來傳遞數(shù)據(jù)和接收數(shù)據(jù);
  4. vuex
  5. 祖?zhèn)鲗O:通過provide
//祖
provide: {
    foo: {
      a: 1,
      b: 2,
      c: 3
    }
  }
 
//在孫組件中
inject: ["foo"],
  data() {
    return {
      bar: this.foo.a
    };
  },
  created() {
    console.log(1);
    console.log(this.bar); // => "bar"
  }

Vue-router的鉤子函數(shù)

  1. 全局導(dǎo)航鉤子函數(shù)
    1. router.beforeEach(to, from, next),
    2. router.beforeResolve(to, from, next),
    3. router.afterEach(to, from ,next)
  2. 組件內(nèi)鉤子:
    1. beforeRouterEnter
    2. beforeRouterUpdate
    3. beforeRouterLeave
  3. 單獨(dú)路由獨(dú)享組件:
    beforeEnter

完整的導(dǎo)航解析流程

  • 導(dǎo)航被觸發(fā)
  • 在失活的組件里調(diào)用離開守衛(wèi)
  • 調(diào)用全局的 beforeEach 守衛(wèi)
  • 在重用的組件里調(diào)用 beforeRouteUpdate 守衛(wèi)
  • 在路由配置里調(diào)用 beforEnter
  • 解析異步路由組件
  • 在被激活的組件里調(diào)用 beforeRouteEnter
  • 調(diào)用全局的 beforeResolve 守衛(wèi)
  • 導(dǎo)航被確認(rèn)
  • 調(diào)用全局的 afterEach 鉤子
  • 觸發(fā) DOM 更新
  • 在創(chuàng)建好的實(shí)例調(diào)用 beforeRouteEnter 守衛(wèi)中傳給 next 的回調(diào)函數(shù)

vue組件中data為什么必須是函數(shù)

因?yàn)橐粋€(gè)組件是可以共享的,但他們的data是私有的,所以每個(gè)組件都要return一個(gè)新的data對象,返回一個(gè)唯一的對象,不要和其他組件共用一個(gè)對象

從源碼看Vue中數(shù)組的問題

由于JavaScript的限制,Vue不能做以下操作

  1. 利用索引直接設(shè)置一個(gè)數(shù)組項(xiàng)。vm.items[indexofitem] = newValue
  2. 修改數(shù)組的長度,vm.items.length = newLength

解決方法

在源代碼中,采用數(shù)組變異思路,首先對功能進(jìn)行擴(kuò)展,之后進(jìn)行數(shù)組劫持。

功能擴(kuò)展思路:

  1. 創(chuàng)建一個(gè)繼承原Array的新函數(shù)對象。
  2. 重新定義函數(shù)對象
  3. 在新定義的函數(shù)中調(diào)用原函數(shù)
// 變異方法名稱
const methodsToPatch = [
  'push',
  'pop',
  'shift',
  'unshift',
  'splice',
  'sort',
  'reverse'
]

const arrayProto = Array.prototype
// 繼承原有數(shù)組的方法
const arrayMethods = Object.create(arrayProto)

mutationMethods.forEach(method => {
    // 緩存原生數(shù)組方法
    const original = arrayProto[method]
    arrayMethods[method] = function (...args) {
        const result = original.apply(this, args)
        
        console.log('執(zhí)行響應(yīng)式功能')
        
        return result
    }

共有7種變異函數(shù)。

數(shù)據(jù)劫持思路
使用原型鏈,將普通函數(shù)指向我們所擴(kuò)展的新組對象

let arr = []
// 通過隱式原型繼承arrayMethods
arr.__proto__ = arrayMethods

// 執(zhí)行變異后方法
arr.push(1)

Vue 的變異數(shù)組從本質(zhì)上是來說是一種裝飾器模式,通過學(xué)習(xí)它的原理,我們在實(shí)際工作中可以輕松處理這類保持原有功能不變的前提下對其進(jìn)行功能拓展的需求。


// Vue.set
Vue.set(vm.items, indexOfItem, newValue)
// vm.$set,Vue.set的一個(gè)別名
vm.$set(vm.items, indexOfItem, newValue)
// Array.prototype.splice
vm.items.splice(indexOfItem, 1, newValue)

vm.items.splice(newLength)

在vue中有的時(shí)候是不能獲取到數(shù)組的,那么vue源碼是怎樣去處理這些數(shù)組,并獲取到的呢?

答:組件處理 vue做了攔截,重寫了數(shù)組的方法,最終還是通過數(shù)據(jù)劫持獲取到的。

Vue 怎么用 vm.$set() 解決對象新增屬性不能響應(yīng)的問題 ?

vue 無法檢測到對象屬性的添加或者刪除。所以Vue提供了Vue.set (object, propertyName, value) / vm.$set (object, propertyName, value) 來實(shí)現(xiàn)為對象添加響應(yīng)式屬性。

源碼實(shí)現(xiàn)思想

  1. 如果目標(biāo)是數(shù)組,直接使用擴(kuò)展數(shù)組的splice方法觸發(fā)響應(yīng)式。

  2. 如果目標(biāo)是對象,會(huì)先判讀屬性是否存在、對象是否是響應(yīng)式,最終如果要對屬性進(jìn)行響應(yīng)式處理,則是通過調(diào)用 defineReactive 方法進(jìn)行響應(yīng)式處理( defineReactive 方法就是 Vue 在初始化對象時(shí),給對象屬性采用 Object.defineProperty 動(dòng)態(tài)添加 getter 和 setter 的功能所調(diào)用的方法)

父子組件生命周期調(diào)用順序

父組件beforeMounted階段之后進(jìn)入子組件,子組件完成mounted之后繼續(xù)父組件的周期。當(dāng)子組件觸發(fā)數(shù)據(jù)更新,先觸發(fā)父組件beforeUpdate,之后觸發(fā)子組件beforeUpdate,然后觸發(fā)子組件updated,最后觸發(fā)父組件updated。

Vuex

  • state: vuex store實(shí)例的根狀態(tài)對象,用于定位共享的狀態(tài)
  • action: 動(dòng)作,執(zhí)行本地操作或者異步操作(相當(dāng)于state的methods)。action可以進(jìn)行異步操作。store.dispatch()來執(zhí)行action
  • Mutations: 修改器。唯一只用于修改state。store.commit()來執(zhí)行。
  • getter:讀取器,外部程序通過他獲取變量的具體值,或者是在取值前做一些計(jì)算,可以認(rèn)為是store的計(jì)算屬性。

vuex提供了三種輔助函數(shù)用于獲取、修改vuex:
mapState、mapGetters、mapActions
即將vuex的變量或者方法映射到vue組件this指針上。

methods: {
       //下述中的 ... 是拓展運(yùn)算符
       // 使用 [] 是解構(gòu)賦值
    ...mapActions([
      'increment', // 將 `this.increment()` 映射為 `this.$store.dispatch('increment')`
 
      // `mapActions` 也支持載荷:
      'incrementBy' // 將 `this.incrementBy(amount)` 映射為 `this.$store.dispatch('incrementBy', amount)`
    ]),
    ...mapActions({
      add: 'increment' // 將 `this.add()` 映射為 `this.$store.dispatch('increment')`
    })
  }

Vue-router原理

spa實(shí)現(xiàn)方式分為三種

hash模式

地址欄中#符號。特點(diǎn)是hash雖然出現(xiàn)在瀏覽器url中,但是不會(huì)包含在HTTP請求中,對后端沒有影響,不會(huì)重新加載頁面

history模式

利用HTML5新增的pushState()和replaceState()實(shí)現(xiàn)。這兩個(gè)方法應(yīng)用于瀏覽器的歷史記錄棧。但是需要后端對路由進(jìn)行配置,重定向到Vue打包生成的index.html的頁面上尋找相應(yīng)的代碼,否則會(huì)報(bào)錯(cuò)。

 window.history.pushState(state, title, url)
 - state: 一個(gè)與指定網(wǎng)址相關(guān)的狀態(tài)對象,popstate事件觸發(fā)時(shí),該對象會(huì)傳入回調(diào)函數(shù)
 - title:新頁面的標(biāo)題,大部分瀏覽器不支持這個(gè)
 - url: 新的網(wǎng)址,必須是與當(dāng)前頁面同一個(gè)域名。瀏覽器顯示的地址
 
 重點(diǎn)是 pushstate方法不會(huì)觸發(fā)頁面刷新,只是會(huì)導(dǎo)致history對象發(fā)生變化,地址欄會(huì)有反應(yīng)
 
 window.onpopstate = function (event) {}
 
 popstate事件會(huì)在點(diǎn)擊后退、前進(jìn)按鈕(或調(diào)用history.back()、history.forward()、history.go()方法)時(shí)觸發(fā)。前提是不能真的發(fā)生了頁面跳轉(zhuǎn),而是在由history.pushState()或者h(yuǎn)istory.replaceState()形成的歷史節(jié)點(diǎn)中前進(jìn)后退

注意:用history.pushState()或者h(yuǎn)istory.replaceState()不會(huì)觸發(fā)popstate事件。

在Vue中需要這樣配置node:'history'

abstract模式

abstract模式是使用一個(gè)不依賴于瀏覽器的瀏覽歷史虛擬管理后端。

根據(jù)平臺(tái)差異可以看出,在 Weex 環(huán)境中只支持使用 abstract 模式。 不過,vue-router 自身會(huì)對環(huán)境做校驗(yàn),如果發(fā)現(xiàn)沒有瀏覽器的 API,vue-router 會(huì)自動(dòng)強(qiáng)制進(jìn)入 abstract 模式,所以 在使用 vue-router 時(shí)只要不寫 mode 配置即可,默認(rèn)會(huì)在瀏覽器環(huán)境中使用 hash 模式,在移動(dòng)端原生環(huán)境中使用 abstract 模式。 (當(dāng)然,你也可以明確指定在所有情況下都使用 abstract 模式)

注意

  1. hash模式不會(huì)生成404的錯(cuò)誤
  2. history模式需要后端支持。指定的路徑需要返回對應(yīng)的HTML頁面。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容