在vue react中如何使用Web Components组件
作者:pg_li
在vue react中使用Web Components组件
1、web组件部分代码(git地址)
(function () { // 配置模板 const getEemplate = () => { // 创建模板 const template = document.createElement('template'); // 给模板设置id 方便查找 template.id = 'userCardTemplate'; template.innerHTML = ` <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; } .container { box-sizing: border-box; padding: 20px; height: 160px; } .container > .name { font-size: 20px; font-weight: 600; line-height: 1; margin: 0; margin-bottom: 5px; } .container > .email { font-size: 12px; opacity: 0.75; line-height: 1; margin: 0; margin-bottom: 15px; } .container > .button { padding: 10px 25px; font-size: 12px; border-radius: 5px; text-transform: uppercase; } </style> <img class="image"> <div class="container"> <p class="name"></p> <p class="email"></p> <button class="button">Follow John</button> </div> `; return template; }; // 讲模板放到dom结构中去 const createEemplate = () => { document.body.appendChild(getEemplate()); }; createEemplate(); class UserCard extends HTMLElement { constructor() { super(); this.creatShadow(); // 此处防止vue等框架类型的组件使用时 生命周期导致的参数异常 因此延迟绑定参数 setTimeout(() => { this.creatContent(); }); } /** * 封闭内部dom */ creatShadow() { this.shadow = this.attachShadow({mode: 'closed'}); } /** * 创建内部显示内容 */ creatContent() { var templateElem = document.getElementById('userCardTemplate'); var content = templateElem.content.cloneNode(true); content.querySelector('img').setAttribute('src', this.getAttribute('image')); content.querySelector('.container>.name').innerText = this.getAttribute('name'); content.querySelector('.container>.email').innerText = this.getAttribute('email'); this.shadow.appendChild(content); } /** * 当自定义元素第一次被连接到文档DOM时被调用 * 相当于mounted */ connectedCallback() { console.log('connectedCallback') } /** * 当自定义元素与文档DOM断开连接时被调用。 * 与beforeDestroy类似 */ disconnectedCallback() { console.log('disconnectedCallback') } /** * 当自定义元素被移动到新文档时被调用。 */ adoptedCallback() { console.log('adoptedCallback') } /** * 暴露哪些属性可以被监听 * @returns {string[]} */ static get observedAttributes() { return ['image', 'name', 'email'] } /** * 当自定义元素的一个属性被增加、移除或更改时被调用。 */ attributeChangedCallback() { console.log('attributeChangedCallback') } } window.customElements.define('user-card', UserCard); })(); /** * 自定义事件 */ this.dispatchEvent(new CustomEvent('submit', { detail: { data: {} } })); this.dispatchEvent(new CustomEvent('afterSubmit', { detail: { data: {} } }));
2、vue中使用部门代码
在public目录下得index.html中导入
<script src="./UserCard.js"></script> <template> <div id="app"> <user-card v-if="show" image="https://semantic-ui.com/images/avatar2/large/kristy.png" name="User Name" email="yourmail@some-email.com" ></user-card> <user-card image="https://semantic-ui.com/images/avatar2/large/kristy.png" name="test" email="yourmail@some-email.com" ></user-card> <button @click="onclick"> 测试 </button> </div> </template> <script> export default { data: function() { return { show: true } }, name: 'App', mounted() { }, methods: { // 测试web组件生命周期 onclick() { this.show = !this.show; } } } </script> <style> #app { font-family: Avenir, Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; } </style>
3、在react中使用
// submit事件 在点击登录时触发,传递的登录信息在,detail字段中 // afterSubmit 在登录数据下发服务端后触发 用于处理登录后的路由跳转等逻辑 <user-card url="https://www.baidu.com/" user="account" password="password" id="form" style="background-image: url(/assets/background.jpg)" body-style="right: 200px;" title="系统"> </user-card> <script> const form = document.querySelector('#form'); form.addEventListener('submit', (data)=> { console.log(data) }); form.addEventListener('afterSubmit', (data)=> { console.log(data) }); </script> /** * 处理react tsx中直接使用web components报错问题 */ interface UserCardModuleProps extends React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement> { title: string, ... } declare global { namespace JSX { interface IntrinsicElements { 'user-card': UserCardModuleProps } } }
4、在html中使用
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width"> <title>JS Bin</title> </head> <body> <user-card image="https://semantic-ui.com/images/avatar2/large/kristy.png" name="User Name" email="yourmail@some-email.com" ></user-card> <user-card image="https://semantic-ui.com/images/avatar2/large/kristy.png" name="test" email="yourmail@some-email.com" ></user-card> <script src="./public/UserCard.js"></script> <script > </script> </body> </html>
组件化统一标准——Web Components
Web Components是什么
一句话概括,Web Components是一个Web组件标准。现在的前端开发几乎已经离不开组件化开发了,无论是vue中的模板语法还是react中的JSX,都是把结构、样式和逻辑封装成一个组件,采用组件复用来提高开发效率。
既然组件如此重要,Web Components就是提供浏览器底层的支持,不依赖各种框架的支持和webpack的编译,让我们也能使用组件。
Web Components通过一种标准化的非侵入的方式封装一个组件,每个组件能组织好它自身的HTML、CSS、JavaScript,并且不会干扰页面上的其他代码。
Web Components的组成
Web Components由以下四个部分组成:
HTML templates
支持template标签和slot标签。slot标签支持动态替换模板中的HTML内容,它用name属性来作为唯一表示。template中的内容被插入到DOM之前,不会渲染,它可以放在document中的任何位置。
HTML Imports
改造一下上面的例子,将template的内容写到一个新的main.html文件中,然后通过link引入。
Shadow DOM
Shadow DOM提供了一种健壮的封装方式来做到页面节点的隔离,避免全局样式冲突,这也是Web Component的核心优势。
Shadow DOM中设置的样式没有影响外部<p>标签的样式。
Custom elements
在custom element的构造函数中,可以指定多个不同的回调函数,它们将会在元素的不同生命时期被调用:
connectedCallback
:当 custom element首次被插入文档DOM时,被调用。disconnectedCallback
:当 custom element从文档DOM中删除时,被调用。adoptedCallback
:当 custom element被移动到新的文档时,被调用。attributeChangedCallback
: 当 custom element增加、删除、修改自身属性时,被调用。
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。