淺析vue中的MVVM實(shí)現(xiàn)原理
現(xiàn)成MVVM
菜單教程
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Vue 測(cè)試實(shí)例 - 菜鳥教程(runoob.com)</title> <script src="https://unpkg.com/vue/dist/vue.js"></script> </head> <body> <div id="app"> <input type="text" v-model="message"> <p>{{ message }}</p> </div> <script> let vm = new Vue({ el: '#app', data: { message: 'Hello Vue.js!' } }) </script> </body> </html>
視圖影響數(shù)據(jù)
數(shù)據(jù)影響視圖
項(xiàng)目構(gòu)架
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> </body> </html> <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Vue 測(cè)試實(shí)例 - 菜鳥教程(runoob.com)</title> <script src="./js/mvvm.js"></script> <script src="./js/compile.js"></script> </head> <body> <div id="app"> <input type="text" v-model="message"> <div>{{message}}</div> <ul> <li></li> </ul> {{message}} </div> <script> let vm = new MVVM({ el: '#app', data: { message: 'Hello Vue.js!' } }) </script> </body> </html>
mvvm.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> </body> </html> <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Vue 測(cè)試實(shí)例 - 菜鳥教程(runoob.com)</title> <script src="./js/mvvm.js"></script> <script src="./js/compile.js"></script> </head> <body> <div id="app"> <input type="text" v-model="message"> <div>{{message}}</div> <ul> <li></li> </ul> {{message}} </div> <script> let vm = new MVVM({ el: '#app', data: { message: 'Hello Vue.js!' } }) </script> </body> </html>
mvvm.js
class MVVM { constructor(options) { this.$el = options.el; this.$data = options.data; if (this.$el) { new Compile(this.$el); } } }
compile把dom節(jié)點(diǎn),放在內(nèi)存中操作(到35分鐘)
class Compile { constructor(el, vm) { this.el = this.isElementNode(el) ? el : document.querySelector(el); this.vm = vm; if (this.el) { let fragment = this.node2frament(this.el); this.compile(fragment); } } //輔助方法 isElementNode(node) { return node.nodeType === 1; } //核心方法 compile(fragment) { let childNodes = fragment.childNodes; console.log(childNodes) } node2frament(el) { let fragment = document.createDocumentFragment(); let firstChild; while (firstChild = el.firstChild) { fragment.appendChild(firstChild); } return fragment } }
分類元素節(jié)點(diǎn)和文本節(jié)點(diǎn)(52分鐘)
class Compile { constructor(el, vm) { this.el = this.isElementNode(el) ? el : document.querySelector(el); this.vm = vm; if (this.el) { let fragment = this.node2frament(this.el); this.compile(fragment); } } //輔助方法 isElementNode(node) { return node.nodeType === 1; } isDirective(name) { return name.includes('v-') } //核心方法 compileElement(node) { let attrs = node.attributes; Array.from(attrs).forEach(arrt => { let attrName = attr.name; if (this.isDirective(attrName)) { let expr = attr.value; } }) } compileText(node) { let text = node.textContent; let reg = /\{\{([^}]+)\}\}/g; if (reg.test(text)) { } } compile(fragment) { let childNodes = fragment.childNodes; Array.from(childNodes).forEach(node => { if (this.isElementNode(node)) { this.compile(node) } else { console.log('text', node) } }) } node2frament(el) { let fragment = document.createDocumentFragment(); let firstChild; while (firstChild = el.firstChild) { fragment.appendChild(firstChild); } return fragment } }
元素節(jié)點(diǎn)
文本節(jié)點(diǎn)
把data中的數(shù)據(jù),顯示在視圖上(到1:16分)
class Compile { constructor(el, vm) { this.el = this.isElementNode(el) ? el : document.querySelector(el); this.vm = vm; if (this.el) { let fragment = this.node2frament(this.el); this.compile(fragment); this.el.appendChild(fragment) } } //輔助方法 isElementNode(node) { return node.nodeType === 1; } isDirective(name) { return name.includes('v-') } //核心方法 compileElement(node) { let attrs = node.attributes; Array.from(attrs).forEach(attr => { let attrName = attr.name; if (this.isDirective(attrName)) { let expr = attr.value; let [, type] = attrName.split('-'); CompileUtil[type](node, this.vm, expr) } }) } compileText(node) { console.log(node) let expr = node.textContent; let reg = /\{\{([^}]+)\}\}/g; if (reg.test(expr)) { CompileUtil['text'](node, this.vm, expr) } } compile(fragment) { let childNodes = fragment.childNodes; Array.from(childNodes).forEach(node => { if (this.isElementNode(node)) { this.compileElement(node) this.compile(node) } else { this.compileText(node) } }) } node2frament(el) { let fragment = document.createDocumentFragment(); let firstChild; while (firstChild = el.firstChild) { fragment.appendChild(firstChild); } return fragment } } CompileUtil = { getVal(vm, expr) { // 獲取實(shí)例上對(duì)應(yīng)的數(shù)據(jù) expr = expr.split('.'); // [message,a] return expr.reduce((prev, next) => { // vm.$data.a return prev[next]; }, vm.$data); }, getTextVal(vm, expr) { // 獲取編譯文本后的結(jié)果 return expr.replace(/\{\{([^}]+)\}\}/g, (...arguments) => { return this.getVal(vm, arguments[1]); }) }, text(node, vm, expr) { //文本處理 let updateFn = this.updater['textUpdater']; let value = this.getTextVal(vm, expr); updateFn && updateFn(node, value) }, model(node, vm, expr) { let updateFn = this.updater['modelUpdater']; updateFn && updateFn(node, this.getVal(vm, expr)); }, updater: { textUpdater(node, value) { node.textContent = value; }, modelUpdater(node, value) { node.value = value; } } }
v-model類型
modelUpdater(node, value) { node.value = value; console.log(node) console.log(value) console.log(node.value) }
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
解決vue項(xiàng)目,npm run build后,報(bào)路徑錯(cuò)的問(wèn)題
這篇文章主要介紹了解決vue項(xiàng)目,npm run build后,報(bào)路徑錯(cuò)的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-08-08Vue element商品列表的增刪改功能實(shí)現(xiàn)
這篇文章主要介紹了Vue+element 商品列表、新增、編輯、刪除業(yè)務(wù)實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-08-08強(qiáng)烈推薦!Vue3.2中的setup語(yǔ)法糖
script?setup是vue3的新語(yǔ)法糖,并不是新增的功能模塊,只是簡(jiǎn)化了以往的組合式API必須返回(return)的寫法,并且有更好的運(yùn)行時(shí)性能,這篇文章主要給大家介紹了關(guān)于Vue3.2中setup語(yǔ)法糖的相關(guān)資料,需要的朋友可以參考下2021-12-12vue中axios給后端傳遞參數(shù)出現(xiàn)等于號(hào)和雙引號(hào)的問(wèn)題及解決方法
這篇文章主要介紹了vue中axios給后端傳遞參數(shù)出現(xiàn)等于號(hào)和雙引號(hào)要怎么解決,項(xiàng)目場(chǎng)景我是傳遞一個(gè)string字符給后端時(shí)候報(bào)錯(cuò),隨手把這個(gè)問(wèn)題記錄下來(lái)了,需要的朋友可以參考下解決方案2022-11-11antd Select下拉菜單動(dòng)態(tài)添加option里的內(nèi)容操作
這篇文章主要介紹了antd Select下拉菜單動(dòng)態(tài)添加option里的內(nèi)容操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-11-11如何使用Vue3+Vite+TS快速搭建一套實(shí)用的腳手架
Vite是一個(gè)面向現(xiàn)代瀏覽器的一個(gè)更輕、更快的?Web?應(yīng)用開發(fā)工具,下面這篇文章主要給大家介紹了關(guān)于如何使用Vue3+Vite+TS快速搭建一套實(shí)用腳手架的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-10-10vue二級(jí)菜單導(dǎo)航點(diǎn)擊選中事件的方法
今天小編就為大家分享一篇vue二級(jí)菜單導(dǎo)航點(diǎn)擊選中事件的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-09-09vue+swiper實(shí)現(xiàn)左右滑動(dòng)的測(cè)試題功能
這篇文章主要介紹了vue+swiper實(shí)現(xiàn)左右滑動(dòng)的測(cè)試題功能,本文通過(guò)實(shí)例代碼給大介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-10-10element-ui vue input輸入框自動(dòng)獲取焦點(diǎn)聚焦方式
這篇文章主要介紹了element-ui vue input輸入框自動(dòng)獲取焦點(diǎn)聚焦方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-04-04vue2 如何實(shí)現(xiàn)div contenteditable=“true”(類似于v-model)的效果
這篇文章主要給大家介紹了利用vue2如何實(shí)現(xiàn)div contenteditable="true",就是類似于v-model的效果,文中給出了兩種解決的思路,對(duì)大家具有一定的參考價(jià)值,有需要的朋友們下面來(lái)一起看看吧。2017-02-02