【Vue温故】粗略实现VUE源码Computed

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

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <div id="app"></div>
</body>
<script>

    //计算属性:解决模板中复杂的逻辑运算及复用的问题
    //计算属性只有在内部逻辑依赖的数据发生变化的时候才会被再次调用
    //计算属性会缓存其依赖的上一次计算出的数据结果
    //多次复用一个相同值得数据,计算属性只调用一次
    let Vue = (function () {
        var reg_var = /\{\{(.+?)\}\}/g,
            computedData = {},
            dataPool = {};
        //参数传递处理
        var Vue = function (options) {
            this.$el = document.querySelectorAll(options.el)[0];
            this.$data = options.data();
            this._init(this, options.computed, options.template);
        }
        //初始化
        Vue.prototype._init = function (vm, computed, template) {
            //data值拦截
            dataReactive(vm);
            //computed拦截
            computedReactive(vm, computed);
            //渲染
            render(vm, template);
        }
        //模板编译渲染
        function render(vm, template) {
            var container = document.createElement('div'),
                _el = vm.$el;
            container.innerHTML = template;
            var domTree = _compileTemplate(vm, container);
            _el.appendChild(domTree);
        }
        //计算属性拦截
        function computedReactive(vm, computed) {
            _initComputedData(vm, computed);
            for (var key in computedData) {
                (function (key) {
                    Object.defineProperty(vm, key, {
                        get() {
                            return computedData[key].value;
                        },
                        set(newValue) {
                            computedData[key].value = newValue;
                        }
                    })
                })(key)
            }
        }
        //data属性绑定拦截
        function dataReactive(vm) {
            var _data = vm.$data;
            for (var key in _data) {
                (function (key) {
                    Object.defineProperty(vm, key, {
                        get() {
                            return _data[key];
                        },
                        set(newValue) {
                            _data[key] = newValue;
                            //对data记录进行缓存
                            update(vm, key);
                            //值改变去判断是不是computed依赖的值变了
                            _updateComputeData(vm, key, function (key) {
                                
                                update(vm, key)
                            })
                        }
                    })
                })(key);
            }
        }
        //完成模板渲染以及记录和data有绑定的dom
        function _compileTemplate(vm, container) {
            var allNodes = container.getElementsByTagName('*'),
                nodeItem = null;
            for (var i = 0; i < allNodes.length; i++) {
                nodeItem = allNodes[i];
                var matched = nodeItem.textContent.match(reg_var);
                if (matched) {
                    nodeItem.textContent = nodeItem.textContent.replace(reg_var, function (node, key) {
                        console.log(vm)
                        dataPool[key.trim()] = nodeItem;
                        return vm[key.trim()]
                    })
                }
            }
            return container;
        }
        //构建computed处理对象,记录计算结果的值和计算函数及牵扯到的data对象
        function _initComputedData(vm, computed) {
            for (var key in computed) {

                var descriptor = Object.getOwnPropertyDescriptor(computed, key),
                    descriptorFn = descriptor.value.get
                        ? descriptor.value.get
                        : descriptor.value
                computedData[key] = {};
                computedData[key].value = descriptorFn.call(vm);
                computedData[key].get = descriptorFn.bind(vm);
                computedData[key].dep = _collectDep(descriptorFn)
            }
        }
        //分析出依赖了那些data中的值
        function _collectDep(fn) {
            var _collection = fn.toString().match(/this.(.+?)/g);
            if (_collection.length > 0) {
                for (var i = 0; i < _collection.length; i++) {
                    _collection[i] = _collection[i].split('.')[1];
                }
            }
            return _collection;
        }
        //当依赖的data值发生改变时
        function _updateComputeData(vm, key, update) {
            var _dep = null;
            for (var _key in computedData) {
                _dep = computedData[_key].dep;
                for (var i = 0; i < _dep.length; i++) {
                    //如果要更改的值是被computed依赖的值
                    if (_dep[i] === key) {
                        //计算的最终结果给到data属性值
                        vm[_key] = computedData[_key].get();
                        //数据缓存
                        update(_key)
                    }
                }
            }
        }
        function update(vm, key) {
            dataPool[key].textContent = vm[key];
            console.log( dataPool)
        }
        
        return Vue;
    })()

    let vm =new Vue({
        el: '#app',
        template:
            `
            <span>{{a}}</span>
            <span>+</span>
            <span>{{b}}</span>
            <span>=</span>
            <span>{{total}}</span>
            `,

        data() {
            return {
                a: 1,
                b: 2
            }
        },
        computed: {
            total() {
                console.log('computed total');
                return this.a + this.b;
            }
        },
    })
    console.log(vm.total);
    console.log(vm.total);
    console.log(vm.total);
    console.log(vm.total);
    // vm.a = 100;
    // vm.b = 200;
    console.log(vm.total);
    console.log(vm.total);
</script>

</html>

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值