资讯专栏INFORMATION COLUMN

BiuJS[v1.0]说明文档(4):$if 指令

_ang / 3312人阅读

摘要:是一个轻巧的框架它实现了数据的双向绑定并提供一些基本的指令帮助你提升效率,比如,,,,是的,如你所见,以开头的指令是它的独特标识行左右的代码量,让应用的开发和加载的一瞬完成仓库指令往下看之前,请大家沐浴更衣,因为我要讲的指令了中的已经被占用

BiuJS
BiuJS是一个轻巧的mvvm框架
它实现了数据的双向绑定
并提供一些基本的指令帮助你提升效率,比如$for$model$if$click$style
是的,如你所见,以$开头的指令是它的独特标识
1000行左右的代码量,让应用的开发和加载biu的一瞬完成
BiuJS仓库: https://github.com/veedrin/biu
$指令

往下看之前,请大家沐浴更衣,因为我要讲BiuJS的$指令了

{{vipName}}

JavaScript中的$已经被jQuery占用了,现在html标签中的$也被BiuJS占用了

我已经为$指令申请了专利,是真的(假的)

Compiler.prototype.compileElement = function(ele) {
        let self = this;
        Array.from(ele.attributes).forEach((attr) => {
            let name = attr.name;
            let type;
            if (name.indexOf("$") === 0) {
                type = name;
            } else {
                return;
            }
            let exp = attr.value;
            let handler = self[type];
            if (handler) {
                handler.call(self, ele, exp, self.vm);
            }
            ele.removeAttribute(name);
        });
    };

因为每一个指令的编译规则都是不一样的,所以我们要提取出$指令,然后交给相应的函数处理

注意,handler需要用call方法调用,否则handler内部的this不会指向Compiler构造函数

$for

编写html的时候,我们经常会遇到DOM结构一样但数据不一样的情况

这时候如果有一个工具,能够遍历数据,然后插入到相应份拷贝的DOM结构中,简直太好了

$for指令就是为这个而生的

我们先来看$for指令的用法

这里的itemindex可以随意更换成你顺手的单词,只需要记住item是总数据的一项,如果需要索引则要加一对括号

让我们提取其中的表达式

let regIterate = /^(([w,s]+))/;

let split = exp.split("in");
let expItem = split[0].trim();
let expList = split[1].trim();
let expIndex;

if (regIterate.test(expItem)) {
    let match = regIterate.exec(expItem)[1];
    split = match.split(",");
    expItem = split[0].trim();
    expIndex = split[1].trim();
}

目前$for指令有一个缺陷,它需要用一层div包裹起来,虽然页面效果是一样的,但毕竟破坏了DOM结构。如果有好的解决方案,可以在文末留言

let divWrap = document.createElement("div");

ele.parentNode.insertBefore(divWrap, ele);
ele.parentNode.removeChild(ele);

ele.removeAttribute("$for");
let cloneOrigin = ele.cloneNode(true);

先插入一个div,然后把元素移除

这里需要克隆一个元素的副本,因为之后数据变更,我们要拿这个副本去重新编译

因为子元素可能会(应该是一定会)使用带有itemindex的胡子模板

所以我们要把它们都替换成实际的值

let regItem = new RegExp(`{{${expItem}}}`, "g");
let regIndex = new RegExp(`{{${expIndex}}}`, "g");

if (child.nodeType === 3 && !regBlank.test(child.textContent)) {
    let content = child.textContent.trim();
    let str = self.replace$for(content, item, regItem);

    if (expIndex) {
        str = self.replace$for(str, index, regIndex);
    }
    child.textContent = str;
}

replace$for和文本编译是差不多的,算是简化版

Compiler.prototype.replace$for = function(content, value, reg) {
    let i = 0;
    let match;
    let text;
    let temp = "";

    while (match = reg.exec(content)) {
        if (i < match.index) {
            text = content.slice(i, match.index);
            temp += text;
        }
        i = reg.lastIndex;
        temp += value;
    }
    if (i < content.length) {
        text = content.slice(i);
        temp += text;
    }
    return temp;
};

