javascript - 将自定义元素的属性链接到其属性

标签 javascript html properties

问题和演示

<小时/>

我最近开始与 custom elements 合作.

如您所知,HTMLElement 在文档中既有标记,又有 JavaScript 对象。因此,对于我的自定义元素,我尝试将 JavaScript 对象 properties 与元素的 attributes 链接起来。

因此,如果其中任何一个更新,另一个也会更新。但这并没有发生,我发誓我已经尝试了一切,也许是我错过了一些愚蠢的事情,但对我来说,这段代码的行为方式是一个令人困惑的谜团。

看完下面的代码解释并看了demo,你应该能够明白我的问题了:

  • 为什么自定义元素 attributes 可以正确更新,但 properties 却不能正确更新?

I've setup a JSFiddle to illustrate my problem, and I will be going over how the code is supposed to work in this post.

<小时/>

HTML

<e-button color="red" width="250px">RED BUTTON</e-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";

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

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

最佳答案

你的问题似乎是在 for 循环中,getter 和 setter 是稍后调用的,所以 i 的值不是你想象的那样,循环完成并将 i 设置为最新的迭代值。

你可以用闭包来解决它

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

FIDDLE

关于javascript - 将自定义元素的属性链接到其属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27737286/

相关文章:

javascript - NodeJS 中的数组理解

javascript - animate.css 的滚动效果

javascript - Google 登录 - 刷新时退出

javascript - 仅在定义值时才内联设置 JS 对象的属性

javascript - 如何从数组对象属性值中删除重复项?

javascript - Html Javascript网站在移动设备上删除水平滚动

html - CSS 导航栏的子子菜单未向右扩展

javascript - HTML 输入元素范围检测拖动何时结束

php - 如何将版权和作者信息添加到用 PHP 创建的图像中?

c# - 属性(property)(没有额外处理)与公共(public)领域