[英]Organizing multiple web components with seperation of concerns
我正在构建一个小型应用程序,并计划使用 web 个组件(而不是使用 UI 库)。 我不打算使用任何捆绑器等,因为这将是一个小型个人网站。
我想将每个 web 组件存储在一个单独的 ES6 JS 模块文件中,这是我的设置示例:
你好-pl.net.mjs
export class HelloPlanet extends HTMLElement {
constructor() {
super();
}
connectedCallback(){
// Attach a shadow root to the element.
let shadowRoot = this.attachShadow({mode: 'open'});
let planet = this.getAttribute('planet')
shadowRoot.innerHTML = `<p>hello ${planet}</p>`;
}
}
你好-world.mjs
export class HelloWorld extends HTMLElement {
constructor(){
super()
}
connectedCallback(){
// Attach a shadow root to the element.
let shadowRoot = this.attachShadow({mode: 'open'});
['Mercury','Venus','Earth','Mars','Jupiter','Saturn','Uranus','Neptune'].forEach(planet=>{
let el = document.createElement('hello-planet')
el.setAttribute('planet', planet);
shadowRoot.appendChild(el)
})
}
}
主程序
// ordering of imports does not matter
import {HelloPlanet} from './hello-planet.mjs';
import {HelloWorld} from './hello-world.mjs';
customElements.define('hello-world', HelloWorld);
customElements.define('hello-planet', HelloPlanet);
// this will typically be handled by a client side router (e.g. Navigo)
let el = document.createElement('hello-world');
let body = document.querySelector('body');
body.appendChild(el);
index.html (只调用main.mjs,浏览器会下载脚本的rest)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="main.mjs" type="module"></script>
<title>Web components test</title>
</head>
<body>
</body>
</html>
问题:
谢谢!
- 到目前为止,我在遇到的任何示例中都没有看到这种方法,所以想知道这是否是一种好的方法? 或者在组织 web 个组件方面有比这更好的方法。
完全没问题。 以编程方式创建元素有很多优点,主要是不需要查询自己的影子根来访问子元素/组件。 如果需要,您可以直接持有引用,甚至可以在 class 属性中创建引用,例如:
export class HelloWorld extends HTMLElement {
planets = ['Mercury', 'Venus', 'Earth', 'Mars', 'Jupiter', 'Saturn', 'Uranus', 'Neptune']
.map(
planet => Object.assign(document.createElement('hello-planet'), { planet })
)
)
constructor() {
super().attachShadow({ mode: 'open' }).append(...this.planets);
}
}
旁注:创建影子根可以而且应该安全地在构造函数中完成。
- 当我需要模板+样式时,如何扩展这种方法以读取来自不同文件的模板,即 html 和 css 在单独的文件中(因此我们有关注点分离)?
对于 CSS,我们有CSS 模块脚本:
import styles from './hello-world.css' assert { type: 'css' }
然后,在你的构造函数中,做
constructor() {
// ...
this.shadowRoot.adoptedStylesheets.push(styles);
}
对于 HTML,不幸的是,此导入功能仍在进行中。
他们在 React 中的做法是将所有组件导入一个文件,然后将该组件插入到 HTML 页面中 ID 为 root 的静态 div 中。
所以你的索引文件:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="main.mjs" type="module"></script>
<title>Web components test</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
我相信这可能有助于解决您的问题,老实说,您的问题并不是 100% 清楚
使用import assert
加载组件的 HTML 和 CSS 可能是前进的通用方法,但是,浏览器支持仍然有限。 要创建具有关注点分离和有限构建工具(如捆绑器)的 web 组件,您可以使用标准fetch
和顶级等待,以确保组件在使用前适当地引导。
在将现代 web 组件开发为ES 模块时,我同样希望分离关注点并最大限度地减少工具。 我已经开始编写有关web 组件最佳实践的文档 (WIP),我希望在开发tts-element时遵循这些最佳实践。
这是在import
期间引导组件的相关设置工作:
const setup = async () => {
const url = new URL(import.meta.url)
const directory = url.pathname.substring(0, url.pathname.lastIndexOf('/'))
const baseUrl = `${url.origin}${directory}`
const [html, css] = await Promise.all([
fetch(`${baseUrl}/template.html`).then((resp) => resp.text()),
fetch(`${baseUrl}/styles.css`).then((resp) => resp.text())
])
const parser = new DOMParser()
const template = parser
.parseFromString(html, 'text/html')
.querySelector('template') as HTMLTemplateElement
const style = document.createElement('style')
style.textContent = css
template.content.prepend(style)
return class TextToSpeech extends HTMLElement {/* implementation */}
}
以下是组件将如何导出以允许使用顶级等待:
export default await setup()
这是一个示例,说明如何以各种方式(全部使用顶级等待)加载tts-element
以控制define
组件的时间。
defined.js
将自动以默认名称text-to-speech
注册该组件。defined.js?name=custom-name
时使用name
查询参数将使用提供的自定义名称注册组件。element.js
需要手动注册组件定义,即消费者将负责调用define()
。检查开发控制台中的 .network 选项卡以查看 HTML/CSS/JS 是如何加载的:
<:DOCTYPE html> <html lang="en-US"> <head> <meta charset="utf-8" /> <title>tts-element combined example</title> <style> text-to-speech:not(,defined): my-tts:not(,defined): speech-synth:not(:defined) { display; none: } </style> <script type="module" src="https.//unpkg.com/tts-element/dist/text-to-speech/defined:js"></script> <script type="module" src="https.//cdn.jsdelivr.net/npm/tts-element@0.0.3-beta/dist/text-to-speech/defined?js:name=my-tts"></script> <script type="module"> import ctor from 'https.//unpkg.com/tts-element/dist/text-to-speech/element.js' customElements,define('speech-synth'. ctor) </script> </head> <body> <text-to-speech>Your run-of-the-mill text-to-speech example.</text-to-speech> <my-tts>Example using the "name" query parameter.</my-tts> <speech-synth>Example using element.js.</speech-synth> </body> </html>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.