vue2.0仿照,简单实现

参考:[ http://www.jb51.net/article/107936.htm]


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

</head>
<body>

<div id="id1" style="width:800px; height:400px; background-color:#F23">
    <div id="id2" style="width:400px; height:300px; background-color:#0F8; display:none;">
    </div>
</div>


</body>

<!--<script type="text/javascript" src="https://code.jquery.com/jquery-1.12.4.js"></script>-->
<script type="text/javascript">
    function VNode(tag, data, children, text) {
        return {
            tag: tag,
            data: data,
            children: children,
            text: text
        }
    }

    class Vue {
        constructor(options) {
            debugger
            this.$options = options
            this._data = options.data
            Object.keys(options.data).forEach(key => this._proxy(key))
            observer(options.data)
            const vdom = watch(this, this._render.bind(this), this._update.bind(this))
            console.log(vdom)
        }
        _proxy(key) {
            const self = this
            Object.defineProperty(self, key, {
                configurable: true,
                enumerable: true,
                get: function proxyGetter () {
                    return self._data[key]
                },
                set: function proxySetter (val) {
                    self._data.text = val
                }
            })
        }
        _update() {
            console.log("我需要更新");
            const vdom = this._render.call(this)
            console.log(vdom);
        }
        _render() {
            return this.$options.render.call(this)
        }
        __h__(tag, attr, children) {
            return VNode(tag, attr, children.map((child)=>{
                if(typeof child === 'string'){
                    return VNode(undefined, undefined, undefined, child)
                }else{
                    return child
                }
            }))
        }
        __toString__(val) {
            return val == null ? '' : typeof val === 'object' ? JSON.stringify(val, null, 2) : String(val);
        }
    }

    function observer(value, cb){
        Object.keys(value).forEach((key) => defineReactive(value, key, value[key] , cb))
    }

    function defineReactive(obj, key, val, cb) {
        const dep = new Dep()
        Object.defineProperty(obj, key, {
            enumerable: true,
            configurable: true,
            get: ()=>{
                if(Dep.target){
                    dep.add(Dep.target)
                }
                return val
            },
            set: newVal => {
                if(newVal === val)
                    return
                val = newVal
                dep.notify()
            }
        })
    }
    function watch(vm, exp, cb){
        Dep.target = cb
        return exp()
    }

    class Dep {
        constructor() {
            this.subs = []
        }
        add(cb) {
            this.subs.push(cb)
        }
        notify() {
            this.subs.forEach((cb) => cb())
        }
    }
    Dep.target = null


    var demo = new Vue({
        el: '#demo',
        data: {
            text: "before",
        },
        render(){
            return this.__h__('div', {}, [
                this.__h__('span', {}, [this.__toString__(this.text)])
            ])
        }
    })


    setTimeout(function(){
        demo.text = "after"
    }, 3000)
</script>
</html>
posted @ 2017-08-17 15:05  _白马非马  阅读(352)  评论(0编辑  收藏  举报