javascript - 如何访问模板内脚本中的组件?
问题描述
我想重用包含一些 javascript 代码的 html 组件,所以为了简化我举一个简单的例子:
索引.html:
<!DOCTYPE html>
<html>
<head></head>
<body>
<my-component></my-component>
<script src="index.js"></script>
</body>
</html>
我的组件.html:
<template>
<div id="something"></div>
<script>
// It doesn't work, this here is "window"
document.getElementById("something").innerHTML = "Something"
</script>
</template>
index.js:
window.makeComponent = (function () {
function fetchAndParse(url) {
return fetch(url, {mode: "no-cors"})
.then(res => res.text())
.then(html => {
const parser = new DOMParser()
const document = parser.parseFromString(html, 'text/html')
const head = document.head
const template = head.querySelector('template')
return template
})
}
function defineComponent(name, template) {
class UnityComponent extends HTMLElement {
connectedCallback() {
const shadow = this.attachShadow({mode: 'open'})
shadow.appendChild(document.importNode(template.content, true))
}
}
return customElements.define(name, UnityComponent)
}
function loadComponent (name, url) {
fetchAndParse(url).then((template) => defineComponent(name, template))
}
return {loadComponent}
}())
makeComponent.loadComponent("my-component", "my-component.html")
我可以使用此代码,但它将脚本的所有变量复制到窗口:
<template>
<div id="something"></div>
<style onload="templFunc.apply(this.getRootNode())"></style>
<script>
function templFunc() {
// It works
let text = "Something"
this.querySelector('#something').innerHTML = text
// but...
console.log(window.text) // => "Something"
}
</script>
</template>
没有意义,如果脚本在模板内至少应该可以访问模板内的元素,否则模板几乎不能用于javascript,所以,我无法理解在里面使用脚本的意图模板或如何重用使用 javascript 的 web 组件,这样做有错吗?
那么,如何在不将所有脚本变量复制到窗口的情况下访问模板内脚本中的组件?
解决方案
正如您在全局范围<script>
内的<template>
运行中发现的那样
如果您使用 Angular,请注意 Angular会直接从模板中删除所有<script>
内容。
一种解决方法是添加一个在Element 范围内触发代码的 HTML 元素。
<img src onerror="[CODE]">
是最有可能的候选人:
然后可以调用全局函数,或this.getRootNode().host
立即运行。
<template id=scriptContainer>
<script>
console.log("script runs in Global scope!!");
function GlobalFunction(scope, marker) {
scope = scope.getRootNode().host || scope;
console.log('run', marker, 'scope:', scope);
scope.elementMethod && scope.elementMethod();
}
</script>
<img src onerror="(()=>{
this.onerror = null;// prevent endless loop if function generates an error
GlobalFunction(this,'fromIMGonerror');
})()">
</template>
<my-element id=ONE></my-element>
<my-element id=TWO></my-element>
<script>
console.log('START SCRIPT');
customElements.define('my-element',
class extends HTMLElement {
connectedCallback() {
console.log('connectedCallback', this.id);
this.attachShadow({ mode: 'open' })
.append(scriptContainer.content.cloneNode(true));
}
});
</script>
更详细的游乐场,包括注入 SCRIPT,位于:https ://jsfiddle.net/CustomElementsExamples/g134yp7v/
推荐阅读
- gstreamer - 在 ubuntu1804 上编译 Gstreamer/orc 0.4.32 以使用 ninja 在 rootfs 中运行 arm 发生未定义的引用异常
- c - 使用链表中的堆栈反转C中的字符串
- rust - 我们如何处理 gtk-rs 中输入框的按钮单击事件?
- .net-core - “处理组件 pubsub 错误:组件 pubsub 的初始化超时超过 5 秒”
- modelsim - 获取 Modelsim 库中已编译模块的列表
- iis - 隐藏/删除堆栈跟踪信息
- sonarqube - 声纳中用于竹子(插件)配置的正确主机 url 是什么?
- android - Cordova emulate android 应用程序运行正常,但在安装生成的 apk 应用程序时无法正常运行
- vulkan - Vulkan 实例化渲染奇怪的深度缓冲区行为
- apache2 - 将 Mod_evasive apache2 与 ufw 链接