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) }

优质内容筛选与推荐>>
1、Python中字符串的Format用法。
2、网上购物族的福音!不用在为买电脑和数码产品发愁
3、在Postman中使用不受信任的SSL证书
4、常用模块学习(六)
5、Java的字符串转int算法


长按二维码向我转账

受苹果公司新规定影响,微信 iOS 版的赞赏功能被关闭,可通过二维码转账支持公众号。

    阅读
    好看
    已推荐到看一看
    你的朋友可以在“发现”-“看一看”看到你认为好看的文章。
    已取消,“好看”想法已同步删除
    已推荐到看一看 和朋友分享想法
    最多200字,当前共 发送

    已发送

    朋友将在看一看看到

    确定
    分享你的想法...
    取消

    分享想法到看一看

    确定
    最多200字,当前共

    发送中

    网络异常,请稍后重试

    微信扫一扫
    关注该公众号





    联系我们

    欢迎来到TinyMind。

    关于TinyMind的内容或商务合作、网站建议,举报不良信息等均可联系我们。

    TinyMind客服邮箱:support@tinymind.net.cn