Joh*_*ist 17 html javascript json web-component
我的理解是数据通过其属性传递给自定义html元素,并通过调度CustomEvent发送出去.
显然,JavaScript对象可以在事件的详细信息字段中发送出去,但是如果元素需要传递大量数据,该怎么办呢?有没有办法在JavaScript中为它提供一个对象.
如果元素例如包含需要动态初始化或更改的可变数量的部分(例如,具有可变行数的表),该怎么办?我可以设想设置和修改由在组件内部解析的JSON字符串组成的属性,但它不是一种优雅的继续方式:
<my-element tableRowProperties="[{p1:'v1', p2:'v2'}, {p1:'v1',p2:'v2'}, {p1:'v1',p2:'v2'}]"></my-element>
Run Code Online (Sandbox Code Playgroud)
或者,您是否可以让元素监听来自外部的包含数据有效负载的事件?
Int*_*lia 26
如果您确实需要/需要将大量数据传递到组件中,那么您可以通过以下四种方式执行此操作:
1)使用财产.这是最简单的,因为您只需通过赋予元素值传递Object,如下所示:el.data = myObj;
2)使用属性.我个人讨厌这种方式,但是有些框架需要通过属性传递数据.这与您在问题中的显示方式类似.<my-el data="[{a:1},{a:2}....]"></my-el>
.请注意遵循与转义属性值相关的规则.如果使用此方法,则需要JSON.parse
在属性上使用,否则可能会失败.它也可能在HTML中变得非常难看,以便在属性中显示大量数据.
3 通过子元素传入它.想想<select>
带有<option>
子元素的元素.您可以将任何元素类型用作子元素,它们甚至不需要是真实元素.在您的connectedCallback
函数中,您的代码只会抓取所有子代,并将元素,属性或内容转换为组件所需的数据.
4 使用Fetch.提供元素的URL以获取自己的数据.想一想<img src="imageUrl.png"/>
.如果您已经拥有组件的数据,那么这似乎是一个糟糕的选择.但浏览器提供了一种很酷的嵌入数据功能,类似于上面的选项2,但是由浏览器自动处理.
img {
height: 32px;
width: 32px;
}
Run Code Online (Sandbox Code Playgroud)
<img src="data:image/svg+xml;charset=utf8,%3C?xml version='1.0' encoding='utf-8'?%3E%3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' x='0px' y='0px' viewBox='0 0 314.7 314.7'%3E%3Cstyle type='text/css'%3E .st0{fill:transparent;stroke:%23231F20;stroke-width:12;} .st1{fill:%23231F20;stroke:%23231F20;stroke-width:10;stroke-linejoin:round;stroke-miterlimit:10;} %3C/style%3E%3Cg%3E%3Ccircle class='st0' cx='157.3' cy='157.3' r='150.4'/%3E%3Cpolygon class='st1' points='108,76.1 248.7,157.3 108,238.6'/%3E%3C/g%3E%3C/svg%3E">
Run Code Online (Sandbox Code Playgroud)
function readSrc(el, url) {
var fetchHeaders = new Headers({
Accept: 'application/json'
});
var fetchOptions = {
cache: 'default',
headers: fetchHeaders,
method: 'GET',
mode: 'cors'
};
return fetch(url, fetchOptions).then(
(resp) => {
if (resp.ok) {
return resp.json();
}
else {
return {
error: true,
status: resp.status
}
}
}
).catch(
(err) => {
console.error(err);
}
);
}
class MyEl extends HTMLElement {
static get observedAttributes() {
return ['src'];
}
attributeChangedCallback(attrName, oldVal, newVal) {
if (oldVal !== newVal) {
this.innerHtml = '';
readSrc(this, newVal).then(
data => {
this.innerHTML = `<pre>
${JSON.stringify(data,0,2)}
</pre>`;
}
);
}
}
}
// Define our web component
customElements.define('my-el', MyEl);
Run Code Online (Sandbox Code Playgroud)
<!--
This component would go load its own data from "data.json"
<my-el src="data.json"></my-el>
<hr/>
The next component uses embedded data but still calls fetch as if it were a URL.
-->
<my-el src="data:json,[{"a":9},{"a":8},{"a":7}]"></my-el>
Run Code Online (Sandbox Code Playgroud)
您可以使用XHR执行相同的操作,但如果您的浏览器支持Web组件,则它可能支持fetch.如果您确实需要填充,可以使用几种优质的填充剂.
使用选项4的最大优点是,你可以从一个网址让您的数据和您可以直接嵌入您的数据.这正是大多数预定义的HTML元素,如<img>
工作.
UPDATE
我确实想到了将JSON数据放入对象的第5种方法.这是通过<template>
在组件中使用标记.这仍然需要你调用,JSON.parse
但它可以清理你的代码因为你不需要像JSON那样多地转义它.
class MyEl extends HTMLElement {
connectedCallback() {
var data;
try {
data = JSON.parse(this.children[0].content.textContent);
}
catch(ex) {
console.error(ex);
}
this.innerHTML = '';
var pre = document.createElement('pre');
pre.textContent = JSON.stringify(data,0,2);
this.appendChild(pre);
}
}
// Define our web component
customElements.define('my-el', MyEl);
Run Code Online (Sandbox Code Playgroud)
<my-el>
<template>[{"a":1},{"b":"<b>Hi!</b>"},{"c":"</template>"}]</template>
</my-el>
Run Code Online (Sandbox Code Playgroud)
有三种方法可以从组件中获取数据:
1)从属性中读取值.这是理想的,因为属性可以是任何东西,通常采用您想要的数据格式.属性可以返回字符串,对象,数字等.
2)读取属性.这要求组件使属性保持最新,并且可能不是最佳的,因为所有属性都是字符串.因此,您的用户需要知道他们是否需要调用JSON.parse
您的价值.
3)事件.这可能是添加到组件中最重要的事情.当组件中的状态发生变化时,事件应该触发.事件应基于用户交互触发,并仅提醒用户已发生某事或某些事物可用.传统上,您会在活动中包含相关数据.这减少了组件用户需要编写的代码量.是的,他们仍然可以读取属性或属性,但如果您的事件包含所有相关数据,那么他们可能不需要做任何额外的事情.
log*_*gan 11
有第 6 种方式与上面@Intervalia 的答案非常相似,但使用<script>
标签而不是<template>
标签。
这与Markdown Element使用的方法相同。
class MyEl extends HTMLElement {
connectedCallback() {
var data;
try {
data = JSON.parse(this.children[0].innerHTML);
}
catch(ex) {
console.error(ex);
}
this.innerHTML = '';
var pre = document.createElement('pre');
pre.textContent = JSON.stringify(data,0,2);
this.appendChild(pre);
}
}
// Define our web component
customElements.define('my-el', MyEl);
Run Code Online (Sandbox Code Playgroud)
<my-el>
<script type="application/json">[{"a":1},{"b":"<b>Hi!</b>"},{"c":"</template>"}]</script>
</my-el>
Run Code Online (Sandbox Code Playgroud)