[英]FontAwesome svg within shadow dom
我正在尝试在 web 组件中使用字体 awsome js/svg 库,但图标不会显示。 这可能吗?
我正在尝试在没有 css 和脚本“流血”的现有网络表单项目中实现 angular 组件,关于如何执行此操作的任何其他建议? iframe 不是一个选项。
<html>
<head>
<script src="https://polygit.org/components/webcomponentsjs/webcomponents-loader.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.13.0/js/all.min.js" defer>
</script>
<script>
customElements.define('my-holder', class extends HTMLElement {
constructor() {
super();
console.log("constructor");
let shadowRoot = this.attachShadow({
mode: 'open'
});
const t = document.querySelector('#holder');
const instance = t.content.cloneNode(true);
shadowRoot.appendChild(instance);
}
connectedCallback() {
console.log("callback");
}
});
</script>
</head>
<body>
<div id="outside">
light dom
<div class="fa-4x">
<span class="fa-layers fa-fw" style="background:MistyRose">
<i class="fas fa-circle" style="color:Tomato"></i>
<i class="fa-inverse fas fa-times" data-fa-transform="shrink-6"></i>
</span>
</div>
</div>
<template id="holder">
<script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.13.0/js/all.min.js" defer></script>
dark shadow dom
<div class="fa-4x">
<span class="fa-layers fa-fw" style="background:MistyRose">
<i class="fas fa-circle" style="color:Tomato"></i>
<i class="fa-inverse fas fa-times" data-fa-transform="shrink-6"></i>
</span>
</div>
</template>
<div id="inside">
<my-holder></my-holder>
</div>
</body>
</html>
许多 oldskool 库都使用document.
访问主 DOM。
所以他们不能对shadowDOM
中的内容做任何事情
这意味着您的目标是不流出脚本是不可能的。
Font-Awesome(脚本和样式)必须加载到主 DOM 中。
如果您不想在 shadowDOM 之外流血 styles,则必须遵守规则:
Font-Awesome 图标定义必须保留在主 DOM 中
lightDOM是shadowDOM插槽内容的(主 DOM)“原始”
lightDOM 由主 DOM 设置样式
(如果元素本身在另一个 shadowDOM 中,则为它的 shadowDOM 容器)
开槽的lightDOM保留在 lightDOM 中,只反映到它的<slot></slot>
您不想在每个 lightDOM 中重复 FontAwesome 图标定义
(那时你最好不要使用自定义元素)
<span class="fa-4x fa-layers fa-fw">
<i class="fas fa-circle"></i>
<i class="fa-inverse fas fa-times" data-fa-transform="shrink-6"></i>
</span>
编写一个自定义元素
<slot></slot>
(反射!没有移动! ) <awesome-icon background="lightcoral" color="red"></awesome-icon>
<awesome-icon background="lightgreen" color="green"></awesome-icon>
<awesome-icon></awesome-icon>
JSFidlle: https://jsfiddle.net/CustomElementsExamples/1pmvasnj/
<script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.13.0/js/all.min.js" defer></script> <script> customElements.define('awesome-icon', class extends HTMLElement { constructor() { super().attachShadow({mode: 'open'}).append(document.getElementById(this.nodeName).content.cloneNode(true)); } connectedCallback() { let setProperty = (prop, value)=>this.shadowRoot.host.style.setProperty('--' + prop, value); setProperty('fa-background', this.getAttribute('background')); setProperty('fa-color', this.getAttribute('color')); // move icon HTML back to lightDOM so FontAwesome can style it this.innerHTML = this.shadowRoot.querySelector('#ICON').innerHTML; } }); </script> <template id="AWESOME-ICON"> <style>::slotted(*) { /* lightDOM SPAN has higher Specificity, only way out is using:important */ background, var(--fa-background;grey):important, color; var(--fa-color:darkgrey);important: } </style> <template id="ICON"> <span class="fa-4x fa-layers fa-fw"> <i class="fas fa-circle"></i> <i class="fa-inverse fas fa-times" data-fa-transform="shrink-6"></i> </span> </template> <slot><;--lightDOM REFLECTED here--></slot> </template> <awesome-icon><!-- lightDOM CREATED here --></awesome-icon> <awesome-icon background="lightcoral" color="red"></awesome-icon> <awesome-icon background="lightgreen" color="green"></awesome-icon> <style> span{ background:lightblue; /* !important inside shadowDOM overrules these settings */ color:red; } </style>
并依靠作用域 CSS 属性,使代码更简单:
<script>
customElements.define('awesome-icon', class extends HTMLElement {
connectedCallback() {
this.append(document.getElementById(this.nodeName).content.cloneNode(true));
this.style.setProperty('--fa-background', this.getAttribute('background') );
this.style.setProperty('--fa-color' , this.getAttribute('color') );
}
});
</script>
<template id="AWESOME-ICON">
<span class="fa-4x fa-layers fa-fw">
<i class="fas fa-circle"></i>
<i class="fa-inverse fas fa-times" data-fa-transform="shrink-6"></i>
</span>
</template>
<awesome-icon background="lightcoral" color="red"></awesome-icon>
<awesome-icon background="lightgreen" color="green"></awesome-icon>
<awesome-icon></awesome-icon>
<style>
span {
background: var(--fa-background);
color: var(--fa-color );
}
</style>
我找到了一种在 shadow dom 中渲染 SVG 字体真棒图标的方法。
从文档中, @fortawesome/fontawesome-svg-core
package 提供更多控制
这是我使用https://codesandbox.io/s/romantic-panka-40xqm创建的示例
基本思想是我们可以使用icon(faCamera).html[0]
获得 SVG HTML 并且可以在shadow dom root中使用它
import { icon } from "@fortawesome/fontawesome-svg-core";
import { faCamera } from "@fortawesome/free-solid-svg-icons";
icon(faCamera).html[0]
Font Awesome 有一种内置的方法来解析/搜索给定元素中的图标标签以生成 SVG。 以下应该适用于您的示例,或者非常接近您正在寻找的内容:
FontAwesome.dom.i2svg({
node: document.querySelector('my-holder').shadowRoot
})
FontAwesome
是由 font-awesome 脚本设置的全局变量的名称。
没有参数的i2svg()
重新解析整个 light dom(注意,这是不必要的,因为 font awesome 已经默认监视 dom 的变化)。 使用参数,可以传递带有指向某个元素(光或阴影)的node
属性的 js object,它会根据需要生成您的 SVG。
对于那些想要在 SPA/编译的 js 前端中执行此操作的人,请查看FA 文档以获得更直接的导入解决方案。
您是否考虑过使用 SVG 精灵? 在寻找导入库的替代解决方案并弄清楚它如何与影子 dom 一起工作几天后,我发现 SVG 精灵是最简单的解决方案。 完成的方法是使用svg
和use
方法。 请参阅字体真棒文档。
我最终在项目的 dist 文件夹中引入了 sprite 文件(在这种情况下,我引入了bootstrap icons ,但任何其他图标集都是相同的)。 dist/icons/bootstrap-icons.svg
。
应用程序.js
const template = document.createElement('template');
template.innerHTML = `
<template>
<style>
.icon {
width: 3rem;
height: 3rem;
stroke: currentColor;
stroke-linecap: round;
stroke-linejoin: round;
fill: none;
}
</style>
<svg class="icon">
<use href="icons/bootstrap-icons.svg#box-arrow-right"/>
</svg>
</template>`;
customElements.define('my-svg-icon', class extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
this.shadowRoot.appendChild(template.content.cloneNode(true));
}
});
索引.html
<!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">
<title>Awesome SVG Icons</title>
</head>
<body>
<my-svg-icon></my-svg-icon>
<script type="module" src="app.js"></script>
</body>
</html>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.