重整旗鼓,2019自結前端面試小冊【Vue.Js】

前言

臨近2019年的尾聲,是否是該爲了更好的2020年再戰一回呢? ‘勝敗兵家事不期,包羞忍恥是男兒。江東子弟多才俊,捲土重來未可知’,那些在秋招失利的人,難道就心甘情願放棄嗎!css

此文總結2019年以來本人經歷以及瀏覽文章中,較熱門的一些面試題,涵蓋從CSS到JS再到Vue再到網絡等前端基礎到進階的一些知識。html

總結面試題涉及的知識點是對本身的一個提高,也但願能夠幫助到同窗們,在2020年會有一個更好的競爭能力。前端

Module Four - Vue

「About Base」

講一講你對MVVM的理解?與MVC有什麼不一樣?

  • MVC指的是Model-View-Controller,即模型-視圖-控制器。
    • 使用MVC的目的就是將模型與視圖分離
    • MVC屬於單向通訊,必須經過Controller來承上啓下,既必須由控制器來獲取數據,將結果返回給前端,頁面從新渲染
  • MVVM指的是Model-View-ViewModel,即模型-視圖-視圖模型,「模型」指的是後端傳遞的數據,「視圖」指的是所看到的頁面,「視圖模型」是MVVM的核心,它是鏈接ViewModel的橋樑,實現view的變化會自動更新到viewModel中,viewModel中的變化也會自動顯示在view,是一種數據驅動視圖的模型

區別:vue

  • MVC中的ControlMVVM中演變成viewModel
  • MVVM經過數據來顯示視圖,而不是經過節點操做
  • MVVM主要解決了MVC中大量的DOM操做,使頁面渲染性能下降,加載速度慢,影響用戶體驗的問題

請說一下Vue響應式數據的原理?

Vue底層對於響應式數據的核心是object.definePropertyVue在初始化數據時,會給data中的屬性使用object.defineProperty從新定義屬性(劫持屬性的gettersetter),當頁面使用對應屬性時,會經過Dep類進行依賴收集(收集當前組件的watcher),若是屬性發生變化,會通知相關依賴調用其update方法進行更新操做node

  • 總結: Vue經過數據劫持配合發佈者-訂閱者的設計模式,內部經過調用object.defineProperty()來劫持各個屬性的gettersetter,在數據變化的時候通知訂閱者,並觸發相應的回調

關於底層源碼,能夠看看這篇文章:segmentfault.com/a/119000001…面試


Vue是如何實現響應式數據的?

Vue數據雙向綁定是指:數據變化更新視圖,視圖變化更新數據,例如輸入框輸入內容變化時,data中的數據同步變化;data中的數據變化時,文本節點的內容同步變化正則表達式

Vue主要經過如下4個步驟實現響應式數據算法

  • 實現一個監聽器「Observer」:對數據對象進行遍歷,包括子屬性對象的屬性,利用Object.defineProperty()在屬性上都加上gettersetter,這樣後,給對象的某個值賦值,就會觸發setter,那麼就能監聽到數據變化
  • 實現一個解析器「Compile」:解析Vue模板指令,將模板中的變量都替換成數據,而後初始化渲染頁面視圖,並將每一個指令對應的節點綁定更新函數,添加監聽數據的訂閱者,一旦數據有變更,收到通知,調用更新函數進行數據更新
  • 實現一個訂閱者「Watcher」:Watcher訂閱者是ObserverCompile之間通訊的橋樑,主要任務是訂閱Observer中的屬性值變化的消息,當收到屬性值變化的消息時,觸發解析器Compile中對應的更新函數
  • 實現一個訂閱器「Dep」:訂閱器採用發佈-訂閱設計模式,用來收集訂閱者Watcher,對監聽器Observer和訂閱者Watcher進行統一管理

Vue如何實現對象和數組的監聽?

