我们是粉丝 自定义元素 这周围。 他们的设计使他们 特别适合延迟加载,这可能是性能的福音。
这篇文章我准备写一个女生。我的灵感来自 一个同事的 实验,我最近着手编写一个简单的自动加载器:每当自定义元素出现在 DOM 中时,如果它还不可用,我们就想加载相应的实现。 然后浏览器负责从那里升级这些元素。
您可能实际上并不需要所有这些; 通常有一个更简单的方法。 如果有意使用,此处显示的技术可能仍然对您的工具集有用。
为了保持一致性,我们希望我们的自动加载器也成为一个自定义元素——这也意味着我们可以通过 HTML 轻松配置它。 但首先,让我们逐步确定那些未解决的自定义元素:
class AutoLoader extends HTMLElement { connectedCallback() { let scope = this.parentNode; this.discover(scope); }
}
customElements.define("ce-autoloader", AutoLoader);
假设我们已经预先加载了这个模块(使用 async
是理想的),我们可以放下一个 <ce-autoloader>
元素进入 <body>
我们的文件。 这将立即开始对所有子元素的发现过程 <body>
,它现在构成了我们的根元素。 我们可以通过添加将发现限制在文档的子树中 <ce-autoloader>
改为各自的容器元素——事实上,我们甚至可能有不同子树的多个实例。
当然,我们还是要实现 discover
方法(作为 AutoLoader
上课):
discover(scope) { let candidates = [scope, ...scope.querySelectorAll("*")]; for(let el of candidates) { let tag = el.localName; if(tag.includes("-") && !customElements.get(tag)) { this.load(tag); } }
}
在这里,我们检查我们的根元素以及每个后代(*
). 如果它是一个自定义元素——如带连字符的标签所示——但尚未升级,我们将尝试加载相应的定义。 以这种方式查询 DOM 可能代价高昂,所以我们应该小心一点。 我们可以通过推迟这项工作来减轻主线程上的负载:
connectedCallback() { let scope = this.parentNode; requestIdleCallback(() => { this.discover(scope); });
}
requestIdleCallback
尚未得到普遍支持,但我们可以使用 requestAnimationFrame
作为后备:
let defer = window.requestIdleCallback || requestAnimationFrame; class AutoLoader extends HTMLElement { connectedCallback() { let scope = this.parentNode; defer(() => { this.discover(scope); }); } // ...
}
现在我们可以继续实施缺失的 load
动态注入方法 <script>
元件:
load(tag) { let el = document.createElement("script"); let res = new Promise((resolve, reject) => { el.addEventListener("load", ev => { resolve(null); }); el.addEventListener("error", ev => { reject(new Error("failed to locate custom-element definition")); }); }); el.src = this.elementURL(tag); document.head.appendChild(el); return res;
} elementURL(tag) { return `${this.rootDir}/${tag}.js`;
}
请注意中的硬编码约定 elementURL
。 该 src
属性的 URL 假设有一个目录,所有自定义元素定义都驻留在其中(例如 <my-widget>
→ /components/my-widget.js
). 我们可以提出更详尽的策略,但这足以满足我们的目的。 将此 URL 委托给一个单独的方法允许在需要时进行特定于项目的子类化:
class FancyLoader extends AutoLoader { elementURL(tag) { // fancy logic }
}
无论哪种方式,请注意我们依赖 this.rootDir
. 这就是前面提到的可配置性的用武之地。让我们添加一个相应的 getter:
get rootDir() { let uri = this.getAttribute("root-dir"); if(!uri) { throw new Error("cannot auto-load custom elements: missing `root-dir`"); } if(uri.endsWith("/")) { // remove trailing slash return uri.substring(0, uri.length - 1); } return uri;
}
你可能会想到 observedAttributes
现在,但这并没有真正让事情变得更容易。 加更新 root-dir
在运行时似乎是我们永远不需要的东西。
现在我们可以——而且必须——配置我们的元素目录: <ce-autoloader root-dir="/components">
.
有了这个,我们的自动加载器就可以完成它的工作了。 除了它只工作一次,对于初始化自动加载器时已经存在的元素。 我们可能还想考虑动态添加的元素。 就是那个地方 MutationObserver
发挥作用:
connectedCallback() { let scope = this.parentNode; defer(() => { this.discover(scope); }); let observer = this._observer = new MutationObserver(mutations => { for(let { addedNodes } of mutations) { for(let node of addedNodes) { defer(() => { this.discover(node); }); } } }); observer.observe(scope, { subtree: true, childList: true });
} disconnectedCallback() { this._observer.disconnect();
}
这样,每当 DOM 中出现新元素时,浏览器就会通知我们——或者更确切地说,我们各自的子树——然后我们使用它来重新启动发现过程。 (你可能会争辩说我们在这里重新发明了自定义元素,你是对的。)
我们的自动装载机现在功能齐全。 未来的增强可能会研究潜在的竞争条件并研究优化。 但对于大多数情况来说,这可能已经足够好了。 如果您有不同的方法,请在评论中告诉我,我们可以比较意见!
- SEO 支持的内容和 PR 分发。 今天得到放大。
- 柏拉图区块链。 Web3 元宇宙智能。 知识放大。 访问这里。
- Sumber: https://css-tricks.com/an-approach-to-lazy-loading-custom-elements/
- 1
- a
- 关于我们
- 以上
- 账号管理
- 通
- 添加
- 增加
- 所有类型
- 缓和
- 允许
- 已经
- 和
- 的途径
- 争论
- 围绕
- 可使用
- 浏览器
- 候选人
- 不能
- 关心
- 小心
- 可能性
- 查
- 孩子
- 程
- 如何
- 注释
- 比较
- 条件
- 容器
- 相应
- 可以
- 课程
- 习俗
- 设计
- 不同
- 发现
- 文件
- 不会
- DOM
- 下降
- 动态
- 更容易
- 容易
- 阐述
- 分子
- 更多
- 错误
- 醚(ETH)
- EV
- 甚至
- 所有的
- 除
- 昂贵
- 失败
- 球迷
- 姓氏:
- 止
- 充分
- 实用
- 未来
- 去
- 非常好
- 头
- 点击此处
- HTML
- HTTPS
- 理想
- 鉴定
- 立即
- 实施
- 履行
- 实施
- in
- 代替
- 调查
- IT
- JavaScript的
- 工作
- 类
- 知道
- 长度
- 极限
- 小
- 加载
- 装载
- 看
- 主要
- 使
- 制作
- 手段
- 方法
- 可能
- 失踪
- 模块
- 更多
- 最先进的
- 移动
- Mozilla的
- 多
- 需求
- 打印车票
- 全新
- 节点
- 部分
- 性能
- 柏拉图
- 柏拉图数据智能
- 柏拉图数据
- 播放
- 加
- 潜力
- 大概
- 过程
- 目的
- 种族
- 最近
- 去掉
- 那些
- 回报
- 根
- 情景
- 范围
- 似乎
- 分开
- 集
- 应该
- 如图
- 简易
- 单
- So
- 东西
- 开始
- 步
- 仍
- 策略
- 这样
- 支持
- 行李牌
- 需要
- 技术
- 其
- 事
- 思维
- 至
- true
- 更新
- 升级
- 的URI
- 网址
- us
- 使用
- 平时
- 通过
- 这
- 将
- 工作
- 合作
- 写作
- 您一站式解决方案
- 和风网