omi 入门

375 阅读3分钟

OMI 是一个开发 WebComponents 的框架

Web Components

Web Components包括以下三个主要技术:

  • Custom Elements:允许开发者创建自定义的HTML元素,并定义它们的行为。
  • Shadow DOM:为自定义元素提供封装的DOM结构,使其与主文档隔离,避免样式和脚本的冲突。
  • HTML Templates:提供一种创建HTML模板的方法,这些模板可以在运行时被克隆和填充,提高渲染性能。

比如不使用任何框架实现一个自定义元素:

class MyElement extends HTMLElement {
  constructor() {
    super();
    const shadowRoot = this.attachShadow({ mode: 'open' });
    const div = document.createElement('div');
    div.textContent = 'Hello, Shadow DOM!';
    shadowRoot.appendChild(div);
  }
}

customElements.define('my-element', MyElement);

在这个例子中,我们创建了一个自定义元素my-element,并在其内部创建了一个 Shadow DOM。当浏览器遇到<my-element>标签时,会自动创建一个MyElement实例,并将其附加到文档中。<my-element>是框架无关的,任何框架都可以使用该元素。

其中 OMI 框架使用了其中两种:Custom Elements 和 Shadow DOM,而 HTML Templates 则由编程体验更好 JSX 语法来代替来实现。

import { tag, Component, h } from 'omi'

@tag('my-element')
class MyElement extends Component {
  render() {
    return <div>Hello, Shadow DOM!</div>
  }
}

Constructable Stylesheets

Constructable Stylesheets 是 Web Components 的黄金搭档。在使用 Shadow DOM 时创建和分布可重复使用的样式的一种方式,既降低了尺寸,还能提高性能。

这个 API 主要包含以下几个部分:

  • CSSStyleSheet 类:这个类代表一个样式表。
  • adoptedStyleSheets 属性:这个属性存在于 Document 和 ShadowRoot 对象上。

我们可以通过 new CSSStyleSheet() 来创建一个新的样式表,然后通过 sheet.replace(text) 或者 sheet.replaceSync(text) 来设置样式表的内容。这里的 text 是一个包含 CSS 代码的字符串。

然后通过 document.adoptedStyleSheets = [sheet1, sheet2, ...] 或者 shadowRoot.adoptedStyleSheets = [sheet1, sheet2, ...] 来应用样式表。这里的 sheet1, sheet2, ... 是 CSSStyleSheet 对象。

使用 Constructable Stylesheets,我们可以在 JavaScript 中创建和管理样式表,然后在需要的地方动态地应用样式表。这样,我们就可以复用样式,而且只需要加载一次样式代码,从而提高性能。

例如,我们可以创建一个样式表,然后在多个 Shadow DOM 中应用这个样式表,这里举一个不使用 OMI 框架原生使用 Constructable Stylesheets 的例子:

const sheet = new CSSStyleSheet();
sheet.replaceSync('p { color: red; }');

customElements.define('my-element', class extends HTMLElement {
  constructor() {
    super();
    this.attachShadow({mode: 'open'});
  }
  connectedCallback() {
    this.shadowRoot.adoptedStyleSheets = [sheet];
    this.shadowRoot.innerHTML = '<p>Hello, world!</p>';
  }
});

在这个例子中,我们创建了一个样式表 sheet,然后在 my-element 组件的 Shadow DOM 中应用了这个样式表。无论我们创建了多少个 my-element 组件,样式表的代码都只需要加载一次。

omi

?raw

vite 中可用这种方式加载字符串

props

render 函数接收 props

static defaultProps 来设置默认值,使用 static propTypes 来设置类型:

也可以合并到 static props 一起定义

css

static css = 'h1 { color: red }' 

也可以是数组

static css = [style, 'h3 { color: red; }']

事件

和 React 一样

class x {
  onClick = (evt) => {
    alert('Hello Omi!')
  }

  render() {
    return (
      <h1 onClick={this.onClick}></h1>
    )
  }
}

通过 fire 触发事件,对应 Vue 中的 emit

onClick = event => {
  this.fire('my-event', { name: 'yang' })
}

render() {
  return (
    <h1 onClick={this.onClick}></h1>
  )
}

外层使用者绑定事件,通过 event.detail 拿到参数

<my-element onMyEvent={(event) => alert(event.detail.name)}></my-element>

或者通过 addEventListener

myElement.addEventListener('my-event', () => {})

Ref

想在 JS 中获取元素

onClick = () => {
  console.log(this.myRef)
}

render() {
  return (
    <h1 ref={e => { this.myRef = e}}></h1>
  )
}

提前赋值

onClick = () => {
  console.log(this.myRef)
}

myRef = e => this.myRef = e;

render() {
  return (
    <h1 ref={this.myRef}></h1>
  )
}

createRef 方法

onClick = () => {
  console.log(this.myRef.current)
}

myRef = createRef()

render() {
  return (
    <h1 ref={this.myRef}></h1>
  )
}

provide/inject

provide = {
  name: 'yang'
}
inject = ['name']
render() {
  return (
    <h1>{this.injection.name}</h1>
  )
}

参考:

  1. juejin.cn/post/729824…