温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

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

发布时间:2022-07-08 09:30:41 来源:亿速云 阅读:214 作者:iii 栏目:开发技术

这篇“Web Components如何实现类Element UI中的Card卡片”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Web Components如何实现类Element UI中的Card卡片”文章吧。

    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 h2 {
            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">
      <h2>Web Component</h2>
      <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.jpg" alt="天問">
      </com-card>
      <br>
      <br>
      <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.jpg" 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卡片”这篇文章的内容,相信大家都有了一定的了解,希望小编分享的内容对大家有帮助,若想了解更多相关的知识内容,请关注亿速云行业资讯频道。

    向AI问一下细节

    免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

    AI