• 手撕Vue-编译指令数据


    经过上一篇的分析,完成了查找指令和模板的功能,接下来就是编译指令的数据了。

    所以本章节主要处理的方法则是 buildElement 方法,我们先分析一下我们所拿到的数据在进行编码,这样会更加清晰一些。

    我将 name, value 打印出来,分别对应的值是 name: v-model, value: name,在今后我们的命令中可不止只有 v-model,还有 v-text、v-html、v-on 等等,所以我们需要对这些指令进行分类,然后再进行编译。

    所以我这里特意定义了一个工具类叫 CompilerUtil,用来处理指令的分类,代码如下:

    let CompilerUtil = {
        /**
         * 处理 v-model 指令
         * @param node 当前元素
         * @param value 指令的值
         * @param vm Nue 的实例对象
         */
        model: function (node, value, vm) {
        },
        html: function (node, value, vm) {
        },
        text: function (node, value, vm) {
        }
    }

    然后我们在 buildElement 方法中调用这个方法,代码如下:

    // 解构 name
    let [, directive] = name.split('-');
    // v-model -> [v, model]
    
    // 2.根据指令名称, 调用不同的处理函数
    CompilerUtil[directive](node, value, this.vm);

    这样我们就可以根据指令的名称,调用不同的处理函数了。

    接下来我们就来处理 v-model 指令,代码如下:

    /**
     * 处理 model 指令
     * @param node 当前元素
     * @param value 指令的值
     * @param vm Nue 的实例对象
     */
    model: function (node, value, vm) {
        node.value = vm.$data[value];
    },

    这样我们就可以将数据渲染到页面上了,打开浏览器,可以看到效果如下:

    image-20231015171034901

    v-model 指令已经可以正常使用了,但是还有问题,就是我们的数据结构目前是比较简单的,那么如果我们的数据是一个对象呢,例如:

    image-20231015172334067

    time: {
        h: 10,
        m: 10,
        s: 10
    }

    在用 input 绑定 v-model 进行渲染发现,只有第一个 input 能够正常渲染,其他的 input 都是 undefined,这是为什么呢?

    "text" v-model="time.h">
    
    

    那么这里就要去看一下我们 model 方法的实现了,如果是 time.h,value 等于的值为 time.h, 然后我们在执行 vm.$data[value] 就变为了 vm.$data[time.h], 正常的获取这种数据结构的方式应该是先 vm.$data[time] 拿到 time 对象,然后再 time[h] 拿到 h 的值,所以我们需要对这种数据结构进行处理,为了已维护,我这里单独抽离了一个方法出来进行处理获取 value,方法名字叫做 getValue,代码如下:

    getValue(vm, value) {
        // time.h --> [time, h]
        return value.split('.').reduce((data, currentKey) => {
            // 第一次执行: data=$data, currentKey=time
            // 第二次执行: data=time, currentKey=h
            return data[currentKey];
        }, vm.$data);
    },

    reduce 方法被用于迭代这个字符串数组。它接受一个回调函数,这个回调函数在每次迭代中被调用。在这个回调函数中,data 是上一次迭代的结果,而 currentKey 是当前迭代的数组元素(键路径中的一个部分)在每次迭代中,回调函数通过 data[currentKey] 的方式访问嵌套对象的属性,然后将这个属性的值作为下一次迭代的 data, 最终,reduce 方法将遍历整个键路径,直到达到最深层的属性,然后返回该属性的值。这样我们就可以正常的获取到数据了,最后在改造一下之前 model 方法获取值的地方,调用下刚刚编写的 getValue 方法即可:

    model: function (node, value, vm) {
        node.value = this.getValue(vm, value);
    },

    再次打开浏览器,可以看到效果如下:

    image-20231015172812038

    这个搞定之后,我们紧接着把 v-html 和 v-text 也搞定,代码基本上都是一样的,只是渲染的方式不一样,代码如下:

    /**
     * 处理 html 指令
     * @param node 当前元素
     * @param value 指令的值
     * @param vm Nue 的实例对象
     */
    html: function (node, value, vm) {
        node.innerHTML = this.getValue(vm, value);
    },
    /**
     * 处理 text 指令
     * @param node 当前元素
     * @param value 指令的值
     * @param vm Nue 的实例对象
     */
    text: function (node, value, vm) {
        node.innerText = this.getValue(vm, value);
    }

    编写测试代码:

    image-20231015173151943

    html: `<div>我是divdiv>`,
    text: `<div>我是divdiv>`

    编写HTML代码:

    <div v-html="html">abcdiv>
    <div v-text="text">123div>

    打开浏览器,可以看到效果如下:

    image-20231015173252270


    __EOF__

  • 本文作者: BNTang
  • 本文链接: https://www.cnblogs.com/BNTang/p/17765874.html
  • 关于博主: 评论和私信会在第一时间回复。或者直接私信我。
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
  • 声援博主: 如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。
  • 相关阅读:
    java的Integer中也会有缓存
    SpringBoot2.0数据访问之整合数据源(Druid)
    JavaScript从入门到精通系列第三十七篇:详解JavaScript中文档的加载顺序
    小样本目标检测:ECEA: Extensible Co-Existing Attention for Few-Shot Object Detection
    C++ map和hashmap用法
    golang的channel实现原理
    进程通信的方式
    vscode用密钥文件连接ssh:如果一直要输密码怎么办
    安装编译openssl支持https访问
    BGP——6种邻居状态讲解
  • 原文地址:https://www.cnblogs.com/BNTang/p/17765874.html