|
正文
WebComponent 是官方定义的自定义组件实现方式,它可以让开发者不依赖任何第三方框架(如Vue,React)来实现自定义页面组件;达到组件复用效果
一个简单例子,让页面显示 hello world:- <body>
- <!-- 使用组件的方式 -->
- <my-text />
- <script>
- class MyText extends HTMLElement {
- constructor() {
- super();
- this.append("hello world");
- }
- }
- window.customElements.define("my-text", MyText);
- </script>
- </body>
复制代码 三项主要技术
1、Custom elements (自定义元素)
- 一组 JavaScript API,允许您定义 custom elements 及其行为,然后可以在您的用户界面中按照需要使用它们
分为两种形式:
自主定制元素:是独立的元素,它不继承其他内建的 HTML 元素,可以直接把它们写成 HTML 标签的形式,来在页面上使用,例如我们刚才自定义的自定义内置元素:继承自内置的 HTML 元素。指定所需扩展的元素
- 使用时需通过属性指定的名称,必须包含一个短横线
- 注册的时候必须使用的属性
- <!-- 自定义内置元素 使用 is-->
- <body>
- <!-- 使用组件的方式 -->
- <p is="color-p" color="green">云牧</p>
- <script>
- class ColorP extends HTMLParagraphElement {
- constructor() {
- super();
- this.style.color = this.getAttribute("color");
- }
- }
- window.customElements.define("color-p", ColorP, { extends: "p" });
- </script>
- </body>
复制代码 推荐在生命周期函数,处理节点操作- <!-- 自主定制元素-->
- <body>
- <my-text />
- <script>
- class MyText extends HTMLElement {
- constructor() {
- super();
- }
- connectedCallback() {
- this.append("hello world");
- }
- }
- window.customElements.define("my-text", MyText);
- </script>
- </body>
复制代码 生命周期函数
:插入文档时,可能被多次触发,比如删除后又添加到文档:从文档删除时,可配置做清理工作:被移动新文档时:属性变化时
- 配合属性一起使用,指定监听的属性
- 使用方法更新属性
不同操作触发的生命周期函数:
例子:- <body>
- <div id="container">
- <p is="my-text" text="云牧" id="myText"></p>
- </div>
- <button id="btnUpdateText">更新属性</button>
- <button id="btnRemove">删除节点</button>
- <button id="btnRestore">恢复节点</button>
- <button id="btnAdopt">移动节点</button>
- <iframe src="./ifr.html" id="ifr"></iframe>
- <script>
- class MyText extends HTMLParagraphElement {
- constructor() {
- super();
- }
- connectedCallback() {
- console.log("生命周期:connectedCallback");
- this.append("你好:" + this.getAttribute("text"));
- }
- disconnectedCallback() {
- console.log("生命周期:disconnectedCallback");
- this.innerHTML = "";
- }
- // 监测的属性
- static get observedAttributes() {
- return ["text"];
- }
- attributeChangedCallback(name, oldValue, newValue) {
- console.log("生命周期:attributeChangedCallback", name, oldValue, newValue);
- // 最先触发是此函数,判断是不是第一次触发,第一次的话,只由 connectedCallback 处理
- if (oldValue != null) {
- this.replaceChildren("你好:" + newValue);
- }
- }
- adoptedCallback() {
- console.log("生命周期:adoptedCallback");
- }
- }
- window.customElements.define("my-text", MyText, { extends: "p" });
- const myText = document.getElementById("myText");
- btnUpdateText.addEventListener("click", function (e) {
- myText.setAttribute("text", "黛玉");
- });
- btnRemove.addEventListener("click", function (e) {
- myText.remove();
- });
- btnRestore.addEventListener("click", function (e) {
- container.appendChild(myText);
- });
- btnAdopt.addEventListener("click", () => {
- const textNode = ifr.contentWindow.document.getElementById("myText");
- container.appendChild(document.adoptNode(textNode));
- });
- </script>
- </body>
复制代码 2、HTML templates(HTML 模板)
- 使用 JS 模板字串符的方式创建模板,提示不友好,复用性差
- <body>
- <product-item
- name="关东煮"
- img="//img10.360buyimg.com/seckillcms/s200x200_jfs/t1/121953/18/20515/175357/61e7dc79Ee0acbf20/4f4f56abd2ea2f75.jpg!cc_200x200.webp"
- price="49.8"
- ></product-item>
- <script>
- class ProductItem extends HTMLElement {
- constructor() {
- super();
- }
- connectedCallback() {
- const content = `
- <img class="img" src="https://misc.360buyimg.com/lib/skin/e/i/error-jd.gif" />
- <div class="name"></div>
- <div class="price"></div>
- `;
- this.innerHTML = content;
- this.querySelector(".img").src = this.getAttribute("img");
- this.querySelector(".name").innerText = this.getAttribute("name");
- this.querySelector(".price").innerText = this.getAttribute("price");
- }
- }
- window.customElements.define("product-item", ProductItem);
- </script>
- </body>
复制代码 template 方式- <body>
- <!-- template -->
- <template id="tpl-product-item">
- <img class="img" src="https://misc.360buyimg.com/lib/skin/e/i/error-jd.gif" />
- <div class="name"></div>
- <div class="price"></div>
- </template>
- <product-item
- name="关东煮"
- img="//img10.360buyimg.com/seckillcms/s200x200_jfs/t1/121953/18/20515/175357/61e7dc79Ee0acbf20/4f4f56abd2ea2f75.jpg!cc_200x200.webp"
- price="49.8"
- ></product-item>
- <script>
- class ProductItem extends HTMLElement {
- constructor() {
- super();
- }
- connectedCallback() {
- const content = document.getElementById("tpl-product-item").content.cloneNode(true);
- // 插入克隆的模板内容
- this.append(content);
- this.querySelector(".img").src = this.getAttribute("img");
- this.querySelector(".name").innerText = this.getAttribute("name");
- this.querySelector(".price").innerText = this.getAttribute("price");
- }
- }
- window.customElements.define("product-item", ProductItem);
- </script>
- </body>
复制代码 slot- <body>
- <template id="tpl-test">
- <style>
- .title {
- color: green;
- }
- </style>
- <div class="title">标题</div>
- <slot name="slot-des">默认内容</slot>
- </template>
- <test-item>
- <div slot="slot-des">不是默认内容</div>
- </test-item>
- <script>
- class TestItem extends HTMLElement {
- constructor() {
- super();
- }
- connectedCallback() {
- const content = document.getElementById("tpl-test").content.cloneNode(true);
- const shadow = this.attachShadow({ mode: "open" });
- shadow.append(content);
- }
- }
- window.customElements.define("test-item", TestItem);
- </script>
- </body>
复制代码 3、Shadow DOM(影子 DOM)
影子DOM,其内部样式不共享- <body>
- <!-- 不受外部 .container.container 的颜色影响 -->
- <my-item-s></my-item-s>
- <div class="container">My item</div>
- <style>
- .container.container {
- color: green;
- }
- </style>
- <template id="tpl">
- <style>
- .container {
- color: pink;
- }
- </style>
- <div class="container">My Item</div>
- </template>
- <script>
- class MyItemShadow extends HTMLElement {
- constructor() {
- super();
- }
- connectedCallback() {
- const content = document.getElementById("tpl").content.cloneNode(true);
- const shadow = this.attachShadow({ mode: "open" });
- shadow.append(content);
- }
- }
- window.customElements.define("my-item-s", MyItemShadow);
- </script>
- </body>
复制代码 影子DOM,其内部元素不可以直接被访问到
有一个重要的参数 mode
- open: shadow root 元素通过 js 从外部访问根节点
- closed:拒绝 js 从外部访问关闭的 shadow root 节点
- <body>
- <template id="tpl">
- <div class="title"></div>
- <div class="des"></div>
- </template>
- <note-item class="note-item" title="标题" des="内容"></note-item>
- <script>
- class NoteItem extends HTMLElement {
- constructor() {
- super();
- }
- connectedCallback() {
- const content = document.getElementById("tpl").content.cloneNode(true);
- const shadow = this.attachShadow({ mode: "open" });
- shadow.append(content);
- // 如果是 open 则可以继续访问操作内部 dom
- // console.log(document.querySelector(".note-item").shadowRoot.querySelector(".title"));
- shadow.querySelector(".title").textContent = this.getAttribute("title");
- shadow.querySelector(".des").textContent = this.getAttribute("des");
- }
- }
- window.customElements.define("note-item", NoteItem);
- </script>
- </body>
复制代码 引入外部样式:- <body>
- <template id="tpl">
- <!-- 方式一: -->
- <link rel="stylesheet" href="index.css" rel="external nofollow" />
- <div>My Item</div>
- </template>
- <my-item></my-item>
- <script>
- class MyItem extends HTMLElement {
- constructor() {
- super();
- }
- connectedCallback() {
- const content = document.getElementById("tpl").content.cloneNode(true);
- const shadow = this.attachShadow({ mode: "open" });
- shadow.append(content);
- // 方式二:
- const linkEl = document.createElement("link");
- linkEl.setAttribute("rel", "stylesheet");
- linkEl.setAttribute("href", "index.css");
- shadow.appendChild(linkEl);
- }
- }
- window.customElements.define("my-item", MyItem);
- </script>
- </body>
复制代码 动态创建 webComponent 组件例子
- <body>
- <div id="product-list" style="display: flex"></div>
- <template id="product-item">
- <style>
- .product-item {
- margin-left: 15px;
- cursor: pointer;
- }
- .img {
- width: 100px;
- }
- .name {
- text-align: center;
- }
- .price {
- color: #999;
- text-align: center;
- }
- </style>
- <div class="product-item">
- <img class="img" src="https://misc.360buyimg.com/lib/skin/e/i/error-jd.gif" />
- <div class="name"></div>
- <div class="price"></div>
- </div>
- </template>
- <script>
- class ProductItemElement extends HTMLElement {
- constructor(props) {
- super(props);
- this.addEventListener("click", () => {
- window.open(`https://item.jd.com/${this.id}.html`);
- });
- }
- connectedCallback() {
- const shadow = this.attachShadow({ mode: "open" });
- const content = document.getElementById("product-item").content.cloneNode(true);
- content.querySelector(".img").src = this.img;
- content.querySelector(".name").innerText = this.name;
- content.querySelector(".price").innerText = this.price;
- shadow.appendChild(content);
- }
- }
- window.customElements.define("product-item", ProductItemElement);
- </script>
- <script>
- const products = [
- {
- name: "关东煮",
- img: "//img10.360buyimg.com/seckillcms/s200x200_jfs/t1/121953/18/20515/175357/61e7dc79Ee0acbf20/4f4f56abd2ea2f75.jpg!cc_200x200.webp",
- id: "10026249568453",
- price: 49.8
- },
- {
- name: "土鸡蛋",
- img: "//img11.360buyimg.com/seckillcms/s200x200_jfs/t1/172777/32/27438/130981/61fbd2e0E236000e0/7f5284367e2f5da6.jpg!cc_200x200.webp",
- id: "10024773802639",
- price: 49.8
- },
- {
- name: "东北蜜枣粽子",
- img: "//img20.360buyimg.com/seckillcms/s200x200_jfs/t1/129546/31/19459/110768/60b1f4b4Efd47366c/3a5b80c5193bc6ce.jpg!cc_200x200.webp",
- id: "10035808728318",
- price: 15
- }
- ];
- const productList = document.getElementById("product-list");
- const elList = products.map(product => {
- // 创建组件
- const el = document.createElement("product-item");
- el.img = product.img;
- el.name = product.name;
- el.price = product.price;
- el.id = product.id;
- return el;
- });
- productList.append.apply(productList, elList);
- </script>
- </body>
复制代码 以上就是2023年了该了解下WebComponent使用教程的详细内容,更多关于WebComponent使用教程的资料请关注脚本之家其它相关文章!
来源:https://www.jb51.net/article/276362.htm
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作! |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
x
|