前言
本文匯總了vue常用知識點與常見面試題,附上本人對該vue知識介紹相關博客,適合收藏,經常回顧,也許每次閱讀都會有進一步理解,
Vue 的優缺點
優點
1、創建單頁面應用的輕量級Web應用框架
2、簡單易用
3、雙向資料系結
4、組件化的思想
5、虛擬DOM
6、資料驅動視圖
7、前后端分離
缺點
1、Vue在開發多頁應時不夠靈活,需要配置多入口
2、不支持IE8
SPA的理解
SPA是 Single-Page-Application 的縮寫,翻譯過來就是單頁應用,在WEB頁面初始化時一同加載Html、Javascript、Css,一旦頁面加載完成,SPA不會因為用戶操作而進行頁面重新加載或跳轉,取而代之的是利用路由機制實作Html內容的變換,
優點
1、良好的用戶體驗,內容更改無需多載頁面
2、SPA相對服務端壓力更小
3、前后端職責分離,架構清晰
缺點
1、由于前端渲染,搜索引擎不會決議JS,只能抓取首頁未渲染的模板,不利于SEO
2、單頁面應用,在加載頁面的時候將JavaScript、CSS統一加載,所以首次加載耗時更多
3、單頁面應用需在一個頁面顯示所有的內容,默認不支持瀏覽器的前進后退(前端路由機制解決了該窘境,Hash模式中Hash變化會被瀏覽器記錄,History模式利用 H5 新增的pushState和replaceState方法可改變瀏覽器歷史記錄堆疊)
MVVM的理解
MVVM是Model-View-ViewModel的縮寫,Model 代表資料層,可定義修改資料、撰寫業務邏輯,View 代表視圖層,負責將資料渲染成頁面,ViewModel 負責監聽資料層資料變化,控制視圖層行為互動,簡單講,就是同步資料層和視圖層的物件,ViewModel 通過雙向系結把 View 和 Model 層連接起來,且同步作業無需人為干涉,使開發人員只關注業務邏輯,無需頻繁操作DOM,不需關注資料狀態的同步問題,
具體細節參考文章
面試官:你了解MVVM框架嗎?(Vue MVVM詳細介紹,一看就會)_czjl6886的博客-CSDN博客隨著前端的發展,MVVM思想越來越受到大家的歡迎,那么MVVM到底是什么呢?下面,我將簡要介紹MVVM的思想,并從Vue的角度,分析具體代碼中是怎么實作這種思想的,https://blog.csdn.net/czjl6886/article/details/121717212?spm=1001.2014.3001.5502
單向資料流的理解
我們經常說 Vue 的雙向系結,其實是在單向系結的基礎上給元素添加 input/change 事件,來動態修改視圖,Vue 組件間傳遞資料仍然是單項的,即父組件傳遞到子組件,子組件內部可以定義依賴 props 中的值,但無權修改父組件傳遞的資料,這樣做防止子組件意外變更父組件的狀態,導致應用資料流向難以理解,
如果在子組件內部直接更改prop,會遇到警告處理,
以下為2種定義依賴props中的值
1、通過 data 定義屬性并將 prop 作為初始值
<script>
export default {
props: ['userName'],
data() {
return {
name: this.userName
}
}
}
</script>
2、 用 computed 計算屬性去定義依賴 prop 的值
<script>
export default {
props: ['userName'],
computed: {
helloName() {
return "hello" + this.userName
}
}
}
</sciprt>
回應式原理
當你把一個普通的 JavaScript 物件傳入 Vue 實體作為 data 選項,Vue 將遍歷此物件所有的 property,并使用 Object.defineProperty 把這些 property 全部轉為 getter/setter,Object.defineProperty 是 ES5 中一個無法 shim 的特性,這也就是 Vue 不支持 IE8 以及更低版本瀏覽器的原因,
這些 getter/setter 對用戶來說是不可見的,但是在內部它們讓 Vue 能夠追蹤依賴,在 property 被訪問和修改時通知變更,這里需要注意的是不同瀏覽器在控制臺列印資料物件時對 getter/setter 的格式化并不同,所以建議安裝 vue-devtools 來獲取對檢查資料更加友好的用戶界面,
每個組件實體都對應一個 watcher 實體,它會在組件渲染的程序中把“接觸”過的資料 property 記錄為依賴,之后當依賴項的 setter 觸發時,會通知 watcher,從而使它關聯的組件重新渲染,

