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