目录
我们知道的Web组件使用名称规范组件传参数并可以写模板包括js和cssShadow Dom 影子节点类中的构造函数和钩子函数getter/setter属性和属性反射扩展原生 HTML我们知道的
第一:我们熟知的HTML标签有 a, p, div, section, ul, li, h2, article, head, body, strong, video, audio 等等
(资料图片)
第二:我们知道,a标签是链接,p标签是段落,div是块级,h2是字体,strong 是粗体,video 可以播放视频,标签可以添加click等事件等等
所以,那么显然我们知道这些标签的名称,而且知道他们的默认的css样式,而且知道他们默认的js事件
由此,我们是否可以自定义标签呢,由我们自己规定名称,规定默认css样式,规定标签默认显示dom结构,规定默认事件呢?
答案当然是肯定的!!下面就介绍主角Web组件
Web组件使用
名称规范
在定义它们时必须使用至少两个单词和一个连字符必须小写自定义元素不能自闭合class UserCard extends HTMLElement { constructor() { super(); } } window.customElements.define("user-card", UserCard);
组件传参数并可以写模板包括js和css
组件的样式应该与代码封装在一起,只对自定义元素生效,不影响外部的全局样式,:host伪类,指代自定义元素本身
<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>
Shadow Dom 影子节点
没有开启Shadow Dom 前template的内容会直接append到user-card节点上开启Shadow Dom后,template和user-card中间多了一个节点叫shadowRootattachShadow 的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))。 |
getter/setter属性和属性反射
html中attribute 和 类中property 是各自独立,想要建立映射需要手动设置
getter和setter生效
<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>
测试
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 :
<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>
方式二 重写 observedAttributes和attributeChangedCallback 监听 name :
<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>
由此,可以看到组件在页面渲染时会进入setter方法,而且 setAttribute,getAttribute 均进入到setter方法
document.getElementById("usercard").setAttribute("name","bob") // 会进入setter document.getElementById("usercard").getAttribute("name") // 会进入getter,返回bob
扩展原生 HTML
假设您想创建一个更高级的
扩展现有元素的主要好处是获得其所有特性(DOM 属性、方法、可访问性)。Safari浏览器兼容性待提高要扩展一个元素,您需要创建一个继承自正确 DOM 接口的类定义。前面例子都是继承HTMLElement,现在更多继承例如,按钮HTMLButtonElement,图片HTMLImageElementclass 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() 略有变化。必需的第三个参数告诉浏览器您正在扩展哪个标签
调用方式一:调用方式二:Fancy 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组件自定义元素示例详解的详细内容,更多关于微前端Web组件自定义元素的资料请关注脚本之家其它相关文章!
X 关闭
X 关闭
- 1联想拯救者Y70发布最新预告:售价2970元起 迄今最便宜的骁龙8+旗舰
- 2亚马逊开始大规模推广掌纹支付技术 顾客可使用“挥手付”结账
- 3现代和起亚上半年出口20万辆新能源汽车同比增长30.6%
- 4如何让居民5分钟使用到各种设施?沙特“线性城市”来了
- 5AMD实现连续8个季度的增长 季度营收首次突破60亿美元利润更是翻倍
- 6转转集团发布2022年二季度手机行情报告:二手市场“飘香”
- 7充电宝100Wh等于多少毫安?铁路旅客禁止、限制携带和托运物品目录
- 8好消息!京东与腾讯续签三年战略合作协议 加强技术创新与供应链服务
- 9名创优品拟通过香港IPO全球发售4100万股 全球发售所得款项有什么用处?
- 10亚马逊云科技成立量子网络中心致力解决量子计算领域的挑战