手写实现 Vue 1.0 源码原理

  • Vue 1.0 源码原理

原理

  • 直接上代码
    ~~本人自己练习 大神勿喷 ~~
// xxVue.js

// 属性响应
function define (obj, key, val) {
    observable(val)

    const dep = new Dep()
    Object.defineProperty(obj, key, {
        get() {
            console.log('get', val);
            Dep.target && dep.addDep(Dep.target)
            return val
        },
        set(newval) {
            if( newval != val) {
                console.log('set', newval);
                observable(val)
                val = newval

                dep.notfiy()
            }
        }

    })
}

// 对象响应式处理
function observable(obj) {
    if (typeof obj != 'object' || obj == null) {
        return
    }

    // 每次生成一个劫持监听
    new Observe(obj)
}

// 代理
function proxy(vm, type) {
    Object.keys(vm[type]).forEach(key => {
        Object.defineProperty(vm, key ,{
            get () {
                return vm.$data[key]
            },

            set (v) {
                vm.$data[key] = v
            }
        })
    })
    
}

// 创建构造函数
class Zvue {
    constructor (options) {
        // 保存选项
        this.$options = options

        this.$data = options.data

        this.$methods = options.methods

        // 响应话处理
        observable(this.$data)

        // 代理
        proxy(this,'$data')
        proxy(this,'$methods')
        new Complie("#app", this)
    }

    
}

// 数据劫持 
class Observe {

    constructor (value) {
        this.value = value

        this.walk(this.value)
    }
    
    walk(obj) {
        Object.keys(obj).forEach(key => define(obj, key, obj[key]))
    }

}

// 解析渲染
class Complie {
    constructor(el, vm) {
        this.$vm = vm

        this.$el = document.querySelector(el)

        // 编译模版
        if(this.$el) {
            this.complie(this.$el)
        }
    }

    complie(el) {
        // 递归遍历
        
        el.childNodes.forEach( node => {
            // 判断其类型
            if(this.isElement(node)) {
                console.log('编译原属',node.nodeName);
                this.complieElement(node)
            } else if(this.isInter(node)) { //
                console.log('差值文本',node.textContent);
                this.complieText(node)
            } 
             
            if (node.childNodes) {
                this.complie(node)
            }
        })

    }

    isElement(node) {
        return node.nodeType === 1
    }

    isInter(node) {
        return node.nodeType == 3 && /\{\{(.*)\}\}/.test(node.textContent)
    }

    complieText(node) {
        this.update(node, RegExp.$1, 'text')
    }
    
    complieElement(node) {
        console.log(node.attributes);
        
        const attrs = node.attributes

        Array.from(attrs).forEach( item => {
            const names = item.name
            const exp = item.value
            if(this.isDrivet(item)) {
                console.log(item.name.split('z-'));
                const _attr = names.split('z-')[1]
                // 如果有 执行 对应指令函数
                this[_attr] && this[_attr](node, exp)
            } else if(this.isMethdos(item)) {
                const _attr = names.split('@')[1]
                // 如果有 执行 对应指令函数
                this[_attr] && this[_attr](node, exp, this)
            }
        })
    }

    textUpdater(node, val) {
        node.textContent =  val
    }

    text (node, exp) {
        this.update(node, exp, 'text')
    }

    html(node,exp) {
        this.update(node, exp, 'html')
    }
    htmlUpdater(node, val) {
        node.innerHTML = val
    }

    model(node,exp) {
        console.log(this);
        var vm = this
        node.addEventListener("input", (_attr,a) => {
            vm.$vm[exp] = _attr.target.value
        })
        
    }

    click(node, exp) {
        console.log(this);
        var vm = this
        node.addEventListener("click", () => {
            vm.$vm[exp]()
        })
    }

    isDrivet(node) {
        return node.name.indexOf('z-') == 0
    }

    isMethdos(node) {
        return node.name.indexOf('@') == 0
    }

    // 所有动态绑定 需要创建一个watcher是咧
    update(node, exp, dir) {
        // 初始化
        const fn = this[dir+ 'Updater']
        fn && fn(node, this.$vm[exp])
        // 更新

        new watcher(this.$vm, exp, function(val) {
            fn && fn(node, val)
        })
    }

}

// watcher
class watcher {
    constructor(vm, key, updatefn) {
        this.$vm = vm
        this.$key = key
        this.$updatefn = updatefn

        Dep.target = this
        this.$vm[this.$key]
        Dep.target = null
    }

    // 管家调用
    update() {
        this.$updatefn.call(this.$vm, this.$vm[this.$key])
    }
}

// Dep
class Dep {
    constructor() {
        this.deps = []
    }
    // 收集
    addDep(watchers) {
        this.deps.push(watchers)
    }
    // 通知
    notfiy () {
        this.deps.forEach( watcher => watcher.update())
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值