zoukankan      html  css  js  c++  java
  • 跨框架实现方案

    Web Components 简介

    • Custom Elements
    • Shadow DOM
    • HTML Template

    使用Stencil

    使用原生语法去编写 Web Components 相当繁琐,因此我们需要一个框架帮助我们提高开发效率和开发体验。

    <template id="template">
      <h1>Hello World!</h1>
    </template>
    
    class App extends HTMLElement {
      constructor () {
        super(...arguments)
    
        // 开启 Shadow DOM
        const shadowRoot = this.attachShadow({ mode: 'open' })
    
        // 复用 <template> 定义好的结构 
        const template = document.querySelector('#template')
        const node = template.content.cloneNode(true)
        shadowRoot.appendChild(node)
      }
    }
    window.customElements.define('my-app', App)
    

    在 React 与 Vue 中使用 Stencil

    兼容 React

    React 使用 setAttribute 的形式给 Web Components 传递参数。当参数为原始类型时是可以运行的,但是如果参数为对象或数组时,由于 HTML 元素的 attribute 值只能为字符串或 null,最终给 WebComponents 设置的 attribute 会是 attr="[object Object]"。

    const reactifyWebComponent = WC => {
      return class extends React.Component {
        ref = React.createRef()
    
        update () {
          Object.entries(this.props).forEach(([prop, val]) => {
            if (prop === 'children' || prop === 'dangerouslySetInnerHTML') {
              return
            }
            if (prop === 'style' && val && typeof val === 'object') {
              for (const key in val) {
                this.ref.current.style[key] = val[key]
              }
              return
            }
            this.ref.current[prop] = val
          })
        }
    
        componentDidUpdate () {
          this.update()
        }
    
        componentDidMount () {
          this.update()
        }
    
        render () {
          const { children, dangerouslySetInnerHTML } = this.props
          return React.createElement(WC, {
            ref: this.ref,
            dangerouslySetInnerHTML
          }, children)
        }
      }
    }
    
    const MyComponent = reactifyWebComponent('my-component')
    
    

    children、dangerouslySetInnerHTML 属性需要透传。

    React 中 style 属性值可以接受对象形式,这里需要额外处理

    Events

    通过 ref 获取到Web Compoent 元素,通过 Object.entries(this.props) 遍历props,手动 addEventListenr 绑定事件

    const reactifyWebComponent = WC => {
      class Index extends React.Component {
        update (prevProps) {
          Object.entries(this.props).forEach(([prop, val]) => {
            if (prop.toLowerCase() === 'classname') {
              this.ref.current.className = prevProps
                // getClassName 在保留内置类名的情况下,返回最新的类名
                ? getClassName(this.ref.current, prevProps, this.props)
                : val
              return
            }
    
            ...
          })
        }
    
        componentDidUpdate (prevProps) {
          this.update(prevProps)
        }
    
        componentDidMount () {
          this.update()
        }
    
        ...
      }
      return React.forwardRef((props, ref) => (
        React.createElement(Index, { ...props, forwardRef: ref })
      ))
    }
    

    Ref

    domRef 会获取到 MyComponent,而不是

    使用 forwardRef 传递 ref。

    const reactifyWebComponent = WC => {
      class Index extends React.Component {
        ...
        
        render () {
          const { children, forwardRef } = this.props
          return React.createElement(WC, {
            ref: forwardRef
          }, children)
        }
      }
      return React.forwardRef((props, ref) => (
        React.createElement(Index, { ...props, forwardRef: ref })
      ))
    }
    
    
  • 相关阅读:
    泛型的内部原理:类型擦除以及类型擦除带来的问题
    Redis的那些最常见面试问题
    线程池全面解析
    对线程调度中Thread.sleep(0)的深入理解
    集群环境下Redis分布式锁
    3.8
    3.7
    3.6任务
    3.5任务
    3.4
  • 原文地址:https://www.cnblogs.com/fuGuy/p/12781155.html
Copyright © 2011-2022 走看看