问题和演示
<小时/>我最近开始与 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=red
和 width=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);
}
}
关于javascript - 将自定义元素的属性链接到其属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27737286/