html:

在HTML中使用v-model的指令,并且引入自定义的vue.js

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <div id="app">
        <span>姓名:{{ name }}</span>
        <input type="text" v-model="name"></input>
        <span>更多:{{ more.like }}</span>
        <input type="text" v-model="more.like">
    </div>

    <script src="./vue.js"></script>

    <script>
        const vm = new Vue({
            el: '#app',
            data: {
                name: '猿小野',
                more: {
                    like: '打篮球'
                }
            }
        })
        console.log(vm);
    </script>
</body>

</html>

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <div id="app">
        <span>姓名:{{ name }}</span>
        <input type="text" v-model="name"></input>
        <span>更多:{{ more.like }}</span>
        <input type="text" v-model="more.like">
    </div>

    <script src="./vue.js"></script>

    <script>
        const vm = new Vue({
            el: '#app',
            data: {
                name: '猿小野',
                more: {
                    like: '打篮球'
                }
            }
        })
        console.log(vm);
    </script>
</body>

</html>

js:

 class Vue {
     constructor(obj_instance) {
         this.$data = obj_instance.data;
         // 数据监听函数
         Observer(this.$data);
         // 模版解析函数
         Compile(obj_instance.el, this)
     }
 }
 
 // 数据劫持 - 监听实例里的数据
 function Observer(data_instance) {
     console.log(Object.keys(data_instance));
     // 递归出口
     if (!data_instance || typeof data_instance !== 'object') return;
     const dependency = new Dependency();
     Object.keys(data_instance).forEach(key => {
         let value = data_instance[key];
         Observer(value) // 递归 - 子属性数据劫持
         Object.defineProperty(data_instance, key, {
             enumerable: true,// 是否可以遍历/枚举
             configurable: true,// 是否可再次修改/删除配置项
             get() {
                 console.log(`访问了属性:${key} -> 值:${ value }`);
                 if (Dependency.temp) {
                     console.log(Dependency.temp);
                 }
                 // 订阅者加入依赖实例的数组
                 Dependency.temp && dependency.addSub(Dependency.temp);
                 return value;
             },
             set(newValue) {
                 console.log(`属性${key}的值${value}修改为 -> ${newValue}`);
                 value = newValue;
                 Observer(newValue);
                 dependency.notify();
             }
         })
     })
 }
 
 // HTML模版解析 - 替换DOM
 function Compile(element, vm) {
     vm.$el = document.querySelector(element);
     const fragment = document.createDocumentFragment();
     let child;
     while (child = vm.$el.firstChild) {
        fragment.append(child);
     }
     console.log(fragment);
     console.log(fragment.childNodes);
     fragment_compile(fragment);
     // 替换文档碎片内容
     function fragment_compile(node) {
         const pattern = /\{\{\s*(\S+)\s*\}\}/;
         if (node.nodeType === 3) {
             console.log(node);
             console.log(node.nodeValue);
             const xxx = node.nodeValue;
             const result_regex = pattern.exec(node.nodeValue);
             if (result_regex) {
                 console.log(node.nodeValue);
                 console.log(result_regex);
                 console.log(vm.$data[result_regex[1]]);
                 const arr = result_regex[1].split('.');
                 const value = arr.reduce((total, current) => total[current], vm.$data);
                 console.log(value);
                 node.nodeValue = xxx.replace(pattern, value);
                 console.log(node.nodeValue);
                 // 创建订阅者
                 new Watcher(vm, result_regex[1], newValue => {
                     node.nodeValue = xxx.replace(pattern, newValue);
                 })
             }
             return
         }
         if (node.nodeType === 1 && node.nodeName === 'INPUT') {
             const attr = Array.from(node.attributes);
             console.log(attr);
             attr.forEach(i => {
                 if (i.nodeName === 'v-model') {
                     console.log(i.nodeValue);
                     const value = i.nodeValue.split('.').reduce((total, current) => total[current], vm.$data);
                     node.value = value;
                     new Watcher(vm, i.nodeValue, newValue => {
                         node.value = newValue;
                     });
                     node.addEventListener('input', e => {
                         // ['more', 'like']
                         const arr1 = i.nodeValue.split('.');
                         // ['more']
                         const arr2 = arr1.slice(0, arr1.length - 1);
                         // vm.$data.more
                         const final = arr2.reduce((total, current) => total[current], vm.$data);
                         // vm.$data.more['like'] = e.target.value
                         final[arr1[arr1.length - 1]] = e.target.value;
                     })
                 }
             })
         }
         node.childNodes.forEach(child => fragment_compile(child));
     }
     vm.$el.appendChild(fragment);
 }
 
 // 依赖 - 收集和通知订阅者
 class Dependency {
     constructor() {
         this.subscribers = [];
     }
     addSub(sub) {
         this.subscribers.push(sub);
     }
     notify() {
         this.subscribers.forEach(sub => sub.update());
     }
 }
 
 // 订阅者
 class Watcher {
     constructor(vm, key, callback) {
         this.vm = vm;
         this.key = key;
         this.callback = callback;
         // 临时属性 - 触发getter
         Dependency.temp = this;
         console.log(`用属性${key}创建订阅者`);
         key.split('.').reduce((total, current) => total[current], vm.$data);
         Dependency.temp = null;
     }
     update() {
         const value = this.key.split('.').reduce((total, current) => total[current], this.vm.$data);
         this.callback(value);
     }
 }

 class Vue {
     constructor(obj_instance) {
         this.$data = obj_instance.data;
         // 数据监听函数
         Observer(this.$data);
         // 模版解析函数
         Compile(obj_instance.el, this)
     }
 }

 // 数据劫持 - 监听实例里的数据
 function Observer(data_instance) {
     console.log(Object.keys(data_instance));
     // 递归出口
     if (!data_instance || typeof data_instance !== 'object') return;
     const dependency = new Dependency();
     Object.keys(data_instance).forEach(key => {
         let value = data_instance[key];
         Observer(value) // 递归 - 子属性数据劫持
         Object.defineProperty(data_instance, key, {
             enumerable: true,// 是否可以遍历/枚举
             configurable: true,// 是否可再次修改/删除配置项
             get() {
                 console.log(`访问了属性:${key} -> 值:${ value }`);
                 if (Dependency.temp) {
                     console.log(Dependency.temp);
                 }
                 // 订阅者加入依赖实例的数组
                 Dependency.temp && dependency.addSub(Dependency.temp);
                 return value;
             },
             set(newValue) {
                 console.log(`属性${key}的值${value}修改为 -> ${newValue}`);
                 value = newValue;
                 Observer(newValue);
                 dependency.notify();
             }
         })
     })
 }

 // HTML模版解析 - 替换DOM
 function Compile(element, vm) {
     vm.$el = document.querySelector(element);
     const fragment = document.createDocumentFragment();
     let child;
     while (child = vm.$el.firstChild) {
        fragment.append(child);
     }
     console.log(fragment);
     console.log(fragment.childNodes);
     fragment_compile(fragment);
     // 替换文档碎片内容
     function fragment_compile(node) {
         const pattern = /\{\{\s*(\S+)\s*\}\}/;
         if (node.nodeType === 3) {
             console.log(node);
             console.log(node.nodeValue);
             const xxx = node.nodeValue;
             const result_regex = pattern.exec(node.nodeValue);
             if (result_regex) {
                 console.log(node.nodeValue);
                 console.log(result_regex);
                 console.log(vm.$data[result_regex[1]]);
                 const arr = result_regex[1].split('.');
                 const value = arr.reduce((total, current) => total[current], vm.$data);
                 console.log(value);
                 node.nodeValue = xxx.replace(pattern, value);
                 console.log(node.nodeValue);
                 // 创建订阅者
                 new Watcher(vm, result_regex[1], newValue => {
                     node.nodeValue = xxx.replace(pattern, newValue);
                 })
             }
             return
         }
         if (node.nodeType === 1 && node.nodeName === 'INPUT') {
             const attr = Array.from(node.attributes);
             console.log(attr);
             attr.forEach(i => {
                 if (i.nodeName === 'v-model') {
                     console.log(i.nodeValue);
                     const value = i.nodeValue.split('.').reduce((total, current) => total[current], vm.$data);
                     node.value = value;
                     new Watcher(vm, i.nodeValue, newValue => {
                         node.value = newValue;
                     });
                     node.addEventListener('input', e => {
                         // ['more', 'like']
                         const arr1 = i.nodeValue.split('.');
                         // ['more']
                         const arr2 = arr1.slice(0, arr1.length - 1);
                         // vm.$data.more
                         const final = arr2.reduce((total, current) => total[current], vm.$data);
                         // vm.$data.more['like'] = e.target.value
                         final[arr1[arr1.length - 1]] = e.target.value;
                     })
                 }
             })
         }
         node.childNodes.forEach(child => fragment_compile(child));
     }
     vm.$el.appendChild(fragment);
 }

 // 依赖 - 收集和通知订阅者
 class Dependency {
     constructor() {
         this.subscribers = [];
     }
     addSub(sub) {
         this.subscribers.push(sub);
     }
     notify() {
         this.subscribers.forEach(sub => sub.update());
     }
 }

 // 订阅者
 class Watcher {
     constructor(vm, key, callback) {
         this.vm = vm;
         this.key = key;
         this.callback = callback;
         // 临时属性 - 触发getter
         Dependency.temp = this;
         console.log(`用属性${key}创建订阅者`);
         key.split('.').reduce((total, current) => total[current], vm.$data);
         Dependency.temp = null;
     }
     update() {
         const value = this.key.split('.').reduce((total, current) => total[current], this.vm.$data);
         this.callback(value);
     }
 }

 如果帮助到您了,可以留下一个赞👍告诉我 

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