一,使用jquery和使用vue的區別 二,對MVVM的理解 三,vue中如何實現響應式 四,vue如何解析模版 五,vue整個實現流程 一,使用jquery和使用vue的區別 jquery實現todo-list <!DOCTYPE html> <html lang="en"> <head> <me ...
一,使用jquery和使用vue的區別 二,對MVVM的理解 三,vue中如何實現響應式 四,vue如何解析模版 五,vue整個實現流程 一,使用jquery和使用vue的區別 jquery實現todo-list
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>todo-list-jquery</title> </head> <body> <div> <input type="text" id="txt-title"> <button id="btn-submit">submit</button> </div> <ul id="ul-list"></ul> <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script> <script> var $txtTitle = $('#txt-title'); var $btnSubmit = $('#btn-submit'); var $ulList = $('#ul-list'); $btnSubmit.click(function() { var title = $txtTitle.val(); if (!title) { return; } var $li = $('<li>' + title + '</li>'); $ulList.append($li); $txtTitle.val(''); }) </script> </body> </html>vue實現todo-list
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>todo-list-vue</title> <script src="./vue-2.5.13.js"></script> </head> <body> <div id="app"> <div> <input v-model="title"> <button v-on:click="add">submit</button> </div> <ul> <li v-for="item in list">{{item}}</li> </ul> </div> <script> var vm = new Vue({ el: "#app", data: { title: '', list: [], }, methods: { add: function() { if (this.title) { this.list.push(this.title); this.title = ''; } } } }) </script> </body> </html>jquery和vue兩者的區別: 數據和視圖的分離-解耦(開放封閉原則) 以數據驅動視圖-只關心數據變化,DOM操作被封裝 二,對MVVM的理解 1,先說下MVC: M-Model 數據 V-VIew 視圖、界面 C-Controller 控制器、邏輯處理 兩種場景:




<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>vue-demo</title> <script src="https://cdn.bootcss.com/vue/2.5.16/vue.min.js"></script> </head> <body> <div id="app"> <p>{{name}}</p> <p>{{age}}</p> </div> <script> var vm = new Vue({ el:'#app', data:{ name:'zs', age:20 } }) console.log(vm.age) </script> </body> </html>
在控制台修改vm.age 或者vm.name,立刻會被監聽渲染出來
2,Object.defineProperty:直接在一個對象上定義一個新屬性,或者修改一個對象的現有屬性, 並返回這個對象。 語法:Object.defineProperty(obj, prop, descriptor)
例子:
var obj = {}; var _name = 'zs'; Object.defineProperty(obj,'name',{ get:function(){ console.log('get',_name);//監聽 return _name; }, set:function(newVal){ console.log('set',newVal);//監聽 _name = newVal; } });3,模擬實現(監聽+代理)
var vm = {}; var data = { name: 'zs', age: 20 }; var key, value; for (key in data) { // 命中閉包,新建一個函數,保證key的獨立的作用域 (function(key) { Object.defineProperty(vm, key, { //data屬性代理到vm上 get: function() { console.log('get', data[key]); //監聽 return data[key]; }, set: function(newVal) { console.log('set', newVal); //監聽 data[key] = newVal; } }) })(key) }看下控制臺中,此時列印的vm

var obj = { name: 'xx', age:20, getAddress:function(){ console.log('bj'); } } // 不用with function fn(){ console.log(obj.name); console.log(obj.age); obj.getAddress(); } fn() // 使用with function fn1(){ with(obj) { console.log(name); console.log(age); getAddress(); } } fn1()3,render函數 模版:
<div id="app"> <p>{{price}}</p> </div> <script> var vm = new Vue({ el:'#app', data:{ price:100 } }) </script>
render函數如下:
// 以下是手寫的 render 函數 使用 with ,代碼簡潔一些 function render() { with(this) { return _c( 'div', { attrs: { "id", "app" } }, [ _c('p', [_v(_s(price))]) ] ) } } // 不用 with 的改寫的 render 函數 function render1() { return vm._c( 'div', { attrs: { "id", "app" } }, [ vm._c('p', [_vm.v(vm._s(vm.price))]) ] ) } // 模版中所有信息都包含在了 render 函數中 // this === vm // price 即 this.price 即vm.price, 即 data 中的 price // _c 即 this._c , 即 vm._c
看下控制台:
<div id="app"> <div> <input v-model="title"> <button v-on:click="add">submit</button> </div> <ul> <li v-for="item in list">{{item}}</li> </ul> </div>
對應的render函數:(通過在vue-2.5.13.js源碼中 console.log(code.render)得出)
with(this){ return _c( 'div', {attrs:{"id":"app"}}, [_c('div', [_c( 'input', { directives:[ { name:"model", rawName:"v-model", value:(title), expression:"title" } ], domProps:{"value":(title)}, on:{ "input":function($event){ if($event.target.composing)return; title=$event.target.value } } } ), _v(" "), _c( 'button', { on:{ "click":add } }, [_v("submit")] ) ]), _v(" "), _c( 'ul', _l( (list),function(item){ return _c( 'li', [ _v( _s(item) ) ] ) } ) ) ] ) }根據todo-list demo的render函數: v-model是怎麼實現的?:雙向數據綁定,既有get,又有set v-on:click是怎麼實現的?:渲染時綁定click事件 v-for是怎麼實現的?:對數組進行遍歷,li標簽,最後歸結為數組,作為ul的子元素 模版生成html vm.c其實就相當於snabbdom中的h函數 render函數執行之後,返回的是vnode
vm._update(vnode) { const prevVnode = vm._vnode; vm._vnode = vnode; if (!prevVnode) { // 初次渲染 vm.$el = vm.__patch__(vm.$el, vnode); } else { // re-render vm.$el = vm.__patch__(prevVnode, vnode); } } function updateComponent() { // vm._render即上面的render函數,返回vnode vm._update(vm._render()) } // updateComponent實現了vdom的patch // 頁面首次渲染執行updateComponent(執行第一個patch) // data中每次修改屬性,執行updateComponent,修改data,set中可以執行updateComponent
vue如何解析模版: 模版:字元串(本質),有邏輯,嵌入js變數... 模版必須轉換為js代碼(有邏輯,渲染html,js變數)前端中,只有js才能處理邏輯和渲染html等 render函數: with語法,就是snabbdom里h函數的樣子 render函數執行是返回vnode updateComponent 首次渲染,非首次渲染(data屬性修改) 五,vue的整個實現流程 第一步:解析模版成render函數 with用法(瞭解即可,自己開發的時候,儘量避免使用) 模版中的所有信息都被render函數包含 模版中用到的data中的屬性,都變成了js變數 模版中的v-model,v-for,v-on都變成了js邏輯 render函數返回vnode 第二步:響應式開始監聽 Object.defineProperty中設置監聽 將data的屬性代理到vm上 第三步:首次渲染,顯示頁面,且綁定依賴 初次渲染,執行updateComponent,執行vm._render() 執行render函數,會訪問到vm.list和vm.title 會被響應式的get方法監聽到(後面詳細講) 執行updateComponent,會走到vdom的patch方法 patch將vnode渲染成DOM,初次渲染完成 疑問: 為何要監聽get,直接監聽set不行嗎? data中有很多屬性,有些被用到,有些可能不被用到 被用到的會走到get,不被用到的不會走到get 未走到get中的屬性,set的時候我們也無須關心 避免不必要的重覆渲染 第四步:data屬性變化,觸發rerender 修改屬性,被響應式的set監聽到 set中執行updateComponent (這裡是非同步的) updateComponent重新執行vm._render() 生成的vnode和prevVnode,通過patch進行對比 渲染到html中