如何传递属性来帮助实现自定义元素?
How to pass attributes to help implement a custom element?
当我们使用 Web 组件技术创建自定义元素时,有时自定义元素的实现涉及使用主文档中生成的元素上存在的属性。如以下示例所示:
主文档:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="import" href="web-components/my-portrait.html">
</head>
<body>
<my-portrait src="images/pic1.jpg" />
</body>
</html>
我的-portrait.html:
<template id="my-portrait">
<img src="" alt="portait">
</template>
<script>
(function() {
var importDoc = document.currentScript.ownerDocument;
var proto = Object.create(HTMLElement.prototype, {
createdCallback: {
value: function() {
var t = importDoc.querySelector("#my-portrait");
var clone = document.importNode(t.content, true);
var img = clone.querySelector("img");
img.src = this.getAttribute("src");
this.createShadowRoot().appendChild(clone);
}
}
});
document.registerElement("my-portrait", {prototype: proto});
})();
</script>
在 createdCallback 中,我们使用 this.getAttribute("src") 获取肖像元素上定义的 src 属性。
但是,这种获取属性的方式只能在通过元素标签声明实例化元素时使用。但是,如果元素是使用 JavaScript 创建的:document.createElement("my-portrait") 怎么办?当此语句执行完毕时,createdCallback 已被调用,并且 this.getAttribute("src") 将 return null 因为该元素没有 src创建时立即属性。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="import" href="web-components/my-portrait.html">
</head>
<body>
<!--<my-portrait src="images/pic1.jpg" />-->
<script>
var myPortrait = document.createElement("my-portrait");
myPortrait.src = "images/pic2.jpg"; // too late
document.getElementsByTagName("body")[0].appendChild(myPortrait);
</script>
</body>
</html>
那么当我们使用 JavaScript 实例化自定义元素时,我们如何将属性传递给 createdCallback?如果有beforeAttach回调,我们可以在那里设置属性,但是没有这样的回调。
您可以实施名为 attributeChangedCallback
:
的生命周期回调
我的-portrait.html:
proto.attributeChangedCallback = function ( name, old, value )
{
if ( name == "src" )
this.querySelector( "img" ).src = value
//...
}
name
是修改(或添加)属性的名称,
old
是属性的旧值,或者undefined
如果是刚创建的,
value
是属性的新值(string
类型)。
要调用回调,请对您的自定义元素使用 setAttribute
方法。
主文档:
<script>
var myPortrait = document.createElement( "my-portrait" )
myPortrait.setAttribute( "src", "images/pic2.jpg" ) // OK
document.body.appendChild( myPortrait )
</script>
例子:
var proto = Object.create(HTMLElement.prototype, {
createdCallback: {
value: function() {
this.innerHTML = document.querySelector("template").innerHTML
var path = this.getAttribute("src")
if (path)
this.load(path)
}
},
attributeChangedCallback: {
value: function(name, old, value) {
if (name == "src")
this.load(value)
}
},
load: {
value: function(path) {
this.querySelector("img").src = path
}
}
})
document.registerElement("image-test", { prototype: proto })
function add() {
var el = document.createElement("image-test")
el.setAttribute("src", "https://placehold.it/100x50")
document.body.appendChild(el)
}
<image-test src="https://placehold.it/100x100">
</image-test>
<template>
<img title="portrait" />
</template>
<button onclick="add()">
add
</button>
当我们使用 Web 组件技术创建自定义元素时,有时自定义元素的实现涉及使用主文档中生成的元素上存在的属性。如以下示例所示:
主文档:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="import" href="web-components/my-portrait.html">
</head>
<body>
<my-portrait src="images/pic1.jpg" />
</body>
</html>
我的-portrait.html:
<template id="my-portrait">
<img src="" alt="portait">
</template>
<script>
(function() {
var importDoc = document.currentScript.ownerDocument;
var proto = Object.create(HTMLElement.prototype, {
createdCallback: {
value: function() {
var t = importDoc.querySelector("#my-portrait");
var clone = document.importNode(t.content, true);
var img = clone.querySelector("img");
img.src = this.getAttribute("src");
this.createShadowRoot().appendChild(clone);
}
}
});
document.registerElement("my-portrait", {prototype: proto});
})();
</script>
在 createdCallback 中,我们使用 this.getAttribute("src") 获取肖像元素上定义的 src 属性。
但是,这种获取属性的方式只能在通过元素标签声明实例化元素时使用。但是,如果元素是使用 JavaScript 创建的:document.createElement("my-portrait") 怎么办?当此语句执行完毕时,createdCallback 已被调用,并且 this.getAttribute("src") 将 return null 因为该元素没有 src创建时立即属性。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="import" href="web-components/my-portrait.html">
</head>
<body>
<!--<my-portrait src="images/pic1.jpg" />-->
<script>
var myPortrait = document.createElement("my-portrait");
myPortrait.src = "images/pic2.jpg"; // too late
document.getElementsByTagName("body")[0].appendChild(myPortrait);
</script>
</body>
</html>
那么当我们使用 JavaScript 实例化自定义元素时,我们如何将属性传递给 createdCallback?如果有beforeAttach回调,我们可以在那里设置属性,但是没有这样的回调。
您可以实施名为 attributeChangedCallback
:
我的-portrait.html:
proto.attributeChangedCallback = function ( name, old, value )
{
if ( name == "src" )
this.querySelector( "img" ).src = value
//...
}
name
是修改(或添加)属性的名称,old
是属性的旧值,或者undefined
如果是刚创建的,value
是属性的新值(string
类型)。
要调用回调,请对您的自定义元素使用 setAttribute
方法。
主文档:
<script>
var myPortrait = document.createElement( "my-portrait" )
myPortrait.setAttribute( "src", "images/pic2.jpg" ) // OK
document.body.appendChild( myPortrait )
</script>
例子:
var proto = Object.create(HTMLElement.prototype, {
createdCallback: {
value: function() {
this.innerHTML = document.querySelector("template").innerHTML
var path = this.getAttribute("src")
if (path)
this.load(path)
}
},
attributeChangedCallback: {
value: function(name, old, value) {
if (name == "src")
this.load(value)
}
},
load: {
value: function(path) {
this.querySelector("img").src = path
}
}
})
document.registerElement("image-test", { prototype: proto })
function add() {
var el = document.createElement("image-test")
el.setAttribute("src", "https://placehold.it/100x50")
document.body.appendChild(el)
}
<image-test src="https://placehold.it/100x100">
</image-test>
<template>
<img title="portrait" />
</template>
<button onclick="add()">
add
</button>