• 运行avalon.define()发生的事情


     
    avalon.define = function(id, factory) {
        var $id = id.$id || id
        if (!$id) {
            log("warning: vm必须指定$id")
        }
        if (VMODELS[$id]) {
            log("warning: " + $id + " 已经存在于avalon.vmodels中")
        }
        if (typeof id === "object") {
            var model = modelFactory(id)
        } else {
            var scope = {
                $watch: noop
            }
            factory(scope) //得到所有定义
            model = modelFactory(scope) //偷天换日,将scope换为model
            stopRepeatAssign = true
            factory(model)
            stopRepeatAssign = false
        }
        model.$id = $id
        return VMODELS[$id] = model
    }
    avalon.define源代码

    运行这段代码的过程中,会把id在modelFactory中进行加工

    function modelFactory(source, $special, $model) {
        if (Array.isArray(source)) {
            var arr = source.concat()
            source.length = 0
            var collection = Collection(source)
            collection.pushArray(arr)
            return collection
        }
        if (typeof source.nodeType === "number") {
            return source
        }
        if (source.$id && source.$events) { //fix IE6-8 createWithProxy $val: val引发的BUG
            return source
        }
        if (!Array.isArray(source.$skipArray)) {
            source.$skipArray = []
        }
        source.$skipArray.$special = $special || {} //强制要监听的属性
        var $vmodel = {} //要返回的对象, 它在IE6-8下可能被偷龙转凤
        $model = $model || {} //vmodels.$model属性
        var $events = {} //vmodel.$events属性
        var watchedProperties = {} //监控属性
        var initCallbacks = [] //初始化才执行的函数
        for (var i in source) {
            (function(name, val) {
                $model[name] = val
                if (!isObservable(name, val, source.$skipArray)) {
                    return //过滤所有非监控属性
                }
                //总共产生三种accessor
                $events[name] = []
                var valueType = avalon.type(val)
                var accessor = function(newValue) {
                    var name = accessor._name
                    var $vmodel = this
                    var $model = $vmodel.$model
                    var oldValue = $model[name]
                    var $events = $vmodel.$events
    
                    if (arguments.length) {
                        if (stopRepeatAssign) {
                            return
                        }
                        //计算属性与对象属性需要重新计算newValue
                        if (accessor.type !== 1) {
                            newValue = getNewValue(accessor, name, newValue, $vmodel)
                        }
                        if (!isEqual(oldValue, newValue)) {
                            $model[name] = newValue
                            if ($events.$digest) {
                                if (accessor.pedding)
                                    return
                                accessor.pedding = true
                                setTimeout(function() {
                                    notifySubscribers($events[name]) //同步视图
                                    safeFire($vmodel, name, $model[name], oldValue) //触发$watch回调
                                    accessor.pedding = false
                                })
                            } else {
                                notifySubscribers($events[name]) //同步视图
                                safeFire($vmodel, name, newValue, oldValue) //触发$watch回调
                            }
                        }
                    } else {
                        if (accessor.type === 0) { //type 0 计算属性 1 监控属性 2 对象属性
                            //计算属性不需要收集视图刷新函数,都是由其他监控属性代劳
                            return $model[name] = accessor.get.call($vmodel)
                        } else {
                            collectSubscribers($events[name]) //收集视图函数
                            return accessor.svmodel || oldValue
                        }
                    }
                }
                //总共产生三种accessor
                if (valueType === "object" && isFunction(val.get) && Object.keys(val).length <= 2) {
                    //第1种为计算属性, 因变量,通过其他监控属性触发其改变
                    accessor.set = val.set
                    accessor.get = val.get
                    accessor.type = 0
                    initCallbacks.push(function() {
                        var data = {
                            evaluator: function() {
                                data.element = null
                                data.type = new Date - 0
                                $model[name] = accessor.get.call($vmodel)
                            },
                            element: head,
                            type: new Date - 0,
                            handler: noop,
                            args: []
                        }
                        Registry[expose] = data
                        accessor.call($vmodel)
                        delete Registry[expose]
                    })
                } else if (rcomplexType.test(valueType)) {
                    //第2种为对象属性,产生子VM与监控数组
                    accessor.type = 2
                    accessor.valueType = valueType
                    initCallbacks.push(function() {
                        var svmodel = modelFactory(val, 0, $model[name])
                        accessor.svmodel = svmodel
                        svmodel.$events[subscribers] = $events[name]
                    })
                } else {
                    accessor.type = 1
                    //第3种为监控属性,对应简单的数据类型,自变量
                }
                accessor._name = name
                /*给需要监控的属性添加set和get方法*/
                watchedProperties[name] = accessor
            })(i, source[i])
        }
    
        $$skipArray.forEach(function(name) {
            delete source[name]
            delete $model[name] //这些特殊属性不应该在$model中出现
        })
    /* 下面方法是给属性生成如下格式:
     * var descriptorFactory = W3C ? function(obj) {
        var descriptors = {}
        for (var i in obj) {
            descriptors[i] = {
                get: obj[i],
                set: obj[i],
                enumerable: true,
                configurable: true
            }
        }
        return descriptors
    } : function(a) {
        return a
    }
     */
        $vmodel = defineProperties($vmodel, descriptorFactory(watchedProperties), source) //生成一个空的ViewModel
        for (var name in source) {
            if (!watchedProperties[name]) {
                $vmodel[name] = source[name]
            }
        }
        //添加$id, $model, $events, $watch, $unwatch, $fire
        $vmodel.$id = generateID()
        $vmodel.$model = $model
        $vmodel.$events = $events
        for (var i in EventBus) {
            var fn = EventBus[i]
            if (!W3C) { //在IE6-8下,VB对象的方法里的this并不指向自身,需要用bind处理一下
                fn = fn.bind($vmodel)
            }
            $vmodel[i] = fn
        }
    
        if (canHideOwn) {
            Object.defineProperty($vmodel, "hasOwnProperty", {
                value: function(name) {
                    return name in this.$model
                },
                writable: false,
                enumerable: false,
                configurable: true
            })
    
        } else {
            $vmodel.hasOwnProperty = function(name) {
                return name in $vmodel.$model
            }
        }
        initCallbacks.forEach(function(cb) { //收集依赖
            cb()
        })
        return $vmodel
    }
    just do myself
  • 相关阅读:
    [转载]--python3.6 错误: ModuleNotFoundError:No module named "Crypto"
    [笔记]--RedHat6.5使用CentOS的yum源
    [笔记]--Linux公社,想要的都在里面
    [笔记]--vsftpd配置教程
    Vue 中 axios 配置使用
    Element-ui自定义主题换肤
    vue-cli项目打包需要修改的路径问题
    cookie和session 以及 localStorage和sessionStorage之间的区别和应用场景
    正则表达式
    详解-vue项目中的文件和目录
  • 原文地址:https://www.cnblogs.com/rookieCat/p/4633434.html
Copyright © 2020-2023  润新知