-
1.v-if 和v-show區別
v-if 真正條件渲染 DOM切換 銷毀 重建,不停的銷毀和創建比較消耗性能。
v-show本質就是通過控制css中的display設置為none,控制隱藏,只會編譯一次;
-
2 .created()和mounted()的區別
created()最早使用data中的數據 mounted()最早操作dom節點的函數
接口請求一般放在mounted中,但需要注意的是服務端渲染時不支持mounted,需要放到created中。
-
3.vue中data為什么必須是一個函數
1.data是一個函數時,每個組件實例都有自己的作用域,每個實例相互獨立,不會相互影響。Object是引用數據類型,如果不用function返回,每個組件的data都是內存的同一個地址,一個數據改變了其他也改變了
2.對象為引用類型,當重用組件時,由于數據對象都指向同一個data對象,當在一個組件中修改data時,其他重用的組件中的data會同時被修改;而使用返回對象的函數,由于每次返回的都是一個新對象(Object的實例),引用地址不同,則不會出現這個問題。
-
4.watch、computed和methods的區別
computed 計算屬性 計算結果會緩存,只有當依賴值改變才會重新計算
watch 監聽屬性 一個值的改變 需要另一個值的改變而改變,結果不會緩存
methods 事件方法 調用一次,執行一次,結果不會緩存
-
5. mvvm的理解
mvvm主要解決mvc中大量使用DOM,使頁面渲染性能降低,加載速度變慢,影響使用體驗,mvc模式當mode發生變化,開發者需要主動更新view
-
6.template 只有一個根元素
每一個組件的本質就是Vue實例,既然是Vue的實例就需要一個根入口,如果沒有,多個div就無法指定Vue的實例根入口,就像HTML只有一個根元素一樣,多個根元素無法構成一棵樹,所以template只有一個根元素。
-
7.vue中怎么重置data
Object.assign()方法用于將所有可枚舉屬性的值從一個或多個源對象復制到目標對象
this.$data獲取當前狀態下的data
this.$options.data()獲取該組件初始狀態下的data。
Object.assign(this.$data, this.$options.data())
-
8.Object.defineProperty的理解
Object.defineProperty定義新屬性或修改原有的屬性;
vue的數據雙向綁定的原理就是用的Object.defineProperty這個方法,里面定義了setter和getter方法,通過觀察者模式(發布訂閱模式)來監聽數據的變化,從而做相應的邏輯處理。
-
9.vue組件會在什么時候下被銷毀?
頁面關閉、路由跳轉、v-if和改變key值
-
10.vue的is這個特性
vue中is的屬性引入是為了解決dom結構中對放入html的元素有限制的問題;
動態組件的例子
<ul><li is='my-component'></li></ul>
<div id="app">
<button @click="switchComp('A')">首頁 -- 點我顯示A 組件 </button>
<button @click="switchComp('B')">推薦頁 -- 點我顯示B 組件</button>
<button @click="switchComp('C')">搜索 -- 點我顯示 C 組件</button>
<button @click="switchComp('D')">點我顯示 D組件 </button>
<component :is="currentComp"></component> <!-- is -->
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
Vue.component('componentA', {
template: '<div>你好呀~ 歡迎來到首頁 ~~ </div>'
});
Vue.component('componentB',{
template: '<div>你好呀~ 歡迎來到推薦頁 ~~ </div>'
});
Vue.component('componentC',{
template: '<div> 你好呀~ 歡迎來到搜索頁 ~~ </div>'
})
let componentD = {
template: '<div>D</div>'
}
let app = new Vue({
el: '#app',
components: { componentD },
data: {
currentComp: 'componentA'
},
methods: {
switchComp(tag) {
this.currentComp = 'component' + tag
}
}
})
</script>
-
11.vue的:class和:style有幾種表示方式?
:class 1.綁定變量 2.綁定對象 3.綁定一個數組 4.綁定三元表達式
:style 1.綁定變量 2.綁定對象 3.綁定函數返回值 4.綁定三元表達式
-
12.怎么在watch監聽開始之后立即被調用?
watch時有一個特點,就是當值第一次綁定的時候,不會執行監聽函數,只有值發生改變才會執行。如果我們需要在最初綁定值的時候也執行函數,則就需要用到immediate屬性。
let vm=new Vue({
el:"#first",
data:{msg:'liuneng'},
watch:{
msg:{
handler (newMsg,oldMsg){
console.log(newMsg);
},
immediate:true //設置immediate屬性為true
}
}
})
-
13.Vue怎么在路由中配置404頁面
在router.js中,由于路由是從上到下執行的,只要在路由配置中最后面放個*號就可以了,例如:
最后一個就是404
import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/index'
import na from '@/components/newDetail'
import ga from '@/components/goodlist'
import notfount from '@/components/404'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
name: 'HelloWorld',
component: HelloWorld
},
{
path: '/newDetail',
name: 'newDetail',
component: na
},
{
path: '/goodlist',
name: 'goodlist',
component: ga
},
{
path: '*',
name: 'notfount',
component: notfount
}
]
})
-
14.CLI2 Runtime-Compiler和Runtime-only的區別
runtime-compiler(v1)(運行過程)): template -> ast -> render -> vdom -> UI
runtime-only(v2 1.性能更高, 2.代碼量更少):render -> vdom -> UI
那.vue文件中的template是由誰處理的呢? 是由vue-template-compiler這個開發時 工具依賴來處理的,他將.vue文件解析成了render函數,解析之后,是沒有tamplate這個 東西的
總結:
如果在開發中,依然使用template,就需要選擇Runtime-Compiler
如果在開發中,使用的是.vue文件夾開發,那么可以選擇Runtime-Only
-
15.強制更新組件的方法有哪些?分別有何利弊?
簡單粗暴的方式:重新加載整個頁面
不妥的方式:使用 v-if
較好的方法:使用Vue的內置forceUpdate方法
最好的方法:在組件上進行 key 更改
調用強制更新方法this.$forceUpdate()會更新視圖和數據,觸發updated生命周期。
<button @click="reload()">強制更新</button>
updated(){
console.log("更新了");
},
methods:{
reload(){
this.$forceUpdate();
}
}
-
16.什么是虛擬DOM?
虛擬DOM是:用JS來模擬一顆 DOM 樹,放在瀏覽器內存中
當你要改變時,虛擬 DOM 使用 diff 算法進行 新舊虛擬 dom 的比較將修改了的更新到實際的 DOM 樹,減少了 DOM 操作
虛擬 dom 是相對于瀏覽器所渲染出來的真實 dom 的,在react,vue等技術出現之前,我們要改變頁面展示的內容只能通過遍歷查詢 dom 樹的方式找到需要修改的 dom 然后修改樣式行為或者結構,來達到更新 ui 的目的。這種方式相當消耗計算資源,因為每次查詢 dom 幾乎都需要遍歷整顆 dom 樹,如果建立一個與 dom 樹對應的虛擬 dom 對象( js 對象),以對象嵌套的方式來表示 dom 樹,那么每次 dom 的更改就變成了 js 對象的屬性的更改,這樣一來就能查找 js 對象的屬性變化要比查詢 dom 樹的性能開銷小。
-
17.vue組件之間的通信都有哪些?
父子Coms: 1/2/3 ..
兄弟Coms: 4/5
跨級Coms: 4/5/6/7
1.props
2.$emit/$on
3.( $parents/$children ) / $refs
4.Vuex
5.Bus
6.( provide/inject )
7.( $attrs/$listeners )
-
18.route 和$router的區別
$router是new Router的實例,是全局路由對象,用于進行路由跳轉等操作,想要導航到不同 URL,則使用 $router.push 方法;
$route是路由信息對象,表示當前活躍的路由對象,用于讀取路由參數;可以從里面獲取name,path,params,query等;
簡單來說也就是,操作找$router,讀參找$route。
-
19.@click 綁定多個事件?
1,v-on綁定多個方法多個函數?:
<p v-on="{click:dbClick,mousemove:MouseClick}"></p>
一個事件綁定多個函數:
<p @click="one(),two()">點擊</p>
-
20.切換到新路由時,頁面要滾動到頂部或保持原先的滾動位置
在路由實例中配置
scrollBehavior(ro,form,savedPosition){
//滾動到頂部
return {x:0,y:0}
//保持原先的滾動位置
return {selector:falsy}
}
-
21.vue 修飾符sync的功能
vue 修飾符sync的功能是:當一個子組件改變了一個 prop 的值時,這個變化也會同步到父組件中所綁定,這樣就實現了prop的雙向綁定。
-
22.vue complier
compiler模塊Vue框架中用于模板編譯的,它的作用就是將Vue中的組件模板轉換成render函數,render函數在運行時可以生成虛擬節點vnode,它是Vue中虛擬DOM樹的基本實現流程。完整版的Vue是包含runtime和compiler的,也就是說模板的編譯過程可以在運行時進行,這無疑是一種性能負擔。Vue官方也提供了獨立的runtime版本,其中只包含運行時環境,把從template到render函數的生成部分放在構建時完成(利用vue-templete-compiler模塊),以提高運行時的效率。
-
23.Vue.use() 作用
提供
install
方法,只是為了讓 Vue 可以將組件注冊到框架里去,使其能夠被全局使用。
-
24.怎么解決vue動態設置img的src不生效的問題?
因為動態添加src被當做靜態資源處理了,沒有進行編譯,所以要加上require。
<img :src="require('@/assets/images/xxx.png')" />
-
25.怎么解決vue打包后靜態資源圖片失效的問題?
找到config/index.js 配置文件,找build打包對象里的assetsPublicPath屬性
默認值為/,更改為./就好了
最新的vue-cli 需要在根目錄下建一個vue.config.js 在里面配置publicPath即可
-
26.vue渲染模板時怎么保留模板中的HTML注釋呢?
設置comments屬性,官網默認為舍棄注釋
<template comments> ... </template>
-
27.vue中使用插件的步驟?
安裝:
npm install xxx
引入:import ... from ...;
使用:Vue.use(xxx)
-
28.vue中引入組件有幾種方式?
兩種:采用 ES6 的 import ... from ... 語法或 CommonJS 的 require() 方法引入組件
//方法一
import Calendar from "./calendar";
export default {
name: "SymptomMain",
components: {
Calendar
},
}
//方法二
export default {
//1.直接在components中寫入子組件
components: {
Calendar:require('./calendar.vue').default
},
}
-
29.vue-router 有哪幾種導航鉤子
1.全局導航鉤子 作用:跳轉前進行判斷攔截。
router.beforeEach(to,from,next);
router.beforeResolve(to,from,next);
router.afterEach(to,from,next);
2.組件內鉤子
beforeRouteEnter
beforeRouteUpdate
beforeRouteLeave
3.單獨路由獨享組件
beforeEnter
-
30.v-model的原理
原生input其實只是一個語法糖
:bind="value"與@change="value = $event.target.value"的結合。
-
31.父組件怎么接收子組件的多個參數
this.$emit("eventName",data)
data為一個對象
data 對象或數組都可以的。
-
32.怎么解決vue動態設置img的src不生效的問題?
因為動態添加src被當做靜態資源處理了,沒有進行編譯,所以要加上require。
<img :src="require('../../../assets/images/xxx.png')" />
-
33.keep-alive有關的生命周期是哪些?描述下這些生命周期
activated和deactivated
keep-alive的生命周期
1.activated: 頁面第一次進入的時候,鉤子觸發的順序是created->mounted->activated
2.deactivated: 頁面退出的時候會觸發deactivated,當再次前進或者后退的時候只觸發activated
-
34.vue中怎么重置data?
Object.assign()方法用于將所有可枚舉屬性的值從一個或多個源對象復制到目標對象。
this.$data獲取當前狀態下的data
this.$options.data()獲取該組件初始狀態下的data。
Object.assign(this.$data, this.$options.data())
-
35.在vue事件中傳入$event,使用e.target和e.currentTarget有什么區別?
currentTarget:事件綁定的元素
target:鼠標觸發的元素
event.currentTarget指向事件所綁定的元素,而event.target始終指向事件發生時的元素。
-
36.vue如果想擴展某個現有的組件時,怎么做呢?
1.使用Vue.extend直接擴展
2.使用Vue.mixin全局混入
3.HOC封裝
4.slot擴展
-
36.v-once的使用場景
v-once這個指令不需要任何表達式,它的作用就是定義它的元素或組件只會渲染一次,包括元素或者組件的所有字節點。首次渲染后,不再隨著數據的改變而重新渲染。也就是說使用v-once,那么該塊都將被視為靜態內容。<div v-once>{{count}}</div>
-
37.表單修飾符和事件修飾符
事件修飾符.stop .prevent .capture .self .once .passive
表單修飾符.number .lazy .trim
-
38.v-clock和v-pre指令
v-cloak指令只是在標簽中加入一個v-cloak自定義屬性,在HTML還編譯完成之后該屬性會被刪除。
v-pre可以用來阻止預編譯,有v-pre指令的標簽內部的內容不會被編譯,會原樣輸出。
-
39.proxy的理解
vue的數據劫持有兩個缺點:
1、無法監聽通過索引修改數組的值的變化
2、無法監聽object也就是對象的值的變化
所以vue2.x中才會有$set屬性的存在
proxy是es6中推出的新api,可以彌補以上兩個缺點,所以vue3.x版本用proxy替換object.defineproperty
-
40. Proxy只會代理對象的第一層,那么Vue3又是怎樣處理這個問題的呢?
判斷當前Reflect.get的返回值是否為Object,如果是則再通過reactive方法做代理, 這樣就實現了深度觀測。
-
41. 監測數組的時候可能觸發多次get/set,那么如何防止觸發多次呢?
我們可以判斷key是否為當前被代理對象target自身屬性,也可以判斷舊值與新值是否相等,只有滿足以上兩個條件之一時,才有可能執行trigger。
-
42.父組件可以監聽到子組件的生命周期嗎?
可以通過@hook來監聽生命周期事件,用法如下:
// Parent.vue
<Child @hook:mounted="doSomething" ></Child>
doSomething() {
console.log('父組件監聽到 mounted 鉤子函數 ...');
},
// Child.vue
mounted(){
console.log('子組件觸發 mounted 鉤子函數 ...');
},
// 以上輸出順序為:
// 子組件觸發 mounted 鉤子函數 ...
// 父組件監聽到 mounted 鉤子函數 ...
-
43.Vue實現數據雙向綁定的原理:Object.defineProperty()
1.vue實現數據雙向綁定主要是:采用數據劫持結合發布者-訂閱者模式的方式,通過Object.defineProperty()來劫持各個屬性的setter,getter,在數據變動時發布消息給訂閱者,觸發相應監聽回調。當把一個普通 Javascript 對象傳給 Vue 實例來作為它的 data 選項時,Vue 將遍歷它的屬性,用 Object.defineProperty 將它們轉為 getter/setter。用戶看不到 getter/setter,但是在內部它們讓 Vue 追蹤依賴,在屬性被訪問和修改時通知變化。
2.vue的數據雙向綁定 將MVVM作為數據綁定的入口,整合Observer,Compile和Watcher三者,通過Observer來監聽自己的model的數據變化,通過Compile來解析編譯模板指令(vue中是用來解析 {{}}),最終利用watcher搭起observer和Compile之間的通信橋梁,達到數據變化 —>視圖更新;視圖交互變化(input)—>數據model變更雙向綁定效果。
3.通過Observer 把數據劫持(Object.defineProperty()) 、加入到訂閱器(Dep) 訂閱器收集訂閱者(Watcher )、視圖通過編譯(Compile)、解析指令(Directive)等一些列操作收集給訂閱者 、最后通過觸發數據變化update 通知所有訂閱者完成數據驅動
-
44.服務端渲染(SSR)和預渲染(Prerendering)有什么區別?
1.服務端渲染的過程為:解析執行JS => 構建HTML頁面 => 輸出給瀏覽器
2.預渲染:直接輸出HTML頁面給瀏覽器
-
45.vue從data改變到頁面渲染的過程
(1)把模板編譯為render函數
(2)實例進行掛載,根據節點render函數的調用,遞歸的生成虛擬dom;
(3)對比虛擬dom,渲染真實dom;
(4)組件內部data發生變化,組件和子組件引用data作為props重新調用render函數生成虛擬dom返回 對比虛擬dom,渲染真實dom的操作;
-
46 介紹一下Vue的響應式系統
Vue為MVVM框架,當數據模型data變化時,頁面視圖會得到響應更新,其原理對data的getter/setter方法進行攔截(Object.defineProperty或者Proxy),利用發布訂閱的設計模式,在getter方法中進行訂閱,在setter方法中發布通知,讓所有訂閱者完成響應。
在響應式系統中,Vue會為數據模型data的每一個屬性新建一個訂閱中心作為發布者,而監聽器watch、計算屬性computed、視圖渲染template/render三個角色同時作為訂閱者,對于監聽器watch,會直接訂閱觀察監聽的屬性,對于計算屬性computed和視圖渲染template/render,如果內部執行獲取了data的某個屬性,就會執行該屬性的getter方法,然后自動完成對該屬性的訂閱,當屬性被修改時,就會執行該屬性的setter方法,從而完成該屬性的發布通知,通知所有訂閱者進行更新。
-
47computed與watch的區別
計算屬性computed和監聽器watch都可以觀察屬性的變化從而做出響應,不同的是:
計算屬性computed更多是作為緩存功能的觀察者,它可以將一個或者多個data的屬性進行復雜的計算生成一個新的值,提供給渲染函數使用,當依賴的屬性變化時,computed不會立即重新計算生成新的值,而是先標記為臟數據,當下次computed被獲取時候,才會進行重新計算并返回。
而監聽器watch并不具備緩存性,監聽器watch提供一個監聽函數,當監聽的屬性發生變化時,會立即執行該函數。
-
48介紹一下Vue的生命周期
beforeCreate:是new Vue()之后觸發的第一個鉤子,在當前階段data、methods、computed以及watch上的數據和方法都不能被訪問。
created:在實例創建完成后發生,當前階段已經完成了數據觀測,也就是可以使用數據,更改數據,在這里更改數據不會觸發updated函數。可以做一些初始數據的獲取,在當前階段無法與Dom進行交互,如果非要想,可以通過vm.$nextTick來訪問Dom。
beforeMount:發生在掛載之前,在這之前template模板已導入渲染函數編譯。而當前階段虛擬Dom已經創建完成,即將開始渲染。在此時也可以對數據進行更改,不會觸發updated。
mounted:在掛載完成后發生,在當前階段,真實的Dom掛載完畢,數據完成雙向綁定,可以訪問到Dom節點,使用$refs屬性對Dom進行操作。
beforeUpdate:發生在更新之前,也就是響應式數據發生更新,虛擬dom重新渲染之前被觸發,你可以在當前階段進行更改數據,不會造成重渲染。
updated:發生在更新完成之后,當前階段組件Dom已完成更新。要注意的是避免在此期間更改數據,因為這可能會導致無限循環的更新。
beforeDestroy:發生在實例銷毀之前,在當前階段實例完全可以被使用,我們可以在這時進行善后收尾工作,比如清除計時器。
destroyed:發生在實例銷毀之后,這個時候只剩下了dom空殼。組件已被拆解,數據綁定被卸除,監聽被移出,子實例也統統被銷毀。
-
49為什么組件的data必須是一個函數
一個組件可能在很多地方使用,也就是會創建很多個實例,如果data是一個對象的話,對象是引用類型,一個實例修改了data會影響到其他實例,所以data必須使用函數,為每一個實例創建一個屬于自己的data,使其同一個組件的不同實例互不影響。
-
50組件之間是怎么通信的
父子組件通信
父組件 -> 子組件:prop
子組件 -> 父組件:emit
獲取組件實例:使用children,$refs.xxx,獲取到實例后直接獲取屬性數據或調用組件方法
兄弟組件通信
Event Bus:每一個Vue實例都是一個Event Bus,都支持emit,可以為兄弟組件的實例之間new一個Vue實例,作為Event Bus進行通信。
Vuex:將狀態和方法提取到Vuex,完成共享
跨級組件通信
使用provide/inject
Event Bus:同兄弟組件Event Bus通信
Vuex:將狀態和方法提取到Vuex,完成共享
-
51 Vue事件綁定原理說一下
每一個Vue實例都是一個Event Bus,當子組件被創建的時候,父組件將事件傳遞給子組件,子組件初始化的時候是有$on方法將事件注冊到內部,在需要的時候使用$emit觸發函數,而對于原生native事件,使用addEventListener綁定到真實的DOM元素上。
-
52 slot是什么?有什么作用?原理是什么?
slot又名插槽,是Vue的內容分發機制,組件內部的模板引擎使用slot元素作為承載分發內容的出口。插槽slot是子組件的一個模板標簽元素,而這一個標簽元素是否顯示,以及怎么顯示是由父組件決定的。
slot又分三類,默認插槽,具名插槽和作用域插槽。
默認插槽:又名匿名查抄,當slot沒有指定name屬性值的時候一個默認顯示插槽,一個組件內只有有一個匿名插槽。
具名插槽:帶有具體名字的插槽,也就是帶有name屬性的slot,一個組件可以出現多個具名插槽。
作用域插槽:默認插槽、具名插槽的一個變體,可以是匿名插槽,也可以是具名插槽,該插槽的不同點是在子組件渲染作用域插槽時,可以將子組件內部的數據傳遞給父組件,讓父組件根據子組件的傳遞過來的數據決定如何渲染該插槽。
實現原理:當子組件vm實例化時,獲取到父組件傳入的slot標簽的內容,存放在vm.$slot中,默認插槽為vm.$slot.default,具名插槽為vm.$slot.xxx,xxx 為插槽名,當組件執行渲染函數時候,遇到slot標簽,使用$slot中的內容進行替換,此時可以為插槽傳遞數據,若存在數據,則可稱該插槽為作用域插槽。
-
53 Vue模板渲染的原理是什么?
vue中的模板template無法被瀏覽器解析并渲染,因為這不屬于瀏覽器的標準,不是正確的HTML語法,所有需要將template轉化成一個JavaScript函數,這樣瀏覽器就可以執行這一個函數并渲染出對應的HTML元素,就可以讓視圖跑起來了,這一個轉化的過程,就成為模板編譯。
模板編譯又分三個階段,解析parse,優化optimize,生成generate,最終生成可執行函數render。
parse階段:使用大量的正則表達式對template字符串進行解析,將標簽、指令、屬性等轉化為抽象語法樹AST。
optimize階段:遍歷AST,找到其中的一些靜態節點并進行標記,方便在頁面重渲染的時候進行diff比較時,直接跳過這一些靜態節點,優化runtime的性能。
generate階段:將最終的AST轉化為render函數字符串。
-
54 template預編譯是什么?
對于 Vue 組件來說,模板編譯只會在組件實例化的時候編譯一次,生成渲染函數之后在也不會進行編譯。因此,編譯對組件的 runtime 是一種性能損耗。
而模板編譯的目的僅僅是將template轉化為render function,這個過程,正好可以在項目構建的過程中完成,這樣可以讓實際組件在 runtime 時直接跳過模板渲染,進而提升性能,這個在項目構建的編譯template的過程,就是預編譯。
-
55 template和jsx的有什么分別?
對于 runtime 來說,只需要保證組件存在 render 函數即可,而我們有了預編譯之后,我們只需要保證構建過程中生成 render 函數就可以。
在 webpack 中,我們使用vue-loader編譯.vue文件,內部依賴的vue-template-compiler模塊,在 webpack 構建過程中,將template預編譯成 render 函數。
與 react 類似,在添加了jsx的語法糖解析器babel-plugin-transform-vue-jsx之后,就可以直接手寫render函數。
所以,template和jsx的都是render的一種表現形式,不同的是:
JSX相對于template而言,具有更高的靈活性,在復雜的組件中,更具有優勢,而 template 雖然顯得有些呆滯。但是 template 在代碼結構上更符合視圖與邏輯分離的習慣,更簡單、更直觀、更好維護。
-
56 說一下什么是Virtual DOM
Virtual DOM 是 DOM 節點在 JavaScript 中的一種抽象數據結構,之所以需要虛擬DOM,是因為瀏覽器中操作DOM的代價比較昂貴,頻繁操作DOM會產生性能問題。虛擬DOM的作用是在每一次響應式數據發生變化引起頁面重渲染時,Vue對比更新前后的虛擬DOM,匹配找出盡可能少的需要更新的真實DOM,從而達到提升性能的目的。
-
57 介紹一下Vue中的Diff算法
在新老虛擬DOM對比時
首先,對比節點本身,判斷是否為同一節點,如果不為相同節點,則刪除該節點重新創建節點進行替換
如果為相同節點,進行patchVnode,判斷如何對該節點的子節點進行處理,先判斷一方有子節點一方沒有子節點的情況(如果新的children沒有子節點,將舊的子節點移除)
比較如果都有子節點,則進行updateChildren,判斷如何對這些新老節點的子節點進行操作(diff核心)。
匹配時,找到相同的子節點,遞歸比較子節點
在diff中,只對同層的子節點進行比較,放棄跨級的節點比較,使得時間復雜從O(n^3)降低值O(n),也就是說,只有當新舊children都為多個子節點時才需要用核心的Diff算法進行同層級比較。
-
58 key屬性的作用是什么
key值得作用:增加唯一性,更高效的更新虛擬DOM,便于diff算法的更新,key值得唯一性更快的更新虛擬DOM。
diff算法對DOM進行原地復用,減少DOM性能耗費。
-
59 說說Vue2.0和Vue3.0有什么區別
重構響應式系統,使用Proxy替換Object.defineProperty,使用Proxy優勢:
可直接監聽數組類型的數據變化
監聽的目標為對象本身,不需要像Object.defineProperty一樣遍歷每個屬性,有一定的性能提升
可攔截apply、ownKeys、has等13種方法,而Object.defineProperty不行
直接實現對象屬性的新增/刪除
新增Composition API,更好的邏輯復用和代碼組織
重構 Virtual DOM
模板編譯時的優化,將一些靜態節點編譯成常量
slot優化,將slot編譯為lazy函數,將slot的渲染的決定權交給子組件
模板中內聯事件的提取并重用(原本每次渲染都重新生成內聯函數)
代碼結構調整,更便于Tree shaking,使得體積更小
使用Typescript替換Flow
-
60 為什么要新增Composition API,它能解決什么問題
Vue2.0中,隨著功能的增加,組件變得越來越復雜,越來越難維護,而難以維護的根本原因是Vue的API設計迫使開發者使用watch,computed,methods選項組織代碼,而不是實際的業務邏輯。
另外Vue2.0缺少一種較為簡潔的低成本的機制來完成邏輯復用,雖然可以minxis完成邏輯復用,但是當mixin變多的時候,會使得難以找到對應的data、computed或者method來源于哪個mixin,使得類型推斷難以進行。
所以Composition API的出現,主要是也是為了解決Option API帶來的問題,第一個是代碼組織問題,Compostion API可以讓開發者根據業務邏輯組織自己的代碼,讓代碼具備更好的可讀性和可擴展性,也就是說當下一個開發者接觸這一段不是他自己寫的代碼時,他可以更好的利用代碼的組織反推出實際的業務邏輯,或者根據業務邏輯更好的理解代碼。
第二個是實現代碼的邏輯提取與復用,當然mixin也可以實現邏輯提取與復用,但是像前面所說的,多個mixin作用在同一個組件時,很難看出property是來源于哪個mixin,來源不清楚,另外,多個mixin的property存在變量命名沖突的風險。而Composition API剛好解決了這兩個問題。
-
61 都說Composition API與React Hook很像,說說區別
從React Hook的實現角度看,React Hook是根據useState調用的順序來確定下一次重渲染時的state是來源于哪個useState,所以出現了以下限制
不能在循環、條件、嵌套函數中調用Hook
必須確保總是在你的React函數的頂層調用Hook
useEffect、useMemo等函數必須手動確定依賴關系
而Composition API是基于Vue的響應式系統實現的,與React Hook的相比
聲明在setup函數內,一次組件實例化只調用一次setup,而React Hook每次重渲染都需要調用Hook,使得React的GC比Vue更有壓力,性能也相對于Vue來說也較慢
Compositon API的調用不需要顧慮調用順序,也可以在循環、條件、嵌套函數中使用
響應式系統自動實現了依賴收集,進而組件的部分的性能優化由Vue內部自己完成,而React Hook需要手動傳入依賴,而且必須必須保證依賴的順序,讓useEffect、useMemo等函數正確的捕獲依賴變量,否則會由于依賴不正確使得組件性能下降。
雖然Compositon API看起來比React Hook好用,但是其設計思想也是借鑒React Hook的。
-
62 SSR有了解嗎?原理是什么?
在客戶端請求服務器的時候,服務器到數據庫中獲取到相關的數據,并且在服務器內部將Vue組件渲染成HTML,并且將數據、HTML一并返回給客戶端,這個在服務器將數據和組件轉化為HTML的過程,叫做服務端渲染SSR。
而當客戶端拿到服務器渲染的HTML和數據之后,由于數據已經有了,客戶端不需要再一次請求數據,而只需要將數據同步到組件或者Vuex內部即可。除了數據意外,HTML也結構已經有了,客戶端在渲染組件的時候,也只需要將HTML的DOM節點映射到Virtual DOM即可,不需要重新創建DOM節點,這個將數據和HTML同步的過程,又叫做客戶端激活。
-
63 使用SSR的好處:
有利于SEO:其實就是有利于爬蟲來爬你的頁面,因為部分頁面爬蟲是不支持執行JavaScript的,這種不支持執行JavaScript的爬蟲抓取到的非SSR的頁面會是一個空的HTML頁面,而有了SSR以后,這些爬蟲就可以獲取到完整的HTML結構的數據,進而收錄到搜索引擎中。
白屏時間更短:相對于客戶端渲染,服務端渲染在瀏覽器請求URL之后已經得到了一個帶有數據的HTML文本,瀏覽器只需要解析HTML,直接構建DOM樹就可以。而客戶端渲染,需要先得到一個空的HTML頁面,這個時候頁面已經進入白屏,之后還需要經過加載并執行 JavaScript、請求后端服務器獲取數據、JavaScript 渲染頁面幾個過程才可以看到最后的頁面。特別是在復雜應用中,由于需要加載 JavaScript 腳本,越是復雜的應用,需要加載的 JavaScript 腳本就越多、越大,這會導致應用的首屏加載時間非常長,進而降低了體驗感。
-
64 vue 數組使用push pop 等為什么是響應式的?
把數組原有的方法, 繼續執行, 后面增加了ob.dep.notify() ,這個里面放著訂閱者模式里面的訂閱者,通過notify來通知訂閱者做處理
-
65 render和template 的關系
1.性質相同 都是類編譯器. 2. template=>render(創建)=》虛擬DOM(js對象)=》真實DOM. 3.互補的關系
-
66 vuex為什么不建議在action中修改state
action的回調會被當作普通函數執行,而當如果有多個聲明時,它們是被視為Promise實例,并且用Promise.all執行,總所周知,Promise.all在執行Promise時是不保證順序的,也就是說,假如有3個Promise實例:P1、P2、P3,它們3個之中不一定哪個先有返回結果,那么我們仔細思考一下:如果同時在多個action中修改了同一個state,那會有什么樣的結果?