[Day04] - 新拟物风按钮(二) - shadow dom 介绍

昨天我们做了一个不能点的 neuomorphic-button

今天我们把他可以点击 & 加上 shadow-dom 让元件内外的 styling 区隔开来吧 !


回顾昨天进度

昨天我们做了一个不能点的 neuomorphic-button 元件

// neuomorphic-button.js
class NeuomorphicButton extends HTMLElement {

  // as Component mounted to page
  constructor() {

    // Always call super first in constructor
    super();

    // Element functionality written in here
    const div = document.createElement('div')
    div.classList.add('icon-box')
    div.innerHTML = `<i class="fas fa-wifi"></i>`

    this.append(div)
  }
}

window.customElements.define('neuomorphic-button', NeuomorphicButton);

首先我们先补上 checkbox 让其可以被点击 ,

因为我们要客制化 checkbox 的样式 , 因此会需要设定 checkbox 的样式为 display:none 把它隐藏起来

这时我们可以请出 label 这个 Html tag , 用 labelinput 元素包住 , 将 onclick 事件转送到 input[type="checkbox"]

// neuomorphic-button.js
class NeuomorphicButton extends HTMLElement {

  constructor() {

    super();

    // 利用 div 显示按钮的样式
    const div = document.createElement('div')
    div.classList.add('icon-box')
    div.innerHTML = `<i class="fas fa-wifi"></i>`

    // label & 其内部的 checkbox
    const label = document.createElement('label')
    label.innerHTML = `<input type="checkbox">`
    label.append(div)

    this.append(label)
  }
}

window.customElements.define('neuomorphic-button', NeuomorphicButton);

当然在 html 中我们需要补上一些样式设定

<style>
    /* neuomorphic-button 的样式 */
    label input[type='checkbox'] {
      display: none;
    }

    label .icon-box {
      width: 60px;
      height: 60px;
      position: relative;
      background-color: #ebf5fc;
      box-shadow: 8px 8px 16px #bcbcbc,
      -8px -8px 16px #ffffff;
      display: flex;
      justify-content: center;
      align-items: center;
      border-radius: 10px;
      cursor: pointer;
      transition:all 0.3s;
    }

    label .icon-box:hover {
      transform:translateY(3px)
    }

    label .icon-box i {
      font-size: 2em;
      color: #6a9bd8;
    }

    // 被点选後的样式
    label input[type='checkbox']:checked ~ .icon-box {
      box-shadow: inset -2px -2px 5px rgba(255, 255, 255, 1),
      inset 3px 3px 5px rgba(0, 0, 0, 0.1);
    }

    label input[type='checkbox']:checked ~ .icon-box i {
      transform: scale(0.95);
      filter: hue-rotate(90deg);
    }

  </style>

之後我们得到了一个可点击的 neuomorphic-button

目前我们的 style 是定义在 html 的 header 中 , 如果有其他的 css 设定可能会造成互相影响

这时我们就可以请出 shadow dom 来 ~~~

const shadowRoot = this.attachShadow({mode: 'open'})

既然我们都改用 shadow dom 那当然需要将挂在 this 上的那些 HTML 元素 , 改挂在 shadowRoot 的上面

// neuomorphic-button.js
class NeuomorphicButton extends HTMLElement {

  // as Component mounted to page
  constructor() {

    ...跟之前相同的设定

    // 将 label 改 append 到 shadowRoot 上面
    const shadowRoot = this.attachShadow({mode: 'open'})
    shadowRoot.append(label)
  }
}

window.customElements.define('neuomorphic-button', NeuomorphicButton);

改後我们会获得以下截图

奇怪 , 外部有定义样式阿 ~ , 那 neuomorphic-button 元件内的样式为何会没有吃到呢 ?

原来 shadow dom 也就是 this.attachShadow({mode: 'open'}) 会将 shadowRoot 中的样式跟外部 Html 的样式做一个区隔

所以 , 我们需要在 shadowRoot 的内部再定义一次样式

// neuomorphic-button.js
class NeuomorphicButton extends HTMLElement {

  // as Component mounted to page
  constructor() {

    ...跟之前相同的设定

     // 将样式相关的部分 , 定义在此
+    const fontAwesomeStyle = `<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/css/all.min.css">`
+    const styleStr =  'neuomorphic-button 的样式'

    // 将 label 改 append 到 shadowRoot 上面
    const shadowRoot = this.attachShadow({mode: 'open'})
+    shadowRoot.innerHTML = fontAwesomeStyle + styleStr  // 将定义出来的样式 , 挂载到 shadowRoot 内部
    shadowRoot.append(label)
  }
}

window.customElements.define('neuomorphic-button', NeuomorphicButton);

太棒了 ! 按钮吃到我们设定的样式了 (^∀^●)ノシ

如果想查看实际页面 , 请到 shadow-dom.html 查看

补充的小贴士

1. label 的特点

下方情况 label 会将 onclick 事件做一个转送 , 事件将传给对应的元素并触发其 onclick

A. for 对应的那个 name HTML 元素

<div class="preference">
    <label for="cheese">Do you like cheese?</label>
    <input type="checkbox" name="cheese" id="cheese">
</div>

B. 包在 label 内的 input 元素

<label>
  <input type="checkbox">
  I agree to the Terms and Conditions
</label>

2. checkbox 无法用 css 直接设定底色 & 边框样式

因此我们需要利用 隐藏原生 checkbox + 设定 div 样式 来制作自身想要的 checkbox

<label>
  <!-- 隐藏原生 checkbox -->
  <input type="checkbox" style="display:none">
  
  <!-- 将想要的 checkbox 样式设定在 myCheckbox 中 -->
  <div class="myCheckbox">
</label>

详细的 Styling checkbox 步骤请参考 这篇

参考资料 :


<<:  Day 8-单元测试完善 HelloBank、基础总结与核心技术概述 (基础-7)

>>:  #8 - Reading & Writing Files (fs)

字母呈现大小写混合转换的波浪型态之C#写法(墨西哥波浪舞)

就是在某天,得到一题关於组字串的练习题,对於小弱弱如我的来说 =.=a 需要绞尽脑汁的狂烧脑去解这一...

[自学笔记]关於SVN(Subversion) 版本控制系统

安妞大家 以下一样是自学笔记 什麽是SVN(Subversion) ? SVN(Subversion...

Consistency and Consensus (4-3) - Coordination Services & Summary

续 Day 21 协调服务 (Coordination Services) 像 Apache Zo...

自组NAS:针对unRaid

前面讲了那麽多,当然在部属unRaid还是要优先考虑设备的选择 当然用淘汰的旧电脑也是可以(小雨这次...

Python & Celery 学习笔记_基本操作

这边主要是纪录一下目前学习 Celery 的一些纪录,想要知道完整的 Celery 的介绍可以自行 ...