App下載

2021年最新 vue面試題整理

猿友 2021-02-24 10:58:47 瀏覽數(shù) (31915)
反饋

一、對(duì)MVVM的理解

MVVM分為Model、View、ViewModel。

Model 代表數(shù)據(jù)模型,數(shù)據(jù)和業(yè)務(wù)邏輯都在Model層中定義;泛指后端進(jìn)行的各種業(yè)務(wù)邏輯處理和數(shù)據(jù)操控,對(duì)于前端來(lái)說(shuō)就是后端提供的 api 接口。

View 代表UI視圖,負(fù)責(zé)數(shù)據(jù)的展示;視圖層,也就是用戶(hù)界面。前端主要由 HTML 和 CSS 來(lái)構(gòu)建 。

ViewModel 負(fù)責(zé)監(jiān)聽(tīng) Model 中數(shù)據(jù)的改變并且控制視圖的更新,處理用戶(hù)交互操作;

Model 和 View 并無(wú)直接關(guān)聯(lián),而是通過(guò) ViewModel 來(lái)進(jìn)行聯(lián)系的,Model 和 ViewModel 之間有著雙向數(shù)據(jù)綁定的聯(lián)系。因此當(dāng) Model 中的數(shù)據(jù)改變時(shí)會(huì)觸發(fā) View 層的刷新,View 中由于用戶(hù)交互操作而改變的數(shù)據(jù)也會(huì)在 Model 中同步。+

這種模式實(shí)現(xiàn)了 Model 和 View 的數(shù)據(jù)自動(dòng)同步,因此開(kāi)發(fā)者只需要專(zhuān)注對(duì)數(shù)據(jù)的維護(hù)操作即可,而不需要自己操作 dom。

ViewModel 是由前端開(kāi)發(fā)人員組織生成和維護(hù)的視圖數(shù)據(jù)層。在這一層,前端開(kāi)發(fā)者對(duì)從后端獲取的 Model 數(shù)據(jù)進(jìn)行轉(zhuǎn)換處理,做二次封裝,以生成符合 View 層使用預(yù)期的視圖數(shù)據(jù)模型。需要注意的是 ViewModel 所封裝出來(lái)的數(shù)據(jù)模型包括視圖的狀態(tài)和行為兩部分,而 Model 層的數(shù)據(jù)模型是只包含狀態(tài)的,比如頁(yè)面的這一塊展示什么,而頁(yè)面加載進(jìn)來(lái)時(shí)發(fā)生什么,點(diǎn)擊這一塊發(fā)生什么,這一塊滾動(dòng)時(shí)發(fā)生什么這些都屬于視圖行為(交互),視圖狀態(tài)和行為都封裝在了 ViewModel 里。這樣的封裝使得 ViewModel 可以完整地去描述 View 層。

MVVM 框架實(shí)現(xiàn)了雙向綁定,這樣 ViewModel 的內(nèi)容會(huì)實(shí)時(shí)展現(xiàn)在 View 層,前端開(kāi)發(fā)者再也不必低效又麻煩地通過(guò)操縱 DOM 去更新視圖,MVVM 框架已經(jīng)把最臟最累的一塊做好了,我們開(kāi)發(fā)者只需要處理和維護(hù) ViewModel,更新數(shù)據(jù)視圖就會(huì)自動(dòng)得到相應(yīng)更新。這樣 View 層展現(xiàn)的不是 Model 層的數(shù)據(jù),而是 ViewModel 的數(shù)據(jù),由 ViewModel 負(fù)責(zé)與 Model 層交互,這就完全解耦了 View 層和 Model 層,這個(gè)解耦是至關(guān)重要的,它是前后端分離方案實(shí)施的重要一環(huán)。

二、vue常見(jiàn)指令

1. v-text

v-text 主要用來(lái)更新 textContent,可以等同于 JS 的 text 屬性。

<span v-text="msg"></span>

這兩者等價(jià):

<span>插值表達(dá)式{{msg}}</span>

2. v-html

雙大括號(hào)的方式會(huì)將數(shù)據(jù)解釋為純文本,而非 HTML。為了輸出真正的 HTML,可以用 v-html 指令。它等同于 JS 的 innerHtml 屬性。


<div v-html="rawHtml"></div>

這個(gè)div的內(nèi)容將會(huì)替換成屬性值 rawHtml,直接作為 HTML 進(jìn)行渲染。

3. v-pre

v-pre 主要用來(lái)跳過(guò)這個(gè)元素和它的子元素編譯過(guò)程??梢杂脕?lái)顯示原始的 Mustache 標(biāo)簽。跳過(guò)大量沒(méi)有指令的節(jié)點(diǎn)加快編譯。

