無(wú)Vue最全知識(shí)點(diǎn),面試必備(基礎(chǔ)到進(jìn)階怯邪,覆蓋vue3.0绊寻,持續(xù)更新整理,歡迎補(bǔ)充討論)標(biāo)題文章

基礎(chǔ)篇

說(shuō)說(shuō)你對(duì)MVVM的理解

Model-View-ViewModel的縮寫(xiě)擎颖,Model代表數(shù)據(jù)模型榛斯,View代表UI組件,ViewModel將Model和View關(guān)聯(lián)起來(lái)

數(shù)據(jù)會(huì)綁定到viewModel層并自動(dòng)將數(shù)據(jù)渲染到頁(yè)面中,視圖變化的時(shí)候會(huì)通知viewModel層更新數(shù)據(jù)

了解mvc/mvp/mvvm的區(qū)別

Vue2.x響應(yīng)式數(shù)據(jù)/雙向綁定原理

Vue 數(shù)據(jù)雙向綁定主要是指:數(shù)據(jù)變化更新視圖搂捧,視圖變化更新數(shù)據(jù)驮俗。其中,View變化更新Data允跑,可以w通過(guò)事件監(jiān)聽(tīng)的方式來(lái)實(shí)現(xiàn)王凑,所以 Vue數(shù)據(jù)雙向綁定的工作主要是如何根據(jù)Data變化更新View搪柑。

簡(jiǎn)述

當(dāng)你把一個(gè)普通的 JavaScript 對(duì)象傳入 Vue 實(shí)例作為 data 選項(xiàng),Vue 將遍歷此對(duì)象所有的 property索烹,并使用 Object.defineProperty 把這些 property 全部轉(zhuǎn)為 getter/setter工碾。

這些 getter/setter 對(duì)用戶來(lái)說(shuō)是不可見(jiàn)的,但是在內(nèi)部它們讓 Vue 能夠追蹤依賴百姓,在 property 被訪問(wèn)和修改時(shí)通知變更渊额。

每個(gè)組件實(shí)例都對(duì)應(yīng)一個(gè) watcher 實(shí)例,它會(huì)在組件渲染的過(guò)程中把“接觸”過(guò)的數(shù)據(jù) property 記錄為依賴垒拢。之后當(dāng)依賴項(xiàng)的 setter 觸發(fā)時(shí)旬迹,會(huì)通知 watcher,從而使它關(guān)聯(lián)的組件重新渲染求类。


深入理解:

監(jiān)聽(tīng)器 Observer:對(duì)數(shù)據(jù)對(duì)象進(jìn)行遍歷奔垦,包括子屬性對(duì)象的屬性,利用 Object.defineProperty() 對(duì)屬性都加上 setter 和 getter尸疆。這樣的話椿猎,給這個(gè)對(duì)象的某個(gè)值賦值,就會(huì)觸發(fā) setter寿弱,那么就能監(jiān)聽(tīng)到了數(shù)據(jù)變化犯眠。

解析器 Compile:解析 Vue 模板指令,將模板中的變量都替換成數(shù)據(jù)脖捻,然后初始化渲染頁(yè)面視圖阔逼,并將每個(gè)指令對(duì)應(yīng)的節(jié)點(diǎn)綁定更新函數(shù),添加監(jiān)聽(tīng)數(shù)據(jù)的訂閱者地沮,一旦數(shù)據(jù)有變動(dòng)嗜浮,收到通知,調(diào)用更新函數(shù)進(jìn)行數(shù)據(jù)更新摩疑。

訂閱者 Watcher:Watcher 訂閱者是 Observer 和 Compile 之間通信的橋梁 危融,主要的任務(wù)是訂閱 Observer 中的屬性值變化的消息,當(dāng)收到屬性值變化的消息時(shí)雷袋,觸發(fā)解析器 Compile 中對(duì)應(yīng)的更新函數(shù)吉殃。每個(gè)組件實(shí)例都有相應(yīng)的 watcher 實(shí)例對(duì)象,它會(huì)在組件渲染的過(guò)程中把屬性記錄為依賴楷怒,之后當(dāng)依賴項(xiàng)的 setter 被調(diào)用時(shí)蛋勺,會(huì)通知 watcher 重新計(jì)算,從而致使它關(guān)聯(lián)的組件得以更新——這是一個(gè)典型的觀察者模式

訂閱器 Dep:訂閱器采用 發(fā)布-訂閱 設(shè)計(jì)模式鸠删,用來(lái)收集訂閱者 Watcher抱完,對(duì)監(jiān)聽(tīng)器 Observer 和 訂閱者 Watcher 進(jìn)行統(tǒng)一管理。

你知道Vue3.x響應(yīng)式數(shù)據(jù)原理嗎刃泡?

Vue3.x改用Proxy替代Object.defineProperty巧娱。

因?yàn)镻roxy可以直接監(jiān)聽(tīng)對(duì)象和數(shù)組的變化碉怔,并且有多達(dá)13種攔截方法。并且作為新標(biāo)準(zhǔn)將受到瀏覽器廠商重點(diǎn)持續(xù)的性能優(yōu)化禁添。

Proxy只會(huì)代理對(duì)象的第一層撮胧,Vue3是怎樣處理這個(gè)問(wèn)題的呢?

判斷當(dāng)前Reflect.get的返回值是否為Object老翘,如果是則再通過(guò)reactive方法做代理芹啥, 這樣就實(shí)現(xiàn)了深度觀測(cè)。

