JavaScript

超轻量级php框架startmvc

浅析vue中的MVVM实现原理

更新时间:2020-08-16 14:36:02 作者:startmvc
现成MVVM菜单教程<!DOCTYPEhtml><html><head><metacharset="utf-8"><title>Vue测试实

现成MVVM

菜单教程


<!DOCTYPE html>
<html>

<head>
 <meta charset="utf-8">
 <title>Vue 测试实例 - 菜鸟教程(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>

视图影响数据

数据影响视图

项目构架


<!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 测试实例 - 菜鸟教程(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 测试实例 - 菜鸟教程(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节点,放在内存中操作(到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
 }
}

分类元素节点和文本节点(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
 }
}

元素节点

文本节点

把data中的数据,显示在视图上(到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) { // 获取实例上对应的数据
 expr = expr.split('.'); // [message,a]
 return expr.reduce((prev, next) => { // vm.$data.a
 return prev[next];
 }, vm.$data);
 },
 getTextVal(vm, expr) { // 获取编译文本后的结果
 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)
 }

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。