手冊(cè)簡(jiǎn)介

由騰訊AlloyTeam發(fā)起,由微軟、騰訊、阿里等互聯(lián)網(wǎng)公司工程師開(kāi)發(fā)維護(hù)的現(xiàn)代化Web組件化框架。 網(wǎng)址:omijs.org

手冊(cè)說(shuō)明

Omi - 合一

Github 地址:https://github.com/tencent/omi

下一代 Web 框架,去萬(wàn)物糟粕,合精華為一。

omi

特性

  • 4KB 的代碼尺寸,比小更小
  • 順勢(shì)而為,順從瀏覽器的發(fā)展和 API 設(shè)計(jì)
  • Webcomponents + JSX 相互融合為一個(gè)框架 Omi
  • Webcomponents 也可以數(shù)據(jù)驅(qū)動(dòng)視圖, UI = fn(data)
  • JSX 是開(kāi)發(fā)體驗(yàn)最棒(智能提示)、語(yǔ)法噪音最少的 UI 表達(dá)式
  • 獨(dú)創(chuàng)的 Path Updating 機(jī)制,基于 Proxy 全自動(dòng)化的精準(zhǔn)更新,功耗低,自由度高,性能卓越,方便集成 requestIdleCallback
  • 使用 store 系統(tǒng)不需要調(diào)用 this.udpate,它會(huì)自動(dòng)化按需更新局部視圖
  • 看看Facebook React 和 Web Components對(duì)比優(yōu)勢(shì),Omi 融合了各自的優(yōu)點(diǎn),而且給開(kāi)發(fā)者自由的選擇喜愛(ài)的方式
  • Shadom DOM 與 Virtual DOM 融合,Omi 既使用了虛擬 DOM,也是使用真實(shí) Shadom DOM,讓視圖更新更準(zhǔn)確更迅速
  • 類似 WeStore 體系,99.9% 的項(xiàng)目不需要什么時(shí)間旅行,也不僅僅 redux 能時(shí)間旅行,請(qǐng)不要上來(lái)就 redux,Omi store 體系可以滿足所有項(xiàng)目
  • 局部 CSS 最佳解決方案(Shadow DOM),社區(qū)為局部 CSS 折騰了不少框架和庫(kù)(使用js或json寫樣式,如:Radium,jsxstyle,react-style;與webpack綁定使用生成獨(dú)特的className文件名—類名—hash值,如:CSS Modules,Vue),都是 hack 技術(shù);Shadow DOM Style 是最完美的方案

對(duì)比同樣開(kāi)發(fā) TodoApp, Omi 和 React 渲染完的 DOM 結(jié)構(gòu):

 

左邊是Omi,右邊是 React,Omi 使用 Shadow DOM 隔離樣式和語(yǔ)義化結(jié)構(gòu)。

一個(gè) HTML 完全上手

下面這個(gè)頁(yè)面不需要任何構(gòu)建工具就可以執(zhí)行

<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8" />
  <title>Add Omi in One Minute</title>
</head>

<body>
  <script src="https://unpkg.com/omi" rel="external nofollow" ></script>
  <script>
    const { WeElement, h, render, define } = Omi

    class LikeButton extends WeElement {
      install() {
        this.data = { liked: false }
      }

      render() {
        if (this.data.liked) {
          return 'You liked this.'
        }

        return h(
          'button',
          {
            onClick: () => {
              this.data.liked = true
              this.update()
            }
          },
          'Like'
        )
      }
    }

    define('like-button', LikeButton)

    render(h('like-button'), 'body')
  </script>
</body>

</html>

Getting Started

Install

$ npm i omi-cli -g               # install cli
$ omi init your_project_name     # init project, you can also exec 'omi init' in an empty folder
$ cd your_project_name           # please ignore this command if you executed 'omi init' in an empty folder
$ npm start                      # develop
$ npm run build                  # release

Hello Element

先創(chuàng)建一個(gè)自定義元素:

import { tag, WeElement, render } from 'omi'

@tag('hello-element')
class HelloElement extends WeElement {

    onClick = (evt) => {
        //trigger CustomEvent
        this.fire('abc', { name : 'dntzhang', age: 12 })
        evt.stopPropagation()
    }

    css() {
        return `
         div{
             color: red;
             cursor: pointer;
         }`
    }

    render(props) {
        return (
            <div onClick={this.onClick}>
                Hello {props.msg} {props.propFromParent}
                <div>Click Me!</div>
            </div>
        )
    }   
}

使用該元素:

import { tag, WeElement, render } from 'omi'
import './hello-element'

@tag('my-app')
class MyApp extends WeElement {
    static get data() {
        return { abc: '', passToChild: '' }
    }

    //bind CustomEvent 
    onAbc = (evt) => {
        // get evt data by evt.detail
        this.data.abc = ' by ' + evt.detail.name
        this.update()   
    }

    css() {
        return `
         div{
             color: green;
         }`
    }

    render(props, data) {
        return (
            <div>
                Hello {props.name} {data.abc}
                <hello-element onAbc={this.onAbc} prop-from-parent={data.passToChild} msg="WeElement"></hello-element>
            </div>
        )
    }
}

render(<my-app name='Omi v4.0'></my-app>, 'body')

告訴 Babel 把 JSX 轉(zhuǎn)化成 Omi.h() 的調(diào)用:

{
    "presets": ["env", "omi"]
}

需要安裝下面兩個(gè) npm 包支持上面的配置:

"babel-preset-env": "^1.6.0",
"babel-preset-omi": "^0.1.1",

