我正在构建一个将 svg 图标呈现到 Shadow Dom 页面上的 Web 组件。IE
<ba-icon i="airplane"></ba-icon>
Run Code Online (Sandbox Code Playgroud)
我有一个外部 svg sprite 文件,其中包含大量 SVG 图标。
Web 组件的内部将以下内容渲染到 Shadow Dom 中:
<svg>
<use xlink:href="i.dist.svg#i-airplane"></use>
<svg>
Run Code Online (Sandbox Code Playgroud)
一切都在屏幕上正确呈现,但我想要一些嵌入在 SVG 内部的信息,特别是包含在viewbox, 中的信息(例如:)viewBox="0 0 32 32"。
我知道在 中渲染的内容use也输入到 Shadow Dom 中。但我试图找到另一种获取嵌入到use. 我试图对 svg 的内容进行 ajax,但这对于页面上的多个图标来说变成了一个大问题,因为 Web 组件的每个实例现在都在进行该调用。我还能怎么做?
以供参考:
我正在尝试构建一个没有任何外部依赖项的简单 Web 组件。只有两个 html 文件,一个 index.html 和一个 webcomponent.html。
我有一些个人 html 项目,我想将全局 html 命名空间分成更小的文件。我不想为此使用任何像聚合物这样的外部库。我不想使用任何构建系统或网络服务器。
我在网上找到的所有示例都需要外部构建系统或库。此外,如果没有网络服务器,它们也不会工作。例如,webcomponents/hello-world声称使用 vanilla-js。但事实上,它不是,因为它取决于鲍尔。
只有两个 html 文件在我的本地编辑-保存-刷新开发周期中工作。这真的可能吗?如果是这样,如何?如果没有,最接近的妥协是什么?
我目前正在使用自定义元素(Web 组件)实现数据表元素。表格可以具有用于呈现每一行的不同类型的单元格(文本、数字、日期等)。
例如
<my-table>
<my-table-cell-text column="name"></my-table-cell-text>
<my-table-cell-date column="dob" format="YYYY-MM-DD"></my-table-cell-date>
<my-table-cell-number column="salary" decimals="2"></my-table-cell-number >
</my-table>
Run Code Online (Sandbox Code Playgroud)
我还有一个MyTableCell所有单元格元素都扩展的类。这适用于共享通用功能,但样式可能很麻烦,因为每个单元格类型都是它自己的 html 标签。目前,我在扩展时添加了一个 css 类MyTableCell,但为了论证,可以说我不想这样做。
理想的解决方案是能够扩展自定义元素,使用is关键字,例如<my-table-cell is="my-table-cell-text">,但只允许内置 html 元素。
我可以想到解决这个问题的 3 种方法:
具有类似于 的语法<input type="">,但需要做更多的工作,因为您不再扩展基类,而是创建相同元素的变体,这意味着您需要一种自定义方式来注册不同的变体,例如静态MyTableCell.registerType
一种可组合的方法,我将渲染器元素 包裹<my-table-renderer-text>在通用<my-table-cell>. 这避免了自定义注册方法,但它更难编写,并导致更多元素和更多样板代码,这反过来意味着性能下降。
两者的混合,用户写入<my-table-cell type="text">和单元格在document.createElement('my-table-rendener-'+ type)内部使用类似的东西。这保留了选项 1 的更简单的语法,同时仍然避免了自定义寄存器方法,但它具有与选项 2 相同的性能影响。
你能提出更好的选择吗?我错过了什么吗?
我正在使用自定义元素 polyfill构建一个简单的自定义元素。我已经注册了一个要“监视”的属性(使用observedAttributes()),当我更改此属性的值时,该函数会attributeChangedCallback被调用两次。
这是 HTML 代码:
<my-component id="compo" foo="bar"></my-component>
<button id="myBtn">Change attribute value</button>
Run Code Online (Sandbox Code Playgroud)
这是我的组件定义:
class MyComponent extends HTMLElement {
constructor() {
super();
}
static get observedAttributes() {
return ['foo'];
}
attributeChangedCallback(attrName, oldVal, newVal) {
console.log('[my component] attribute', attrName, 'changed from', oldVal, 'to', newVal);
}
}
window.customElements.define('my-component', MyComponent);
// Change value of the component attribute
$('#myBtn').click(() => $('#compo').attr('foo', 'baz'));
Run Code Online (Sandbox Code Playgroud)
在该页面上,当我单击按钮时,我在以下日志中有以下日志console.log:
[我的组件] 属性 foo 从 bar 更改为 baz
[我的组件] 属性 foo 从 bar …
背景:这个问题与 Chrome 最新版本扩展的开发有关。它依赖于 javascript 功能,例如并非在所有浏览器上都可用的 HTML 导入和自定义元素,但在这种情况下是可以的。
我正在尝试实现一个简化的 HTML 自定义元素,如下所示:
<custom-el>
<span slot="head">Great</span>
<span slot="item">Item one</span>
<span slot="item">Item two</span>
<span slot="foot">done</span>
</custom-el>
Run Code Online (Sandbox Code Playgroud)
我注册了<custom-el>. 每次创建元素时,我的代码的自定义元素类都会附加一个影子根并附加到以下模板中的影子根内容:
<template id="main">
<h1><slot name="head"></slot></h1>
<ul>
<slot name="item"></slot>
</ul>
<i><slot name="foot"></slot></i>
</template>
Run Code Online (Sandbox Code Playgroud)
我想将每个<span>属性重新分配slot="item"给负责呈现单个项目的辅助模板:
<template id="sub">
<li><slot name="item"></slot></li>
</template>
Run Code Online (Sandbox Code Playgroud)
带属性的槽数name="item"不固定。它从数据库生成并定期更改。
我知道可以通过将 shadowRoot 附加到插槽的父元素并设置插槽的插槽属性来重新分配插槽,例如<slot name="item" slot="newItem">. 但我认为这在我的情况下不起作用,因为子模板需要包装每个项目实例,而不是项目列表。
我可以将影子根和子模板附加到主文档中的每个项目。这会起作用,但我的偏好是主模板导入并应用任何嵌套的 shadowRoots 和模板。这样,主文档只需要导入包含主模板的文件。组件细节的实现被封装在主模板html文件中。
我还可以使用slotchange事件和HTMLSlotElement.assignedNodes方法来拼凑脚本解决方案。但我宁愿不走那条路。
还有另一种方法吗?我的实际用例涉及更复杂的 HTML 结构。或者我的架构或对 Web 组件的理解有缺陷?
html web-component google-chrome-extension shadow-dom custom-element
我有一个自定义元素(没有 shadow DOM),我希望能够在任何地方使用,甚至在另一个可能使用 shadow DOM 的自定义元素中。但是,我不确定如何让样式在这两个地方都有效。
例如,假设我创建了一个简单的fancy-button元素:
class fancyButton extends HTMLElement {
constructor() {
super();
this.innerHTML = `
<style>
fancy-button button {
padding: 10px 15px;
background: rgb(62,118,194);
color: white;
border: none;
border-radius: 4px
}
</style>
<button>Click Me</button>`;
}
}
customElements.define('fancy-button', fancyButton);Run Code Online (Sandbox Code Playgroud)
<fancy-button></fancy-button>Run Code Online (Sandbox Code Playgroud)
在 shadow DOM 元素内,插入的样式标签将允许fancy-button样式工作。但是,如果在 shadow DOM 元素之外使用此组件,则每次使用该元素时都会复制样式标记。
相反,如果我将样式标记添加为 html 导入文件的一部分,那么样式只能在 shadow DOM 之外工作,但至少它们只声明一次。
<!-- fancy-button.html -->
<style>
fancy-button button {
padding: 10px 15px;
background: rgb(62,118,194);
color: white;
border: none;
border-radius: 4px
}
</style>
<script> …Run Code Online (Sandbox Code Playgroud) 与原生 HTML 元素相比,Web 组件是否提供更好的性能。因为每个元素只有在附加到 DOM 时才会发生变异。因此,元素回调中的昂贵操作会导致性能不佳。
我写了一个示例 Web 组件,在 connectedCallback 句柄中有一些昂贵的实现,当我尝试渲染组件时,每个组件都以连续的顺序花费时间。
我在 Web Components 上没有看到任何与参考相关的性能指标。
更新 1
我创建了一个带有 Native 和 Web Component 实现的小页面,似乎 Web Components 页面需要 4ms 才能完成,但 Native 只需要 1ms。请参阅我的性能屏幕。在 Web 组件中,脚本编写需要更多时间。
原生 HTML 示例:
Web 组件示例:
html javascript web-component html-rendering web-performance
考虑以下:
class MyElem extends HTMLElement {};
customElements.define('my-element', MyElem);
class MyMoreSpecificElem extends MyElem {};
customElements.define('my-more-specific-element', MyMoreSpecificElem);
Run Code Online (Sandbox Code Playgroud)
在对象继承的说法中,第二个类的实例与第一个类具有“is-a”关系: aMyMoreSpecificElem 是 a MyElem。
这种关系在 JavaScript 中被捕获:
let subclassInstance = document.querySelector('my-more-specific-element');
let parentClass = document.querySelector('my-element').constructor;
subclassInstance instanceof parentClass; // true
Run Code Online (Sandbox Code Playgroud)
但是我想不出任何MyElem使用 CSS 选择器选择所有s(包括子类 MyMoreSpecificElem)的方法。标签选择器只会获得超类或子类,我知道的所有关系描述选择器(例如~、>)都是关于文档中的位置,而不是类层次结构。
我的意思是,当然,我可以在构造函数中添加一个 CSS 类并通过它进行选择,调用super将确保甚至可以以这种方式选择子类实例。但这很粗糙。有没有办法在纯 CSS 中做到这一点?
是否可以将函数传递给stencilJs组件?
就像是:
@Prop() okFunc: () => void;
Run Code Online (Sandbox Code Playgroud)
我有一个模态,想Ok在模态页脚中单击的按钮上动态调用传递的函数,就像onClick在普通 HTML 按钮上一样。
我被一个无法解决的问题困住了几个小时。我创建了一个组件并将其捆绑为一个 js 文件。我想将此js文件加载到另一个项目中。到目前为止,一切都很好。但是我创建了一个带有 @Input() 装饰器的组件。现在,当我在另一个项目的 html 中添加我的自定义组件并直接传递 @Input() 属性时,仍然一切正常。但我希望这个属性不直接在 html 文件中传递,我想将它绑定到这个组件中。说得够多了,让我们一步一步地看看我到目前为止所做的
已安装的库和依赖项
npm i @angular/elements @webcomponents/custom-elements fs-extra concat --save
导入的脚本
"scripts":
[
"node_modules/@webcomponents/custom-elements/custom-elements.min.js",
"node_modules/@webcomponents/custom-elements/src/native-shim.js"
]
Run Code Online (Sandbox Code Playgroud)
创建组件
打字稿文件
@Component({
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
@Input() subtitle: string;
}
Run Code Online (Sandbox Code Playgroud)
html文件
<h1>Any Title<h1/>
<h4>{{subtitle}}</h4>
Run Code Online (Sandbox Code Playgroud)
将组件注册在 AppModule.ts
export class AppModule {constructor(private injector: Injector) { }
ngDoBootstrap() {
const widgetName = createCustomElement(AppComponent, {injector: this.injector});
customElements.define('widget-name', widgetName);
}
Run Code Online (Sandbox Code Playgroud)
现在我可以在 index.html 中添加这个自定义组件,ng serve并且一切正常。
我有一个构建脚本,它将组件捆绑到一个 js 文件中。这对这段代码非常有效。这是我添加到另一个项目中的内容。
工作示例
<widget-name subtitle="Subtitle of this …
web-component ×10
html ×7
javascript ×5
css ×2
shadow-dom ×2
angular ×1
dom ×1
function ×1
html-imports ×1
stencils ×1
subclassing ×1
svg ×1
typescript ×1