<div id="app">
    <span v-pre>{{message}}</span>  //這條語(yǔ)句不進(jìn)行編譯
    <span>{{message}}</span>
</div>

最終僅顯示第二個(gè) span 的內(nèi)容

4. v-cloak

這個(gè)指令是用來(lái)保持在元素上直到關(guān)聯(lián)實(shí)例結(jié)束時(shí)進(jìn)行編譯。

<div id="app" v-cloak>
    <div>
        {{message}}
    </div>
</div>
<script type="text/javascript">
    new Vue({
      el:'#app',
      data:{
        message:'hello world'
      }
    })
</script>

在頁(yè)面加載時(shí)會(huì)閃爍(插值閃爍問(wèn)題),先顯示:

<div>
    {{message}}
</div>

然后才會(huì)編譯為:

<div>
    hello world!
</div>

可以用 v-cloak 指令解決插值表達(dá)式閃爍問(wèn)題,v-cloak 在 css 中用屬性選擇器設(shè)置為 display: none;

5. v-once

v-once 關(guān)聯(lián)的實(shí)例,只會(huì)渲染一次。之后的重新渲染,實(shí)例極其所有的子節(jié)點(diǎn)將被視為靜態(tài)內(nèi)容跳過(guò),這可以用于優(yōu)化更新性能。

<span v-once>This will never change:{{msg}}</span>  //單個(gè)元素
<div v-once>//有子元素
    <h1>comment</h1>
    <p>{{msg}}</p>
</div>
<my-component v-once:comment="msg"></my-component>  //組件
<ul>
    <li v-for="i in list">{{i}}</li>
</ul>

上面的例子中,msg,list 即使產(chǎn)生改變,也不會(huì)重新渲染。

6. v-if

v-if 可以實(shí)現(xiàn)條件渲染,Vue 會(huì)根據(jù)表達(dá)式的值的真假條件來(lái)渲染元素。

<a v-if="ok">yes</a>

如果屬性值 ok 為 true,則顯示。否則,不會(huì)渲染這個(gè)元素。

7. v-else

v-else 是搭配 v-if 使用的,它必須緊跟在 v-if 或者 v-else-if 后面,否則不起作用。

<a v-if="ok">yes</a>
<a v-else>No</a>

8. v-else-if
v-else-if 充當(dāng) v-if 的 else-if 塊,可以鏈?zhǔn)降氖褂枚啻巍?梢愿臃奖愕膶?shí)現(xiàn) switch 語(yǔ)句。

<div v-if="type==='A'">
    A
</div>
<div v-else-if="type==='B'">
    B
</div>
<div v-else-if="type==='C'">
    C
</div>
<div v-else>
    Not A,B,C
</div>

9. v-show

<h1 v-show="ok">hello world</h1>

也是用于根據(jù)條件展示元素。和 v-if 不同的是,如果 v-if 的值是 false,則這個(gè)元素被銷(xiāo)毀,不在 dom 中。但是 v-show 的元素會(huì)始終被渲染并保存在 dom 中,它只是簡(jiǎn)單的切換 css 的 dispaly 屬性。

注意:v-if 有更高的切換開(kāi)銷(xiāo) v-show 有更高的初始渲染開(kāi)銷(xiāo)。因此,如果要非常頻繁的切換,則使用 v-show 較好;如果在運(yùn)行時(shí)條件不太可能改變,則 v-if 較好

10. v-for
用 v-for 指令根據(jù)遍歷數(shù)組來(lái)進(jìn)行渲染
有下面兩種遍歷形式

<div v-for="(item,index) in items"></div>   //使用in,index是一個(gè)可選參數(shù),表示當(dāng)前項(xiàng)的索引
<div v-for="item of items"></div>   //使用of

下面是一個(gè)例子,并且在 v-for 中,擁有對(duì)父作用域?qū)傩缘耐耆L(fǎng)問(wèn)權(quán)限。

<ul id="app">
    <li v-for="item in items">
        {{parent}}-{{item.text}}
    </li>
</ul>
<script type="text/javascript">
    var example = new Vue({
      el:'#app',
      data:{
        parent:'父作用域'
        items:[
          {text:'文本1'},
          {text:'文本2'}
        ]
      }
    })
</script>

會(huì)被渲染為:

<ul id="app">
    <li>父作用域-文本1</li>
    <li>父作用域-文本2</li>
</ul>
注意:當(dāng) v-for 和 v-if 同處于一個(gè)節(jié)點(diǎn)時(shí),v-for 的優(yōu)先級(jí)比 v-if 更高。這意味著 v-if 將運(yùn)行在每個(gè) v-for 循環(huán)中

11. v-bind