如果不想把 css 寫在 js 里,你可以使用 to-string-loader, 比如下面配置:

{
    test: /[\\|\/]_[\S]*\.css$/,
    use: [
        'to-string-loader',
        'css-loader'
    ]
}

如果你的 css 文件以 _ 開(kāi)頭, css 會(huì)使用 to-string-loader. 如:

import { tag, WeElement render } from 'omi'
//typeof cssStr is string
import cssStr from './_index.css' 

@tag('my-app')
class MyApp extends WeElement {

  css() {
    return cssStr
  }
  ...
  ...
  ...

TodoApp

下面列舉一個(gè)相對(duì)完整的 TodoApp 的例子:

import { tag, WeElement, render } from 'omi'

@tag('todo-list')
class TodoList extends WeElement {
    render(props) {
        return (
            <ul>
                {props.items.map(item => (
                    <li key={item.id}>{item.text}</li>
                ))}
            </ul>
        );
    }
}

@tag('todo-app')
class TodoApp extends WeElement {
    static get data() {
        return { items: [], text: '' }
    }

    render() {
        return (
            <div>
                <h3>TODO</h3>
                <todo-list items={this.data.items} />
                <form onSubmit={this.handleSubmit}>
                    <input
                        id="new-todo"
                        onChange={this.handleChange}
                        value={this.data.text}
                    />
                    <button>
                        Add #{this.data.items.length + 1}
                    </button>
                </form>
            </div>
        );
    }

    handleChange = (e) => {
        this.data.text = e.target.value
    }

    handleSubmit = (e) => {
        e.preventDefault();
        if (!this.data.text.trim().length) {
            return;
        }
        this.data.items.push({
            text: this.data.text,
            id: Date.now()
        })
        this.data.text = ''
    }
}

render(<todo-app></todo-app>, 'body')

Store

使用 Store 體系可以告別 update 方法,基于 Proxy 的全自動(dòng)屬性追蹤和更新機(jī)制。強(qiáng)大的 Store 體系是高性能的原因,除了靠 props 決定組件狀態(tài)的組件,其余組件所有 data 都掛載在 store 上,

export default {
  data: {
    items: [],
    text: '',
    firstName: 'dnt',
    lastName: 'zhang',
    fullName: function () {
      return this.firstName + this.lastName
    },
    globalPropTest: 'abc', //更改我會(huì)刷新所有頁(yè)面,不需要再組件和頁(yè)面聲明data依賴
    ccc: { ddd: 1 } //更改我會(huì)刷新所有頁(yè)面,不需要再組件和頁(yè)面聲明data依賴
  },
  globalData: ['globalPropTest', 'ccc.ddd'],
  add: function () {
    if (!this.data.text.trim().length) {
        return;
    }
    this.data.items.push({
      text: this.data.text,
      id: Date.now()
    })
    this.data.text = ''
  }
  //默認(rèn) false,為 true 會(huì)無(wú)腦更新所有實(shí)例
  //updateAll: true
}

自定義 Element 需要聲明依賴的 data,這樣 Omi store 根據(jù)自定義組件上聲明的 data 計(jì)算依賴 path 并會(huì)按需局部更新。如:

class TodoApp extends WeElement {
    static get data() {
        //如果你用了 store,這個(gè)只是用來(lái)聲明依賴,按需 Path Updating
        return { items: [], text: '' }
    }
    ...
    ...
    ...
    handleChange = (e) => {
        this.store.data.text = e.target.value
    }

    handleSubmit = (e) => {
        e.preventDefault()
        this.store.add()
    }
}
  • 數(shù)據(jù)的邏輯都封裝在了 store 定義的方法里 (如 store.add)
  • 視圖只負(fù)責(zé)傳遞數(shù)據(jù)給 store (如上面調(diào)用 store.add 或設(shè)置 store.data.text)

需要在 render 的時(shí)候從根節(jié)點(diǎn)注入 store 才能在所有自定義 Element 里使用 this.store:

render(<todo-app></todo-app>, 'body', store)

→ Store 完整的代碼

總結(jié)一下:

  • store.data 用來(lái)列出所有屬性和默認(rèn)值(除去 props 決定的視圖的組件)
  • 組件和頁(yè)面的 data 用來(lái)列出依賴的 store.data 的屬性 (omi會(huì)記錄path),按需更新
  • 如果頁(yè)面簡(jiǎn)單組件很少,可以 updateAll 設(shè)置成 true,并且組件和頁(yè)面不需要聲明 data,也就不會(huì)按需更新
  • globalData 里聲明的 path,只要修改了對(duì)應(yīng) path 的值,就會(huì)刷新所有頁(yè)面和組件,globalData 可以用來(lái)列出所有頁(yè)面或大部分公共的屬性 Path

生命周期

Lifecycle methodWhen it gets called
installbefore the component gets mounted to the DOM
installedafter the component gets mounted to the DOM
uninstall    prior to removal from the DOM                  
beforeUpdatebefore render()
afterUpdateafter render()

生態(tài)

在里面查找你想要的組件,直接使用,或者花幾分鐘就能轉(zhuǎn)換成 Omi Element(把模板拷貝到 render 方法,style拷貝到 css 方法)。

瀏覽器兼容

Omi 4.0+ works in the latest two versions of all major browsers: Safari 10+, IE 11+, and the evergreen Chrome, Firefox, and Edge.

Browsers Support

→ polyfills

Links

License

MIT ? Tencent

Please contact me@dntzhang for any questions.


更新記錄

在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)