監(jiān)測(cè)數(shù)組的時(shí)候可能觸發(fā)多次get/set酪捡,那么如何防止觸發(fā)多次呢叁征?我們可以判斷key是否為當(dāng)前被代理對(duì)象target自身屬性纳账,也可以判斷舊值與新值是否相等逛薇,只有滿足以上兩個(gè)條件之一時(shí),才有可能執(zhí)行trigger疏虫。

Proxy 與 Object.defineProperty 優(yōu)劣對(duì)比

Proxy 的優(yōu)勢(shì)如下:

Proxy 可以直接監(jiān)聽(tīng)對(duì)象而非屬性永罚;

Proxy 可以直接監(jiān)聽(tīng)數(shù)組的變化;

Proxy 有多達(dá) 13 種攔截方法,不限于 apply卧秘、ownKeys呢袱、deleteProperty、has 等等是 Object.defineProperty 不具備的翅敌;

Proxy 返回的是一個(gè)新對(duì)象,我們可以只操作新的對(duì)象達(dá)到目的,而 Object.defineProperty 只能遍歷對(duì)象屬性直接修改羞福;

Proxy 作為新標(biāo)準(zhǔn)將受到瀏覽器廠商重點(diǎn)持續(xù)的性能優(yōu)化,也就是傳說(shuō)中的新標(biāo)準(zhǔn)的性能紅利蚯涮;

Object.defineProperty 的優(yōu)勢(shì)如下:

兼容性好治专,支持 IE9,而 Proxy 的存在瀏覽器兼容性問(wèn)題,而且無(wú)法用 polyfill 磨平遭顶,因此 Vue 的作者才聲明需要等到下個(gè)大版本( 3.0 )才能用 Proxy 重寫(xiě)张峰。

VUEX篇

Vuex 是什么?

運(yùn)用到了js設(shè)計(jì)模式中的單例模式棒旗,單例模式想要做到的是喘批,不管我們嘗試去創(chuàng)建多少次,它都只給你返回第一次所創(chuàng)建的那唯一的一個(gè)實(shí)例铣揉。

Vuex 是一個(gè)專為 Vue.js 應(yīng)用程序開(kāi)發(fā)的狀態(tài)管理模式饶深。每一個(gè) Vuex 應(yīng)用的核心就是 store(倉(cāng)庫(kù))」涔埃“store” 基本上就是一個(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)的變化嗡官。

Vuex 使用單一狀態(tài)樹(shù),用一個(gè)對(duì)象就包含了全部的應(yīng)用層級(jí)狀態(tài)毯焕。至此它便作為一個(gè)“唯一數(shù)據(jù)源 (SSOT)”而存在衍腥。這也意味著,每個(gè)應(yīng)用將僅僅包含一個(gè) store 實(shí)例纳猫。單一狀態(tài)樹(shù)讓我們能夠直接地定位任一特定的狀態(tài)片段婆咸,在調(diào)試的過(guò)程中也能輕易地取得整個(gè)當(dāng)前應(yīng)用狀態(tài)的快照∥咴——Vuex官方文檔

主要包括以下幾個(gè)模塊:

State:定義了應(yīng)用狀態(tài)的數(shù)據(jù)結(jié)構(gòu)尚骄,可以在這里設(shè)置默認(rèn)的初始狀態(tài)。

Getter:允許組件從 Store 中獲取數(shù)據(jù)侵续,mapGetters 輔助函數(shù)僅僅是將 store 中的 getter 映射到局部計(jì)算屬性倔丈。

Mutation:是唯一更改 store 中狀態(tài)的方法,且必須是同步函數(shù)状蜗。

Action:用于提交 mutation需五,而不是直接變更狀態(tài),可以包含任意異步操作轧坎。

Module:允許將單一的 Store 拆分為多個(gè) store 且同時(shí)保存在單一的狀態(tài)樹(shù)中宏邮。

什么情況下使用 Vuex?

如果應(yīng)用夠簡(jiǎn)單缸血,最好不要使用 Vuex蜜氨,一個(gè)簡(jiǎn)單的 store 模式即可

需要構(gòu)建一個(gè)中大型單頁(yè)應(yīng)用時(shí),使用Vuex能更好地在組件外部管理狀態(tài)

Vuex和單純的全局對(duì)象有什么區(qū)別属百?

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)。改變 store 中的狀態(tài)的唯一途徑就是顯式地提交 (commit) mutation渔呵。這樣使得我們可以方便地跟蹤每一個(gè)狀態(tài)的變化怒竿,從而讓我們能夠?qū)崿F(xiàn)一些工具幫助我們更好地了解我們的應(yīng)用。

為什么 Vuex 的 mutation 中不能做異步操作扩氢?

Vuex中所有的狀態(tài)更新的唯一途徑都是mutation耕驰,異步操作通過(guò) Action 來(lái)提交 mutation實(shí)現(xiàn),這樣使得我們可以方便地跟蹤每一個(gè)狀態(tài)的變化录豺,從而讓我們能夠?qū)崿F(xiàn)一些工具幫助我們更好地了解我們的應(yīng)用朦肘。

每個(gè)mutation執(zhí)行完成后都會(huì)對(duì)應(yīng)到一個(gè)新的狀態(tài)變更饭弓,這樣devtools就可以打個(gè)快照存下來(lái),然后就可以實(shí)現(xiàn) time-travel 了媒抠。如果mutation支持異步操作弟断,就沒(méi)有辦法知道狀態(tài)是何時(shí)更新的,無(wú)法很好的進(jìn)行狀態(tài)的追蹤趴生,給調(diào)試帶來(lái)困難阀趴。