v-bind 用來(lái)動(dòng)態(tài)的綁定一個(gè)或者多個(gè)特性。沒(méi)有參數(shù)時(shí),可以綁定到一個(gè)包含鍵值對(duì)的對(duì)象。常用于動(dòng)態(tài)綁定 class 和 style。以及 href 等。簡(jiǎn)寫(xiě)為一個(gè)冒號(hào)【 :】

<1>對(duì)象語(yǔ)法:

//進(jìn)行類(lèi)切換的例子
<div id="app">
    <!--當(dāng)data里面定義的isActive等于true時(shí),is-active這個(gè)類(lèi)才會(huì)被添加起作用-->
    <!--當(dāng)data里面定義的hasError等于true時(shí),text-danger這個(gè)類(lèi)才會(huì)被添加起作用-->
    <div :class="{'is-active':isActive, 'text-danger':hasError}"></div>
</div>
<script>
    var app = new Vue({
        el: '#app',
        data: {
            isActive: true,  
            hasError: false
        }
    })
</script>

渲染結(jié)果:

<!--因?yàn)閔asError: false,所以text-danger不被渲染-->
<div class = "is-active"></div>

<2>數(shù)組語(yǔ)法

<div id="app">
    <!--數(shù)組語(yǔ)法:errorClass在data對(duì)應(yīng)的類(lèi)一定會(huì)添加-->
    <!--is-active是對(duì)象語(yǔ)法,根據(jù)activeClass對(duì)應(yīng)的取值決定是否添加-->
    <p :class="[{'is-active':activeClass},errorClass]">12345</p>
</div>
<script>
    var app = new Vue({
        el: '#app',
        data: {
            activeClass: false,
            errorClass: 'text-danger'
        }
    })
</script>

渲染結(jié)果:

<!--因?yàn)閍ctiveClass: false,所以is-active不被渲染-->
<p class = "text-danger"></p>

<3>直接綁定數(shù)據(jù)對(duì)象

<div id="app">
    <!--在vue實(shí)例的data中定義了classObject對(duì)象,這個(gè)對(duì)象里面是所有類(lèi)名及其真值-->
    <!--當(dāng)里面的類(lèi)的值是true時(shí)會(huì)被渲染-->
    <div :class="classObject">12345</div>
</div>
<script>
    var app = new Vue({
        el: '#app',
        data: {
            classObject:{
                'is-active': false,
                'text-danger':true
            }           
        }
    })
</script>

渲染結(jié)果:

<!--因?yàn)?#39;is-active': false,所以is-active不被渲染-->
<div class = "text-danger"></div>

12. v-model
這個(gè)指令用于在表單上創(chuàng)建雙向數(shù)據(jù)綁定。
v-model 會(huì)忽略所有表單元素的 value、checked、selected 特性的初始值。因?yàn)樗x擇 Vue 實(shí)例數(shù)據(jù)做為具體的值。

<div id="app">
    <input v-model="somebody">
    <p>hello {{somebody}}</p>
</div>
<script>
    var app = new Vue({
        el: '#app',
        data: {
            somebody:'小明'
        }
    })
</script>

這個(gè)例子中直接在瀏覽器 input 中輸入別的名字,下面的 p 的內(nèi)容會(huì)直接跟著變。這就是雙向數(shù)據(jù)綁定。

v-model 修飾符<1> .lazy 默認(rèn)情況下,v-model 同步輸入框的值和數(shù)據(jù)。可以通過(guò)這個(gè)修飾符,轉(zhuǎn)變?yōu)樵?change 事件再同步。

<input v-model.lazy="msg">

<2> .number
自動(dòng)將用戶(hù)的輸入值轉(zhuǎn)化為數(shù)值類(lèi)型

<input v-model.number="msg">

<3> .trim
自動(dòng)過(guò)濾用戶(hù)輸入的首尾空格

<input v-model.trim="msg">

13. v-on
v-on 主要用來(lái)監(jiān)聽(tīng) dom 事件,以便執(zhí)行一些代碼塊。表達(dá)式可以是一個(gè)方法名。
簡(jiǎn)寫(xiě)為:【 @ 】

<div id="app">
    <button @click="consoleLog"></button>
</div>
<script>
    var app = new Vue({
        el: '#app',
        methods:{
            consoleLog:function (event) {
                console.log(1)
            }
        }
    })
</script>

事件修飾符

  • ?.stop? 阻止事件繼續(xù)傳播
  • ?.prevent? 事件不再重載頁(yè)面
  • ?.capture? 使用事件捕獲模式,即元素自身觸發(fā)的事件先在此處處理,然后才交由內(nèi)部元素進(jìn)行處理
  • ?.self ?只當(dāng)在 ?event.target? 是當(dāng)前元素自身時(shí)觸發(fā)處理函數(shù)
  • ?.once? 事件將只會(huì)觸發(fā)一次
  • ?.passive? 告訴瀏覽器你不想阻止事件的默認(rèn)行為
