一、對MVVM的理解
MVVM分為Model、View、ViewModel。
Model 代表數(shù)據(jù)模型,數(shù)據(jù)和業(yè)務(wù)邏輯都在Model層中定義;泛指后端進行的各種業(yè)務(wù)邏輯處理和數(shù)據(jù)操控,對于前端來說就是后端提供的 api 接口。
View 代表UI視圖,負責數(shù)據(jù)的展示;視圖層,也就是用戶界面。前端主要由 HTML 和 CSS 來構(gòu)建 。
ViewModel 負責監(jiān)聽 Model 中數(shù)據(jù)的改變并且控制視圖的更新,處理用戶交互操作;
Model 和 View 并無直接關(guān)聯(lián),而是通過 ViewModel 來進行聯(lián)系的,Model 和 ViewModel 之間有著雙向數(shù)據(jù)綁定的聯(lián)系。因此當 Model 中的數(shù)據(jù)改變時會觸發(fā) View 層的刷新,View 中由于用戶交互操作而改變的數(shù)據(jù)也會在 Model 中同步。+
這種模式實現(xiàn)了 Model 和 View 的數(shù)據(jù)自動同步,因此開發(fā)者只需要專注對數(shù)據(jù)的維護操作即可,而不需要自己操作 dom。
ViewModel 是由前端開發(fā)人員組織生成和維護的視圖數(shù)據(jù)層。在這一層,前端開發(fā)者對從后端獲取的 Model 數(shù)據(jù)進行轉(zhuǎn)換處理,做二次封裝,以生成符合 View 層使用預期的視圖數(shù)據(jù)模型。需要注意的是 ViewModel 所封裝出來的數(shù)據(jù)模型包括視圖的狀態(tài)和行為兩部分,而 Model 層的數(shù)據(jù)模型是只包含狀態(tài)的,比如頁面的這一塊展示什么,而頁面加載進來時發(fā)生什么,點擊這一塊發(fā)生什么,這一塊滾動時發(fā)生什么這些都屬于視圖行為(交互),視圖狀態(tài)和行為都封裝在了 ViewModel 里。這樣的封裝使得 ViewModel 可以完整地去描述 View 層。
MVVM 框架實現(xiàn)了雙向綁定,這樣 ViewModel 的內(nèi)容會實時展現(xiàn)在 View 層,前端開發(fā)者再也不必低效又麻煩地通過操縱 DOM 去更新視圖,MVVM 框架已經(jīng)把最臟最累的一塊做好了,我們開發(fā)者只需要處理和維護 ViewModel,更新數(shù)據(jù)視圖就會自動得到相應更新。這樣 View 層展現(xiàn)的不是 Model 層的數(shù)據(jù),而是 ViewModel 的數(shù)據(jù),由 ViewModel 負責與 Model 層交互,這就完全解耦了 View 層和 Model 層,這個解耦是至關(guān)重要的,它是前后端分離方案實施的重要一環(huán)。
二、vue常見指令
1. v-text
v-text 主要用來更新 textContent,可以等同于 JS 的 text 屬性。
<span v-text="msg"></span>
這兩者等價:
<span>插值表達式{{msg}}</span>
2. v-html
雙大括號的方式會將數(shù)據(jù)解釋為純文本,而非 HTML。為了輸出真正的 HTML,可以用 v-html 指令。它等同于 JS 的 innerHtml 屬性。
<div v-html="rawHtml"></div>
這個div的內(nèi)容將會替換成屬性值 rawHtml,直接作為 HTML 進行渲染。
3. v-pre
v-pre 主要用來跳過這個元素和它的子元素編譯過程??梢杂脕盹@示原始的 Mustache 標簽。跳過大量沒有指令的節(jié)點加快編譯。
<div id="app">
<span v-pre>{{message}}</span> //這條語句不進行編譯
<span>{{message}}</span>
</div>
最終僅顯示第二個 span 的內(nèi)容
4. v-cloak
這個指令是用來保持在元素上直到關(guān)聯(lián)實例結(jié)束時進行編譯。
<div id="app" v-cloak>
<div>
{{message}}
</div>
</div>
<script type="text/javascript">
new Vue({
el:'#app',
data:{
message:'hello world'
}
})
</script>
在頁面加載時會閃爍(插值閃爍問題),先顯示:
<div>
{{message}}
</div>
然后才會編譯為:
<div>
hello world!
</div>
可以用 v-cloak 指令解決插值表達式閃爍問題,v-cloak 在 css 中用屬性選擇器設(shè)置為 display: none;
5. v-once
v-once 關(guān)聯(lián)的實例,只會渲染一次。之后的重新渲染,實例極其所有的子節(jié)點將被視為靜態(tài)內(nèi)容跳過,這可以用于優(yōu)化更新性能。
<span v-once>This will never change:{{msg}}</span> //單個元素
<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)生改變,也不會重新渲染。
6. v-if
v-if 可以實現(xiàn)條件渲染,Vue 會根據(jù)表達式的值的真假條件來渲染元素。
<a v-if="ok">yes</a>
如果屬性值 ok 為 true,則顯示。否則,不會渲染這個元素。
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 充當 v-if 的 else-if 塊,可以鏈式的使用多次??梢愿臃奖愕膶崿F(xiàn) switch 語句。
<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,則這個元素被銷毀,不在 dom 中。但是 v-show 的元素會始終被渲染并保存在 dom 中,它只是簡單的切換 css 的 dispaly 屬性。
注意:v-if 有更高的切換開銷 v-show 有更高的初始渲染開銷。因此,如果要非常頻繁的切換,則使用 v-show 較好;如果在運行時條件不太可能改變,則 v-if 較好
10. v-for
用 v-for 指令根據(jù)遍歷數(shù)組來進行渲染
有下面兩種遍歷形式
<div v-for="(item,index) in items"></div> //使用in,index是一個可選參數(shù),表示當前項的索引
<div v-for="item of items"></div> //使用of
下面是一個例子,并且在 v-for 中,擁有對父作用域?qū)傩缘耐耆L問權(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>
會被渲染為:
<ul id="app">
<li>父作用域-文本1</li>
<li>父作用域-文本2</li>
</ul>
注意:當 v-for 和 v-if 同處于一個節(jié)點時,v-for 的優(yōu)先級比 v-if 更高。這意味著 v-if 將運行在每個 v-for 循環(huán)中
11. v-bind
v-bind 用來動態(tài)的綁定一個或者多個特性。沒有參數(shù)時,可以綁定到一個包含鍵值對的對象。常用于動態(tài)綁定 class 和 style。以及 href 等。簡寫為一個冒號【 :】
<1>對象語法:
//進行類切換的例子
<div id="app">
<!--當data里面定義的isActive等于true時,is-active這個類才會被添加起作用-->
<!--當data里面定義的hasError等于true時,text-danger這個類才會被添加起作用-->
<div :class="{'is-active':isActive, 'text-danger':hasError}"></div>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
isActive: true,
hasError: false
}
})
</script>
渲染結(jié)果:
<!--因為hasError: false,所以text-danger不被渲染-->
<div class = "is-active"></div>
<2>數(shù)組語法
<div id="app">
<!--數(shù)組語法:errorClass在data對應的類一定會添加-->
<!--is-active是對象語法,根據(jù)activeClass對應的取值決定是否添加-->
<p :class="[{'is-active':activeClass},errorClass]">12345</p>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
activeClass: false,
errorClass: 'text-danger'
}
})
</script>
渲染結(jié)果:
<!--因為activeClass: false,所以is-active不被渲染-->
<p class = "text-danger"></p>
<3>直接綁定數(shù)據(jù)對象
<div id="app">
<!--在vue實例的data中定義了classObject對象,這個對象里面是所有類名及其真值-->
<!--當里面的類的值是true時會被渲染-->
<div :class="classObject">12345</div>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
classObject:{
'is-active': false,
'text-danger':true
}
}
})
</script>
渲染結(jié)果:
<!--因為'is-active': false,所以is-active不被渲染-->
<div class = "text-danger"></div>
12. v-model
這個指令用于在表單上創(chuàng)建雙向數(shù)據(jù)綁定。
v-model 會忽略所有表單元素的 value、checked、selected 特性的初始值。因為它選擇 Vue 實例數(shù)據(jù)做為具體的值。
<div id="app">
<input v-model="somebody">
<p>hello {{somebody}}</p>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
somebody:'小明'
}
})
</script>
這個例子中直接在瀏覽器 input 中輸入別的名字,下面的 p 的內(nèi)容會直接跟著變。這就是雙向數(shù)據(jù)綁定。
v-model 修飾符<1> .lazy 默認情況下,v-model 同步輸入框的值和數(shù)據(jù)。可以通過這個修飾符,轉(zhuǎn)變?yōu)樵?change 事件再同步。
<input v-model.lazy="msg">
<2> .number
自動將用戶的輸入值轉(zhuǎn)化為數(shù)值類型
<input v-model.number="msg">
<3> .trim
自動過濾用戶輸入的首尾空格
<input v-model.trim="msg">
13. v-on
v-on 主要用來監(jiān)聽 dom 事件,以便執(zhí)行一些代碼塊。表達式可以是一個方法名。
簡寫為:【 @ 】
<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
? 事件不再重載頁面 - ?
.capture
? 使用事件捕獲模式,即元素自身觸發(fā)的事件先在此處處理,然后才交由內(nèi)部元素進行處理 - ?
.self
?只當在 ?event.target
? 是當前元素自身時觸發(fā)處理函數(shù) - ?
.once
? 事件將只會觸發(fā)一次 - ?
.passive
? 告訴瀏覽器你不想阻止事件的默認行為
<!-- 阻止單擊事件繼續(xù)傳播 -->
<a v-on:click.stop="doThis"></a>
<!-- 提交事件不再重載頁面 -->
<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)聽器時使用事件捕獲模式 -->
<!-- 即元素自身觸發(fā)的事件先在此處處理,然后才交由內(nèi)部元素進行處理 -->
<div v-on:click.capture="doThis">...</div>
<!-- 只當在 event.target 是當前元素自身時觸發(fā)處理函數(shù) -->
<!-- 即事件不是從內(nèi)部元素觸發(fā)的 -->
<div v-on:click.self="doThat">...</div>
<!-- 點擊事件將只會觸發(fā)一次 -->
<a v-on:click.once="doThis"></a>
<!-- 滾動事件的默認行為 (即滾動行為) 將會立即觸發(fā) -->
<!-- 而不會等待 `onScroll` 完成 -->
<!-- 這其中包含 `event.preventDefault()` 的情況 -->
<div v-on:scroll.passive="onScroll">...</div>
使用修飾符時,順序很重要;相應的代碼會以同樣的順序產(chǎn)生。因此,用v-on:click.prevent.self
會阻止所有的點擊,而 v-on:click.self.prevent
只會阻止對元素自身的點擊。
3、v-if 和 v-show 有什么區(qū)別?
共同點:?v-if
? 和 ?v-show
? 都能實現(xiàn)元素的顯示隱藏
區(qū)別:
1. v-show 只是簡單的控制元素的 display 屬性,而 v-if 才是條件渲染(條件為真,元素將會被渲染,條件為假,元素會被銷毀);
2. v-show 有更高的首次渲染開銷,而 v-if 的首次渲染開銷要小的多;
3. v-if 有更高的切換開銷,v-show 切換開銷小;
4. v-if 有配套的 v-else-if 和 v-else,而 v-show 沒有
5. v-if 可以搭配 template 使用,而 v-show 不行
四、Vue核心思想:數(shù)據(jù)驅(qū)動、組件化
1、數(shù)據(jù)驅(qū)動
傳統(tǒng)的前端數(shù)據(jù)交互是用 Ajax 從服務(wù)端獲取數(shù)據(jù),然后操作 DOM 來改變視圖;或者前端交互要改變數(shù)據(jù)時,又要再來一次上述步驟,而手動操作 DOM 是一個繁瑣的過程且易出錯。Vue.js 是一個提供了 MVVM 風格的雙向數(shù)據(jù)綁定的 Javascript 庫,專注于 View 層。它讓開發(fā)者省去了操作 DOM 的過程,只需要改變數(shù)據(jù)。Vue 會通過 Dircetives 指令,對 DOM 做一層封裝,當數(shù)據(jù)發(fā)生改變會通知指令去修改對應的 DOM,數(shù)據(jù)驅(qū)動 DOM 變化,DOM 是數(shù)據(jù)的一種自然映射。Vue 還會對操作進行監(jiān)聽,當視圖發(fā)生改變時,vue 監(jiān)聽到這些變化,從而改變數(shù)據(jù),這樣就形成了數(shù)據(jù)的雙向綁定。Vue 是一種 MVVM 框架。而 DOM 是數(shù)據(jù)的一個種自然映射。傳統(tǒng)的模式是通過 Ajax 請求從 model 請求數(shù)據(jù),然后手動的觸發(fā) DOM 傳入數(shù)據(jù)修改頁面。Vue 中,Directives 對 view 進行了封裝,當 model 里的數(shù)據(jù)發(fā)生變化是,Vue 就會通過 Directives 指令去修改 DOM。同時也通過 DOM Listener實現(xiàn)對視圖 view 的監(jiān)聽,當DOM 改變時,就會被監(jiān)聽到,實現(xiàn) model 的改變,實現(xiàn)數(shù)據(jù)的雙向綁定。
2、組件響應原理數(shù)據(jù)(model)改變驅(qū)動視圖(view)自動更新
當你把一個普通的 JavaScript 對象傳給 Vue 實例的 data選項,Vue 將遍歷此對象所有的屬性,并使用 Object.defineProperty 把這些屬性全部轉(zhuǎn)為 getter/setter。Object.defineProperty 是 ES5 中一個無法 shim 的特性,這也就是為什么 Vue 不支持 IE8 以及更低版本瀏覽器的原因。用戶看不到 getter/setter,但是在內(nèi)部它們讓 Vue 追蹤依賴,在屬性被訪問和修改時通知變化。這里需要注意的問題是瀏覽器控制臺在打印數(shù)據(jù)對象時 getter/setter 的格式化并不同,所以你可能需要安裝 vue-devtools 來獲取更加友好的檢查接口。每個組件實例都有相應的 watcher 實例對象,它會在組件渲染的過程中把屬性記錄為依賴,之后當依賴項的 setter 被調(diào)用時,會通知 watcher 重新計算,從而致使它關(guān)聯(lián)的組件得以更新。
3、組件化
擴展 HTML 元素,封裝可重用的代碼。每一個組件都對應一個 ViewModel。頁面上每個獨立的可視/可交互區(qū)域都可以視為一個組件。每個組件對應一個工程目錄,組件所需要的各種資源在這個目錄下就進維護。頁面是組件的容器,組件可以嵌套自由組合形成完整的頁面。
組件化實現(xiàn)了擴展 HTML 元素,封裝可用的代碼。頁面上每個獨立的可視/可交互區(qū)域視為一個組件;每個組件對應一個工程目錄,組件所需要的各種資源在這個目錄下就近維護;頁面不過是組件的容器,組件可以嵌套自由組合形成完整的頁面。
五、Vue 生命周期
六、組件中 data 為什么是一個函數(shù)?
為什么組件中的 data 必須是一個函數(shù),然后 return 一個對象,而 new Vue 實例里,data 可以直接是一個對象?
// data
data() {
return {
message: "子組件",
childName:this.name
}
}
// new Vue
new Vue({
el: '#app',
router,
template: '<App/>',
components: {App}
})
因為組件是用來復用的,且 JS 里對象是引用關(guān)系,如果組件中 data 是一個對象,那么這樣作用域沒有隔離,子組件中的 data 屬性值會相互影響,如果組件中 data 選項是一個函數(shù),那么每個實例可以維護一份被返回對象的獨立的拷貝,組件實例之間的 data 屬性值不會互相影響;而 new Vue 的實例,是不會被復用的,因此不存在引用對象的問題。
七、Vue 組件間通信有哪幾種方式?
Vue 組件間通信是面試??嫉闹R點之一,這題有點類似于開放題,你回答出越多方法當然越加分,表明你對 Vue 掌握的越熟練。Vue 組件間通信只要指以下 3 類通信:父子組件通信、隔代組件通信、兄弟組件通信,下面我們分別介紹每種通信方式且會說明此種方法可適用于哪類組件間通信。
(1)props / $emit 適用 父子組件通信
這種方法是 Vue 組件的基礎(chǔ),相信大部分同學耳聞能詳,所以此處就不舉例展開介紹。
(2)ref 與 $parent / $children 適用 父子組件通信
- ref:如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子組件上,引用就指向組件實例
- $parent / $children:訪問父 / 子實例
(3)EventBus ($emit / $on) 適用于 父子、隔代、兄弟組件通信
這種方法通過一個空的 Vue 實例作為中央事件總線(事件中心),用它來觸發(fā)事件和監(jiān)聽事件,從而實現(xiàn)任何組件間的通信,包括父子、隔代、兄弟組件。
(4)$attrs/$listeners 適用于 隔代組件通信
- $attrs:包含了父作用域中不被 prop 所識別 (且獲取) 的特性綁定 ( class 和 style 除外 )。當一個組件沒有聲明任何 prop 時,這里會包含所有父作用域的綁定 ( class 和 style 除外 ),并且可以通過 v-bind="$attrs" 傳入內(nèi)部組件。通常配合 inheritAttrs 選項一起使用。
- $listeners:包含了父作用域中的 (不含 .native 修飾器的) v-on 事件監(jiān)聽器。它可以通過 v-on="$listeners" 傳入內(nèi)部組件
(5)provide / inject 適用于 隔代組件通信
祖先組件中通過 provider 來提供變量,然后在子孫組件中通過 inject 來注入變量。 provide / inject API 主要解決了跨級組件間的通信問題,不過它的使用場景,主要是子組件獲取上級組件的狀態(tài),跨級組件間建立了一種主動提供與依賴注入的關(guān)系。
(6)Vuex 適用于 父子、隔代、兄弟組件通信
Vuex 是一個專為 Vue.js 應用程序開發(fā)的狀態(tài)管理模式。每一個 Vuex 應用的核心就是 store(倉庫)。“store” 基本上就是一個容器,它包含著你的應用中大部分的狀態(tài) ( state )。
- Vuex 的狀態(tài)存儲是響應式的。當 Vue 組件從 store 中讀取狀態(tài)的時候,若 store 中的狀態(tài)發(fā)生變化,那么相應的組件也會相應地得到高效更新。
- 改變 store 中的狀態(tài)的唯一途徑就是顯式地提交 (commit) mutation。這樣使得我們可以方便地跟蹤每一個狀態(tài)的變化。
八、computed 和 watch 的區(qū)別和運用的場景?
computed: 是計算屬性,依賴其它屬性值,并且 computed 的值有緩存,只有它依賴的屬性值發(fā)生改變,下一次獲取 computed 的值時才會重新計算 computed 的值;watch: 更多的是「觀察」的作用,類似于某些數(shù)據(jù)的監(jiān)聽回調(diào) ,每當監(jiān)聽的數(shù)據(jù)變化時都會執(zhí)行回調(diào)進行后續(xù)操作;運用場景:
- 當我們需要進行數(shù)值計算,并且依賴于其它數(shù)據(jù)時,應該使用 computed,因為可以利用 computed 的緩存特性,避免每次獲取值時,都要重新計算;
- 當我們需要在數(shù)據(jù)變化時執(zhí)行異步或開銷較大的操作時,應該使用 watch,使用 watch 選項允許我們執(zhí)行異步操作 ( 訪問一個 API ),限制我們執(zhí)行該操作的頻率,并在我們得到最終結(jié)果前,設(shè)置中間狀態(tài)。這些都是計算屬性無法做到的。
九、虛擬 DOM
優(yōu)點:
- 保證性能下限: 框架的虛擬 DOM 需要適配任何上層 API 可能產(chǎn)生的操作,它的一些 DOM 操作的實現(xiàn)必須是普適的,所以它的性能并不是最優(yōu)的;但是比起粗暴的 DOM 操作性能要好很多,因此框架的虛擬 DOM 至少可以保證在你不需要手動優(yōu)化的情況下,依然可以提供還不錯的性能,即保證性能的下限;
- 無需手動操作 DOM: 我們不再需要手動去操作 DOM,只需要寫好 View-Model 的代碼邏輯,框架會根據(jù)虛擬 DOM 和 數(shù)據(jù)雙向綁定,幫我們以可預期的方式更新視圖,極大提高我們的開發(fā)效率;
- 跨平臺: 虛擬 DOM 本質(zhì)上是 JavaScript 對象,而 DOM 與平臺強相關(guān),相比之下虛擬 DOM 可以進行更方便地跨平臺操作,例如服務(wù)器渲染、weex 開發(fā)等等。
缺點:
- 無法進行極致優(yōu)化: 雖然虛擬 DOM + 合理的優(yōu)化,足以應對絕大部分應用的性能需求,但在一些性能要求極高的應用中虛擬 DOM 無法進行針對性的極致優(yōu)化。
虛擬 DOM 實現(xiàn)原理:
虛擬 DOM 的實現(xiàn)原理主要包括以下 3 部分:
- 用 JavaScript 對象模擬真實 DOM 樹,對真實 DOM 進行抽象;
- diff 算法 — 比較兩棵虛擬 DOM 樹的差異;
- pach 算法 — 將兩個虛擬 DOM 對象的差異應用到真正的 DOM 樹。
十、vue-router 路由模式有幾種?
- ?
Hash
?: 使用 URL 的 hash 值來作為路由。支持所有瀏覽器。 - ?
History
?: 以來 HTML5 History API 和服務(wù)器配置。參考官網(wǎng)中 HTML5 History 模式 - ?
Abstract
?: 支持所有 javascript 運行模式。如果發(fā)現(xiàn)沒有瀏覽器的 API,路由會自動強制進入這個模式。
十一、delete和Vue.delete刪除數(shù)組的區(qū)別
delete 只是被刪除的元素變成了 empty/undefined 其他的元素的鍵值還是不變。Vue.delete 直接刪除了數(shù)組 改變了數(shù)組的鍵值。
十二、SPA 單頁面的理解,它的優(yōu)缺點分別是什么?
SPA( single-page application )僅在 Web 頁面初始化時加載相應的 HTML、JavaScript 和 CSS。一旦頁面加載完成,SPA 不會因為用戶的操作而進行頁面的重新加載或跳轉(zhuǎn);取而代之的是利用路由機制實現(xiàn) HTML 內(nèi)容的變換,UI 與用戶的交互,避免頁面的重新加載。優(yōu)點:
- 用戶體驗好、快,內(nèi)容的改變不需要重新加載整個頁面,避免了不必要的跳轉(zhuǎn)和重復渲染;
- 基于上面一點,SPA 相對對服務(wù)器壓力??;
- 前后端職責分離,架構(gòu)清晰,前端進行交互邏輯,后端負責數(shù)據(jù)處理;
缺點:
- 初次加載耗時多:為實現(xiàn)單頁 Web 應用功能及顯示效果,需要在加載頁面的時候?qū)?JavaScript、CSS 統(tǒng)一加載,部分頁面按需加載;
- 前進后退路由管理:由于單頁應用在一個頁面中顯示所有的內(nèi)容,所以不能使用瀏覽器的前進后退功能,所有的頁面切換需要自己建立堆棧管理;
- SEO 難度較大:由于所有的內(nèi)容都在一個頁面中動態(tài)替換顯示,所以在 SEO 上其有著天然的弱勢。
十三、簡述Vue的響應式原理
當一個 Vue 實例創(chuàng)建時,vue 會遍歷 data 選項的屬性,用 Object.defineProperty 將它們轉(zhuǎn)為 getter/setter 并且在內(nèi)部追蹤相關(guān)依賴,在屬性被訪問和修改時通知變化。每個組件實例都有相應的 watcher 程序?qū)嵗?,它會在組件渲染的過程中把屬性記錄為依賴,之后當依賴項的 setter 被調(diào)用時,會通知 watcher 重新計算,從而致使它關(guān)聯(lián)的組件得以更新。
十四、Vue中如何在組件內(nèi)部實現(xiàn)一個雙向數(shù)據(jù)綁定?
假設(shè)有一個輸入框組件,用戶輸入時,同步父組件頁面中的數(shù)據(jù)具體思路:父組件通過 props 傳值給子組件,子組件通過 $emit 來通知父組件修改相應的 props 值,具體實現(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'
}
}
})
可以看到,當輸入數(shù)據(jù)時,父子組件中的數(shù)據(jù)是同步改變的:
我們在父組件中做了兩件事,一是給子組件傳入 props,二是監(jiān)聽 input 事件并同步自己的 value 屬性。那么這兩步操作能否再精簡一下呢?答案是可以的,你只需要修改父組件:
template: `
<div>
<!--<comp-one :value1="value" @input="value = arguments[0]"></comp-one>-->
<comp-one v-model="value"></comp-one>
</div>
`
v-model 實際上會幫我們完成上面的兩步操作。
十五、 Vue中如何監(jiān)控某個屬性值的變化?
比如現(xiàn)在需要監(jiān)控 data 中,obj.a 的變化。Vue 中監(jiān)控對象屬性的變化你可以這樣:
watch: {
obj: {
handler (newValue, oldValue) {
console.log('obj changed')
},
deep: true
}
}
deep 屬性表示深層遍歷,但是這么寫會監(jiān)控 obj 的所有屬性變化,并不是我們想要的效果,所以做點修改:
watch: {
'obj.a': {
handler (newName, oldName) {
console.log('obj.a changed')
}
}
}
還有一種方法,可以通過 computed 來實現(xiàn),只需要:
computed: {
a1 () {
return this.obj.a
}
}
利用計算屬性的特性來實現(xiàn),當依賴改變時,便會重新計算一個新值。
推薦好課:vue2.x微課、Vue項目實戰(zhàn)精講、Vue.js三天學習實戰(zhàn)教程