新增:vuex的action有返回值嗎?返回的是什么苍匆?

store.dispatch 可以處理被觸發(fā)的 action 的處理函數(shù)返回的 Promise刘急,并且 store.dispatch 仍舊返回 Promise

Action 通常是異步的,要知道 action 什么時(shí)候結(jié)束或者組合多個(gè) action以處理更加復(fù)雜的異步流程浸踩,可以通過(guò)定義action時(shí)返回一個(gè)promise對(duì)象叔汁,就可以在派發(fā)action的時(shí)候就可以通過(guò)處理返回的 Promise處理異步流程

一個(gè) store.dispatch 在不同模塊中可以觸發(fā)多個(gè) action 函數(shù)。在這種情況下民轴,只有當(dāng)所有觸發(fā)函數(shù)完成后攻柠,返回的 Promise 才會(huì)執(zhí)行。

新增:為什么不直接分發(fā)mutation,而要通過(guò)分發(fā)action之后提交 mutation變更狀態(tài)

mutation 必須同步執(zhí)行后裸,我們可以在 action 內(nèi)部執(zhí)行異步操作

可以進(jìn)行一系列的異步操作,并且通過(guò)提交 mutation 來(lái)記錄 action 產(chǎn)生的副作用(即狀態(tài)變更)

常規(guī)篇

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

computed:是計(jì)算屬性微驶,依賴其它屬性值,并且 computed 的值有緩存开睡,只有它依賴的屬性值發(fā)生改變因苹,下一次獲取 computed 的值時(shí)才會(huì)重新計(jì)算 computed 的值;

watch:沒(mé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ù)操作胁艰;當(dāng)我們需要深度監(jiān)聽(tīng)對(duì)象中的屬性時(shí)款筑,可以打開(kāi)deep:true選項(xiàng),這樣便會(huì)對(duì)對(duì)象中的每一項(xiàng)進(jìn)行監(jiān)聽(tīng)

運(yùn)用場(chǎng)景

當(dāng)我們需要進(jìn)行數(shù)值計(jì)算腾么,并且依賴于其它數(shù)據(jù)時(shí)奈梳,應(yīng)該使用 computed,因?yàn)榭梢岳?computed 的緩存特性解虱,避免每次獲取值時(shí)攘须,都要重新計(jì)算;

當(dāng)我們需要在數(shù)據(jù)變化時(shí)執(zhí)行異步或開(kāi)銷較大的操作時(shí)殴泰,應(yīng)該使用 watch于宙,使用watch選項(xiàng)允許我們執(zhí)行異步操作 ( 訪問(wèn)一個(gè) API )浮驳,限制我們執(zhí)行該操作的頻率,并在我們得到最終結(jié)果前捞魁,設(shè)置中間狀態(tài)抹恳。這些都是計(jì)算屬性無(wú)法做到的。

Vue2.x組件通信有哪些方式署驻?

父子組件通信

事件機(jī)制(**父->子props,子->父?$on奋献、$emit)

獲取父子組件實(shí)例?$parent、$children

Ref 獲取實(shí)例的方式調(diào)用組件的屬性或者方法

Provide旺上、inject (不推薦使用瓶蚂,組件庫(kù)時(shí)很常用)

兄弟組件通信Vue.prototype.$bus?= new Vue

Vuex

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

跨級(jí)組件通信

Vuex

$attrs杭攻、$listeners

Provide、inject

說(shuō)一下v-if和v-show的區(qū)別

當(dāng)條件不成立時(shí)疤坝,v-if不會(huì)渲染DOM元素兆解,v-show操作的是樣式(display),切換當(dāng)前DOM的顯示和隱藏跑揉。

v-if 適用于在運(yùn)行時(shí)很少改變條件锅睛,不需要頻繁切換條件的場(chǎng)景;

v-show 則適用于需要非常頻繁切換條件的場(chǎng)景历谍。

為什么 v-for 和 v-if 不建議用在一起

當(dāng) v-for 和 v-if 處于同一個(gè)節(jié)點(diǎn)時(shí)现拒,v-for 的優(yōu)先級(jí)比 v-if 更高,這意味著 v-if 將分別重復(fù)運(yùn)行于每個(gè) v-for 循環(huán)中望侈。如果要遍歷的數(shù)組很大印蔬,而真正要展示的數(shù)據(jù)很少時(shí),這將造成很大的性能浪費(fèi)

這種場(chǎng)景建議使用 computed脱衙,先對(duì)數(shù)據(jù)進(jìn)行過(guò)濾

組件中的data為什么是一個(gè)函數(shù)侥猬?

一個(gè)組件被復(fù)用多次的話,也就會(huì)創(chuàng)建多個(gè)實(shí)例岂丘。本質(zhì)上陵究,這些實(shí)例用的都是同一個(gè)構(gòu)造函數(shù)。

如果data是對(duì)象的話奥帘,對(duì)象屬于引用類型铜邮,會(huì)影響到所有的實(shí)例。所以為了保證組件不同的實(shí)例之間data不沖突,data必須是一個(gè)函數(shù)松蒜。

子組件為什么不可以修改父組件傳遞的Prop扔茅?/怎么理解vue的單向數(shù)據(jù)流?

Vue提倡單向數(shù)據(jù)流,即父級(jí)props的更新會(huì)流向子組件,但是反過(guò)來(lái)則不行秸苗。

這是為了防止意外的改變父組件狀態(tài)召娜,使得應(yīng)用的數(shù)據(jù)流變得難以理解。

