Web Components实现类Element UI中的Card卡片

目录

引言

Web Components 核心组成

1. Custom Elements

2. Shadow DOM

3. templates 和 slots

完整代码

Web Components vs Vue Components

Web Components 生命周期回调函数

优点 and 缺点

基于web components的框架

引言

Web Components 是一个浏览器原生支持的组件化方案,允许你创建新的自定义、可封装、可重用的HTML 标记。不用加载任何外部模块,直接就可以在浏览器中跑。本文就简单介绍一下:使用 Web Components 实现一个类 Element UI 中的 Card 卡片组件。

随着前端工程化生态日益成熟,出现了很多优秀的框架,如:VueReactAngular等等,极大的提高了日常开发效率。

其中组件化开发发挥了至关重要的作用,但是这些组件化开发都需要依赖第三方框架,编译打包之后才能在浏览器正常使用。

而原生组件 Web Components ,相比与第三方框架使用起来更简单直接,符合直觉,不用加载任何外部模块,代码量小。

Web Components 核心组成

自定义元素(custom element),使用 window.customElements.define API注册

Shadow DOM隔离,影藏标记结构、样式和行为

可以在<template>中定义标记结构、样式,多次重用。利用 slot 插槽、命名插槽,可以传入定制化的结构UI,使用上类似 Vue 中的 slot 插槽

1. Custom Elements

自定义的 HTML 标签,称为自定义元素(custom element)。根据规范,自定义元素的名称必须包含连词线-,用与区别原生的 HTML 元素。所以,<com-card>不能写成<comcard>

<div id="custom-card" class="com-card"> <div class="com-card-head"> <slot name="head"></slot> </div> <div class="com-card-body"> <slot></slot> <div class="link-wrap"> <a class="link" href="" title=" rel="external nofollow" rel="external nofollow" "></a> </div> </div> </div> <script> class ComCard extends HTMLElement { constructor() { super() var tplEle = document.getElementById('custom-card') this.append(tplEle) } } window.customElements.define('com-card', ComCard) </script>

这样就注册了浏览器可识别渲染的一个自定义元素标签。

2. Shadow DOM

Shadow DOM 是对DOM的一个封装。可以将标记结构、样式和行为隐藏起来,并与页面上的其他代码相隔离,保证不同的部分不会混在一起,可使代码更加干净、整洁。

使用自定义元素的 this.attachShadow() 方法可以开启 Shadow DOM

