淺析vue中的MVVM實(shí)現(xiàn)原理
現(xiàn)成MVVM
菜單教程
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Vue 測(cè)試實(shí)例 - 菜鳥(niǎo)教程(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í)例 - 菜鳥(niǎo)教程(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í)例 - 菜鳥(niǎo)教程(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
}
}
分類(lèi)元素節(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類(lèi)型
modelUpdater(node, value) {
node.value = value;
console.log(node)
console.log(value)
console.log(node.value)
}

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
vite打包優(yōu)化CDN壓縮的分析實(shí)現(xiàn)
我們?cè)谌粘5墓ぷ髦锌隙〞?huì)遇到項(xiàng)目打包優(yōu)化等問(wèn)題,本文主要介紹了vite打包優(yōu)化CDN壓縮的分析實(shí)現(xiàn),具有一定的參加價(jià)值,感興趣的可以了解一下2024-07-07
vue移動(dòng)端如何解決click事件延遲,封裝tap等事件
這篇文章主要介紹了vue移動(dòng)端如何解決click事件延遲,封裝tap等事件,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03
webpack+vue.js構(gòu)建前端工程化的詳細(xì)教程
這篇文章主要介紹了webpack+vue.js構(gòu)建前端工程化的方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-05-05
詳解vue-property-decorator使用手冊(cè)
這篇文章主要介紹了vue-property-decorator使用手冊(cè),文中較詳細(xì)的給大家介紹了他們的用法,通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-07-07
Vue.extend實(shí)現(xiàn)掛載到實(shí)例上的方法
這篇文章主要介紹了Vue.extend實(shí)現(xiàn)掛載到實(shí)例上的方法,結(jié)合實(shí)例形式分析了Vue.extend實(shí)現(xiàn)掛載到實(shí)例上的具體操作步驟與相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下2019-05-05
解決echarts圖表y軸數(shù)據(jù)間隔過(guò)大的問(wèn)題
這篇文章主要介紹了解決echarts圖表y軸數(shù)據(jù)間隔過(guò)大的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-03-03
uniapp Vue3中如何解決web/H5網(wǎng)頁(yè)瀏覽器跨域的問(wèn)題
存在跨域問(wèn)題的原因是因?yàn)闉g覽器的同源策略,也就是說(shuō)前端無(wú)法直接發(fā)起跨域請(qǐng)求,同源策略是一個(gè)基礎(chǔ)的安全策略,但是這也會(huì)給uniapp/Vue開(kāi)發(fā)者在部署時(shí)帶來(lái)一定的麻煩,這篇文章主要介紹了在uniapp Vue3版本中如何解決web/H5網(wǎng)頁(yè)瀏覽器跨域的問(wèn)題,需要的朋友可以參考下2024-06-06
vuejs實(shí)現(xiàn)遞歸樹(shù)型菜單組件
本篇文章主要介紹了vuejs實(shí)現(xiàn)遞歸樹(shù)型菜單組件,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-01-01