如果破壞了單向數(shù)據(jù)流惊楼,當(dāng)應(yīng)用復(fù)雜時(shí)玖瘸,debug 的成本會(huì)非常高。

v-model是如何實(shí)現(xiàn)雙向綁定的檀咙?

v-model是用來(lái)在表單控件或者組件上創(chuàng)建雙向綁定的

他的本質(zhì)是v-bind和v-on的語(yǔ)法糖

在一個(gè)組件上使用v-model雅倒,默認(rèn)會(huì)為組件綁定名為value的prop和名為input的事件

nextTick的實(shí)現(xiàn)原理是什么?

在下次 DOM 更新循環(huán)結(jié)束之后執(zhí)行延遲回調(diào)弧可,在修改數(shù)據(jù)之后立即使用 nextTick 來(lái)獲取更新后的 DOM蔑匣。

nextTick主要使用了宏任務(wù)微任務(wù)

根據(jù)執(zhí)行環(huán)境分別嘗試采用Promise棕诵、MutationObserver裁良、setImmediate,如果以上都不行則采用setTimeout定義了一個(gè)異步方法校套,多次調(diào)用nextTick會(huì)將方法存入隊(duì)列中价脾,通過(guò)這個(gè)異步方法清空當(dāng)前隊(duì)列。

Vue不能檢測(cè)數(shù)組的哪些變動(dòng)搔确?Vue 怎么用?vm.$set()?解決對(duì)象新增屬性不能響應(yīng)的問(wèn)題 彼棍?

Vue 不能檢測(cè)以下數(shù)組的變動(dòng):

第一類問(wèn)題

// 法一:Vue.set

Vue.set(vm.items, indexOfItem, newValue)

// 法二:Array.prototype.splice

vm.items.splice(indexOfItem, 1, newValue)

復(fù)制代碼

第二類問(wèn)題,可使用 splice:

vm.items.splice(newLength)

復(fù)制代碼

當(dāng)你利用索引直接設(shè)置一個(gè)數(shù)組項(xiàng)時(shí)膳算,例如:vm.items[indexOfItem] = newValue

當(dāng)你修改數(shù)組的長(zhǎng)度時(shí),例如:vm.items.length = newLength

解決辦法:

vm.$set?的實(shí)現(xiàn)原理是:

如果目標(biāo)是數(shù)組弛作,直接使用數(shù)組的 splice 方法觸發(fā)相應(yīng)式涕蜂;

如果目標(biāo)是對(duì)象,會(huì)先判讀屬性是否存在映琳、對(duì)象是否是響應(yīng)式机隙,最終如果要對(duì)屬性進(jìn)行響應(yīng)式處理,則是通過(guò)調(diào)用 defineReactive 方法進(jìn)行響應(yīng)式處理( defineReactive 方法就是 Vue 在初始化對(duì)象時(shí)萨西,給對(duì)象屬性采用 Object.defineProperty 動(dòng)態(tài)添加 getter 和 setter 的功能所調(diào)用的方法)

Vue事件綁定原理是什么有鹿?

原生事件綁定是通過(guò)addEventListener綁定給真實(shí)元素的,組件事件綁定是通過(guò)Vue自定義的$on實(shí)現(xiàn)的谎脯。

說(shuō)一下虛擬Dom以及key屬性的作用

由于在瀏覽器中操作DOM是很昂貴的葱跋。頻繁的操作DOM,會(huì)產(chǎn)生一定的性能問(wèn)題。這就是虛擬Dom的產(chǎn)生原因娱俺。

Virtual DOM本質(zhì)就是用一個(gè)原生的JS對(duì)象去描述一個(gè)DOM節(jié)點(diǎn)稍味。是對(duì)真實(shí)DOM的一層抽象。(也就是源碼中的VNode類荠卷,它定義在src/core/vdom/vnode.js中模庐。)

虛擬 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ù)。

key 是為 Vue 中 vnode 的唯一標(biāo)記慎冤,通過(guò)這個(gè) key疼燥,我們的 diff 操作可以更準(zhǔn)確、更快速粪薛,更準(zhǔn)確:因?yàn)閹?key 就不是就地復(fù)用了悴了,在 sameNode 函數(shù)a.key === b.key對(duì)比中可以避免就地復(fù)用的情況。所以會(huì)更加準(zhǔn)確违寿。更快速:利用 key 的唯一性生成 map 對(duì)象來(lái)獲取對(duì)應(yīng)節(jié)點(diǎn)湃交,比遍歷方式更快

為什么不建議用index作為key?

不建議 用index 作為 key,和沒(méi)寫(xiě)基本上沒(méi)區(qū)別藤巢,因?yàn)椴还苣銛?shù)組的順序怎么顛倒搞莺,index 都是 0, 1, 2 這樣排列,導(dǎo)致 Vue 會(huì)復(fù)用錯(cuò)誤的舊子節(jié)點(diǎn)掂咒,做很多額外的工作

生命周期篇

說(shuō)一下你對(duì)Vue的生命周期的理解

簡(jiǎn)單回答

beforeCreate才沧、created、beforeMount绍刮、mounted温圆、beforeUpdate、updated孩革、beforeDestroy岁歉、destroyed。

keep-alive 有自己獨(dú)立的鉤子函數(shù) activated 和 deactivated膝蜈。

復(fù)雜回答

生命周期