但是到这里还没完,因为$click指令有可能把itemindex作为参数传进自己的函数

itemindex并不在data里面,不能用execChain方法获取实际的值

所以在这里一并把它给编译了

let regCall = /((.*))$/;

Array.from(child.attributes).forEach((attr) => {
    if (attr.name === "$click") {
        let exp = attr.value;
        let match = regCall.exec(exp);

        if (match) {
            let funcName = exp.slice(0, exp.indexOf("("));
            if (match[1] === expItem) {
                attr.value = `${funcName}("${item}")`;
            } else if (match[1] === expIndex) {
                attr.value = `${funcName}("${index}")`;
            }
        }
    }
});

最后是订阅器的回调

做法就是先移除div里面的所有子元素,遍历一下数据,看看新值有几项,然后拿来副本,照上面相应的编译几次

new Watcher(exp, vm, (newValue) => {
    Array.from(divWrap.childNodes).forEach((child) => {
        divWrap.removeChild(child);
    });

    newValue.forEach((item, index) => {
        let cloneNode = cloneOrigin.cloneNode(true);
        self.compile$for(cloneNode, expItem, item, expIndex, index);
        divWrap.appendChild(cloneNode);
    });
});
写在后面

以上就是编译$for指令的过程

欢迎到BiuJS仓库: https://github.com/veedrin/biu了解详情

更欢迎StarFork

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/90338.html

相关文章

  • BiuJS[v1.0]说明文档(3):文本编译

    摘要:如此循环,直到结束如果循环结束之后,比字符串的长度要小,那说明后面还有文本匹配失败了。 showImg(https://segmentfault.com/img/remote/1460000012478667?w=1920&h=926); BiuJS BiuJS是一个轻巧的mvvm框架它实现了数据的双向绑定并提供一些基本的指令帮助你提升效率,比如$for,$model,$if,$cli...

    lucas 评论0 收藏0
  • BiuJS[v1.0]说明文档(1):总体结构

    摘要:是一个轻巧的框架它实现了数据的双向绑定并提供一些基本的指令帮助你提升效率,比如,,,,是的,如你所见,以开头的指令是它的独特标识行左右的代码量,让应用的开发和加载的一瞬完成仓库启动首先我们来看一下是如何启动的是的挂载点,它决定在多大范围的树 showImg(https://segmentfault.com/img/remote/1460000012478667?w=1920&h=926...

    崔晓明 评论0 收藏0
  • BiuJS[v1.0]说明文档(2):数据劫持

    摘要:是一个轻巧的框架它实现了数据的双向绑定并提供一些基本的指令帮助你提升效率,比如,,,,是的,如你所见,以开头的指令是它的独特标识行左右的代码量,让应用的开发和加载的一瞬完成仓库订阅清单前文说到提供了一个强大的接口我们就用它来劫持数据不过在此 showImg(https://segmentfault.com/img/remote/1460000012478667?w=1920&h=926...

    Terry_Tai 评论0 收藏0
  • 是时候拥有一个你自己的命令行工具了

    摘要:本篇博客主要介绍了如何使用以及从零开始,创建属于自己的命令行工具。一分钟体验首先我们先花一分钟的时间,体验一下创建自己的命令行工具是什么感觉。或者是一个环境下的命令行接口解决方案。代表了这个工具向用户暴露的命令行指令。 本篇博客主要介绍了如何使用commander, inquirer以及chalk从零开始,创建属于自己的命令行工具。 0. 一分钟体验 首先我们先花一分钟的时间,体验一下...

    int64 评论0 收藏0
  • gulp自动化打包(上)

    摘要:自动化打包上文章概述本文分为上下两篇,上篇主要介绍一些常用的插件也是此次打包主要用的插件,而下篇主要以一个项目为例,从本地出合适的版本,压缩合并到最后打成包,发送至指定目录,做一个全面的演示。 gulp自动化打包(上) 文章概述 本文分为上下两篇,上篇主要介绍一些常用的gulp插件(也是此次打包主要用的gulp插件),而下篇主要以一个demo项目为例,从本地checkout出合适的g...

    roland_reed 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<