HTML / DOM 规范了 Web Components,浏览提供可以自己定义组件的方式
Vue 的模板系统参考 Web Componets 的规范来进行上层设计
希望有这种方案提供给开发者能自定义可重用的、可被浏览器正常解析的标签,让逻辑样式标签被封装在一个组件中,最终用自定义标签渲染视图
基本使用方法
标签
- 标准化以前
<script type="text/tpl"></script>
这种写法
不会被渲染,要配合自定义标签使用- content 获取其文档片段
方法
window.customElement 定义一个自定义标签
- window.customElement.define(标签名, class extends HTMLElment)
- HTMLElement.attach / HTMLElement.attachShadow 附加到 shadowDOM 的 Node
- 参数为一个 options 对象,有一属性 mode 有两个值,表示是否之后是否对 ShadowDOM 操作
- ‘open’ 打开可以操作
- ‘close’ 封闭不能操作
例子
JS 的方式
<my-info avatar="https://xxx.com/1.jpg" name="XXX" age="36" occupation="teacher" > The information of XXX </my-info>
window.customeElement.define('my-info', class extends HTMLElement { constructor () { super(); // this 就是这个 my-info 的标签 this.title = this.textContent; this.avatar = this.getAttribute('avatar'); this.name = this.getAttribute('name'); this.age = this.getAttribute('age'); this.occupation = this.getAttribute('occupation'); this.init(); } init() { const shadowDOM = this.attachShadow({mode: 'open'}); shadowDOM.appendChild(this.createDOM()) } createDOM () { const oContainer = document.createElement('div'); oConatiner.className = 'my-info-container'; oConatiner.appendChild(this.createTitle()); oConatiner.appendChild(this.createAvatar()); oConatiner.appendChild(this.createName()); oConatiner.appendChild(this.createAge()); oConatiner.appendChild(this.createOccupation()); return oContainer; } createTitle () { const oTitle = document.createElement('h1'); oTitle.className = 'my-info-title'; oTitle.textContent = this.title; return oTitle; } createAvatar () { const oAvatar = document.createElement('div'); oAvatar.className = 'my-info-avatar'; oAvatar.innerHTML = `<img style="width: 100px" src="${this.avatar}" />`; return oAvatar; } createName () { const oName = document.createElement('p'); oName.className = 'my-info-name'; oName.textContent = `name: ${this.myName}`; return oName; } createAge () { const oAge = document.createElement('p'); oAge.className = 'my-info-age'; oAge.textContent = `age: ${this.age}`; return oAge; } createOccupation() { const oOccupation = document.createElement('p'); oOccupation.className = 'my-info-occupation'; oOccupation.textContent = `Name: ${this.occupation}`; return oOccupation; } } )
使用 template 与 slot
<template id="my-article-template"> <style> h1 { color: red; } h1 .autor, h1 .date-time { font-size: 16px; color: #666; font-weight: normal; } </style> <div class="my-article"> <h1 class="my-article-title"> <slot name='title' class="title"></slot> <slot name='author' class="author"></slot> <slot name='dateTime' class="date-time"></slot> </h1> <p class=“my-article-content”> <slot name="content"></slot> </p> </div> </template> <my-article> <p slot="title">This is my TITLE</p> <span slot="author">XXX</span> <span slot="dateTime">- 14:15</span> <p slot="content">This is my CONTENT</p> </my-article>
class MyAtricle extends HTMLElement { constructor(){ super(); const _tpl = document.getElementById('my-article-template').content; const shadowDOM = this.attachShadow({ mode: open }); shadowDOM.appendChild(_tpl.cloneNode(true)); // 把 Node.cloneNode(true) true 为深度克隆 } } window.customeElement.define('my-article', MyArticle);