zoukankan      html  css  js  c++  java
  • Vue源码后记-更多options参数(2)

      写起来感觉都是老三套,AST => render => VNode => patch

      之前是把AST弄完了,对事件和过滤器处理如图:

      render函数也只看这两部分的转换吧!

      首先是el.events,该属性在genData中被处理,这个在之前讲过了!不过,前面没有modifiers,所以,这里可以再看看:

        // name => click
        // handler => {value:'click',modifiers:{self:true,number:true}}
        function genHandler(name, handler) {
            // code...
    
            if (!handler.modifiers) {
                // 无modifiers
            }
            // 处理modifiers 
            else {
                var code = '';
                var genModifierCode = '';
                var keys = [];
                for (var key in handler.modifiers) {
                    // 修饰符部分代码集合
                    if (modifierCode[key]) {
                        genModifierCode += modifierCode[key];
                        // 键盘按键简化
                        if (keyCodes[key]) {
                            keys.push(key);
                        }
                    }
                    // number,trim等 
                    else {
                        keys.push(key);
                    }
                }
                if (keys.length) {
                    // 处理特殊按键的keyCode
                    code += genKeyFilter(keys);
                }
                // Make sure modifiers like prevent and stop get executed after key filtering
                if (genModifierCode) {
                    code += genModifierCode;
                }
                var handlerCode = isMethodPath ?
                    handler.value + '($event)' :
                    isFunctionExpression ?
                    ("(" + (handler.value) + ")($event)") :
                    handler.value;
                return ("function($event){" + code + handlerCode + "}")
            }
        }
    
        function genKeyFilter(keys) {
            return ("if(!('button' in $event)&&" + (keys.map(genFilterCode).join('&&')) + ")return null;")
        }
    
        function genFilterCode(key) {
            var keyVal = parseInt(key, 10);
            if (keyVal) {
                return ("$event.keyCode!==" + keyVal)
            }
            var alias = keyCodes[key];
            return ("_k($event.keyCode," + (JSON.stringify(key)) + (alias ? ',' + JSON.stringify(alias) : '') + ")")
        }

      函数的前半部分会对一些特殊按键的修饰符做处理,包括鼠标按键、键盘按键,以及阻止冒泡与默认事件等。

      其中:

      genModifierCode返回: 

      稍微普及一下target、currentTarget的区别,主要是currentTarget始终指向事件绑定的对象,而target指向事件触发的对象。

      code返回:

      这里强行返回一个number字符串真是奇怪啊!

      完事后,将genModifierCode拼接到code后面,最后return的时候由于handler.value是一个内置事件click,所以handlerCode拼接为click($event)。

      完整的return字符串为:

        "function($event){if(!('button' in $event)&&_k($event.keyCode,"number"))return null;if($event.target !== $event.currentTarget)return null;click($event)}"

      格式化一下:

        (function($event) {
            if (!('button' in $event) && _k($event.keyCode, "number")) return null;
            if ($event.target !== $event.currentTarget) return null;
            click($event)
        })

      至此,事件的render代码处理完毕,作为on属性添加到el上。

      后面会接着处理子节点,由于是表示式,所以直接会被包裹在_s函数中,最后整个AST返回一个_c,参数为tag、data、children,详细过程之前搞过,这里不重复了。

      直接把render => VNode => patch一起看了吧!

      由于proxy的关系,vnode = render.call(vm._renderProxy, vm.$createElement)这个代码的执行过程太长了,不如直接看render函数:

        (function() {
            with(this) {
                return _c('div', {
                    attrs: {
                        "id": "app"
                    }
                }, [_c('div', {
                    on: {
                        "click": function($event) {
                            if (!('button' in $event) && _k($event.keyCode, "number")) return null;
                            if ($event.target !== $event.currentTarget) return null;
                            click($event)
                        }
                    }
                }, [_v("
    " + _s(_f("filter")(computedValue)) + "
    ")])])
            }
        })

      这里唯一比较特殊的是那个filter。

      这里从内到外首先是执行_f函数,这个之前没见过,主要是处理filter:

        Vue.prototype._f = resolveFilter;
    
        function resolveFilter(id) {
            return resolveAsset(this.$options, 'filters', id, true) || identity
        }
    
        function resolveAsset(options, type, id, warnMissing) {
            /* istanbul ignore if */
            if (typeof id !== 'string') {
                return
            }
            var assets = options[type];
            // 返回了定义的filter函数
            if (hasOwn(assets, id)) {
                return assets[id]
            }
            // 驼峰处理
            var camelizedId = camelize(id);
            if (hasOwn(assets, camelizedId)) {
                return assets[camelizedId]
            }
            var PascalCaseId = capitalize(camelizedId);
            if (hasOwn(assets, PascalCaseId)) {
                return assets[PascalCaseId]
            }
            // fallback to prototype chain
            var res = assets[id] || assets[camelizedId] || assets[PascalCaseId];
            // warning...
            return res
        }

      该函数返回了本地定义的fiter函数,即options中的那个函数,然后传入变量computedValue,这个变量在一开始的init中定义了一个Watcher监视,在这里进行调用获取值,执行后面的表达式得到数值2。

      总的来说,filter与computed结合执行过程就是:

        (function /*filter*/ (value) {
            if (!value) {
                return;
            }
            return value * 4;
        })(function /*computed*/ () {
            return this.value * 2
        })()

      下面是on事件,好像没啥讲的,直接把整个on对象按在了data属性里返回一个VNode,看看patch阶段怎么处理那个number字符串。

      我发现我用错了,number这个是用在v-model里面的!好吧,这里会把不认识的字符串默认当成keyCode来处理,所以number会被强行作为判断条件,不过不会报错,也无所谓了。

      简单讲下这里的click事件:

        "click": function($event) {
            if (!('button' in $event) && _k($event.keyCode, "number")) return null;
            if ($event.target !== $event.currentTarget) return null;
            click($event)
        }

      这里有一个_k函数,判断两个参数是否相等:

        Vue.prototype._k = checkKeyCodes;
    
        function checkKeyCodes(eventKeyCode, key, builtInAlias) {
            var keyCodes = config.keyCodes[key] || builtInAlias;
            if (Array.isArray(keyCodes)) {
                return keyCodes.indexOf(eventKeyCode) === -1
            } else {
                return keyCodes !== eventKeyCode
            }
        }

      第二个判断点击事件是否只发生在事件绑定对象上,最后执行click事件的回调函数。

      写得好丑啊!

  • 相关阅读:
    常见运算符_python
    hibernate中的二级缓存
    事务的隔离级别
    java hibernate 一对多和多对多映射关系总结
    hibernate中集合映射总结
    java中静态代码块之我的理解
    select下拉表达设置选中,获取选中项,change
    jquery checkbox设置选中,全选,反选,取值
    javaWeb建立一个简单三层项目具体步骤
    java 异步实现省市联动
  • 原文地址:https://www.cnblogs.com/QH-Jimmy/p/7421804.html
Copyright © 2011-2022 走看看