發(fā)生了什么beforeCreate在當(dāng)前階段data锅移、methods、computed以及watch上的數(shù)據(jù)和方法都不能被訪問(wèn)created在實(shí)例創(chuàng)建完成后發(fā)生饱搏,當(dāng)前階段已經(jīng)完成了數(shù)據(jù)觀測(cè)非剃,也就是可以使用數(shù)據(jù),更改數(shù)據(jù)推沸,在這里更改數(shù)據(jù)不會(huì)觸發(fā)updated函數(shù)备绽∪耄可以做一些初始數(shù)據(jù)的獲取,在當(dāng)前階段無(wú)法與Dom進(jìn)行交互疯坤,如果非要想报慕,可以通過(guò)vm.$nextTick來(lái)訪問(wèn)DombeforeMount發(fā)生在掛載之前,在這之前template模板已導(dǎo)入渲染函數(shù)編譯压怠。而當(dāng)前階段虛擬Dom已經(jīng)創(chuàng)建完成眠冈,即將開(kāi)始渲染。在此時(shí)也可以對(duì)數(shù)據(jù)進(jìn)行更改菌瘫,不會(huì)觸發(fā)updatedmounted在掛載完成后發(fā)生蜗顽,在當(dāng)前階段,真實(shí)的Dom掛載完畢雨让,數(shù)據(jù)完成雙向綁定雇盖,可以訪問(wèn)到Dom節(jié)點(diǎn),使用$refs屬性對(duì)Dom進(jìn)行操作beforeUpdate發(fā)生在更新之前栖忠,也就是響應(yīng)式數(shù)據(jù)發(fā)生更新崔挖,虛擬dom重新渲染之前被觸發(fā),你可以在當(dāng)前階段進(jìn)行更改數(shù)據(jù)庵寞,不會(huì)造成重渲染updated發(fā)生在更新完成之后狸相,當(dāng)前階段組件Dom已完成更新。要注意的是避免在此期間更改數(shù)據(jù)捐川,因?yàn)檫@可能會(huì)導(dǎo)致無(wú)限循環(huán)的更新beforeDestroy發(fā)生在實(shí)例銷毀之前脓鹃,在當(dāng)前階段實(shí)例完全可以被使用,我們可以在這時(shí)進(jìn)行善后收尾工作古沥,**比如清除計(jì)時(shí)器 **destroyed發(fā)生在實(shí)例銷毀之后瘸右,這個(gè)時(shí)候只剩下了dom空殼。組件已被拆解岩齿,數(shù)據(jù)綁定被卸除太颤,監(jiān)聽(tīng)被移出,子實(shí)例也統(tǒng)統(tǒng)被銷毀activited keep-alive 專屬組件被激活時(shí)調(diào)用deactivated keep-alive 專屬組件被銷毀時(shí)調(diào)用

Vue中組件生命周期調(diào)用順序是什么樣的盹沈?

組件的調(diào)用順序都是先父后子,渲染完成的順序是先子后父栋齿。

組件的銷毀操作是先父后子,銷毀完成的順序是先子后父襟诸。

在什么階段才能訪問(wèn)操作DOM?

在鉤子函數(shù) mounted 被調(diào)用前基协,Vue 已經(jīng)將編譯好的模板掛載到頁(yè)面上歌亲,所以在 mounted 中可以訪問(wèn)操作 DOM。

你的接口請(qǐng)求一般放在哪個(gè)生命周期中澜驮?

可以在鉤子函數(shù) created陷揪、beforeMount、mounted 中進(jìn)行調(diào)用,因?yàn)樵谶@三個(gè)鉤子函數(shù)中悍缠,data 已經(jīng)創(chuàng)建卦绣,可以將服務(wù)端端返回的數(shù)據(jù)進(jìn)行賦值。

但是推薦在 created 鉤子函數(shù)中調(diào)用異步請(qǐng)求飞蚓,因?yàn)樵?created 鉤子函數(shù)中調(diào)用異步請(qǐng)求有以下優(yōu)點(diǎn):

能更快獲取到服務(wù)端數(shù)據(jù)滤港,減少頁(yè)面loading 時(shí)間;

ssr不支持 beforeMount 趴拧、mounted 鉤子函數(shù)溅漾,所以放在 created 中有助于一致性;

路由篇

vue路由hash模式和history模式實(shí)現(xiàn)原理分別是什么著榴,他們的區(qū)別是什么添履?

hash 模式:

#后面 hash 值的變化,不會(huì)導(dǎo)致瀏覽器向服務(wù)器發(fā)出請(qǐng)求脑又,瀏覽器不發(fā)出請(qǐng)求暮胧,就不會(huì)刷新頁(yè)面

通過(guò)監(jiān)聽(tīng)?hashchange?事件可以知道 hash 發(fā)生了哪些變化,然后根據(jù) hash 變化來(lái)實(shí)現(xiàn)更新頁(yè)面部分內(nèi)容的操作问麸。

history 模式:

history 模式的實(shí)現(xiàn)往衷,主要是 HTML5 標(biāo)準(zhǔn)發(fā)布的兩個(gè) API,pushState?和?replaceState口叙,這兩個(gè) API 可以在改變 url炼绘,但是不會(huì)發(fā)送請(qǐng)求。這樣就可以監(jiān)聽(tīng) url 變化來(lái)實(shí)現(xiàn)更新頁(yè)面部分內(nèi)容的操作

區(qū)別

url 展示上妄田,hash 模式有“#”俺亮,history 模式?jīng)]有

刷新頁(yè)面時(shí),hash 模式可以正常加載到 hash 值對(duì)應(yīng)的頁(yè)面疟呐,而 history 沒(méi)有處理的話脚曾,會(huì)返回 404,一般需要后端將所有頁(yè)面都配置重定向到首頁(yè)路由

