IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> Web Components - Lifecycle & CSS -> 正文阅读

[JavaScript知识库]Web Components - Lifecycle & CSS

背景

在我们常用的 Vue、React 中,组件除了可以定义展示内容以外,还有一个很重要的点就是组件是有生命周期的,我们可以监听到组件的创建、销毁、属性变化,对于这一些我们 web components 是否也支持,答案是肯定的,今天我们来看看 web components 中的生命周期。

生命周期

在 web components 中,主要包含了以下 4 个回调函数,它们将会在元素的不同生命时期被调用:

  • connectedCallback:当 custom element首次被插入文档DOM时,被调用。
  • disconnectedCallback:当 custom element从文档DOM中删除时,被调用。
  • adoptedCallback:当 custom element被移动到新的文档时,被调用。
  • attributeChangedCallback: 当 custom element增加、删除、修改自身属性时,被调用。

加上 constructor,我们总共有 5 个生命周期。

接下来我们看下例子

<div id="app">
  <ol id="msg"></ol>

  <hello-world age="27">
    <span slot="username">hockor</span>
  </hello-world>

  <button id="remove">remove</button>
  <button id="change">change age</button>

  <template id="hello">
    <style>
      .hello {
        color: red;
      }
    </style>
    <div class="hello">
      hello,
      <slot name="username">world</slot>
      我的年龄是 <span id="age"></span>
    </div>
  </template>

</div>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script>
  function log (msg) {
    const li = document.createElement('span')
    li.innerHTML = msg + '<br/>'
    const msgPanel = document.getElementById('msg')
    msgPanel.appendChild(li)
  }

  class HelloWorld extends HTMLElement {
    constructor () {
      super()
      log('hello world 被构造了')
      const shadow = this.attachShadow({
        // closed 情况下通过this.shadowRoot拿到的是null
        mode: 'open'
      })
      const div = document.getElementById('hello')
      shadow.appendChild(div.content.cloneNode(true))
    }

    // 加入到DOM上
    connectedCallback () {
      log('hello world 被加入到DOM上了')
    }

    // 从DOM上移除了
    disconnectedCallback () {
      log('hello world 被删除了')
    }

    // attributesChangedCallback需要配合这个使用
    static get observedAttributes () {
      return ['age']
    }

    attributeChangedCallback (name, oldVal, newVal) {
      log('attributesChangedCallback')
      if ( name === 'age' ) {
        const age = this.shadowRoot.getElementById('age')
        age.innerHTML = newVal
      }
    }
  }

  customElements.define('hello-world', HelloWorld)


  $('#remove').click(function () {
    const hello = document.querySelector('hello-world')
    hello.parentNode.removeChild(hello)
  })

  $('#change').click(function () {
    const hello = document.querySelector('hello-world')
    hello.setAttribute('age', '34')
  })

</script>

demo地址:https://604n8h.csb.app/4.lifecycle.html

针对上面的 demo,做 1点说明

  • attributeChangedCallback 函数需要配合observedAttributes() get函数来实现,该函数返回一个数组,包含了需要监听的属性名,如果你没有加在这里的话,该属性发生变化的时候并不会触发attributeChangedCallback。

上面的 demo 中我们没有用到adoptedCallback,实际上这个回调在一般开发中是很少用到的。

adoptedCallback

adoptedCallback 本意是指的当 组件被移动到新文档时触发,注意这里的新文档,他一般是指的嵌套 iframe 场景下,我们来看个 demo

<div id="app">
  <ol id="msg"></ol>

  <hello-world age="27">
    <span slot="username">hockor</span>
  </hello-world>

  <button id="move">move</button>

  <iframe height="800" id="frame" src="./1.html" frameborder="0"></iframe>
  <template id="hello">
    <style>
      .hello {
        color: red;
      }
    </style>
    <div class="hello">
      hello,
      <slot name="username">world</slot>
      我的年龄是 <span id="age"></span>
    </div>
  </template>

</div>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script>
  function log (msg) {
    const li = document.createElement('span')
    li.innerHTML = msg + '<br/>'
    const msgPanel = document.getElementById('msg')
    msgPanel.appendChild(li)
  }

  class HelloWorld extends HTMLElement {
    constructor () {
      super()
      log('hello world 被构造了')
      const shadow = this.attachShadow({
        // closed 情况下通过this.shadowRoot拿到的是null
        mode: 'open'
      })
      const div = document.getElementById('hello')
      shadow.appendChild(div.content.cloneNode(true))
    }

    // 加入到DOM上
    connectedCallback () {
      log('hello world 被加入到DOM上了')
    }

    // iframe move
    adoptedCallback () {
      log('hello world 被移动了')
    }
  }

  customElements.define('hello-world', HelloWorld)

  // 按钮事件

  $('#move').click(function () {
    const hello = document.querySelector('hello-world')
    document.getElementById('frame').contentWindow.document.body.appendChild(hello)
  })

