欢迎光临
我们一直在努力

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

这篇“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 Component Web Component
    data 实例属性
    props attributes
    watch observedAttributes、attributeChangedCallback
    computed getters
    methods class methods
    mounted connectedCallback
    destroyed disconnectedCallback
    style scoped template中的style
    template template

    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卡片”这篇文章的内容,相信大家都有了一定的了解,希望小编分享的内容对大家有帮助,若想了解更多相关的知识内容,请关注云搜网行业资讯频道。

    赞(0)
    【声明】:本博客不参与任何交易,也非中介,仅记录个人感兴趣的主机测评结果和优惠活动,内容均不作直接、间接、法定、约定的保证。访问本博客请务必遵守有关互联网的相关法律、规定与规则。一旦您访问本博客,即表示您已经知晓并接受了此声明通告。