<!-- 阻止單擊事件繼續(xù)傳播 -->
<a v-on:click.stop="doThis"></a>
 
<!-- 提交事件不再重載頁(yè)面 -->
<form v-on:submit.prevent="onSubmit"></form>
 
<!-- 修飾符可以串聯(lián) -->
<a v-on:click.stop.prevent="doThat"></a>
 
<!-- 只有修飾符 -->
<form v-on:submit.prevent></form>
 
<!-- 添加事件監(jiān)聽(tīng)器時(shí)使用事件捕獲模式 -->
<!-- 即元素自身觸發(fā)的事件先在此處處理,然后才交由內(nèi)部元素進(jìn)行處理 -->
<div v-on:click.capture="doThis">...</div>
 
<!-- 只當(dāng)在 event.target 是當(dāng)前元素自身時(shí)觸發(fā)處理函數(shù) -->
<!-- 即事件不是從內(nèi)部元素觸發(fā)的 -->
<div v-on:click.self="doThat">...</div>
 
<!-- 點(diǎn)擊事件將只會(huì)觸發(fā)一次 -->
<a v-on:click.once="doThis"></a>
 
<!-- 滾動(dòng)事件的默認(rèn)行為 (即滾動(dòng)行為) 將會(huì)立即觸發(fā) -->
<!-- 而不會(huì)等待 `onScroll` 完成  -->
<!-- 這其中包含 `event.preventDefault()` 的情況 -->
<div v-on:scroll.passive="onScroll">...</div>

使用修飾符時(shí),順序很重要;相應(yīng)的代碼會(huì)以同樣的順序產(chǎn)生。因此,用v-on:click.prevent.self會(huì)阻止所有的點(diǎn)擊,而 v-on:click.self.prevent 只會(huì)阻止對(duì)元素自身的點(diǎn)擊。

3、v-if 和 v-show 有什么區(qū)別?

共同點(diǎn):?v-if? 和 ?v-show? 都能實(shí)現(xiàn)元素的顯示隱藏

區(qū)別:

    1. v-show 只是簡(jiǎn)單的控制元素的 display 屬性,而 v-if 才是條件渲染(條件為真,元素將會(huì)被渲染,條件為假,元素會(huì)被銷(xiāo)毀);

    2.  v-show 有更高的首次渲染開(kāi)銷(xiāo),而 v-if 的首次渲染開(kāi)銷(xiāo)要小的多;

    3. v-if 有更高的切換開(kāi)銷(xiāo),v-show 切換開(kāi)銷(xiāo)小;

    4. v-if 有配套的 v-else-if 和 v-else,而 v-show 沒(méi)有

    5. v-if 可以搭配 template 使用,而 v-show 不行

四、Vue核心思想:數(shù)據(jù)驅(qū)動(dòng)、組件化

1、數(shù)據(jù)驅(qū)動(dòng)

傳統(tǒng)的前端數(shù)據(jù)交互是用 Ajax 從服務(wù)端獲取數(shù)據(jù),然后操作 DOM 來(lái)改變視圖;或者前端交互要改變數(shù)據(jù)時(shí),又要再來(lái)一次上述步驟,而手動(dòng)操作 DOM 是一個(gè)繁瑣的過(guò)程且易出錯(cuò)。Vue.js 是一個(gè)提供了 MVVM 風(fēng)格的雙向數(shù)據(jù)綁定的 Javascript 庫(kù),專(zhuān)注于 View 層。它讓開(kāi)發(fā)者省去了操作 DOM 的過(guò)程,只需要改變數(shù)據(jù)。Vue 會(huì)通過(guò) Dircetives 指令,對(duì) DOM 做一層封裝,當(dāng)數(shù)據(jù)發(fā)生改變會(huì)通知指令去修改對(duì)應(yīng)的 DOM,數(shù)據(jù)驅(qū)動(dòng) DOM 變化,DOM 是數(shù)據(jù)的一種自然映射。Vue 還會(huì)對(duì)操作進(jìn)行監(jiān)聽(tīng),當(dāng)視圖發(fā)生改變時(shí),vue 監(jiān)聽(tīng)到這些變化,從而改變數(shù)據(jù),這樣就形成了數(shù)據(jù)的雙向綁定。Vue 是一種 MVVM 框架。而 DOM 是數(shù)據(jù)的一個(gè)種自然映射。傳統(tǒng)的模式是通過(guò) Ajax 請(qǐng)求從 model 請(qǐng)求數(shù)據(jù),然后手動(dòng)的觸發(fā) DOM 傳入數(shù)據(jù)修改頁(yè)面。Vue 中,Directives 對(duì) view 進(jìn)行了封裝,當(dāng) model 里的數(shù)據(jù)發(fā)生變化是,Vue 就會(huì)通過(guò) Directives 指令去修改 DOM。同時(shí)也通過(guò) DOM Listener實(shí)現(xiàn)對(duì)視圖 view 的監(jiān)聽(tīng),當(dāng)DOM 改變時(shí),就會(huì)被監(jiān)聽(tīng)到,實(shí)現(xiàn) model 的改變,實(shí)現(xiàn)數(shù)據(jù)的雙向綁定。

