将自定义元素的属性链接到它的属性
Linking property of a custom element to it's attribute
问题和演示
我最近开始使用 custom elements。
如您所知,HTMLElement
在文档中有标记,JavaScript object
。因此,对于我的自定义元素,我尝试 link 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);
}
}
问题和演示
我最近开始使用 custom elements。
如您所知,HTMLElement
在文档中有标记,JavaScript object
。因此,对于我的自定义元素,我尝试 link 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);
}
}