兼容性启具,hash 可以支持低版本瀏覽器和 IE本讥。

路由懶加載是什么意思?如何實(shí)現(xiàn)路由懶加載鲁冯?

路由懶加載的含義:把不同路由對(duì)應(yīng)的組件分割成不同的代碼塊拷沸,然后當(dāng)路由被訪問(wèn)的時(shí)候才加載對(duì)應(yīng)組件

實(shí)現(xiàn):結(jié)合 Vue 的異步組件和 Webpack 的代碼分割功能

const Foo = () => Promise.resolve({ /* 組件定義對(duì)象 */ })

復(fù)制代碼

import('./Foo.vue') // 返回 Promise

復(fù)制代碼

結(jié)合這兩者,這就是如何定義一個(gè)能夠被 Webpack 自動(dòng)代碼分割的異步組件

const Foo = () => import('./Foo.vue')

const router = new VueRouter({ routes: [ { path: '/foo', component: Foo } ]})

復(fù)制代碼

在 Webpack 2 中薯演,我們可以使用動(dòng)態(tài) import語(yǔ)法來(lái)定義代碼分塊點(diǎn) (split point)

可以將異步組件定義為返回一個(gè) Promise 的工廠函數(shù) (該函數(shù)返回的 Promise 應(yīng)該 resolve 組件本身)

使用命名 chunk撞芍,和webpack中的魔法注釋就可以把某個(gè)路由下的所有組件都打包在同個(gè)異步塊 (chunk) 中

chunkconst Foo = () => import(/* webpackChunkName: "group-foo" */ './Foo.vue')

Vue-router 導(dǎo)航守衛(wèi)有哪些

全局前置/鉤子:beforeEach、beforeResolve跨扮、afterEach

路由獨(dú)享的守衛(wèi):beforeEnter

組件內(nèi)的守衛(wèi):beforeRouteEnter序无、beforeRouteUpdate验毡、beforeRouteLeave

進(jìn)階篇

說(shuō)說(shuō)vue和react的異同

使用 Virtual DOM

提供了響應(yīng)式 (Reactive) 和組件化 (Composable) 的視圖組件。

將注意力集中保持在核心庫(kù)帝嗡,而將其他功能如路由和全局狀態(tài)管理交給相關(guān)的庫(kù)晶通。

在 React 應(yīng)用中,當(dāng)某個(gè)組件的狀態(tài)發(fā)生變化時(shí)哟玷,它會(huì)以該組件為根狮辽,重新渲染整個(gè)組件子樹(shù)(除非使用PureComponent/shouldComponentUpdate),在 Vue 應(yīng)用中碗降,組件的依賴是在渲染過(guò)程中自動(dòng)追蹤的隘竭,所以系統(tǒng)能精確知曉哪個(gè)組件確實(shí)需要被重渲染

在 React 中,一切都是 JavaScript讼渊。不僅僅是 HTML 可以用 JSX 來(lái)表達(dá)动看,現(xiàn)在的潮流也越來(lái)越多地將 CSS 也納入到 JavaScript 中來(lái)處理

Vue 的路由庫(kù)和狀態(tài)管理庫(kù)都是由官方維護(hù)支持且與核心庫(kù)同步更新的。React 則是選擇把這些問(wèn)題交給社區(qū)維護(hù)爪幻,因此創(chuàng)建了一個(gè)更分散的生態(tài)系統(tǒng)菱皆,所以有更豐富的生態(tài)系統(tǒng)

Vue 提供了CLI 腳手架,能讓你通過(guò)交互式的腳手架引導(dǎo)非常容易地構(gòu)建項(xiàng)目挨稿。你甚至可以使用它快速開(kāi)發(fā)組件的原型仇轻。React 在這方面也提供了create-react-app,但是現(xiàn)在還存在一些局限性

React Native 能使你用相同的組件模型編寫(xiě)有本地渲染能力的 APP奶甘,Vue 和Weex會(huì)進(jìn)行官方合作篷店,Weex 是阿里巴巴發(fā)起的跨平臺(tái)用戶界面開(kāi)發(fā)框架,同時(shí)也正在 Apache 基金會(huì)進(jìn)行項(xiàng)目孵化臭家,另一個(gè)選擇是NativeScript-Vue疲陕,一個(gè)用 Vue.js 構(gòu)建完全原生應(yīng)用的NativeScript插件

什么是 mixin ?

Mixin 使我們能夠?yàn)?Vue 組件編寫(xiě)可插拔和可重用的功能钉赁。

如果你希望再多個(gè)組件之間重用一組組件選項(xiàng)蹄殃,例如生命周期 hook、 方法等你踩,則可以將其編寫(xiě)為 mixin诅岩,并在組件中簡(jiǎn)單的引用它。

然后將 mixin 的內(nèi)容合并到組件中带膜。如果你要在 mixin 中定義生命周期 hook吩谦,那么它在執(zhí)行時(shí)將優(yōu)化于組件自已的 hook。

在 Vue 實(shí)例中編寫(xiě)生命周期 hook 或其他 option/properties 時(shí)膝藕,為什么不使用箭頭函數(shù) 逮京?

箭頭函數(shù)自已沒(méi)有定義 this 上下文中。

當(dāng)你在 Vue 程序中使用箭頭函數(shù) ( => ) 時(shí)束莫,this 關(guān)鍵字病不會(huì)綁定到 Vue 實(shí)例懒棉,因此會(huì)引發(fā)錯(cuò)誤。所以強(qiáng)烈建議改用標(biāo)準(zhǔn)函數(shù)聲明览绿。

