美文网首页
2. 正规军代码

2. 正规军代码

作者: 飞天御剑流co | 来源:发表于2023-12-24 00:40 被阅读0次

    刚刚已经看完了作者 yyx 的第一次尝试,作者可能发现,唉,好像这种方法行得通,然后在 src 下写了一个功能相对更多的代码实现

    里面的 dev.html 则是运行 src 代码的 example

    由于我折腾了好久也没能将 grunt 跑明白,为了节约时间,决定将代码拷出来,用 rollup 去打包,自己跑一个

    将 require 语法改成 import

    导出的地方也用 es 的语法进行导出

    demo 地址在这里

    然后我们来调试这个代码,看一看这个功能相对多一点的是怎么实现的

    老规矩,先看函数的调用方式

    可以看到,引入 Seed(一个自定义名称的对象) 对象,调用了 Seed.create ,传入对象作为参数,两个变量 msg 和 hello ,还有一个方法 changeMessage

    可以看到,导出的 create 函数就是 main.js 中的 Seed 构造函数

    然后开始拆解这个构造函数,看一看 new 的过程干了什么

    可以看到,和上一篇文章执行的是同一个套路,self 指向自身,获取传入 id 的 dom 下的自定义在标签上的 NodeList , 然后初始化自身的作用域 scope

    上图同样的遍历对象,从函数名可知,此流程是 遍历 els -> 处理 Node 节点 -> 克隆节点上的自定义属性 -> 遍历这些属性 -> 解析指令 -> 如果解析成功,将指令绑定

    下面就是一段给 self.scope 赋值,和上一篇文章一样,赋值触发对象的 set , 然后进行响应式更新

    来先看第一个函数

    可以看到,遍历节点的属性,将属性名和对应的值返回一个对象数组

    处理 attr key

    遍历此数组的每一项去尝试解析指令,看看 vue 提供的语法和用户传入的用法是否能对应的上

    此时的 attr 是这种形式的

    var attr = {
        "name": "sd-text",
        "value": "msg | capitalize"
    }
    

    函数返回前,处理了一系列的逻辑,首先判断了是 sd 开头的指令才向下执行,noprefix 记录了没有前缀的指令名,下文拿 sd-text="msg | capitalize" 举例:

    首先,裁剪掉指令前面的 sd- 前缀,留下纯净的指令信息,再去尝试获取 argIndex 的位置

    argIndex = noprefix.indexOf('-') 
    

    这里是为了判断 sd-on-click="changeMessage | .button" 这种情况,有两个 -

    如下图

    对不同的指令进行不同的处理,以获取到对应的 dirname , 如果是普通指令返回诸如 text 这种,如果是事件监听,返回 dirname 为 on

    之后去获取 directives.js 文件下对应 dirname 作为 key 的值

    处理 attr value

    代码如下

    判断有无管道符号 ?裁剪管道符前面的变量赋值给 key : 直接将 attr.value 赋值给 key

    以上是有无管道符号处理 value 值的区别

    处理完成后,将后续所有管道符号进行处理,返回一个 filters 数组

    处理完 attr.key attr.value 之后,函数返回,返回了一个对象,在 update 属性中,区分了一下是事件监听,还是普通的指令

    进行绑定

    下图是参数

      el.removeAttribute(directive.attr.name)
    

    此函数执行了移除标签上的自定义属性,取指令绑定的值对应的变量也就是 key 属性对应的 msg

        if (!binding) {
            bindings[key] = binding = {
                value: undefined,
                directives: []
            }
        }
    

    尝试直接从 bindings 中获取值,但是我们的 bindings 初始化的时候是一个空值,所以函数会进入 if (!binding) 这段逻辑

        directive.el = el
        binding.directives.push(directive)
    

    给 bindings 对象进行赋值 -> 在 directive 上添加 el 属性,指向绑定的 dom -> 将 directive 直接推送到刚刚 bindings[key] 赋值的新对象的 directives 里面,因为 binding 和 bindings[key] 是引用关系,所以面直接向 directives 添加对应的指令信息

        if (directive.bind) {
            directive.bind(el, binding.value)
        }
    

    上面的分析可知,我们每一个 directive 是没有 bind 属性的所以这段逻辑不会执行

        if (!seed.scope.hasOwnProperty(key)) {
            bindAccessors(seed, key, binding)
        }
    

    判断 scope 是否还没有对应绑定的属性(也就是绑定的 key 还没有被 Object.defineProperty 定义对应的 get set),执行 bindAccessors 函数

    拿刚刚的绑定的 msg 举例,当给 scope.msg 赋值的时候,会触发 set 逻辑,下面是此函数的参数

    首先先给指令上绑定的 value 赋值,后面判断如果 value 存在,尝试执行 filter 逻辑

    因为我们没有定义 customFilter 所以执行 else , 在 Filters.js 文件下

    去获取定义好的函数,将传进来的 hello 字符串首字母变成大写,然后将处理完成的值 return

      directive.update(
              directive.el,
              value,
              directive.argument,
              directive,
              seed
            );
          });
    

    最后执行了指令定义的 update,看函数传参,我们有 dom ,value ,directive 下的参数,directive 本身,seed 实例本身,也就是说,所有的数据都有了,update 也早就定义好了对应的行为,那么此函数调用的时候,便会执行,对应的逻辑,这些逻辑都是简单的操作 dom , 就不再赘述了

    好了,这也就是 vue 0.1 版本做到的,运行时 + 指令 + 响应式 的一个实现了

    本文使用 文章同步助手 同步

    相关文章

      网友评论

          本文标题:2. 正规军代码

          本文链接:https://www.haomeiwen.com/subject/bxoqndtx.html