将自定义元素的属性链接到它的属性

时间:2015-01-02 04:13:09

标签: javascript html properties

问题&演示


我最近开始使用custom elements

如您所知,HTMLElement在文档中包含标记和JavaScript object。因此,使用我的自定义元素,我尝试将JavaScript对象properties与元素attributes相关联。

因此,如果其中任何一个更新,另一个也会更新。但这并没有发生,我发誓我已经尝试了一切,也许是一些愚蠢的我不知道但是对我来说,这段代码的表现是一种奇怪的错误。

在阅读下面的代码说明并看到演示后,您应该能够理解我的问题:

  • 为什么自定义元素attributes正确更新,但不是properties
  

我已经设置了一个JSFiddle来说明我的问题,我将在本文中讨论代码应该如何工作。


HTML

<e-button color="red" width="250px">RED BUTTON</e-button>

嗯,它很少比这更简单。我创建了一个名为“电子按钮”的自定义对象,其中包含color=redwidth=250px

的JavaScript

var eButtonProto = Object.create(HTMLElement.prototype);

eButtonProto.createdCallback = function() {
    this.__htmlToJsProp(); //Gets all the HTML attributes and makes them accessible via JS.
    this.__processAttr(); //Makes decision upon predefined attributes.
}

eButtonProto.__htmlToJsProp = function() {
    var attr = this.attributes;
    for (var i = 0; i < attr.length; i++) {
        var current = attr[i];
        var name = current.name;
        var value = current.value;
        this[name] = value;
        Object.defineProperty(this, name, {
            get: function() {
                return this.getAttribute(name);
            },
            set: function(val) {
                this.setAttribute(name, val);
            }
        });
    }
}

eButtonProto.attributeChangedCallback = function(name, oldVal, val) {
    this[name] = val;
    this.__processAttr();
}

eButtonProto.__processAttr = function() {
    var color = this.color || this.defaults.color;
    this.style.backgroundColor = color;
}

eButtonProto.defaults = {
    color: "whitesmoke"
}   

var eButton = document.registerElement("e-button", {
    prototype: eButtonProto
});
window.onload = function() {
    redButton = document.querySelector("e-button[color=red]");
    console.log("button ATTRIBUTES", redButton.getAttribute("color"), redButton.getAttribute("width"));
    console.log("button PROPERTIES", redButton.color, redButton.width);
} < /script>

这里真正重要的代码片段是这些,它们必须使我的想法有效,首先是__htmlToJsProp()函数:

eButtonProto.__htmlToJsProp = function() {
    var attr = this.attributes; //Gets the element's attributes.
    for (var i = 0; i < attr.length; i++) {
        var current = attr[i]; //Element attribute name,value pair.
        var name = current.name; //Attribute name.
        var value = current.value; //Attribute value.
        Object.defineProperty(this, name, { //Defines the element property from the attribute name, for simplicity I will be using the color attribute as my example.
            get: function() {
                return this.getAttribute(name); //When accessing element.color you should get element.getAttribute("color")
            },
            set: function(val) {
                this.setAttribute(name, val); //When setting element.color = "red" you should also be doing element.setAttribute("color","red");
            }
        });
        this[name] = value; //Sets element.color = "red"
    }
}

然后是attributeChangedCallback函数:

eButtonProto.attributeChangedCallback = function(name, oldVal, val) {
    this[name] = val; //This would be the other way around, if the attribute is updated via setAttribute, or the browser console, the property is updated (works).
    this.__processAttr(); //You can ignore this
}

结论

您在测试后看到很多我发现如果您将自己放在for循环中并输出属性值,它会为您提供element.color = "red"element.width = "250px"; < / p>

但是如果你在for循环之外测试它,它会为属性提供element.color = "250px"element.width = "250px",但属性会正确更新,即element.getAttribute("color") = "red"element.getAttribute("width") = "250px"

如果你做到这一点,那么,非常感谢,希望你能找到解决这个问题的方法,我真的似乎无法解决这个问题,快乐的编码:)

1 个答案:

答案 0 :(得分:1)

您的问题似乎在for循环中,稍后会调用getter和setter,因此i的值不是您认为的,循环完成并设置{{ 1}}到最新的迭代值。

你将用一个闭包来解决它

i

FIDDLE