對MVVM的認(rèn)識
深入了解:http://www.ruanyifeng.com/blog/2015/02/mvcmvp_mvvm.html
jquery 和 vue 的區(qū)別
- 數(shù)據(jù)和視圖分離瓮孙,解耦(開放封閉原則)
- 以數(shù)據(jù)驅(qū)動視圖,只關(guān)心數(shù)據(jù)變化,DOM操作被封裝
MVC
視圖(View):用戶界面
控制器(Controller):業(yè)務(wù)邏輯
-
模型(Model):數(shù)據(jù)保存
MVC View 傳送指令到 Controller
Controller 完成業(yè)務(wù)邏輯后,要求 Model 改變狀態(tài)
Model 將新的數(shù)據(jù)發(fā)送到 View钞脂,用戶得到反饋
MVVM
視圖(View):用戶界面
視圖模型(ViewModel):業(yè)務(wù)邏輯
-
模型(Model):數(shù)據(jù)保存
MVVM View 與 Model 不發(fā)生聯(lián)系,都通過 ViewModel 傳遞
各部分之間的通信薄腻,都是雙向的
采用雙向綁定(data-binding):View的變動编振,自動反映在 ViewModel
Vue 三要素
響應(yīng)式:Vue如何監(jiān)聽到data的每個(gè)屬性變化
- 什么是響應(yīng)式
修改data屬性后,vue立刻監(jiān)聽到
data屬性被代理到vm上 - Object.defineProperty
var vm = {}
var data = {
name: 'liuxin',
age: 22
}
for (let key in data){
Object.defineProperty(vm, key, {
get: function() {
return data[key]
},
set: function(newVal) {
data[key] = newVal
}
})
}
模板引擎:Vue的模板如何讓被解析工碾,指令如何處理
模板是什么
本質(zhì)是字符串
有邏輯弱睦,如v-if v-for等
和html格式很像,但有很大區(qū)別
最終還是要轉(zhuǎn)換成html展示
模板最終必須轉(zhuǎn)換成js代碼渊额,有邏輯存在况木,要轉(zhuǎn)換為html渲染頁面,必須用js才能實(shí)現(xiàn)(圖靈完備)旬迹,因此模板最終要轉(zhuǎn)換成一個(gè)js函數(shù)(render函數(shù))render函數(shù)
模板中所有的信息都包含在了render函數(shù)中
this 即 vm
name 即 this.name 即 vm.name火惊,即data中的namerender函數(shù)與vdom
render函數(shù)返回vnode
updateComponent中實(shí)現(xiàn)了vdom的patch
頁面首次渲染執(zhí)行updateComponent
data中每次修改屬性,執(zhí)行updateComponent
渲染: Vue的模板如何被渲染成HTML以及渲染過程
Vue 的整個(gè)實(shí)現(xiàn)流程
解析模板成render函數(shù)
- with的用法
- 模板中的所有信息被render函數(shù)包含
- 模板中用到的data中的屬性奔垦,都變成了js變量
- 模板中的v-model v-for v-on 都變成了js邏輯
- render函數(shù)返回vnode
響應(yīng)式開始監(jiān)聽
- Object.defineProperty
- 將data的屬性代理到vm上
首次渲染屹耐,顯示頁面,且綁定依賴
- 初次渲染宴倍,執(zhí)行updateComponent张症,執(zhí)行vm._render()
- 執(zhí)行render函數(shù)仓技,會訪問到vm.list和vm.title
- 會被響應(yīng)式的get方法監(jiān)聽到
- 執(zhí)行updateComponent,會走到vdom的patch方法
- patch將vnode渲染成DOM俗他,初次渲染完成
data屬性變化脖捻,觸發(fā)re-render
- 修改屬性,被響應(yīng)式的set監(jiān)聽到
- set中執(zhí)行updateComponent
- updateComponent重新執(zhí)行vm.render()
- 生成的vnode 和 preVnode兆衅,通過patch進(jìn)行對比
- 渲染到html中
vue雙向綁定原理
采用數(shù)據(jù)劫持結(jié)合觀察者模式的方式地沮,通過Object.defineProperty()來劫持各個(gè)屬性的setter,getter羡亩,在數(shù)據(jù)變動時(shí)發(fā)布消息給訂閱者摩疑,觸發(fā)相應(yīng)的監(jiān)聽回調(diào)。
- 第一步:需要observe的數(shù)據(jù)對象進(jìn)行遞歸遍歷畏铆,包括子屬性對象的屬性雷袋,都加上 setter和getter
這樣的話,給這個(gè)對象的某個(gè)值賦值辞居,就會觸發(fā)setter楷怒,那么就能監(jiān)聽到了數(shù)據(jù)變化 - 第二步:compile解析模板指令,將模板中的變量替換成數(shù)據(jù)瓦灶,然后初始化渲染頁面視圖鸠删,并將每個(gè)指令對應(yīng)的節(jié)點(diǎn)綁定更新函數(shù),添加監(jiān)聽數(shù)據(jù)的訂閱者贼陶,一旦數(shù)據(jù)有變動刃泡,收到通知,更新視圖
- 第三步:Watcher訂閱者是Observer和Compile之間通信的橋梁碉怔,主要做的事情是:
1烘贴、在自身實(shí)例化時(shí)往屬性訂閱器(dep)里面添加自己
2、自身必須有一個(gè)update()方法
3撮胧、待屬性變動dep.notice()通知時(shí)庙楚,能調(diào)用自身的update()方法,并觸發(fā)Compile中綁定的回調(diào)趴樱,則功成身退馒闷。 - 第四步:MVVM作為數(shù)據(jù)綁定的入口,整合Observer叁征、Compile和Watcher三者纳账,通過Observer來監(jiān)聽自己的model數(shù)據(jù)變化,通過Compile來解析編譯模板指令捺疼,最終利用Watcher搭起Observer和Compile之間的通信橋梁疏虫,達(dá)到數(shù)據(jù)變化 -> 視圖更新;視圖交互變化(input) -> 數(shù)據(jù)model變更的雙向綁定效果。
vue設(shè)計(jì)模式
觀察者模式
1卧秘、松耦合的代碼呢袱;
2、一對多的關(guān)系翅敌;
3羞福、主體狀態(tài)變化時(shí),所有依賴被通知蚯涮;
4治专、主體和觀察者互不知曉。
基本上遭顶,滿足上面四點(diǎn)的张峰,就可以算是觀察者模式了
//發(fā)布者
let pub = {
notice(){
dep.update();
}
}
//訂閱者
let sub1 = {
update(){
console.log('sub1 update')
}
}
let sub2 = {
update(){
console.log('sub2 update')
}
}
let sub3 = {
update(){
console.log('sub3 update')
}
}
//主體
function Dep(_sub){
this.update = ()=>{
for(let i=0; i<_sub.length; i++){
_sub[i].update();
}
}
}
let dep = new Dep([sub1,sub2,sub3]);
//發(fā)布消息
pub.notice();
// > sub1 update
// > sub2 update
// > sub3 update
dep觀察到pub發(fā)生了更新,就會循環(huán)依賴列表棒旗,依次觸發(fā)各個(gè)依賴事件
vue生命周期
總共分為8個(gè)階段創(chuàng)建前/后喘批,載入前/后,更新前/后铣揉,銷毀前/后谤祖。
創(chuàng)建前/后: 在beforeCreated階段,vue實(shí)例的掛載元素
$el
和數(shù)據(jù)對象data都為undefined老速,還未初始化。在created階段凸主,vue實(shí)例的數(shù)據(jù)對象data有了橘券,$el還沒有。載入前/后:在beforeMount階段卿吐,vue實(shí)例的$el和data都初始化了旁舰,但還是掛載之前為虛擬的dom節(jié)點(diǎn),data.message還未替換嗡官。在mounted階段箭窜,vue實(shí)例掛載完成,data.message成功渲染衍腥。
更新前/后:當(dāng)data變化時(shí)磺樱,會觸發(fā)beforeUpdate和updated方法。
銷毀前/后:在執(zhí)行destroy方法后婆咸,對data的改變不會再觸發(fā)周期函數(shù)竹捉,說明此時(shí)vue實(shí)例已經(jīng)解除了事件監(jiān)聽以及和dom的綁定,但是dom結(jié)構(gòu)依然存在