</script>

demo 地址:https://604n8h.csb.app/4.lifecycle2.html

在这个例子中,当我们将 component 从当前文档移动到 iframe 中的时候,adoptedCallback函数会被调用,而如果你是在当前文档移动 component 的话,会发现这个回调是不会触发的。

CSS

host

我们知道在 Antd / elementui 等框架中,当我们使用组件的时候可以传入一些内置的 class,比如 button 的“primary \ danger”,以此来使用 button 的不同样式,那么在 web components 中我们是不是也能这样呢?答案是可以的,我们可以通过 :host 来实现这个目的

老规矩,先上代码,再看 demo

<div id="app">
  <hello-world></hello-world>
  <hello-world class="blue small"></hello-world>
  <hello-world class="green large"></hello-world>

  <!--模板部分-->
  <template id="hello">
    <style>
      :host {
        display: block;
        color: red;
        border: 1px solid #333;
        width: 350px;
        height: 100px;
        line-height: 100px;
        margin: 30px;
        font-size: 16px;
      }

      /*可以通过括号对class做自定义,相当于你提供几套样式对外选择*/
      :host(.blue) {
        color: blue;
        font-size: 24px;
      }

      :host(.small) {
        font-size: 12px;
      }

      :host(.large) {
        font-size: 52px;
      }

      :host(.green) {
        color: green;
      }
    </style>
    <div class="hello">hello world</div>
  </template>

</div>
<script>
  class HelloWorld extends HTMLElement {
    constructor () {
      super()
      const shadow = this.attachShadow({
        mode: 'open'
      })
      const div = document.getElementById('hello')

      shadow.appendChild(div.content.cloneNode(true))
    }
  }
  customElements.define('hello-world', HelloWorld)
</script>

demo 地址:https://604n8h.csb.app/5.css-host.html

我们先看看 :host 官方说明:https://developer.mozilla.org/zh-CN/docs/Web/CSS/:host()

可以看到 :host 表示的就是我们 shadow dom 的宿主,同时我们可以把相关的类选择器作为函数参数包含在内,这样子就能做到内部自定义样式了。

part

同时,shadow dom 中还包含一个以元素中 part 属性名称组成的列表,该列表以空格分隔。通过 Part 的名称,可以使用 CSS 伪元素“::part”来选择 shadow 树中指定元素并设置其样式 。

part 属性官方说明:https://developer.mozilla.org/zh-CN/docs/Web/HTML/Global_attributes/part

例子如下:

<style>
    p {
      font-size: 16px;
    }

    hello-world {
      margin: 20px
    }

    /*在外部通过part去自定义颜色*/
    hello-world::part(name-part) {
      color: orange;
    }

    hello-world::part(age-part) {
      color: #a65563;
    }
  </style>

<div id="app">
  <hello-world></hello-world>
  <hello-world class="blue"></hello-world>
  <hello-world class="green"></hello-world>

  <!--模板部分-->
  <template id="hello">
    <style>
      p {
        font-size: 16px;
        margin: 0
      }

      :host {
        display: block;
        color: red;
        border: 1px solid #333;
        width: 350px;
        margin: 30px
      }
      :host(.blue) {
        color: blue;
        font-size: 24px;
      }

      :host(.green) {
        color: green;
        font-size: 34px;
      }
    </style>
    <div class="hello">
      hello world
      <p part="age-part">我的年龄是:22</p>
      <p part="name-part">我的名字是:hockor </p>

    </div>
  </template>

</div>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/4.5.3/js/bootstrap.min.js"></script>
<script>
  class HelloWorld extends HTMLElement {
    constructor () {
      super()
      const shadow = this.attachShadow({
        mode: 'open'
      })
      const div = document.getElementById('hello')
      shadow.appendChild(div.content.cloneNode(true))
    }
  }

  customElements.define('hello-world', HelloWorld)
</script>

demo 地址:https://604n8h.csb.app/6.css-part.html

在这里我们可以使用该全局属性对外暴露我们一些 dom,由外部使用 CSS 来进行控制,非常的灵活。

总结

好了,本文的内容到这里差不多就结束了,我们看到在本文我们主要讲了 web components 中的生命周期和 css 控制,有了这 2 个我们的组件才能更加灵活,后续我们会继续将组件的事件交互和在实际项目中的运用。同时目前市面上也有一些基于 Web Component 标准开发的组件库,比如

感兴趣的同学可以去看看。

在这里插入图片描述

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2022-02-19 01:03:52  更:2022-02-19 01:04:43 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 10:56:15-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码