解析 DOM 元素里的复杂属性值(上)

在设计一些设计页面应用时,特别是涉及到数据视图绑定或 Web Component 开发时,我们可能需要在 DOM 元素里设置一些,以存储一些信息。然而,这些存储在 DOM 属性里的值,可能形式较为复杂。一个常见的内置属性是 style,当然,浏览器会自动识别这个属性并作为样式的设定依据来进行处理。然而,如果我们也想自定义一些类似这样的 DOM 属性,我们通过常规的 DOM 访问所获取的值,却是一个字符串。但更多的情况下,我们更希望是一个 JSON 对象。

下面是一个可能的示例。

<sample-input data-config="type: 'select', label: 'Gender', require: true, dropdown: [ 'Male', 'Female' ]">
</sample-input>

我们想读取其中的 data-config 属性。假设我们给定一个传入的 DOM 和属性名,我们可以这么实现。

function attr(element, name) {
    var ele = !!element && typeof element === "string" ? document.getElementById(element) : element;
    if (!ele || !ele.tagName || !name) return undefined;
    var attrStr = ele.getAttribute(name);
    return eval("({" + attrStr + "})");
}

看似很轻松,如此就搞定了。最终函数返回的结果自然就如下所示了。

{
    type: 'select',
    label: 'Gender',
    require: true,
    dropdown: ['Male', 'Female']
}

可是,人们并非始终循规蹈矩。我们还希望能处理下面这种情况。

<sample-input data-config="function () { return null; }">
</sample-input>

我可能希望获得的是一个函数,显然上面的做法就挂了。因为外面多了一对大括号。同样,除了函数,里面直接是一个 JSON 对象也是不行的。

<sample-input data-config="{ type: 'select', label: 'Gender', require: true, dropdown: [ 'Male', 'Female' ] }">
</sample-input>

或者就直接是一个字符串、数字、布尔值、数组等等也都不行。那怎么办呢?把那个大括号去掉?不要这么简单粗暴,其实我们可以这么改。

  1. 先进行为空判断。
  2. 去掉左右的空格。
  3. 检查是否存在大括号和冒号是否出现在某些位置上,以确定是否要保留那对最外面的大括号。

于是我们得到以下代码。

if (!attrStr) return null;
attrStr = attrStr.replace(/(^\s*)|(\s*$)/g, "");
var indexA = attrStr.indexOf(":");
var indexB = attrStr.indexOf("{");
attrStr = indexA > 0 && (indexB < 0 || indexA < indexB) ? eval("({" + attrStr + "})") : eval("(" + attrStr + ")");

那简单的一组数据呢?

<sample-input data-config="a;b;c">
</sample-input>

好吧,我们还要做更多的判断和处理。

if (indexA < 0 && indexB < 0 && attrStr.indexOf("=") < 0 && attrStr.indexOf("'") < 0 &&
    attrStr.indexOf("\"") < 0 && attrStr.indexOf("(") < 0 && attrStr.indexOf(")") < 0 && attrStr.indexOf(" ") > 0) {
    attrStr = attrStr.indexOf(";") >= 0 ? attrStr.split(";") : attrStr;
}
嗯,貌似大功告成。等等,说好的绑定类型的呢?
<sample-input data-config="{{dataConfig}}">
</sample-input>
啊哈,你的要求还真多!一并满足你。
if (attrStr.indexOf("{{") === 0 && attrStr.lastIndexOf("}}") === attrStr.length - 2 && attrStr.length > 4) {
    attrStr = eval("(" + attrStr.substring(2, attrStr.length - 2) + ")");
}

这下总该搞定了吧?嗯,是的,解决了各种情况。好了,我们回顾一下刚才写的,总结在一起,于是就变成了下面这样的一个函数。传入 DOM 元素和需要绑定的属性,我们就能解析其中的内容。

/**
  * Parses the specific attribute object of an element.
  * @param element  the element to get attribute.
  * @param name  the attribute name.
  */
function attr(element, name) {
    var ele = !!element && typeof element === "string" ? document.getElementById(element) : element;
    if (!ele || !ele.tagName || !name)
        return undefined;
    var attrStr = ele.getAttribute(name);
    if (!attrStr)
        return null;
    attrStr = attrStr.replace(/(^\s*)|(\s*$)/g, "");
    if (attrStr === "")
        return null;
    if (attrStr.indexOf("{{") === 0 && attrStr.lastIndexOf("}}") === attrStr.length - 2 && attrStr.length > 4) {
        return eval("(" + attrStr.substring(2, attrStr.length - 2) + ")");
    }
    var indexA = attrStr.indexOf(":");
    var indexB = attrStr.indexOf("{");
    if (indexA > 0 && (indexB < 0 || indexA < indexB))
        return eval("({" + attrStr + "})");
    if (indexA < 0 && indexB < 0 && attrStr.indexOf("=") < 0 && attrStr.indexOf("'") < 0 &&
        attrStr.indexOf("\"") < 0 && attrStr.indexOf("(") < 0 && attrStr.indexOf(")") < 0 && attrStr.indexOf(" ") > 0) {
        return attrStr.indexOf(";") >= 0 ? attrStr.split(";") : attrStr;
    }
    return eval("(" + attrStr + ")");
}
不过话说,人类难以获得100%的满足。虽然我们拥有一个这么强大的 DOM 属性解析器,但并不意味着我就停止于此。我还想有个更强大的东西,那就是能快速获取一些指定 DOM 属性值,甚至能在这些 DOM 属性值变更后,我的相关变量也被自动更新。这可怎么办呢?套用一些经典名著里的话:欲知后事如何,请听下回分解。


文章类型及复杂度:Web 进阶。

节选翻译自 MSDN 博文 Parse DOM attribute object,内容有所调整。

http://blogs.msdn.com/b/kingcean/archive/2016/03/18/parse-attribute-object-in-dom.aspx



  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值