1、原生也有组件?

现在Vue、React的大规模流行。前端组件化已经成为潮流,但是原生的组件又有多少人了解了。下面通过几个代码示例,让你快速了解原生怎么写组件。

2、通过继承 HTML 实现组件

代码demo示例

  1. // 通过继承 HTMLImageElement 实现组件化
  2. class MyImg extends HTMLImageElement {
  3. constructor() {
  4. super()
  5. const src = 'https://resource.ttplus.cn/publish/app/pics/2019/04/18/233772/76d96560-7211-483d-988c-dc00d8391f41.jpg'
  6. setTimeout(() => {
  7. // this 指向继承后的新组件
  8. this.src = src
  9. }, 1000)
  10. }
  11. }
  12. // 组件名字 继承后的类 需要继承的标签
  13. customElements.define('my-img', MyImg, {
  14. extends: 'img',
  15. })

使用的时候只需要在你继承的标签中,is="你的组件名" 即可

  1. <img is="my-img" />

3、独立的组件

代码demo示例

demo2.html

  1. <style>
  2. /* 样式隔离,无法操作 MyCom 内部的样式 */
  3. .my_com_main {
  4. background: pink;
  5. }
  6. </style>
  7. <my-com class="my_com" cusAttr="我是自定义属性">
  8. <span slot="middle">我是主要内容</span>
  9. <h2 slot="bottom">我是底部</h2>
  10. <div slot="head">我是头部插槽</div>
  11. </my-com>
  12. <script type="module" src="./demo2.js"></script>

MyCom.js

  1. const template = document.createElement('template')
  2. template.innerHTML = `
  3. <style>
  4. .my_com_wrapper {
  5. border: 1px solid red;
  6. }
  7. .my_com_main {
  8. height: 100px;
  9. background: skyblue;
  10. }
  11. </style>
  12. <div class="my_com_wrapper">
  13. <header>
  14. <slot name="head"></slot>
  15. </header>
  16. <main class="my_com_main">
  17. <slot name="middle"></slot>
  18. </main>
  19. <footer>
  20. <slot name="bottom"></slot>
  21. </footer>
  22. </div>
  23. `
  24. class MyCom extends HTMLElement {
  25. constructor() {
  26. super()
  27. // 获取自定义组件的属性
  28. console.log(this.getAttribute('class'))
  29. console.log(this.getAttribute('cusAttr'))
  30. // 使用 attachShadow 与外面样式进行隔离
  31. const sd = this.attachShadow({ mode: 'open' })
  32. sd.appendChild(template.content)
  33. }
  34. }
  35. customElements.define('my-com', MyCom)

demo2.js

  1. import './MyCom.js'
  2. const myComEl = document.querySelector('.my_com')
  3. // 当 attachShadow 的 mode 为 open 时,可以获取 shadowRoot 的内容并且操作。
  4. // 如果 mode 为 closed 则无法获取该节点信息
  5. console.log(myComEl.shadowRoot)
  6. const myColElChildren = myComEl.shadowRoot.children
  7. ![...myColElChildren].forEach(el => (el.style = 'font-size: 40px;'))

4、如何实现自定义事件

代码demo示例

通过 EventTarget 添加自定义事件。在通过 dispatchEvent 触发 CustomEvent 事件。

  1. <button id="btn_a">自定义事件a</button>
  2. <button id="btn_b">自定义事件b</button>
  3. <script type="module">
  4. // 创建事件
  5. const obj = new EventTarget()
  6. // 添加事件
  7. obj.addEventListener('a', () => alert('触发了事件a'))
  8. obj.addEventListener('b', () => alert('触发了事件b'))
  9. document.querySelector('#btn_a').onclick = () => {
  10. obj.dispatchEvent(new CustomEvent('a'))
  11. }
  12. document.querySelector('#btn_b').onclick = () => {
  13. obj.dispatchEvent(new CustomEvent('b'))
  14. }
  15. </script>

5、实现简易版Dialog组件

由于代码太多,直接放链接了

代码demo示例

6、仓库源码地址

https://github.com/Layouwen/webcomponent-demo