这篇文章主要介绍“怎么使用Web组件自定义元素”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“怎么使用Web组件自定义元素”文章能帮助大家解决问题。
在定义它们时必须使用至少两个单词和一个连字符
必须小写
自定义元素不能自闭合
class UserCard extends HTMLElement { constructor() { super(); } } window.customElements.define('user-card', UserCard);
组件的样式应该与代码封装在一起,只对自定义元素生效,不影响外部的全局样式,:host伪类,指代自定义元素本身
<html> <head></head> <body> <user-card name="Marty Mcfly"></user-card> <template id="userCardTemplate"> <div class="profile-picture"> <img src="marty.png" alt="Marty Mcfly" /> </div> <div class="name"></div> <style> :host { display: flex; align-items: center; width: 450px; height: 180px; background-color: #d4d4d4; border: 1px solid #d5d5d5; box-shadow: 1px 1px 5px rgba(0, 0, 0, 0.1); border-radius: 3px; overflow: hidden; padding: 10px; box-sizing: border-box; font-family: 'Poppins', sans-serif; } .image { flex: 0 0 auto; width: 160px; height: 160px; vertical-align: middle; border-radius: 5px; } </style> </template> <script> class UserCard extends HTMLElement { constructor() { super(); var templateElem = document.getElementById('userCardTemplate'); var content = templateElem.content.cloneNode(true); // 使用name参数 content.querySelector('.container>.name').innerText = this.getAttribute('name'); this.appendChild(content); } } window.customElements.define('user-card', UserCard); </script> </body> </html>
没有开启Shadow Dom 前template的内容会直接append到user-card节点上
开启Shadow Dom后,template和user-card中间多了一个节点叫shadowRoot
attachShadow 的mode参数有 open 和 closed 两个不同参数,区别是open时,外部能访问内部节点,closed时完全隔离
attachShadow 是大多数标签都支持的,比如 div,p,selection,但是a,ul,li等不支持
<script> class UserCard extends HTMLElement { constructor() { super(); var shadow = this.attachShadow( { mode: 'closed' } ); /******这行开启shadow*****/ var templateElem = document.getElementById('userCardTemplate'); var content = templateElem.content.cloneNode(true); // 使用name参数 content.querySelector('.container>.name').innerText = this.getAttribute('name'); shadow.appendChild(content); /******这行template添加到shadow*****/ } } window.customElements.define('user-card', UserCard); </script>
class UserCard extends HTMLElement { // attributeChangedCallback 能监听的属性 static get observedAttributes() {return ['name', 'url']; } constructor() { super(); // 可以创Shadom,通过this.shadowRoot获取 // this.attachShadow({ mode: 'open' }) } connectedCallback (){ console.log('钩子,元素append到ducument触发') } disconnectedCallback (){ console.log('钩子,元素从document删除触发') } // 只有observedAttributes 中监听的属性name,url变化会触发下面回调 attributeChangedCallback (attr, oldVal, newVal){ console.log('钩子,元素属性改变时触发') } } window.customElements.define('user-card', UserCard);
姓名 | 何时调用 |
---|---|
constructor | 元素的一个实例被创建。对于初始化状态、设置事件监听器或创建shadow Dom。 |
connectedCallback | 每次将元素插入 DOM 时调用。一般主要工作代码写在这里。 |
disconnectedCallback | 每次从 DOM 中删除元素时调用。一般写清理的一些代码。 |
attributeChangedCallback(attrName, oldVal, newVal) | 观察属性在添加、删除、更新、替换时被调用。只有属性中列出的observedAttributes属性才会收到此回调。 |
adoptedCallback | 自定义元素已被移动到一个新的document(例如有人称为document.adoptNode(el))。 |
html中attribute 和 类中property 是各自独立,想要建立映射需要手动设置
getter和setter生效
<html> <head></head> <body> <user-card id="usercard" name="Marty"></user-card> <script> class UserCard extends HTMLElement { _name = null; constructor() { super(); } set name(value) { this._name = name; } get name() { return this._name; } } window.customElements.define("user-card", UserCard); </script> </body> </html>
测试
document.getElementById('usercard').name = 'jack' // 会进入setter document.getElementById('usercard').name // 会进入getter,返回jack document.getElementById('usercard').getAttribute('name') // 不会进入getter,返回Marty document.getElementById('usercard').setAttribute('name','bob') // 不会进入setter document.getElementById('usercard').getAttribute('name') // 不会进入getter,返回bob
此时,我们看到 setAttribute 和 gettAttribute 都不会触发类中的 getter 和 setter 方法,但是可以看到如果是 .name 这样的方式可以触发 ,那么改造方式如下:
方式一 重写 setAttribute :
<html> <head></head> <body> <user-card id="usercard" name="Marty"></user-card> <user-card id="uc" name="Marty Mcfly"></user-card> <script> const rawSetAttribute = Element.prototype.setAttribute; class UserCard extends HTMLElement { _name = null; constructor() { super(); Element.prototype.setAttribute = function setAttribute(key, value) { // 特定的指定name if (key == "name") { this.name = value; // 这样就能触发 setter } rawSetAttribute.call(this, key, value); }; } set name(value) { debugger; this._name = name; } get name() { debugger; return this._name; } } window.customElements.define("user-card", UserCard); </script> </body> </html>
方式二 重写 observedAttributes和attributeChangedCallback 监听 name :
<html> <head></head> <body> <user-card id="uc" name="Marty Mcfly"></user-card> <script> class UserCard extends HTMLElement { static get observedAttributes() { return ["name"]; } _name = null; constructor() { super(); } attributeChangedCallback(attr, _oldVal, newVal) { if (attr == "name") { this.name = newVal; } } set name(value) { debugger; this._name = name; } get name() { debugger; return this._name; } } window.customElements.define("user-card", UserCard); </script> </body> </html>
由此,可以看到组件在页面渲染时会进入setter方法,而且 setAttribute,getAttribute 均进入到setter方法
document.getElementById('usercard').setAttribute('name','bob') // 会进入setter document.getElementById('usercard').getAttribute('name') // 会进入getter,返回bob
假设您想创建一个更高级的<button>. 与其复制<button>的行为和功能,更好的选择是使用自定义元素逐步增强现有元素。
扩展现有元素的主要好处是获得其所有特性(DOM 属性、方法、可访问性)。
Safari浏览器兼容性待提高
要扩展一个元素,您需要创建一个继承自正确 DOM 接口的类定义。前面例子都是继承HTMLElement,现在更多继承例如,按钮HTMLButtonElement,图片HTMLImageElement
class FancyButton extends HTMLButtonElement { constructor() { super(); this.addEventListener('click', e => this.drawRipple(e.offsetX, e.offsetY)); } drawRipple(x, y) { let div = document.createElement('div'); div.classList.add('ripple'); this.appendChild(div); div.style.top = `${y - div.clientHeight/2}px`; div.style.left = `${x - div.clientWidth/2}px`; div.style.backgroundColor = 'currentColor'; div.classList.add('run'); div.addEventListener('transitionend', e => div.remove()); } } customElements.define('fancy-button', FancyButton, {extends: 'button'});
注意:扩展基础元素时,对的调用 define() 略有变化。必需的第三个参数告诉浏览器您正在扩展哪个标签
调用方式一:
<button is="fancy-button" disabled>Fancy button!</button>
调用方式二:
let button = document.createElement('button', {is: 'fancy-button'}); button.textContent = 'Fancy button!'; button.disabled = true; document.body.appendChild(button);
调用范式三
let button = new FancyButton(); button.textContent = 'Fancy button!'; button.disabled = true;
关于“怎么使用Web组件自定义元素”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识,可以关注亿速云行业资讯频道,小编每天都会为大家更新不同的知识点。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。