class ComCard extends HTMLElement { constructor() { super() var shadow = this.attachShadow({mode: 'closed'}) // open var tplEle = document.getElementById('custom-card') shadow.appendChild(tplEle) } } window.customElements.define('com-card', ComCard);

其中参数{ mode: 'closed' },表示 Shadow DOM 是封闭的,不允许外部访问。

3. templates 和 slots

因为组件的样式应该与代码封装在一起,只对自定义元素生效,不影响外部的全局样式。所以,可以把样式写在<template>里面,这样作为自定义元素结构的基础可以被多次重用。

<template id="custom-card-template"> <style> .com-card { } </style> <div class="com-card"> </div> </template> <script> class ComCard extends HTMLElement { constructor() { super(); var shadow = this.attachShadow({mode: 'closed'}) // open var tplEle = document.getElementById('custom-card-template') var content = tplEle.content.cloneNode(true) shadow.appendChild(content) } } window.customElements.define('com-card', ComCard); </script> 完整代码 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Web Component</title> <style> * { box-sizing: border-box; } body { font-size: 14px; } .box { padding: 5px 0 30px; } .box .caption { display: none; } .box h1 { text-align: center; } .box li { color: #666; font-size: 14px; line-height: 1.8; margin-top: 15px; } .img { display: block; width: 80%; margin: 0 !important; } .card-head { display: flex; justify-content: space-between; align-items: center; } .card-title { color: #333; font-size: 16px; } .card-head-btn { color: #409eff; cursor: pointer; text-decoration: none !important; } .card-head-btn:hover { text-decoration: none; } </style> </head> <body> <div class="box"> <h1>Web Component</h1> <com-card data-show-head="0" data-url="https://tiven.cn" data-title="天问博客"> <div slot="head" class="card-head"> <div class="card-title">卡片名称</div> <a class="card-head-btn">操作按钮</a> </div> <img class="img" src="https://tiven.cn/static/img/kpl-sunwukong-a3Lt-ed2NG9r4NFDm_9DA.webp" alt="天問"> </com-card> <com-card data-show-head="1" data-url="https://tiven.cn/p/de241e23/" data-title="Vite+Vue3+Vant快速构建项目"> <div slot="head" class="card-head"> <div class="card-title">卡片名称</div> <a class="card-head-btn" onclick="hello()">操作按钮</a> </div> <img class="img" src="https://tiven.cn/static/img/kpl-xuance-JqX71qH7aTflHV_gqvhIc.webp" alt="天問"> <ol> <li>君不见黄河之水天上来,奔流到海不复回。</li> <li>君不见高堂明镜悲白发,朝如青丝暮成雪。</li> <li>天生我材必有用,千金散尽还复来。</li> </ol> </com-card> </div> <template id="custom-card-template"> <style> .com-card { min-width: 200px; min-height: 100px; border-radius: 4px; border: 1px solid #ebeef5; background-color: #fff; overflow: hidden; color: #303133; transition: .3s; box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); } .com-card-head { padding: 10px 20px; border-bottom: 1px solid #ebeef5; box-sizing: border-box; } .com-card-body { padding: 20px; } .link-wrap { text-align: left; padding-top: 20px; } .link { display: inline-block; height: 42px; line-height: 43px; padding: 0 30px; text-align: center; cursor: pointer; color: #fff; background-color: #409eff; border-color: #409eff; -webkit-appearance: none; box-sizing: border-box; outline: none; transition: .1s; font-weight: 500; -moz-user-select: none; -webkit-user-select: none; -ms-user-select: none; font-size: 14px; border-radius: 4px; text-decoration: none !important; } </style> <div class="com-card"> <div class="com-card-head"> <slot name="head"></slot> </div> <div class="com-card-body"> <slot></slot> <div class="link-wrap"> <a class="link" href="" title=" rel="external nofollow" rel="external nofollow" "></a> </div> </div> </div> </template> <script> class ComCard extends HTMLElement { constructor() { super(); var shadow = this.attachShadow({mode: 'closed'}) // open var tplEle = document.getElementById('custom-card-template') var content = tplEle.content.cloneNode(true) var attrList = Array.from(this.attributes); var props = attrList.reduce((prev, item)=>{ prev[item.name] = item.value return prev }, {}) if (props['data-show-head']!=='1') { var head = content.querySelector('.com-card-head') head.remove() } var urlEle = content.querySelector('.link') if (props['data-url'] && props['data-title']) { urlEle.href = props['data-url'] urlEle.title = props['data-title'] urlEle.innerText = props['data-title'] } else { urlEle.remove() } shadow.appendChild(content) } connectedCallback(){ //在这里发送数据请求(Ajax) console.log('connectedCallback') } //被从文档DOM中删除时调用 disconnectedCallback(){ console.log('disconnectedCallback') } //被移动到新的文档时调用 adoptedCallback(){ console.log('adoptedCallback') } //当增加、删除、修改自身的属性时被调用 attributeChangedCallback(){ console.log('attributeChangedCallback') } } window.customElements.define('com-card', ComCard); function hello() { alert('Hello,Web Component') } </script> </body> </html>

最终效果如上图所示

Web Components vs Vue Components Vue ComponentWeb Component
data实例属性
propsattributes
watchobservedAttributes、attributeChangedCallback
computedgetters
methodsclass methods
mountedconnectedCallback
destroyeddisconnectedCallback
style scopedtemplate中的style
templatetemplate
Web Components 生命周期回调函数

connectedCallback:当 custom element首次被插入文档DOM时,被调用。

disconnectedCallback:当 custom element从文档DOM中删除时,被调用。

adoptedCallback:当 custom element被移动到新的文档时,被调用。

attributeChangedCallback: 当 custom element增加、删除、修改自身属性时,被调用。

优点 and 缺点

优点:

浏览器原生支持,不需要引入额外的第三方库

语义化

复用性,移植性高

不同团队不同项目可以共用组件

缺点:

需要操作DOM

目前浏览器兼容性、性能方面不够友好

和外部css交互比较难

基于web components的框架

LitElement 是一个快速、轻量级的 Web UI 框架。使用 lit-html 来渲染元素。

Polymer 是一款实用、基于事件驱动、封装性和交互性强的 Web UI 框架。

Omi 是基于 Web 组件的跨框架跨平台框架 。移动端 & 桌面 & 小程序。

以上就是Web Components实现类Element UI中的Card卡片的详细内容,更多关于Web Components实现Element UI的资料请关注易知道(ezd.cc)其它相关文章!

推荐阅读

    新一代的Office代替Web浏览器

    新一代的Office代替Web浏览器,,如果你用Office来取代网络浏览器,一定会有很多读者感到难以置信,在客户端安装Web浏览器就足够了,不管是因特网

    IE脚本错误如何做Web脚本错误解决技巧

    IE脚本错误如何做Web脚本错误解决技巧,,这个问题是由于这样的事实,对网页的HTML源代码和客户端脚本不正确的工作,如微软Jscript或Visual Basic脚本

    WebRTC视频分辨率设置

    WebRTC视频分辨率设置,视频,宽度,前面我们能够打开摄像头。getUserMedia()时会传入参数,在参数里我们可以指定宽高信息。通过宽高参数控制

    java设置编码格式|javaweb设置编码格式

    java设置编码格式|javaweb设置编码格式,,javaweb设置编码格式从网页登录邮箱,打开你要看的邮件,右键点击右键内容,里边有一项时邮件编码,选你

    1.webpack由浅入深

    1.webpack由浅入深,文件,模块,1.webpack概念:webpack是一个静态模块打包机,webpack处理应用程序时,把一个项目当作整体,通过一个给定的主文件

    web的标注快捷键|标注快捷键word

    web的标注快捷键|标注快捷键word,,1. 标注快捷键wordWord中的常用字体样式快捷键1.打开word文档,按Ctrl+A全选文字内容。2.按Ctrl+B即可把

    webcheck.dll是什么

    webcheck.dll是什么,系统,文件,复制,没声音,电脑蓝屏,打不开,  DLL 文件: webcheck 或者 webcheck.dllDLL 名称: Web Site Monitorwebcheck.dll

    前端界面快捷键|web前端开发快捷键

    前端界面快捷键|web前端开发快捷键,,1. web前端开发快捷键EC1-A鼠标不错定位精准手感舒适长时间使用也不会累 键盘的话建议罗技G710青轴版

    在线书城系统|在线书城系统 java web

    在线书城系统|在线书城系统 java web,,1. 在线书城系统3g书城小说网app是一款专为广大安卓用户打造的手机小说阅读软件,这款软件内容丰富,安