回應式原理3個步驟:資料劫持、依賴收集、派發更新,
資料分為兩類:物件、陣列
物件
遍歷物件,通過Object.defineProperty為每個屬性添加 getter 和 setter,進行資料劫持,getter 函式用于在資料讀取時進行依賴收集,在對應的 dep 中存盤所有的 watcher;setter 則是資料更新后通知所有的 watcher 進行更新,
核心原始碼
function defineReactive(obj, key, val, shallow) {
// 實體化一個 dep, 一個 key 對應一個 dep
const dep = new Dep()
// 獲取屬性描述符
const getter = property && property.get
const setter = property && property.set
if ((!getter || setter) && arguments.length === 2) {
val = obj[key]
}
// 通過遞回的方式處理 val 為物件的情況,即處理嵌套物件
let childOb = !shallow && observe(val)
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
// 攔截obj.key,進行依賴收集
get: function reactiveGetter () {
const value = getter ? getter.call(obj) : val
// Dep.target 是當前組件渲染的 watcher
if (Dep.target) {
// 將 dep 添加到 watcher 中
dep.depend()
if (childOb) {
// 嵌套物件依賴收集
childOb.dep.depend()
// 回應式處理 value 值為陣列的情況
if (Array.isArray(value)) {
dependArray(value)
}
}
}
return value
},
set: function reactiveSetter (newVal) {
// 獲取舊值
const value = getter ? getter.call(obj) : val
// 判斷新舊值是否一致
if (newVal === value || (newVal !== newVal && value !== value)) {
return
}
if (process.env.NODE_ENV !== 'production' && customSetter) {
customSetter()
}
if (getter && !setter) return
// 如果是新值,用新值替換舊值
if (setter) {
setter.call(obj, newVal)
} else {
val = newVal
}
// 新值做回應式處理
childOb = !shallow && observe(newVal)
// 當回應式資料更新,依賴通知更新
dep.notify()
}
})
}
陣列
用陣列增強的方式,覆寫原屬性上默認的陣列方法,保證在新增或洗掉資料時,通過 dep 通知所有的 watcher 進行更新,
核心原始碼
const arrayProto = Array.prototype
// 基于陣列原型物件創建一個新的物件
export const arrayMethods = Object.create(arrayProto)
const methodsToPatch = [
'push',
'pop',
'shift',
'unshift',
'splice',
'sort',
'reverse'
]
methodsToPatch.forEach(function (method) {
const original = arrayProto[method]
// 分別在 arrayMethods 物件上定義7個方法
def(arrayMethods, method, function mutator (...args) {
// 先執行原生的方法
const result = original.apply(this, args)
const ob = this.__ob__
let inserted
switch (method) {
case 'push':
case 'unshift':
inserted = args
break
case 'splice':
inserted = args.slice(2)
break
}
// 針對新增元素進行回應式處理
if (inserted) ob.observeArray(inserted)
// 資料無論是新增還是洗掉都進行派發更新
ob.dep.notify()
return result
})
})
手寫觀察者模式
let uid = 0
class Dep {
constructor() {
this.id = uid++
// 存盤所有的 watcher
this.subs = []
}
addSub(sub) {
this.subs.push(sub)
}
removeSub(sub) {
if(this.subs.length) {
const index = this.subs.indexOf(sub)
if(index > -1) return this.subs.splice(index, 1)
}
}
notify() {
this.subs.forEach(sub => {
sub.update()
})
}
}
class Watcher {
constructor(name) {
this.name = name
}
update() {
console.log('更新')
}
}
手寫發布訂閱模式
與觀察者模式相似,區別在于發布者和訂閱者是解耦的,由中間的調度中心去與發布者和訂閱者通信,Vue回應式原理個人更傾向于發布訂閱模式,其中 Observer 是發布者,Watcher 是訂閱者,Dep 是調度中心,
class EventEmitter {
constructor() {
this.events = {}
}
on(type, cb) {
if(!this.events[type]) this.events[type] = []
this.events[type].push(cb)
}
emit(type, ...args) {
if(this.events[type]) {
this.events[type].forEach(cb => {
cb(...args)
})
}
}
off(type, cb) {
if(this.events[type]) {
const index = this.events[type].indexOf(cb)
if(index > -1) this.events[type].splice(index, 1)
}
}
}
組件中的data為什么是一個函式
資料以函式回傳值形式定義,當每復用一次組件,就會回傳一份新的data,即給每個組件實體創建一個私有的資料空間,讓各個組件實體維護各自的資料,物件在堆疊中存盤的都是地址,函式的作用就是屬性私有化,保證組件修改自身屬性時不會影響其他復用組件,
生命周期
| 生命周期 | 描述 |
|---|---|
| beforeCreate | vue實體初始化后,資料觀測(data observer)和事件配置之前,data、computed、watch、methods都無法訪問, |
| created | vue實體創建完成后立即呼叫 ,可訪問 data、computed、watch、methods,未掛載 DOM,不能訪問 、ref, |
| beforeMount | 在 DOM 掛載開始之前呼叫, |
| mounted | vue實體被掛載到 DOM, |
| beforeUpdate | 資料更新之前呼叫,發生在虛擬 DOM 打補丁之前, |
| updated | 資料更新之后呼叫, |
| beforeDestroy | 實體銷毀前呼叫, |
| destroyed | 實體銷毀后呼叫 , |
呼叫異步請求可在created、beforeMount、mounted生命周期中呼叫,因為相關資料都已創建,在不涉及到DOM操作時,最好的選擇是在created中呼叫,
具體細節參考文章
Vue 生命周期 詳細介紹(面試必考,內附實體截圖)_前端不釋卷leo的博客-CSDN博客Vue的生命周期是不僅是面試必考點,理解它更能為我們在Vue專案開發帶來促進作用,什么是Vue的生命周期?每個 Vue 實體在被創建時都要經過一系列的初始化程序——例如,需要設定資料監聽、編譯模板、將實體掛載到 DOM 并在資料變化時更新 DOM 等,同時在這個程序中也會運行一些叫做生命周期鉤子的函式,這給了用戶在不同階段添加自己的代碼的機會,簡單理解就是Vue實體從創建到銷毀的這么一個程序,如圖(官網)所示:Vue生命周期函式(鉤子)執行順序從上圖可知主要為八大生命周期鉤子:beforhttps://blog.csdn.net/qq_41809113/article/details/121684566?spm=1001.2014.3001.5502
父組件與子組件生命周期鉤子執行順序
加載渲染程序
速記:父先創建,才能有子;子創建完成,父才完整,
順序:父 beforeCreate -> 父 created -> 父 beforeMount -> 子 beforeCreate -> 子 created -> 子 beforeMount -> 子 mounted -> 父 mounted
組件更新程序
順序:父 beforeUpdate -> 子 beforeUpdate -> 子 updated -> 父 updated
銷毀程序
順序:父 beforeDestroy -> 子 beforeDestroy -> 子 destroyed -> 父 destroyed
父組件監聽子組件生命周期鉤子的方式
以mounted為例
1、$emit
// 父組件
<template>
<div class="parent">
<!-- 監聽子組件mounted事件 -->
<Child @mounted="doSomething"/>
</div>
</template>
<script>
export default {
methods: {
doSomething() {
console.log('父組件監聽到子組件 mounted 鉤子函式')
}
}
}
</script>
//子組件
<template>
<div>
</div>
</template>
<script>
export default {
mounted() {
console.log('觸發mounted事件...')
this.$emit("mounted")
}
}
</script>
2、@hook
// 父組件
<template>
<div class="parent">
<Child @hook:mounted="doSomething"/>
</div>
</template>
<script>
export default {
methods: {
doSomething() {
console.log('父組件監聽到子組件 mounted 鉤子函式')
}
}
}
</script>
//子組件
<template>
<div>
</div>
</template>
<script>
export default {
mounted() {
console.log('觸發mounted事件...')
}
}
</script>
組件通信方式
父子組件
1、props、$emit
2、$parent、$children
跨級組件
1、$attrs、$listeners
2、provide、inject
父子、跨級、兄弟
1、EventBus(事件總線)
2、Vuex(狀態管理)
擴展
1、快取
2、路由
具體細節參考文章
Vue組件間的通信方式(多種場景,通俗易懂,建議收藏)_前端不釋卷leo的博客-CSDN博客_vue組件間通信以下是我在作業中用到過的vue組件之間的通信方式,不同的場景使用不同的方式,基本滿足所有開發場景中的通信需求,話不多說直接開始,滿滿的干貨,建議收藏,1、父子組件之間的通信父 >>> 子 (Props)一個組件里面引入另外一個組件,此時構成了一種“父子關系”,當前組件為“父”,引入的組件為“子”,如當前組件(父),在父組件中通過 “:message” 向子組件通信,<template> <div class="paren...https://blog.csdn.net/qq_41809113/article/details/120384336?spm=1001.2014.3001.5502
v-on監聽多個方法
<button v-on="{mouseenter: onEnter, mouseleave: onLeave}">滑鼠進來1</button>
常用修飾符
表單修飾符
1、lazy::失去焦點后同步資訊
2、trim:自動過濾首尾空格
3、number:輸入值轉為數值型別
事件修飾符
1、stop:阻止冒泡(js中stopPropagation)
2、prevent:阻止默認行為(js中preventDefault)
3、self:僅系結元素自身觸發
4、once:只觸發一次
class、style的動態系結方式
物件方式
<template>
<div :class="{ active: isActive }"></div>
<div :style="{ fontSize: fontSize }">
</template>
<script>
export default {
data() {
return {
isActive: true, //如果為false,則不系結"active"類
fontSize: 30
}
}
}
</script>
陣列方式
<template>
<div :class="[activeClass]"></div>
<div :style="[styleFontSize]">
</template>
<script>
export default {
data() {
return {
activeClass: 'active',
styleFontSize: {
fontSize: '30px'
}
}
}
}
</script>
v-show與v-if的區別
相同點
都是控制頁面元素的顯示與隱藏
不同點
1、v-show 控制的是元素的CSS(v-show="false"相當于display:none);v-if 是控制元素本身的添加或洗掉(即是否出現在DOM結構中)
2、v-show 由 false 變為 true 的時候不會觸發組件的生命周期,v-if 由 false 變為 true 則會觸發組件的beforeCreate、create、beforeMount、mounted鉤子,由 true 變為 false 會觸發組件的beforeDestory、destoryed方法
3、頻繁切換時,使用v-show;不頻繁切換、加快頁面渲染、需要銷毀元素使用v-if
為什么v-if不能和v-for一起使用
性能浪費,每次渲染都要先回圈再進行條件判斷,考慮用計算屬性替代,
Vue2.x中v-for比v-if更高的優先級,
Vue3.x中v-if 比 v-for 更高的優先級,
computed與watch的區別與使用場景
computed
計算屬性,依賴其他屬性值,且值具備快取的特性,只有它依賴的屬性值發生改變,下一次獲取的值才會重新計算,
適用于數值計算,并且依賴于其他屬性時,因為可以利用快取特性,避免每次獲取值,都需要重新計算,
watch
觀察屬性,監聽屬性值變動,每當屬性值發生變化,都會執行相應的回呼,
適用于資料變化時執行異步或開銷比較大的操作,
具體細節參考文章
上手Vue:深度理解computed、watch及其區別_czjl6886的博客-CSDN博客_vue中computed和watch的區別computed(計算屬性)與watch(偵聽器),是Vue中常用的屬性,那么什么時候該如何computed,什么時候該使用watch呢?https://blog.csdn.net/czjl6886/article/details/121454266?spm=1001.2014.3001.5502
slot插槽的理解與使用
slot 插槽,可以理解為slot在組件模板中提前占據了位置,當復用組件時,使用相關的slot標簽時,標簽里的內容就會自動替換組件模板中對應slot標簽的位置,作為承載分發內容的出口,
具體細節參考文章
Vue 插槽(slot)詳細介紹(對比版本變化,避免踩坑)_前端不釋卷leo的博客-CSDN博客Vue中的插槽(slot)在專案中用的也是比較多的,今天就來介紹一下插槽的基本使用以及Vue版本更新之后的插槽用法變化,插槽是什么?插槽就是子組件中的提供給父組件使用的一個占位符,用<slot></slot> 表示,父組件可以在這個占位符中填充任何模板代碼,如 HTML、組件等,填充的內容會替換子組件的<slot></slot>標簽,簡單理解就是子組件中留下個“坑”,父組件可以使用指定內容來補“坑”,以下舉例子幫助理解,怎么使用插槽?基本用法https://blog.csdn.net/qq_41809113/article/details/121640035?spm=1001.2014.3001.5502
Vue.$delete和delete的區別
Vue.$delete 是直接洗掉了元素,改變了陣列的長度;delete 是將被洗掉的元素變成內 undefined ,其他元素鍵值不變,
Vue.$set如何解決物件新增屬性不能回應的問題
Vue.$set的出現是由于Object.defineProperty的局限性:無法檢測物件屬性的新增或洗掉,
原始碼位置:vue/src/core/observer/index.js
export function set(target, key, val) {
// 陣列
if(Array.isArray(target) && isValidArrayIndex(key)) {
// 修改陣列長度,避免索引大于陣列長度導致splice錯誤
target.length = Math.max(target.length, key)
// 利用陣列splice觸發回應
target.splice(key, 1, val)
return val
}
// key 已經存在,直接修改屬性值
if(key in target && !(key in Object.prototype)) {
target[key] = val
return val
}
const ob = target.__ob__
// target 不是回應式資料,直接賦值
if(!ob) {
target[key] = val
return val
}
// 回應式處理屬性
defineReactive(ob.value, key, val)
// 派發更新
ob.dep.notify()
return val
}
具體原理
1、若是陣列,直接使用陣列的 splice 方法觸發回應式
2、若是物件,判斷屬性是否存在,物件是否是回應式
3、以上都不滿足,最后通過 defineReactive 對屬性進行回應式處理
具體細節參考文章
Vue 全域API 詳細介紹(nextTick、set、delete、......)_前端不釋卷leo的博客-CSDN博客Tips:Vue全域(內置)API,在實體中對應使用方式this.$apiName,Vue.extend(options)使用基礎 Vue 構造器,創建一個“子類”,引數是一個包含組件選項的物件,data選項是特例,需要注意 - 在Vue.extend()中它必須是函式,// 創建構造器var Greet = Vue.extend({ template: '<p>{{firstName}} {{lastName}} say {{alias}}</p>',...https://blog.csdn.net/qq_41809113/article/details/121581605?spm=1001.2014.3001.5502
Vue.$nextTick的原理
nextTick:在下次 DOM 更新回圈結束之后執行延遲回呼,常用于修改資料后獲取更新后的DOM,
原始碼位置:vue/src/core/util/next-tick.js
import { noop } from 'shared/util'
import { handleError } from './error'
import { isIE, isIOS, isNative } from './env'
// 是否使用微任務標識
export let isUsingMicroTask = false
// 回呼函式佇列
const callbacks = []
// 異步鎖
let pending = false
function flushCallbacks () {
// 表示下一個 flushCallbacks 可以進入瀏覽器的任務佇列了
pending = false
// 防止 nextTick 中包含 nextTick時出現問題,在執行回呼函式佇列前,提前復制備份,清慷訓呼函式佇列
const copies = callbacks.slice(0)
// 清空 callbacks 陣列
callbacks.length = 0
for (let i = 0; i < copies.length; i++) {
copies[i]()
}
}
let timerFunc
// 瀏覽器能力檢測
// 使用宏任務或微任務的目的是宏任務和微任務必在同步代碼結束之后執行,這時能保證是最終渲染好的DOM,
// 宏任務耗費時間是大于微任務,在瀏覽器支持的情況下,優先使用微任務,
// 宏任務中效率也有差距,最低的就是 setTimeout
if (typeof Promise !== 'undefined' && isNative(Promise)) {
const p = Promise.resolve()
timerFunc = () => {
p.then(flushCallbacks)
if (isIOS) setTimeout(noop)
}
isUsingMicroTask = true
} else if (!isIE && typeof MutationObserver !== 'undefined' && (
isNative(MutationObserver) ||
MutationObserver.toString() === '[object MutationObserverConstructor]'
)) {
let counter = 1
const observer = new MutationObserver(flushCallbacks)
const textNode = document.createTextNode(String(counter))
observer.observe(textNode, {
characterData: true
})
timerFunc = () => {
counter = (counter + 1) % 2
textNode.data = String(counter)
}
isUsingMicroTask = true
} else if (typeof setImmediate !== 'undefined' && isNative(setImmediate)) {
timerFunc = () => {
setImmediate(flushCallbacks)
}
} else {
timerFunc = () => {
setTimeout(flushCallbacks, 0)
}
}
export function nextTick (cb?: Function, ctx?: Object) {
let _resolve
// 將 nextTick 的回呼函式用 try catch 包裹一層,用于例外捕獲
// 將包裹后的函式放到 callback 中
callbacks.push(() => {
if (cb) {
try {
cb.call(ctx)
} catch (e) {
handleError(e, ctx, 'nextTick')
}
} else if (_resolve) {
_resolve(ctx)
}
})
// pengding 為 false, 執行 timerFunc
if (!pending) {
// 關上鎖
pending = true
timerFunc()
}
if (!cb && typeof Promise !== 'undefined') {
return new Promise(resolve => {
_resolve = resolve
})
}
}
總結:
1、運用異步鎖的概念,保證同一時刻任務佇列中只有一個 flushCallbacks,當 pengding 為 false 的時候,表示瀏覽器任務佇列中沒有 flushCallbacks 函式;當 pengding 為 true 的時候,表示瀏覽器任務佇列中已經放入 flushCallbacks;待執行 flushCallback 函式時,pengding 會被再次置為 false,表示下一個 flushCallbacks 可進入任務佇列
2、環境能力檢測,選擇可選中效率最高的(宏任務/微任務)進行包裝執行,保證是在同步代碼都執行完成后再去執行修改 DOM 等操作
3、flushCallbacks 先拷貝再清空,為了防止nextTick嵌套nextTick導致回圈不結束
具體細節參考如上文章
虛擬DOM的理解
虛擬 DOM 的出現解決了瀏覽器的性能問題,虛擬 DOM 是一個用 JS 模擬的 DOM 結構物件(Vnode),用于頻繁更改 DOM 操作后不立即更新 DOM,而是對比新老 Vnode,更新獲取最新的Vnode,最后再一次性映射成真實的 DOM,這樣做的原因是操作記憶體中操作 JS 物件速度比操作 DOM 快很多,
舉個例子
<div id="container">
<p>real dom </p>
<ul>
<li class="item">item 1</li>
<li class="item">item 2</li>
<li class="item">item 3</li>
</ul>
</div
用 JS 來模擬以上 DOM 節點實作虛擬 DOM
function Element(tagName, props, children) {
this.tageName = tagName
this.props = props || {}
this.children = children || []
this.key = props.key
let count = 0
this.children.forEach(child => {
if(child instanceof Element) count += child.count
count++
})
this.count = count
}
const tree = Element('div', { id: container }, [
Element('p', {}, ['real dom'])
Element('ul', {}, [
Element('li', { class: 'item' }, ['item1']),
Element('li', { class: 'item' }, ['item2']),
Element('li', { class: 'item' }, ['item3'])
])
])
虛擬 DOM 轉為真實的節點
Element.prototype.render = function() {
let el = document.createElement(this.tagName)
let props = this.props
for(let key in props) {
el.setAttribute(key, props[key])
}
let children = this.children || []
children.forEach(child => {
let child = (child instanceof Element) ? child.render() : document.createTextNode(child)
el.appendChild(child)
})
return el
}
Diff演算法原理
具體細節參考文章
Vue中的Diff演算法_Hayden-CSDN博客_diff演算法Vue中的Diff演算法本篇文章主要介紹Diff演算法的思想和Vue中對Diff演算法的基本實作,1. 為什么要用Diff演算法由于在瀏覽器中操作DOM的代價是非常“昂貴”的,所以才在Vue引入了Virtual DOM,Virtual DOM是對真實DOM的一種抽象描述,不懂的朋友可以自行查閱相關資料,即使使用了Virtual DOM來進行真實DOM的渲染,在頁面更新的時候,也不能全量地將整顆Vi...https://blog.csdn.net/qq_34179086/article/details/88086427?ops_request_misc=&request_id=&biz_id=102&utm_term=vue%20diff%E5%8E%9F%E7%90%86&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-8-88086427.pc_search_mgc_flag&spm=1018.2226.3001.4187
key的作用
key 是 Vue 中 vnode 的唯一標記,我們的 diff 的演算法中 sameVnode 和 updateChildren 中就使用到了 key,
sameVnode 用來判斷是否為同一節點,常見的業務場景是一個串列,若 key 值是串列索引,在新增或洗掉的情況下會存在就地復用的問題,(簡單說,復用了上一個在當前位置元素的狀態)所以 key 值的唯一,確保 diff 更準確,
updateChildren 中當其中四種假設都未匹配,就需要依賴老節點的 key 和 索引創建關系映射表,再用新節點的 key 去關系映射表去尋找索引進行更新,這保證 diff 演算法更加快速,
簡單來說就是:根據key判斷是否復用,實作高效渲染
動態組件 和 異步組件
動態組件通過is特性實作,適用于根據資料、動態渲染的場景,即組件型別不確定,
具體細節參考官網
動態組件 & 異步組件 — Vue.jsVue.js - The Progressive JavaScript Framework
https://cn.vuejs.org/v2/guide/components-dynamic-async.html
Vue.directive 有寫過么,有哪些應用場景
Vue.directive 可以注冊全域指令和區域指令,
指令定義函式提供如下鉤子函式
1、bind:指令第一次系結到元素時呼叫(只呼叫一次)
2、inserted: 被系結元素插入父節點時使用(父節點存在即可呼叫)
3、update:被系結元素所在模板更新時呼叫,不論系結值是否變化,通過比較更新前后的系結值
4、 componentUpdated: 被系結元素所在模板完成一次更新周期時呼叫
5、unbind: 只呼叫一次,指令與元素解綁時呼叫
具體細節參考官網
自定義指令 — Vue.jsVue.js - The Progressive JavaScript Framework
https://cn.vuejs.org/v2/guide/custom-directive.html
Vue 過濾器
Vue 過濾器可用在兩個地方:雙花括號插值和 v-bind 運算式,
Vue3 中已經廢棄這個特點,
過濾器分為 全域過濾器 和 區域過濾器,
區域過濾器
<template>
<div>{{ name | formatName }}</div>
</template>
<script>
export default {
// 區域過濾器
filters: {
formatName: function(value) {
// 可基于源值做一些處理
return value
}
}
}
</script>
全域過濾器
Vue.filter('formatName', function(value) {
// 可基于源值做一些處理
return value
})
過濾器可串聯,執行順序從左到右,第二個過濾器輸入值是第一個過濾器的輸出值
<div>{{ name | formatName1 | formatName2 }}</div>
關于mixin的理解,有什么應用場景
mixin 混入分全域混入和區域混入,本質是 JS 物件,如 data、components、computed、methods 等,
全域混入不推薦使用,會影響后續每個Vue實體的創建,區域混入可提取組件間相同的代碼,進行邏輯復用,
適用場景:如多個頁面具備相同的懸浮定位浮窗,可嘗試用 mixin 封裝,
具體細節參考文章
Vue 混入(mixin)詳細介紹(可復用性、全域混入)_前端不釋卷leo的博客-CSDN博客基礎混入(mixin)提供了一種非常靈活的方式,來分發 Vue 組件中的可復用功能,一個混入物件可以包含任意組件選項(如data、methods、mounted等等),當組件使用混入物件時,所有混入物件的選項將被“混合”進入該組件本身的選項,基本使用1、定義一個混入(mixin)let mixin = { created() { console.log("我是mixin里面的created!") }, methods: { hello() { .https://blog.csdn.net/qq_41809113/article/details/121912330?spm=1001.2014.3001.5502
介紹一下keep-alive
具體細節參考文章
Vue keep-alive 詳細介紹(動態組件、路由組件快取優化)_前端不釋卷leo的博客-CSDN博客用法keep-alive 是Vue的內置組件,當它包裹動態組件時,會快取不活動的組件實體,而不是銷毀它們,和 transition 相似,keep-alive 是一個抽象組件:它自身不會渲染成一個 DOM 元素,也不會出現在父組件鏈中,當組件在<keep-alive>內被切換,它的activated和deactivated這兩個生命周期鉤子函式將會被對應執行,在 2.2.0 及其更高版本中,activated和deactivated將會在<keep-ali...https://blog.csdn.net/qq_41809113/article/details/121959533?spm=1001.2014.3001.5502
Vue-Router 配置 404 頁面
* 代表通配符,若放在任意路由前,會被先匹配,導致跳轉到 404 頁面,所以需將如下配置置于最后,
{
path: '*',
name: '404'
component: () => import('./404.vue')
}
Vue-Router 有哪幾種導航守衛
全域路由守衛
在路由跳轉前觸發,可在執行 next 方法前做一些身份登錄驗證的邏輯
const router = new VueRouter({
// 相關配置
})
// 全域路由守衛(跳轉每個路由頁面前統一處理)
router.beforeEach((to, from, next) => {
...
// 必須執行 next 方法來觸發路由跳轉
next()
})
全域后置鉤子
和守衛不同的是,這些鉤子不會接受 next 函式也不會改變導航本身
// 全域后置鉤子(跳轉每個路由頁面后統一處理)
router.afterEach((to, from) => {
// ...
})
路由獨享守衛
可在路由配置上直接定義 beforeEnter
const router = new VueRouter({
routes: [
{
path: '/home',
component: Home,
// 只有該路由獨享
beforeEnter: (to, from, next) => {
}
},
{
path: '/about',
component: About
}
]
})
組件守衛
組件內可直接定義如下路由導航守衛
onst Foo = {
template: `...`,
beforeRouteEnter(to, from, next) {
// 不能獲取組件實體 this
// 當守衛執行前,組件實體還沒被創建
},
beforeRouteUpdate(to, from, next) {
// 當前路由改變,但是組件被復用時呼叫
// 可訪問實體 this
},
beforeRouteLeave(to, from, next) {
// 導航離開組件時被呼叫
}
}
更多細節參考官網
API 參考 | Vue Router
https://router.vuejs.org/zh/api/#router-link
Vue-Router 完整的導航決議流程
1、導航被觸發
2、在失活的組件里呼叫 beforeRouteLeave 守衛
3、呼叫全域 beforeEach 前置守衛
4、重用的組件呼叫 beforeRouteUpdate 守衛(2.2+)
5、路由配置呼叫 beforeEnter
6、決議異步路由組件
7、在被激活的組件里呼叫 beforeRouteEnter 守衛
8、呼叫全域的 beforeResolve 守衛(2.5+)
9、導航被確認
10、呼叫全域的 afterEach
11、觸發 DOM 更新
12、呼叫 beforeRouteEnter 守衛中傳給 next 的回呼函式,創建好的組件實體會作為回呼函式的引數傳入
推薦本人對Vue router的詳細介紹博客
Vue 路由(Router)詳細介紹(切換,傳參,通信······)_前端不釋卷leo的博客-CSDN博客前言:在一個vue專案中,免不了對組件(頁面)進行切換與跳轉,而用 Vue.js + Vue Router 創建單頁應用,感覺很自然:使用 Vue.js ,我們已經可以通過組合組件來組成應用程式,當你要把 Vue Router 添加進來,我們需要做的是,將組件 (components) 映射到路由 (routes),然后告訴 Vue Router 在哪里渲染它們,話不多說,直接開始!!!準備作業在使用腳手架vue-cli3創建(vue create projectName)一個vue專案時,https://blog.csdn.net/qq_41809113/article/details/121841075?spm=1001.2014.3001.5502
Vuex 的理解及使用
Vuex 是一個專為 Vue.js 應用程式開發的狀態管理模式,采用集中式存盤管理應用的所有組件的狀態,
主要解決如下 兩個 問題
1、多個視圖依賴同一狀態,
2、來自不同視圖的行為需要變更同一個狀態,
其包含如下模塊

State:定義并初始化全域狀態,
Getter:依賴 State 中的狀態,進行二次包裝,不會影響 State 源資料,
Mutation:更改 State 狀態的函式,必須是同步,
Action:用于提交 Mutation,可包含任意異步操作,
Module:若應用復雜,Store 會集中一個比較大的物件而顯得臃腫,Module允許我們將 Store模塊化管理,
當然,若應用比較簡單,共享狀態也比較少,可以用 Vue.observe 去替代 Vuex,省去安裝一個庫也挺好,
具體細節參考文章
Vuex核心用法,一學就會!(中秋特輯,快來get你的月餅啦)_前端不釋卷leo的博客-CSDN博客今天是中秋佳節,祝各位大佬中秋節快樂!來get自己的月餅吧,趁著這個美好的節日,懷著美麗的心情,建造自己的“工廠”,我將以個人理解,用“月餅工廠”,模擬vuex的精簡用法,嘻嘻嘻......話不多說,直接“造”(燥)起來,...https://blog.csdn.net/qq_41809113/article/details/120398625?spm=1001.2014.3001.5502
Vuex 重繪后資料丟失怎么辦
持久化快取:localStorage、sessionStorage
Vuex 如何知道 State 是通過 Mutation 修改還是外部修改
Vuex 中修改 state 唯一渠道是執行 commit 方法,底層通過執行 this._withCommit(fn),且設定_committing識別符號為 true,才能修改 state,修改完還需要將識別符號置為 false,外部修改是無法設定標識位的,所以通過 watch 監聽 state 變化,來判斷修改的合法性,
Vue SSR 了解么
Vue SSR 專案中暫時還沒有運用過,后續會寫個 Demo 單獨成文吧,這邊搬運下其他答案,
SSR 服務端渲染,將 HTML 渲染作業放在服務端完成后,將 HTML 回傳到瀏覽器端,
優點:SSR有更好的 SEO,首屏加載更快,
缺點:服務端負載大,
如果是內部系統,SSR其實沒有太多必要,如果是對外的專案,維護高可用的node服務器是個難點,
Vue2 與 Vue3 的區別 ?Vue3有哪些優化點?
具體細節參考本人博客對Vue3的詳細介紹
Vue 性能優化
1、非回應式資料通過 Object.freeze 凍結資料
2、嵌套層級不要過深
3、computed 和 watch 區別使用
4、v-if 和 v-show 區別使用
5、v-for 避免和 v-if 一起使用,且系結 key 值要唯一
6、串列資料過多采用分頁或者虛擬串列
7、組件銷毀后清除定時器和事件
8、圖片懶加載
9、路由懶加載
10、防抖、節流
11、按需引入外部庫
12、keep-alive快取使用
13、服務端渲染(SSR)和預渲染
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/393957.html
標籤:其他
上一篇:C/S和B/S架構介紹
下一篇:必背-13.小程式