2、組件響應(yīng)原理數(shù)據(jù)(model)改變驅(qū)動(dòng)視圖(view)自動(dòng)更新

當(dāng)你把一個(gè)普通的 JavaScript 對(duì)象傳給 Vue 實(shí)例的 data選項(xiàng),Vue 將遍歷此對(duì)象所有的屬性,并使用 Object.defineProperty 把這些屬性全部轉(zhuǎn)為 getter/setter。Object.defineProperty 是 ES5 中一個(gè)無(wú)法 shim 的特性,這也就是為什么 Vue 不支持 IE8 以及更低版本瀏覽器的原因。用戶(hù)看不到 getter/setter,但是在內(nèi)部它們讓 Vue 追蹤依賴(lài),在屬性被訪(fǎng)問(wèn)和修改時(shí)通知變化。這里需要注意的問(wèn)題是瀏覽器控制臺(tái)在打印數(shù)據(jù)對(duì)象時(shí) getter/setter 的格式化并不同,所以你可能需要安裝 vue-devtools 來(lái)獲取更加友好的檢查接口。每個(gè)組件實(shí)例都有相應(yīng)的 watcher 實(shí)例對(duì)象,它會(huì)在組件渲染的過(guò)程中把屬性記錄為依賴(lài),之后當(dāng)依賴(lài)項(xiàng)的 setter 被調(diào)用時(shí),會(huì)通知 watcher 重新計(jì)算,從而致使它關(guān)聯(lián)的組件得以更新。

3、組件化

擴(kuò)展 HTML 元素,封裝可重用的代碼。每一個(gè)組件都對(duì)應(yīng)一個(gè) ViewModel。頁(yè)面上每個(gè)獨(dú)立的可視/可交互區(qū)域都可以視為一個(gè)組件。每個(gè)組件對(duì)應(yīng)一個(gè)工程目錄,組件所需要的各種資源在這個(gè)目錄下就進(jìn)維護(hù)。頁(yè)面是組件的容器,組件可以嵌套自由組合形成完整的頁(yè)面。

組件化實(shí)現(xiàn)了擴(kuò)展 HTML 元素,封裝可用的代碼。頁(yè)面上每個(gè)獨(dú)立的可視/可交互區(qū)域視為一個(gè)組件;每個(gè)組件對(duì)應(yīng)一個(gè)工程目錄,組件所需要的各種資源在這個(gè)目錄下就近維護(hù);頁(yè)面不過(guò)是組件的容器,組件可以嵌套自由組合形成完整的頁(yè)面。

五、Vue 生命周期

af04d1adba22c394d06f6ba6510d92fc

六、組件中 data 為什么是一個(gè)函數(shù)?

為什么組件中的 data 必須是一個(gè)函數(shù),然后 return 一個(gè)對(duì)象,而 new Vue 實(shí)例里,data 可以直接是一個(gè)對(duì)象?

// data
data() {
  return {
	message: "子組件",
	childName:this.name
  }
}
 
// new Vue
new Vue({
  el: '#app',
  router,
  template: '<App/>',
  components: {App}
})

因?yàn)榻M件是用來(lái)復(fù)用的,且 JS 里對(duì)象是引用關(guān)系,如果組件中 data 是一個(gè)對(duì)象,那么這樣作用域沒(méi)有隔離,子組件中的 data 屬性值會(huì)相互影響,如果組件中 data 選項(xiàng)是一個(gè)函數(shù),那么每個(gè)實(shí)例可以維護(hù)一份被返回對(duì)象的獨(dú)立的拷貝,組件實(shí)例之間的 data 屬性值不會(huì)互相影響;而 new Vue 的實(shí)例,是不會(huì)被復(fù)用的,因此不存在引用對(duì)象的問(wèn)題。

 

七、Vue 組件間通信有哪幾種方式?