Vue模版編譯原理知道嗎策严,能簡(jiǎn)單說(shuō)一下嗎?

簡(jiǎn)單說(shuō)饿敲,Vue的編譯過(guò)程就是將template轉(zhuǎn)化為render函數(shù)的過(guò)程妻导。會(huì)經(jīng)歷以下階段(生成AST樹(shù)/優(yōu)化/codegen):

首先解析模版,生成AST語(yǔ)法樹(shù)(一種用JavaScript對(duì)象的形式來(lái)描述整個(gè)模板)怀各。使用大量的正則表達(dá)式對(duì)模板進(jìn)行解析倔韭,遇到標(biāo)簽、文本的時(shí)候都會(huì)執(zhí)行對(duì)應(yīng)的鉤子進(jìn)行相關(guān)處理瓢对。

Vue的數(shù)據(jù)是響應(yīng)式的寿酌,但其實(shí)模板中并不是所有的數(shù)據(jù)都是響應(yīng)式的。有一些數(shù)據(jù)首次渲染后就不會(huì)再變化硕蛹,對(duì)應(yīng)的DOM也不會(huì)變化醇疼。那么優(yōu)化過(guò)程就是深度遍歷AST樹(shù),按照相關(guān)條件對(duì)樹(shù)節(jié)點(diǎn)進(jìn)行標(biāo)記法焰。這些被標(biāo)記的節(jié)點(diǎn)(靜態(tài)節(jié)點(diǎn))我們就可以跳過(guò)對(duì)它們的比對(duì)秧荆,對(duì)運(yùn)行時(shí)的模板起到很大的優(yōu)化作用。

編譯的最后一步是將優(yōu)化后的AST樹(shù)轉(zhuǎn)換為可執(zhí)行的代碼埃仪。

diff算法說(shuō)一下

同級(jí)比較乙濒,再比較子節(jié)點(diǎn)

先判斷一方有子節(jié)點(diǎn)一方?jīng)]有子節(jié)點(diǎn)的情況(如果新的children沒(méi)有子節(jié)點(diǎn),將舊的子節(jié)點(diǎn)移除)

比較都有子節(jié)點(diǎn)的情況(核心diff)

遞歸比較子節(jié)點(diǎn)

說(shuō)說(shuō)你對(duì)keep-alive組件的了解

keep-alive 是 Vue 內(nèi)置的一個(gè)組件卵蛉,可以使被包含的組件保留狀態(tài)颁股,避免重新渲染 ,其有以下特性:

一般結(jié)合路由和動(dòng)態(tài)組件一起使用毙玻,用于緩存組件豌蟋;

提供 include 和 exclude 屬性,兩者都支持字符串或正則表達(dá)式桑滩, include 表示只有名稱匹配的組件會(huì)被緩存梧疲,exclude 表示任何名稱匹配的組件都不會(huì)被緩存 ,其中 exclude 的優(yōu)先級(jí)比 include 高运准;

對(duì)應(yīng)兩個(gè)鉤子函數(shù) activated 和 deactivated 幌氮,當(dāng)組件被激活時(shí),觸發(fā)鉤子函數(shù) activated胁澳,當(dāng)組件被移除時(shí)该互,觸發(fā)鉤子函數(shù) deactivated。

說(shuō)說(shuō)你對(duì)SSR的了解

SSR也就是服務(wù)端渲染韭畸,也就是將Vue在客戶端把標(biāo)簽渲染成HTML的工作放在服務(wù)端完成宇智,然后再把html直接返回給客戶端

SSR的優(yōu)勢(shì)

更好的SEO

首屏加載速度更快

SSR的缺點(diǎn)

開(kāi)發(fā)條件會(huì)受到限制蔓搞,服務(wù)器端渲染只支持beforeCreate和created兩個(gè)鉤子

當(dāng)我們需要一些外部擴(kuò)展庫(kù)時(shí)需要特殊處理,服務(wù)端渲染應(yīng)用程序也需要處于Node.js的運(yùn)行環(huán)境

更多的服務(wù)端負(fù)載

你都做過(guò)哪些Vue的性能優(yōu)化随橘?

編碼階段

盡量減少data中的數(shù)據(jù)喂分,data中的數(shù)據(jù)都會(huì)增加getter和setter,會(huì)收集對(duì)應(yīng)的watcher

v-if和v-for不能連用

如果需要使用v-for給每項(xiàng)元素綁定事件時(shí)使用事件代理

SPA 頁(yè)面采用keep-alive緩存組件

在更多的情況下机蔗,使用v-if替代v-show

key保證唯一

使用路由懶加載蒲祈、異步組件

防抖、節(jié)流

第三方模塊按需導(dǎo)入

長(zhǎng)列表滾動(dòng)到可視區(qū)域動(dòng)態(tài)加載

圖片懶加載

SEO優(yōu)化

預(yù)渲染

服務(wù)端渲染SSR

打包優(yōu)化

壓縮代碼

Tree Shaking/Scope Hoisting

使用cdn加載第三方模塊

多線程打包happypack

splitChunks抽離公共文件

sourceMap優(yōu)化

用戶體驗(yàn)

骨架屏

PWA

還可以使用緩存(客戶端緩存萝嘁、服務(wù)端緩存)優(yōu)化梆掸、服務(wù)端開(kāi)啟gzip壓縮等。

vue2.x中如何監(jiān)測(cè)數(shù)組變化牙言?