因爲Object.defineProperty()只能對屬性進行數據劫持,而不能對整個對象(數組)進行數據劫持,所以Vue框架經過遍歷數組和對象,對每個屬性進行劫持,從而達到利用Object.defineProperty()也能對對象和數組(部分方法的操做)進行監聽vue-router


直接給一個數組項賦值,Vue能檢測到變化嗎?

因爲JavaScript的限制,Vue不能檢測到如下數組的變更vuex

  • 當利用索引直接設置一個數組項時,例如vm.items[indexOfItem] = newValue
  • 當修改數組的長度時,例如vm.items.length = newLength

爲了解決第一個問題,Vue提供瞭如下操做方式

// Vue.set
Vue.set(vm.items, indexOfItem, newValue)

// vm.$set,Vue.set的一個別名
vm.$set(vm.items, indexOfItem, newValue)

// Array.prototype.splice
vm.items.splice(indexOfItem, 1, newValue)
複製代碼

爲了解決第二個問題,Vue提供瞭如下操做方式

// Array.prototype.splice
vm.items.splice(newLength - 1)
複製代碼

講一講Vue是如何檢測數組的變化?

  • 核心思想:使用了函數劫持的方式,重寫了數組的方法(push,pop,unshift,shift···
  • Vuedata中的數組,進行了原型鏈的重寫,指向了本身所定義的數組原型方法,當調用數組的API時,能夠通知依賴更新,若是數組中包含着引用類型,會對數組中的引用類型再次進行監控

Vue如何經過vm.$set()來解決對象新增/刪除屬性不能響應的問題?

因爲JavaScript的限制,Vue沒法檢測到對象屬性的添加或刪除。這是因爲Vue會在初始化實例時對屬性的gettersetter進行劫持,因此屬性必須在data對象上存在才能讓Vue將它們轉換爲響應式數據。

Vue提供了Vue.set(object, propertyName, value) / vm.$set(object, propertyName, value)來實現爲對象添加響應式屬性,其原理以下:

  • 若是目標是數組,直接使用數組的splice方法觸發響應式
  • 若是目標是對象,會先判斷對象屬性是否存在,對象是不是響應式,最終若是要對屬性進行響應式處理,則是經過調用defineReactive()方法進行響應式處理(defineReactive()是Vue對Object.defineProperty()的二次封裝)

爲何Vue要採起異步渲染?

由於若是不採用異步渲染,那麼每次更新數據都會進行從新渲染,爲了提升性能,Vue經過異步渲染的方式,在本輪數據更新後,再去異步更新視圖


「譯」Object.defineProperty有什麼缺點?(爲何Vue3.0開始使用Proxy實現響應式)

  • Object.defineProperty只能劫持對象的屬性,所以須要遍歷對象的每一個屬性,而Proxy能夠直接代理對象
  • Object.defineProperty對新增屬性須要手動進行觀察,因爲Object.defineProperty劫持的是對象的屬性(第一點),因此新增屬性時,須要從新遍歷對象,對其新增屬性再使用Object.defineProperty進行劫持 (正是這個緣由致使咱們在給data中的數組或對象新增屬性時,須要使用$set才能保證視圖能夠更新)
  • Proxy性能高,支持13種攔截方式

虛擬Dom的優缺點?

優勢:

  • 保證性能下限:框架的虛擬Dom須要適配任何上層API可能產生的操做,它的一些Dom操做的實現必須是廣泛適用的,因此它的性能並非最優的,但比起粗暴的Dom操做要好不少,所以保證了性能的下限
  • 無需手動操做Dom:框架會根據虛擬Dom和數據的雙向綁定,幫咱們更新視圖,提升開發效率
  • 跨平臺:虛擬Dom本質上是JavaScript對象,而真實Dom與平臺相關,相比下虛擬Dom能夠更好地跨平臺操做

缺點:

  • 沒法進行極致優化

虛擬Dom的實現原理?

虛擬Dom的實現原理主要包括如下三部分:

  • JavaScript對象模擬真實Dom樹,對真實Dom進行抽象
  • 經過diff算法對兩個虛擬Dom對象進行比較
  • 經過patch算法將兩個虛擬Dom對象的差別應用到真實Dom樹上

nextTick實現原理是什麼? 在Vue中有什麼做用

  • 原理:EventLoop事件循環
    • 正確的流程是依次去檢測:Promise.then → MutationObserver的回調函數 → setImmediate → setTimeout 是否存在,找到存在的就去使用它,以此來肯定回調函數隊列是以哪一個api來異步執行
    • 在nextTick函數接受到一個callback的時候,先不去調用它,而是把它push到一個全局的queue隊列,等待下一個任務隊列的時候再一次性把這個queue裏的函數依次執行
    • 這個隊列多是microTask隊列,頁多是macroTask隊列,前兩個api屬於微任務隊列,後兩個api屬於宏任務隊列
  • 做用:在下次dom更新循環結束後執行延遲迴調,當咱們修改數據以後當即使用nextTick()來獲取最新更新的Dom

watch中的deep:true是如何實現的?

當用戶指定了watch中的deep:true時,若是當前監控的值是數組類型(對象類型),會對對象中的每一項進行求值,此時會將當前watcher存入到對應屬性的依賴中,這樣數組中的對象發生變化也會通知數據進行更新

本質上是由於Vue內部對設置了deep的watch,會進行遞歸的訪問(只要此屬性也是響應式屬性),而再此過程也會不斷髮生依賴收集

缺點:因爲須要對每一項都進行操做,性能會下降,不建議屢次使用deep:true


爲何v-if與v-for不建議連在一塊兒使用?

v-for優先級高於v-if,若是連在一塊兒使用的話會把v-if給每個元素都添加上,重複運行於每個v-for循環中,會形成性能浪費


「譯」組件的data爲何要寫成函數形式

Vue中,組件都是可複用的,一個組件建立好後,能夠在多個地方重複使用,而無論複用多少次,組件內的data都必須是相互隔離,互不影響的,若是data以對象的形式存在,因爲Javascript中對象是引用類型,做用域沒有隔離,當你在模板中屢次聲明這個組件,組件中的data會指向同一個引用,此時若是對某個組件的data進行修改,會致使其餘組件裏的data也被修改。所以data必須以函數的形式返回

  • 總結:爲了實現每一個組件實例能夠維護獨立的數據拷貝,不會相互影響

❗ 小知識: new Vue根組件不須要複用,所以不須要以函數方式返回


「譯」v-for中的key的做用是什麼?

key是爲每一個vnode指定惟一的id,在同級vnodeDiff過程當中,能夠根據key快速的進行對比,來判斷是否爲相同節點,並利用key的惟一性生成map來更快的獲取相應的節點,另外指定key後,能夠保證渲染的準確性。

注:不建議將index做爲key值,具體學習一下【晨曦時夢見兮】的文章:juejin.cn/post/684490…


Vue每一個生命週期何時被調用?

  • beforeCreate → 在實例初始化以後,數據觀測(data observer)以前被調用
  • created → 實例已經建立完成以後被調用。在這裏,實例已完成如下配置:
    • 數據觀測(data observer)
    • 屬性和方法的運算
    • watch/event事件回調
    • 但這裏尚未$el
  • beforeMount → 在掛載開始以前被調用,相關的render函數首次被調用
  • mounted$el被新建立的vm.$el替換,並掛載到實例上以後調用該鉤子
  • beforeUpdate → 數據更新時調用,發生在虛擬DOM從新渲染和打補丁以前
  • updated → 因爲數據更改致使的虛擬DOM從新渲染和打補丁,在這以後會調用該鉤子(該鉤子在服務器端渲染期間不被調用)
  • beforeDestroy → 實例銷燬以前調用,在這裏,實例仍然徹底可使用
  • destroyedVue實例銷燬後調用。調用該鉤子後,Vue實例指示的全部東西都會解綁,全部的事件監聽器會被移除,全部的子實例也會被銷燬(該鉤子在服務器端渲染期間不被調用)


Vue每一個生命週期內部能夠作什麼事?

  • created → 實例已經建立完成,因爲它是最先觸發的,因此能夠進行一些數據,資源的請求
  • mounted → 實例已經掛載完成,能夠進行一些DOM操做
  • beforeUpdate → 能夠在該鉤子中進一步地更改狀態,這不會觸發附加的渲染過程
  • updated → 能夠執行依賴於DOM的操做。但在大多數狀況下,應避免在該鉤子中更改狀態,由於這可能致使更新無限循環
  • destroyed → 能夠執行一些優化操做,例如清空定時器,清理緩存,解除事件綁定等

Vue組件有哪些聲明生命週期鉤子?

beforeCreate」、「created」、「beforeMount」、「mounted」、「beforeUpdate」、「updated」、「beforeDestroy」、「destroyed

❗ 小知識:

<keep-alive>擁有本身獨立的鉤子函數 activated | deactivated

  • activated → 在被<keep-alive>包裹的組件中才有效,當組件被激活時使用該鉤子
  • deactivated → 在被<keep-alive>包裹的組件中才有效,當組件被中止時使用該鉤子

「譯」Vue的父組件和子組件生命週期鉤子執行順序是什麼?

  • 理解渲染過程:

父組件掛載完成必須是等到子組件都掛載完成以後,纔算父組件掛載完,因此父組件的mounted確定是在子組件mounted以後

So:「父」beforeCreate → 「父」created → 「父」beforeMount → 「子」beforeCreate → 「子」created → 「子」beforeMount → 「子」mounted → 「父」mounted

  • 子組件更新過程(取決於對父組件是否有影響)

    • 影響到父組件: 「父」beforeUpdate → 「子」beforeUpdate → 「子」updated → 「父」updated
    • 不影響父組件: 「子」beforeUpdate → 「子」updated
  • 父組件更新過程(取決於對子組件是否有影響)

    • 影響到子組件: 「父」beforeUpdate → 「子」beforeUpdate → 「子」updated → 「父」updated
    • 不影響子組件: 「父」beforeUpdate → 「父」updated
  • 銷燬過程

    • 「父」beforeDestroy → 「子」beforeDestroy → 「子」destroyed → 「父」destroyed

父組件能夠監聽到子組件的生命週期嗎?

好比有一個父組件Parent和子組件Child,若是父組件監聽到子組件掛載mounted就作一些邏輯處理、

  • 方式一
// Parent.vue
<Child @mounted='doSomething' />

// Child.vue
mounted(){
    this.$emit('mounted')
}
複製代碼
  • 方式二(更簡單 - 經過@hook來監聽)
// Parent.vue
<Child @hook:mounted='doSomething' />

# @hook能夠監聽其餘生命週期
複製代碼

怎麼理解vue的單向數據流

  • vue中,父組件能夠經過prop將數據傳遞給子組件,但這個prop只能由父組件來修改,子組件修改的話會拋出錯誤
  • 若是是子組件想要修改數據,只能經過$emit由子組件派發事件,並由父組件接收事件進行修改

爲何子組件不能夠修改父組件傳遞的Prop?(爲何vue提倡單向數據流)

因爲vue提倡單向數據流,即父級props的更新會流向子組件,但反過來則不行。這是爲了防止意外的改變父組件的狀態,使得應用的數據流變得難以理解。若是破壞了單項數據流,當應用複雜時,debug的成本將會很是高


組件間有哪些通訊方式?

  • 父子組件通訊

    • props / event
    • $parent / $children
    • ref
    • provide / inject
    • .sync
  • 非父子組件通訊

    • eventBus
    • 經過根實例$root
    • vuex
    • $attr / $listeners
    • provide / inject

❗ 小知識: 關於.sync的使用

假設有一個組件 comp

<comp :foo.sync="bar"></comp>

傳遞foo值並用sync修飾,會被擴展成

<comp :foo="bar" @update:foo="val => bar = val"></comp>
複製代碼
當子組件comp須要更新foo的值時,它須要顯示地觸發一個更新事件

this.$emit('update:foo', newValue)
複製代碼

說一說vue的動態組件

多個組件經過同一個掛載點進行組件的切換,is的值是哪一個組件的名稱,那麼頁面就會顯示哪一個組件

<div :is='xxx'></div>
複製代碼

講一講遞歸組件的用法

組件是能夠在它們本身的模板中調用自身的,不過它們只能經過name選項來作這件事

首先咱們要知道,既然是遞歸組件,那麼必定要有一個結束的條件,不然就會致使組件無限循環使用,最終出現max stack size exceeded的錯誤,也就是棧溢出。因此,咱們應該使用v-if = 'false'來做爲遞歸組件的結束條件,當遇到v-if = 'false'時,組件將不會再進行渲染

自定義組件的語法糖v-model是怎麼樣實現的?(v-model如何實現雙向綁定)

v-model本質是v-bindv-on的語法糖,用來在表單控件或組件上建立雙向綁定(僅僅只是語法糖,區分響應式數據)
原理:在表單元素上綁定vlue而且監聽input事件

<input v-model='searchText'>

等價於

<input
    v-bind:value='searchText'
    v-on:input='searchText = $event.target.value'>
複製代碼

在一個組件上使用v-model,默認會爲組件綁定名爲valueprop和名爲input的事件


「譯」Vuex和單純的全局對象有什麼區別?

vuex和全局對象主要有兩大區別:

  • vuex的狀態存儲是響應式的。當vue組件從store中讀取狀態時,若store中的狀態發生變化,那麼相應的組件也會獲得高效更新
  • 不能直接改變store中的狀態,改變store中的狀態惟一方法是顯示地提交mutationcommit)。這樣使得咱們能夠方便地跟蹤每個狀態的變化