Vue 組件間通信是面試??嫉闹R(shí)點(diǎn)之一,這題有點(diǎn)類(lèi)似于開(kāi)放題,你回答出越多方法當(dāng)然越加分,表明你對(duì) Vue 掌握的越熟練。Vue 組件間通信只要指以下 3 類(lèi)通信:父子組件通信、隔代組件通信、兄弟組件通信,下面我們分別介紹每種通信方式且會(huì)說(shuō)明此種方法可適用于哪類(lèi)組件間通信。

(1)props / $emit 適用 父子組件通信

這種方法是 Vue 組件的基礎(chǔ),相信大部分同學(xué)耳聞能詳,所以此處就不舉例展開(kāi)介紹。

(2)ref 與 $parent / $children 適用 父子組件通信

  • ref:如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子組件上,引用就指向組件實(shí)例
  • $parent / $children:訪(fǎng)問(wèn)父 / 子實(shí)例

(3)EventBus ($emit / $on) 適用于 父子、隔代、兄弟組件通信

這種方法通過(guò)一個(gè)空的 Vue 實(shí)例作為中央事件總線(xiàn)(事件中心),用它來(lái)觸發(fā)事件和監(jiān)聽(tīng)事件,從而實(shí)現(xiàn)任何組件間的通信,包括父子、隔代、兄弟組件。

(4)$attrs/$listeners 適用于 隔代組件通信

  • $attrs:包含了父作用域中不被 prop 所識(shí)別 (且獲取) 的特性綁定 ( class 和 style 除外 )。當(dāng)一個(gè)組件沒(méi)有聲明任何 prop 時(shí),這里會(huì)包含所有父作用域的綁定 ( class 和 style 除外 ),并且可以通過(guò) v-bind="$attrs" 傳入內(nèi)部組件。通常配合 inheritAttrs 選項(xiàng)一起使用。
  • $listeners:包含了父作用域中的 (不含 .native 修飾器的) v-on 事件監(jiān)聽(tīng)器。它可以通過(guò) v-on="$listeners" 傳入內(nèi)部組件

(5)provide / inject 適用于 隔代組件通信

祖先組件中通過(guò) provider 來(lái)提供變量,然后在子孫組件中通過(guò) inject 來(lái)注入變量。 provide / inject API 主要解決了跨級(jí)組件間的通信問(wèn)題,不過(guò)它的使用場(chǎng)景,主要是子組件獲取上級(jí)組件的狀態(tài),跨級(jí)組件間建立了一種主動(dòng)提供與依賴(lài)注入的關(guān)系。

(6)Vuex 適用于 父子、隔代、兄弟組件通信

Vuex 是一個(gè)專(zhuān)為 Vue.js 應(yīng)用程序開(kāi)發(fā)的狀態(tài)管理模式。每一個(gè) Vuex 應(yīng)用的核心就是 store(倉(cāng)庫(kù))?!皊tore” 基本上就是一個(gè)容器,它包含著你的應(yīng)用中大部分的狀態(tài) ( state )。

  • Vuex 的狀態(tài)存儲(chǔ)是響應(yīng)式的。當(dāng) Vue 組件從 store 中讀取狀態(tài)的時(shí)候,若 store 中的狀態(tài)發(fā)生變化,那么相應(yīng)的組件也會(huì)相應(yīng)地得到高效更新。
  • 改變 store 中的狀態(tài)的唯一途徑就是顯式地提交 (commit) mutation。這樣使得我們可以方便地跟蹤每一個(gè)狀態(tài)的變化。

八、computed 和 watch 的區(qū)別和運(yùn)用的場(chǎng)景?

computed: 是計(jì)算屬性,依賴(lài)其它屬性值,并且 computed 的值有緩存,只有它依賴(lài)的屬性值發(fā)生改變,下一次獲取 computed 的值時(shí)才會(huì)重新計(jì)算 computed 的值;watch: 更多的是「觀(guān)察」的作用,類(lèi)似于某些數(shù)據(jù)的監(jiān)聽(tīng)回調(diào) ,每當(dāng)監(jiān)聽(tīng)的數(shù)據(jù)變化時(shí)都會(huì)執(zhí)行回調(diào)進(jìn)行后續(xù)操作;運(yùn)用場(chǎng)景:

  • 當(dāng)我們需要進(jìn)行數(shù)值計(jì)算,并且依賴(lài)于其它數(shù)據(jù)時(shí),應(yīng)該使用 computed,因?yàn)榭梢岳?computed 的緩存特性,避免每次獲取值時(shí),都要重新計(jì)算;
  • 當(dāng)我們需要在數(shù)據(jù)變化時(shí)執(zhí)行異步或開(kāi)銷(xiāo)較大的操作時(shí),應(yīng)該使用 watch,使用 watch 選項(xiàng)允許我們執(zhí)行異步操作 ( 訪(fǎng)問(wèn)一個(gè) API ),限制我們執(zhí)行該操作的頻率,并在我們得到最終結(jié)果前,設(shè)置中間狀態(tài)。這些都是計(jì)算屬性無(wú)法做到的。