使用了函數(shù)劫持的方式酸钦,重寫(xiě)了數(shù)組的方法,Vue將data中的數(shù)組進(jìn)行了原型鏈重寫(xiě)嬉挡,指向了自己定義的數(shù)組原型方法钝鸽,當(dāng)調(diào)用數(shù)組api時(shí),可以通知依賴更新庞钢。

如果數(shù)組中包含著引用類型拔恰,會(huì)對(duì)數(shù)組中的引用類型再次遞歸遍歷進(jìn)行監(jiān)控。這樣就實(shí)現(xiàn)了監(jiān)測(cè)數(shù)組變化基括。

說(shuō)說(shuō)你對(duì) SPA 單頁(yè)面的理解颜懊,它的優(yōu)缺點(diǎn)分別是什么?

SPA( single-page application )僅在 Web 頁(yè)面初始化時(shí)加載相應(yīng)的 HTML风皿、JavaScript 和 CSS河爹。一旦頁(yè)面加載完成,SPA 不會(huì)因?yàn)橛脩舻牟僮鞫M(jìn)行頁(yè)面的重新加載或跳轉(zhuǎn)桐款;取而代之的是利用路由機(jī)制實(shí)現(xiàn) HTML 內(nèi)容的變換咸这,UI 與用戶的交互,避免頁(yè)面的重新加載魔眨。

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

用戶體驗(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ì)。

對(duì)于即將到來(lái)的 vue3.0 特性你有什么了解的嗎姻报?

監(jiān)測(cè)機(jī)制的改變

3.0 將帶來(lái)基于代理 Proxy的 observer 實(shí)現(xiàn)己英,提供全語(yǔ)言覆蓋的反應(yīng)性跟蹤。

消除了 Vue 2 當(dāng)中基于 Object.defineProperty 的實(shí)現(xiàn)所存在的很多限制:

只能監(jiān)測(cè)屬性吴旋,不能監(jiān)測(cè)對(duì)象

檢測(cè)屬性的添加和刪除损肛;

檢測(cè)數(shù)組索引和長(zhǎng)度的變更;

支持 Map荣瑟、Set治拿、WeakMap 和 WeakSet。

模板

模板方面沒(méi)有大的變更笆焰,只改了作用域插槽劫谅,2.x 的機(jī)制導(dǎo)致作用域插槽變了,父組件會(huì)重新渲染嚷掠,而 3.0 把作用域插槽改成了函數(shù)的方式捏检,這樣只會(huì)影響子組件的重新渲染,提升了渲染的性能不皆。

同時(shí)贯城,對(duì)于 render 函數(shù)的方面,vue3.0 也會(huì)進(jìn)行一系列更改來(lái)方便習(xí)慣直接使用 api 來(lái)生成 vdom 霹娄。

對(duì)象式的組件聲明方式

vue2.x 中的組件是通過(guò)聲明的方式傳入一系列 option能犯,和 TypeScript 的結(jié)合需要通過(guò)一些裝飾器的方式來(lái)做,雖然能實(shí)現(xiàn)功能项棠,但是比較麻煩悲雳。

3.0 修改了組件的聲明方式,改成了類式的寫(xiě)法香追,這樣使得和 TypeScript 的結(jié)合變得很容易

其它方面的更改

支持自定義渲染器合瓢,從而使得 weex 可以通過(guò)自定義渲染器的方式來(lái)擴(kuò)展,而不是直接 fork 源碼來(lái)改的方式透典。

支持 Fragment(多個(gè)根節(jié)點(diǎn))和 Protal(在 dom 其他部分渲染組建內(nèi)容)組件晴楔,針對(duì)一些特殊的場(chǎng)景做了處理顿苇。

基于 tree shaking 優(yōu)化,提供了更多的內(nèi)置功能税弃。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末纪岁,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子则果,更是在濱河造成了極大的恐慌幔翰,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,113評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件西壮,死亡現(xiàn)場(chǎng)離奇詭異遗增,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)款青,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門(mén)渣锦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)吏够,“玉大人勘天,你說(shuō)我怎么就攤上這事龙助。” “怎么了康震?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,340評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵燎含,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我签杈,道長(zhǎng)瘫镇,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,449評(píng)論 1 279
  • 正文 為了忘掉前任答姥,我火速辦了婚禮铣除,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘鹦付。我一直安慰自己尚粘,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布敲长。 她就那樣靜靜地躺著郎嫁,像睡著了一般。 火紅的嫁衣襯著肌膚如雪祈噪。 梳的紋絲不亂的頭發(fā)上泽铛,一...
    開(kāi)封第一講書(shū)人閱讀 49,166評(píng)論 1 284
  • 那天,我揣著相機(jī)與錄音辑鲤,去河邊找鬼盔腔。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的弛随。 我是一名探鬼主播瓢喉,決...
    沈念sama閱讀 38,442評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼舀透!你這毒婦竟也來(lái)了栓票?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,105評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤愕够,失蹤者是張志新(化名)和其女友劉穎走贪,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體惑芭,經(jīng)...
    沈念sama閱讀 43,601評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡厉斟,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了强衡。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,161評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡码荔,死狀恐怖漩勤,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情缩搅,我是刑警寧澤越败,帶...
    沈念sama閱讀 33,792評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站硼瓣,受9級(jí)特大地震影響究飞,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜堂鲤,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評(píng)論 3 307
  • 文/蒙蒙 一亿傅、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧瘟栖,春花似錦葵擎、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,352評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至寓涨,卻和暖如春盯串,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背戒良。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,584評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工体捏, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,618評(píng)論 2 355
  • 正文 我出身青樓译打,卻偏偏與公主長(zhǎng)得像耗拓,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子奏司,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評(píng)論 2 344