「譯」爲何vuex的mutation中不能作異步操做?

vuex中全部的狀態更新的惟一方式都是提交mutation,異步操做須要經過action來提交mutationdispatch)。這樣使得咱們能夠方便地跟蹤每個狀態的變化,從而讓咱們可以實現一些工具幫助咱們更好地使用vuex

每一個mutation執行完後都會對應獲得一個新的狀態變動,這樣devtools就能夠打個快照存下來,而後就能夠實現time-travel了。

若是mutation支持異步操做,就沒有辦法知道狀態是什麼時候更新,沒法很好的進行狀態追蹤,影響調試效率


v-show / v-if 的區別是什麼?

  • v-if指若是條件不成立則不會渲染當前指令所在節點的Dom元素,會在切換過程當中對條件塊的事件監聽器和子組件進行銷燬和重建
  • v-show只是基於css進行切換,無論條件是什麼,都會進行渲染(切換display:block | none

So:v-if切換的開銷較大,而v-show初始化的開銷較大,因此在須要頻繁切換顯示和隱藏的Dom元素時,使用v-show更合適,渲染後不多進行切換則使用v-if較合適


computed / watch 的區別是什麼?

  • computed是依賴於其餘屬性的一個計算值,而且具有緩存,只有當依賴的值發生變化纔會更新(自動監聽依賴值的變化,從而動態返回內容)
  • watch是在監聽的屬性發生變化的時候,觸發一個回調,在回調中執行一些邏輯

(引用晨曦時夢見兮) 實際上computed會擁有本身的watcher,它具備一個dirty屬性來決定computed的值是須要從新計算仍是直接複用以前的值,例如這個例子:

computed: {
    sum() {
        return this.count + 1
    }
}
複製代碼
  1. sum第一次進行求值的時候會讀取響應式屬性count,收集到這個響應式數據做爲依賴。而且計算出一個值來保存在自身的value上,把dirty設爲false,接下來在模板裏再訪問sum就直接返回這個求好的值value,並不進行從新求值。
  2. 而 count 發生變化了之後會通知 sum 所對應的 watcher 把自身的 dirty 屬性設置成 true,這也就至關於把從新求值的開關打開來了。這個很好理解,只有 count 變化了, sum 才須要從新去求值。
  3. 那麼下次模板中再訪問到 this.sum 的時候,纔會真正的去從新調用 sum 函數求值,而且再次把 dirty 設置爲 false,等待下次的開啓

So:computedwatch區別在於用法上的不一樣,computed適合在模板渲染中,若是是須要經過依賴來獲取動態值,就可使用計算屬性。而若是是想在監聽值變化時執行業務邏輯,就使用watch


Vue中 v-html 有什麼做用?會致使什麼問題?

v-html能夠用來識別HTML標籤並渲染出去

致使問題: 在網站上動態渲染任意Html,很容易致使受到Xss攻擊,因此只能在可信內容上使用v-html,且永遠不能用於用戶提交的內容上


keep-alive在vue中的做用是什麼?

包裹在<keep-alive>裏組件,在切換時會保存其組件的狀態,使其不被銷燬,防止屢次渲染

  • 通常結合路由和動態組件一塊兒使用,用於緩存組件
  • keep-alive擁有兩個獨立的生命週期(activated | deactivated),使keep-alive包裹的組件在切換時不被銷燬,而是緩存到內存中並執行deactivated鉤子,切換回組件時會獲取內存,渲染後執行activated鉤子
  • 提供includeexclude屬性,二者都支持字符串或正則表達式
    • include 表示只有名稱匹配的組件纔會被緩存
    • exclude 表示任何名稱匹配的組件都不會被緩存
    • exclude優先級高於include

如何新增自定義指令?

  • 建立局部指令
var app = new Vue({
    el: '#app',
    data: {    
    },
    // 建立指令(能夠多個)
    directives: {
        // 指令名稱
        dir1: {
            inserted(el) {
                //  toDo
            }
        }
    }
})
複製代碼
  • 建立全局指令
Vue.directive('dir2', {
    inserted(el) {
        // inserted 表示元素插入時
        // toDo
    }
})
複製代碼
  • 指令使用
<div id="app">
    <div :dir1='..'></div>
</div>
複製代碼

如何自定義過濾器

  • 建立局部過濾器
var app = new Vue({
    el: '#app',
    data: {    
    },
    // 建立指令(能夠多個)
    filters: {
        // 指令名稱
        newfilter:function(value){
            // toDo
        }
    }
})
複製代碼
  • 建立全局過濾器
Vue.filter('newfilter', function (value) {
    // toDo
})
複製代碼
  • 過濾器使用
<div>{{xxx | newfilter}}</div>
複製代碼

vue經常使用修飾符有哪些,有什麼用?

  • .prevent :攔截默認事件
  • .passive :不攔截默認事件
  • .stop :阻止事件冒泡
  • .self :當事件發生在該元素而不是子元素的時候會觸發
  • .capture :事件偵聽,事件發生的時候會調用

Class / Style 如何動態綁定

Class能夠經過對象語法和數組語法進行動態綁定

  • 對象語法
<div v-bind:class="{ active: isActive, 'text-danger': hasError }"></div>

data: {
  isActive: true,
  hasError: false
}
複製代碼
  • 數組語法
<div v-bind:class="[isActive ? activeClass : '', errorClass]"></div>

data: {
  activeClass: 'active',
  errorClass: 'text-danger'
}
複製代碼

Style也能夠經過對象語法和數組語法進行動態綁定

  • 對象語法
<div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>

data: {
  activeColor: 'red',
  fontSize: 30
}
複製代碼
  • 數組語法
<div v-bind:style="[styleColor, styleSize]"></div>

data: {
  styleColor: {
     color: 'red'
   },
  styleSize:{
     fontSize:'23px'
  }
}
複製代碼

說說對SPA單頁面的理解,以及它的優缺點是什麼?

SPA(singlg-page application) 僅在Web頁面初始化時加載相應的HtmlJavaScriptCss,一旦頁面加載完成,SPA不會由於用戶的操做而進行頁面的從新加載或跳轉,取而代之的是利用路由機制實現Html內容的變換,UI與用戶的交互,避免頁面的從新加載

  • 優勢:
    • 用戶體驗好,加載速度快,內容改變不須要從新加載整個頁面,避免了沒必要要的跳轉和重複渲染
    • SPA相對對服務器壓力小
    • 先後端職責分離,架構更清晰,前端進行交互邏輯,後端負責數據處理
  • 缺點:
    • 首次加載耗時較多(爲實現單頁面Web應用功能及顯示效果,須要在加載頁面的時候將JavaScriptCss統一加載,部分頁面按需加載)
    • 因爲單頁面應用在一個頁面中顯示全部的內容,因此不能使用瀏覽器的前進後退功能,全部的頁面切換須要本身創建堆棧管理
    • 不利於SEO優化

如何讓css僅在當前組件中起做用

<style>標籤上寫入scoped便可


「About Router」

關於路由,route / router 有什麼區別?

  • route 表示路由信息對象,包括path,params,hash,query,fullPath,matched,name等路由信息參數
  • router 表示路由實例對象,包括了路由的跳轉方法,鉤子函數等

「譯」 vue-Router中有哪些導航守衛

  • 「全局前置鉤子」:beforeEach,beforeResolve,afterEach
  • 「路由獨享守衛」:beforeEnter
  • 「組件內部守衛」:beforeRouteEnter,beforeRouteUpdate,beforeRouteLeave

導航解析流程:

  • 導航被觸發
  • 在失活的組件裏調用beforeRouteLeave離開守衛
  • 調用全局的beforeEach守衛
  • 在重用的組件裏調用beforeRouteUpdate守衛
  • 在路由配置裏調用beforeEnter守衛
  • 解析異步路由組件
  • 在被激活的組件裏調用beforeRouteEnter守衛
  • 調用全局的beforeResolve守衛
  • 導航被確認
  • 調用全局的afterEach守衛
  • 觸發Dom更新
  • 用建立好的實例調用beforeRouteEnter守衛中傳給next的回調

「譯」vue-Router 中 hash / history 兩種模式有什麼區別?

  • hash模式會在url上顯示'#',而history模式沒有
  • 刷新頁面時,hash模式能夠正常加載到hash值對應的頁面,history模式沒有處理的話,會返回404,通常須要後端將全部頁面都配置重定向到首頁路由
  • 兼容性上,hash模式能夠支持低版本瀏覽器和IE

「譯」 vue-router 中 hash / history 是如何實現的?

  • hash模式
    • #後面hash值的變化,不會致使瀏覽器向服務器發出請求,瀏覽器不發出請求,就不會刷新頁面,同時經過監聽hashchange事件能夠知道hash發生了哪些變化。根據hash變化來實現頁面的局部更新
  • history模式
    • history模式的實現,主要是Html5標準發佈的兩個Api(pushStatereplaceState),這兩個Api能夠改變url,可是不會發送請求,這樣就能夠監聽url的變化來實現局部更新

怎麼定義 vue-router 的動態路由?怎麼獲取傳過來的值

  • 動態路由的建立,主要是使用path屬性過程當中,使用動態路徑參數,以冒號開頭
{
    path:'/details/:id',
    name:'Details',
    components:Details
}

# 訪問`details`前綴下的路徑,例如`details/1`,`details/2`等,都會映射到`Details`這個組件
複製代碼
  • 當匹配到/details下的路由時,參數值會被設置到this.$route.params下,因此經過這個屬性能夠獲取動態參數
this.$route.params.id
複製代碼

vue-router 傳參方式有哪些?

  • 經過params
    • 只能用name,不能用path
    • 參數不會顯示在url
    • 瀏覽器強制刷新會清空參數
  • 經過query
    • 只能用path,不能用name
    • name可使用path路徑
    • 參數會顯示在url
    • 瀏覽器刷新不清空參數

「About Vuex」

vuex有什麼優缺點?

  • 優勢
    • 解決了非父子組件的消息傳遞(將數據存放在state中)
    • 減小了Ajax請求次數,有些情景能夠直接從內存中的State獲取
  • 缺點
    • 刷新瀏覽器,vuex中的State就會從新變回初始化狀態

vuex有哪幾種屬性?

  • Statevuex的基本數據,用來存儲變量
  • Getter :從基本數據state派生的數據,至關於state的計算屬性
  • Mutation :提交更新數據的方法,必須是同步的(須要異步則使用action)。每一個mutation都有一個字符串的事件類型(type)和一個回調函數(handler
  • Action :和mutation的功能大體相同,不一樣在於
    • action提交的是mutation,而不是直接變動狀態
    • action能夠包含任意異步操做
  • Module :模塊化vuex,可讓每個模塊擁有本身的statemutationactiongetter,使得結構清晰,方便管理

vuex 中的 state 有什麼特性?

  • vuex就是一個倉庫,倉庫裏面放了不少對象,其中state就是數據源存放地
  • state裏面存放的數據是響應式的,Vue組件從store中讀取數據,如果store中的數據改變,依賴這個數據的組件也會更新數據
  • 它經過mapState把全局的stategetters映射到當前組件的computed計算屬性中

vuex 中的 getters 有什麼特性?

  • getters能夠對state進行計算操做,能夠把它看作storecomputed計算屬性
  • 雖然在組件中也能夠作計算屬性,但getters能夠在多個組件之間複用
  • 若是一個狀態只在一個組件內使用,是能夠不用getters

Vue 中對 Ajax 請求代碼應該寫在組件的 methods 中仍是 vuex 的 actions 中?

  • 若是請求的數據是不被其餘組件公用的,僅僅在請求的組件內使用,就不須要放入vuexstate
  • 若是被其餘地方複用,能夠將請求放入action裏,方便複用;若是不須要複用這個請求,直接寫在Vue文件裏會更方便

「About SSR」

使用過 SSR 嗎?說一說對 SSR 的理解

Vue.js是構建客戶端應用程序的框架,默認狀況下,能夠在瀏覽器中輸出Vue組件,進行生成Dom和操做Dom。然而,也能夠將同一個組件渲染爲服務器的Html字符串,將它們直接發送給瀏覽器,最後將這些靜態標記激活爲客戶端上徹底能夠交互的應用程序

即:SSR大體意思就是vue在客戶端將標籤渲染成整個html片斷的工做交給服務端完成,服務端造成的Html片斷直接返回給前端,這個過程就叫作SSR(服務端渲染)

服務端渲染SSR的優勢:

  • 更好的SEO:因爲SPA頁面的內容是經過Ajax獲取,而搜索引擎爬取工具並不會等待Ajax異步完成後再抓取頁面內容,因此在SPA中是抓取不到頁面經過Ajax獲取到的內容;而SSR是直接由服務器返回已經渲染好的頁面(數據已經包含在頁面中),因此搜索引擎爬取工具能夠抓取渲染好的頁面
  • 更快的內容到達事件(首屏加載更快):SPA會等待全部Vue編譯後的Js文件都下載完成後,纔開始進行頁面渲染,文件下載等須要必定時間,因此首屏渲染須要必定時間;而SSR直接由服務器渲染好頁面直接返回顯示,無需等待下載Js文件後再去渲染,因此SSR有更快的內容到達時間

服務端渲染SSR的缺點:

  • 更多的開發條件限制:例如服務端渲染只支持beforeCreate,created生命週期鉤子,這會致使一些外部擴展庫須要特殊處理,才能在服務端渲染應用程序中運行;而且與能夠部署在任何靜態文件服務器上的徹底靜態單頁面應用程序SPA不一樣,服務器渲染應用程序須要處於NodeJs環境下運行
  • 更多的服務器負載:在NodeJs中渲染完整的應用程序,顯然會比僅僅提供靜態文件的server更佔用CPU資源
相關文章
相關標籤/搜索