九、虛擬 DOM 

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

  • 保證性能下限: 框架的虛擬 DOM 需要適配任何上層 API 可能產(chǎn)生的操作,它的一些 DOM 操作的實(shí)現(xiàn)必須是普適的,所以它的性能并不是最優(yōu)的;但是比起粗暴的 DOM 操作性能要好很多,因此框架的虛擬 DOM 至少可以保證在你不需要手動(dòng)優(yōu)化的情況下,依然可以提供還不錯(cuò)的性能,即保證性能的下限;
  • 無(wú)需手動(dòng)操作 DOM: 我們不再需要手動(dòng)去操作 DOM,只需要寫(xiě)好 View-Model 的代碼邏輯,框架會(huì)根據(jù)虛擬 DOM 和 數(shù)據(jù)雙向綁定,幫我們以可預(yù)期的方式更新視圖,極大提高我們的開(kāi)發(fā)效率;
  • 跨平臺(tái): 虛擬 DOM 本質(zhì)上是 JavaScript 對(duì)象,而 DOM 與平臺(tái)強(qiáng)相關(guān),相比之下虛擬 DOM 可以進(jìn)行更方便地跨平臺(tái)操作,例如服務(wù)器渲染、weex 開(kāi)發(fā)等等。

缺點(diǎn):

  • 無(wú)法進(jìn)行極致優(yōu)化: 雖然虛擬 DOM + 合理的優(yōu)化,足以應(yīng)對(duì)絕大部分應(yīng)用的性能需求,但在一些性能要求極高的應(yīng)用中虛擬 DOM 無(wú)法進(jìn)行針對(duì)性的極致優(yōu)化。

虛擬 DOM 實(shí)現(xiàn)原理:

虛擬 DOM 的實(shí)現(xiàn)原理主要包括以下 3 部分:

  • 用 JavaScript 對(duì)象模擬真實(shí) DOM 樹(shù),對(duì)真實(shí) DOM 進(jìn)行抽象;
  • diff 算法 — 比較兩棵虛擬 DOM 樹(shù)的差異;
  • pach 算法 — 將兩個(gè)虛擬 DOM 對(duì)象的差異應(yīng)用到真正的 DOM 樹(shù)。

十、vue-router 路由模式有幾種?

  1.  ?Hash?:      使用 URL 的 hash 值來(lái)作為路由。支持所有瀏覽器。
  2.  ?History?:   以來(lái) HTML5 History API 和服務(wù)器配置。參考官網(wǎng)中 HTML5 History 模式
  3.  ?Abstract?: 支持所有 javascript 運(yùn)行模式。如果發(fā)現(xiàn)沒(méi)有瀏覽器的 API,路由會(huì)自動(dòng)強(qiáng)制進(jìn)入這個(gè)模式。

十一、delete和Vue.delete刪除數(shù)組的區(qū)別

delete 只是被刪除的元素變成了 empty/undefined 其他的元素的鍵值還是不變。Vue.delete 直接刪除了數(shù)組 改變了數(shù)組的鍵值。

十二、SPA 單頁(yè)面的理解,它的優(yōu)缺點(diǎn)分別是什么?

SPA( single-page application )僅在 Web 頁(yè)面初始化時(shí)加載相應(yīng)的 HTML、JavaScript 和 CSS。一旦頁(yè)面加載完成,SPA 不會(huì)因?yàn)橛脩?hù)的操作而進(jìn)行頁(yè)面的重新加載或跳轉(zhuǎn);取而代之的是利用路由機(jī)制實(shí)現(xiàn) HTML 內(nèi)容的變換,UI 與用戶(hù)的交互,避免頁(yè)面的重新加載。優(yōu)點(diǎn):

  • 用戶(hù)體驗(yàn)好、快,內(nèi)容的改變不需要重新加載整個(gè)頁(yè)面,避免了不必要的跳轉(zhuǎn)和重復(fù)渲染;
  • 基于上面一點(diǎn),SPA 相對(duì)對(duì)服務(wù)器壓力??;
  • 前后端職責(zé)分離,架構(gòu)清晰,前端進(jìn)行交互邏輯,后端負(fù)責(zé)數(shù)據(jù)處理;

