vue的简单实现

Posted caoruichun

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了vue的简单实现相关的知识,希望对你有一定的参考价值。

因为vue主要是通过数据劫持来实现的,通过getset来完成数据的读取和更新

这里简单实现data,v-model,computed

1模版

    <!DOCTYPE html>
    <html>
    <head>
        <title></title>
    </head>
    <body>
    <div id="app">
        <div>{{a.a}}</div>
        <div>{{c}}</div>
        <input type="text" v-model="c">
        {{hello}}
    </div>
    <script src="./mvvm.js"></script>
    <script type="text/javascript">
    
    let vue = new Vue2({
        el:"#app",
        data:{
            a:{a:1},
            b:[1,2,3],
            c:123123
        },
        computed:{
            hello(){
                return this.a.a+this.c;
            }
        }
    })
    </script>
    </body>
    </html>

js

function Vue2(options = {}) {
    this.$options = options;
    let data = this._data = this.$options.data;
    observe(data);
    // this代理了this._data
    for (let key in data) {
        Object.defineProperty(this, key, {
            enumerable: true,
            get() {
                return this._data[key];
            },
            set(newVal) {
                this._data[key] = newVal
            }
        })
    }
initComputed.call(
this);//初始化computed

new Compile(options.el, this) } //计算属性的实现 function initComputed(){ let vm = this; let computed = this.$options.computed; Object.keys(computed).forEach(function (k) { Object.defineProperty(vm,k,{
        //如果给的是函数那么调取函数,如果是对象那么获取对象的get方法 get:
typeof computed[k] === ‘function‘?computed[k]:computed[k].get(), set(){} }) }) } function Compile(el, vm) { // el表示替换的范围 vm.$el = document.querySelector(el); let frament = document.createDocumentFragment();//文案碎片 while (child = vm.$el.firstChild) {//将app中的内容,移入到内存中 frament.appendChild(child) } //查找节点中的{{}} replace(frament); function replace(frament) { Array.from(frament.childNodes).forEach(function (node) { let text = node.textContent; let reg = /\{\{(.*)\}\}/; //判断{{}} if (node.nodeType === 3 && reg.test(text)) { console.log(RegExp.$1)//取出花括号中的变量 let arr = RegExp.$1.split(‘.‘);//[a,a],[b],[c] let val = vm; arr.forEach(function (k) { val = val[k] }) new Watcher(vm,RegExp.$1,function (newVal) { node.textContent = text.replace(/\{\{(.*)\}\}/, newVal) }) // node.textContent = text.replace(/\{\{(.*)\}\}/, val) } //判断v-model if(node.nodeType ===1 /*元素节点*/ ){ let nodeAttrs = node.attributes;//获取属性 console.log(nodeAttrs) Array.from(nodeAttrs).forEach(function (attr) { console.log(attr) let name = attr.name; let exp = attr.value; if(name.indexOf(‘v-‘)==0){ node.value = vm[exp]; } new Watcher(vm,exp,function (newVal) { node.value = newVal; }); node.addEventListener(‘input‘,function (e) { let newVal = e.target.value; vm[exp] = newVal; }) }) } if (node.childNodes) { replace(node) } }); } vm.$el.appendChild(frament) } //观察者 给队形增加Object.defineProperty // 数据劫持 function Observe(data) { let dep = new Dep(); for (let key in data) { let val = data[key]; observe(val); Object.defineProperty(data, key, { enumerable: true, get() { Dep.target&&dep.addSub(Dep.target);//监控值的变化 return val }, set(newVal) { if (newVal === val) { return } val = newVal; observe(newVal) dep.notify()//让所有的watch的update方法执行 } }) } } function observe(data) { if (typeof data !== "object") return; return Observe(data) } //发布订阅 function Dep() { this.subs = [] } Dep.prototype.addSub = function (sub) {//订阅 this.subs.push(sub) } Dep.prototype.notify = function () { this.subs.forEach(sub=>sub.update()) } function Watcher(vm,exp,fn) { this.vm = vm; this.exp = exp; this.fn = fn; Dep.target = this; let val = vm; let arr = exp.split(‘.‘) arr.forEach(function (k) { val = val[k] }) Dep.target = null; } Watcher.prototype.update=function () { let val = this.vm; let arr = this.exp.split(‘.‘); arr.forEach(function (k) { val = val[k] }) this.fn(val) }

 

以上是关于vue的简单实现的主要内容,如果未能解决你的问题,请参考以下文章

vue实现简单的过滤器

VSCode自定义代码片段——.vue文件的模板

代码片段 - Golang 实现简单的 Web 服务器

VSCode自定义代码片段1——vue主模板

VSCode自定义代码片段11——vue路由的配置

VSCode自定义代码片段11——vue路由的配置