缺點(diǎn):

  • 初次加載耗時(shí)多:為實(shí)現(xiàn)單頁(yè) Web 應(yīng)用功能及顯示效果,需要在加載頁(yè)面的時(shí)候?qū)?JavaScript、CSS 統(tǒng)一加載,部分頁(yè)面按需加載;
  • 前進(jìn)后退路由管理:由于單頁(yè)應(yīng)用在一個(gè)頁(yè)面中顯示所有的內(nèi)容,所以不能使用瀏覽器的前進(jìn)后退功能,所有的頁(yè)面切換需要自己建立堆棧管理;
  • SEO 難度較大:由于所有的內(nèi)容都在一個(gè)頁(yè)面中動(dòng)態(tài)替換顯示,所以在 SEO 上其有著天然的弱勢(shì)。

 

十三、簡(jiǎn)述Vue的響應(yīng)式原理

當(dāng)一個(gè) Vue 實(shí)例創(chuàng)建時(shí),vue 會(huì)遍歷 data 選項(xiàng)的屬性,用 Object.defineProperty 將它們轉(zhuǎn)為 getter/setter 并且在內(nèi)部追蹤相關(guān)依賴(lài),在屬性被訪(fǎng)問(wèn)和修改時(shí)通知變化。每個(gè)組件實(shí)例都有相應(yīng)的 watcher 程序?qū)嵗?,它?huì)在組件渲染的過(guò)程中把屬性記錄為依賴(lài),之后當(dāng)依賴(lài)項(xiàng)的 setter 被調(diào)用時(shí),會(huì)通知 watcher 重新計(jì)算,從而致使它關(guān)聯(lián)的組件得以更新。

4dc6548486c4aedd0d9b752a3951e340

十四、Vue中如何在組件內(nèi)部實(shí)現(xiàn)一個(gè)雙向數(shù)據(jù)綁定?

假設(shè)有一個(gè)輸入框組件,用戶(hù)輸入時(shí),同步父組件頁(yè)面中的數(shù)據(jù)具體思路:父組件通過(guò) props 傳值給子組件,子組件通過(guò) $emit 來(lái)通知父組件修改相應(yīng)的 props 值,具體實(shí)現(xiàn)如下:

import Vue from 'vue'
 
const component = {
  props: ['value'],
  template: `
    <div>
      <input type="text" @input="handleInput" :value="value">
    </div>
  `,
  data () {
    return {
    }
  },
  methods: {
    handleInput (e) {
      this.$emit('input', e.target.value)
    }
  }
}
 
new Vue({
  components: {
    CompOne: component
  },
  el: '#root',
  template: `
    <div>
      <comp-one :value1="value" @input="value = arguments[0]"></comp-one>
    </div>
  `,
  data () {
    return {
      value: '123'
    }
  }
})

可以看到,當(dāng)輸入數(shù)據(jù)時(shí),父子組件中的數(shù)據(jù)是同步改變的:

5184b47b9951dd6e27a6ca8b9364532c

2d523f4469cfedbb023c2d821cb2094c

我們?cè)诟附M件中做了兩件事,一是給子組件傳入 props,二是監(jiān)聽(tīng) input 事件并同步自己的 value 屬性。那么這兩步操作能否再精簡(jiǎn)一下呢?答案是可以的,你只需要修改父組件:

template: `
    <div>
      <!--<comp-one :value1="value" @input="value = arguments[0]"></comp-one>-->
      <comp-one v-model="value"></comp-one>
    </div>
  `

v-model 實(shí)際上會(huì)幫我們完成上面的兩步操作。

十五、 Vue中如何監(jiān)控某個(gè)屬性值的變化?

比如現(xiàn)在需要監(jiān)控 data 中,obj.a 的變化。Vue 中監(jiān)控對(duì)象屬性的變化你可以這樣:

watch: {
      obj: {
      handler (newValue, oldValue) {
        console.log('obj changed')
      },
      deep: true
    }
  }

deep 屬性表示深層遍歷,但是這么寫(xiě)會(huì)監(jiān)控 obj 的所有屬性變化,并不是我們想要的效果,所以做點(diǎn)修改:

watch: {
   'obj.a': {
      handler (newName, oldName) {
        console.log('obj.a changed')
      }
   }
  }

還有一種方法,可以通過(guò) computed 來(lái)實(shí)現(xiàn),只需要:

computed: {
    a1 () {
      return this.obj.a
    }
}

利用計(jì)算屬性的特性來(lái)實(shí)現(xiàn),當(dāng)依賴(lài)改變時(shí),便會(huì)重新計(jì)算一個(gè)新值。

推薦好課:vue2.x微課、Vue項(xiàng)目實(shí)戰(zhàn)精講、Vue.js三天學(xué)習(xí)實(shí)戰(zhàn)教程


3 人點(diǎn)贊