eed04e8591
* Add extend, get and set methods |
||
---|---|---|
assets | ||
packages | ||
site | ||
tutorial | ||
.editorconfig | ||
.eslintrc | ||
.gitignore | ||
CONTRIBUTING.md | ||
LICENSE | ||
README.CN.md | ||
README.md | ||
index.html |
README.md
English | 简体中文
Omi - Front End Cross-Frameworks Framework
Merge Web Components, JSX, HTM, Virtual DOM and Proxy into one framework with tiny size and high performance. Write components once, using in everywhere, such as Omi, React, Preact, Vue or Angular.
Ecosystem of Omi
Base
Project | Description |
---|---|
omi-docs and codepen and wcd demos | Omi official documents |
omim | Cross frameworks and themes components.(DOCS & REPL && JOIN US!) |
omis and codepen and docs | Functional Component + Store + Scoped Style + Web Components in tiny size |
omio | Omi for old browsers with same api(IE8+) |
omi-ssr | Server-side rendering(support omio only) |
omi-router | Omi official router in 1KB js |
omi-cli | Project scaffolding. → Base Templates and → Other Templates |
omi-devtools | Browser DevTools extension |
omiu | Simple Omi UI |
omil | Webpack loader for Omi.js components.(DOCS) |
omi-snippets | A beautify VSCode extension for .omi or .eno file, Install now! |
Mini Program(小程序)
Project | Description |
---|---|
omix | 极小却精巧的小程序框架 |
omi-cloud | 小程序•云开发 |
omip | 直接使用 Omi 开发小程序或 H5 SPA |
mps | 原生小程序增强框架(JSX + Less 输出 WXML + WXSS),也支持 QQ 轻应用 |
cax | 小程序 Canvas 和 SVG 渲染引擎 |
omi-mp | 通过微信小程序开发和生成 Web 单页应用(H5 SPA) |
westore | 小程序状态管理 |
comi | 小程序代码高亮和 markdown 渲染组件 |
wx-touch-event | 基于 AlloyFinger/omi-finger 改造的小程序手势解决方案 |
Other
Project | Description |
---|---|
omi-chart | Simple HTML5 Charts using chart-x tag. |
md2site | Static Site Generator with markdown powered by Omio. |
omi-30-seconds | Useful Omi snippets that you can understand in 30 seconds. |
omi-canvas | Perfect fusion of web components, jsx and canvas. |
omi-swiper | Omi + Swiper |
omi-vscode | VSCode extension for omi, Install now! |
omi-ex | Omi.js extension(TypeScript) |
omi-transform | Omi / css3transform integration. Made css3 transform super easy in your Omi project. |
omi-finger | Support touch and gesture events in your Omi project. |
omi-touch | Smooth scrolling, rotation, pull to refresh and any motion for the web. |
omi-native | Render web components to native |
omi-i18n | Internationalization solution for omi.js using i18next ecosystem |
omi-page | Tiny client-side router by page |
omi-piano | Build piano with Omi and Omi Snippets, Enjoy now! |
omie | Build cross platform desktop apps with Omi.js and Electron.js |
Why Omi?
- Tiny size and High performance
- Cross framework(react, preact, vue, angular) custom elements by omi
- One framework. Mobile & desktop & mini program
- Be friendly to custom elements, you can pass
false
attributes to elements through string'0'
or string'flase'
, you can passobject
attributes to elements through:
prefix andOmi.$
- Supports TypeScript
- Reactive data-binding
- Native tap event support
- Having Cross-frameworks UI components - omim
- Excellent compatibility(IE8+) with omio
- Enhanced CSS, rpx unit support base on 750 screen width
- Compliance with browser trend and API design
- Merge Web Components, JSX and HTM into one framework
- Web Components can also be a data-driven view,
UI = fn(data)
. - JSX is the best development experience (code intelligent completion and tip) UI Expression with least grammatical noise and it's turing complete(template engine is not, es template string is but grammatical noise is too loud)
- Look at Facebook React vs Web Components,Omi combines their advantages and gives developers the freedom to choose the way they like
- Shadow DOM merges with Virtual DOM, Omi uses both virtual DOM and real Shadow DOM to make view updates more accurate and faster
- Scoped CSS's best solution is Shadow DOM, the community churning out frameworks and libraries for Scoped CSS (using JS or JSON writing styles such as Radium, jsxstyle, react-style; binding to webpack using generated unique
className
filename-classname-hash
, such as CSS Modules, Vue), are hack technologies; and Shadow DOM Style is the perfect solution. - The original Path Updating store system. Proxy-based automatic accurate update, low power consumption, high degree of freedom, excellent performance, easy integration of
requestIdleCallback
,It will automatically update UI partially when data is changed
Compare TodoApp by Omi and React, Omi and React rendering DOM structure:
Omi | React |
---|---|
Omi uses Shadow DOM based style isolation and semantic structure.
Useful Resources
Overview of the Readme
- Ecosystem of Omi
- Useful Resources
- Add Omi in One Minute
- Add Omi in 30 Seconds
- Getting Started
- Debugging
- Browsers Support
- Contributors
- Maintainers
- Thanks
- License
Add Omi in One Minute
This page demonstrates using Omi with no build tooling, directly run in the browser.
<!DOCTYPE html>
<html>
<head>
<title>Omi demo without transpiler</title>
</head>
<body>
<script src="https://tencent.github.io/omi/packages/omi/dist/omi.js"></script>
<script>
const { define, WeElement, html, render } = Omi
define('my-counter', class extends WeElement {
install() {
this.count = 1
this.sub = this.sub.bind(this)
this.add = this.add.bind(this)
}
sub() {
this.count--
this.update()
}
add() {
this.count++
this.update()
}
render() {
return html`
<div>
<button onClick=${this.sub}>-</button>
<span>${this.count}</span>
<button onClick=${this.add}>+</button>
</div>
`}
})
render(html`<my-counter />`, 'body')
</script>
</body>
</html>
Using store system
Omi Store provides a way to pass data through the component tree without having to pass props down manually at every level, injected from the root component and shared across all subcomponents. It's very simple to use:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Omi demo without transpiler</title>
</head>
<body>
<script src="https://tencent.github.io/omi/packages/omi/dist/omi.js"></script>
<script>
const { define, WeElement, html, render } = Omi
define('my-counter', class extends WeElement {
use() {
return ['count']
}
//or
//static use = ['count']
install() {
this.sub = this.sub.bind(this)
this.add = this.add.bind(this)
}
sub() {
////use this.store in any method of any children components
this.store.data.count--
}
add() {
this.store.data.count++
}
render() {
return html`
<div>
<button onClick=${this.sub}>-</button>
<span>${this.store.data.count}</span>
<button onClick=${this.add}>+</button>
</div>
`}
})
//Injection through a third parameter
render(html`<my-counter />`, 'body', {
data: {
count: 1
}
})
</script>
</body>
</html>
You can also use my-counter
tag directly in HTML:
<body>
<my-counter />
</body>
Add Omi in 30 Seconds
You can also quickly build omi projects using modern JS code:
import { tag, WeElement, render } from 'omi'
@tag('my-counter')
class MyCounter extends WeElement {
count = 1
static css = `
span{
color: red;
}`
sub = () => {
this.count--
this.update()
}
add = () => {
this.count++
this.update()
}
render() {
return (
<div>
<button onClick={this.sub}>-</button>
<span>{this.count}</span>
<button onClick={this.add}>+</button>
</div>
)
}
}
render(<my-counter />, 'body')
Getting Started
Install
$ npm i omi-cli -g # install cli
$ omi init my-app # init project
$ cd my-app
$ npm start # develop
$ npm run build # release
npx omi-cli init my-app
is also supported(npm v5.2.0+).
Directory description:
├─ config
├─ public
├─ scripts
├─ src
│ ├─ assets
│ ├─ elements //Store all custom elements
│ ├─ store //Store all this store of pages
│ ├─ admin.js //Entry js of compiler,will build to admin.html
│ └─ index.js //Entry js of compiler,will build to index.html
Scripts
"scripts": {
"start": "node scripts/start.js",
"build": "PUBLIC_URL=. node scripts/build.js",
"build-windows": "set PUBLIC_URL=.&& node scripts/build.js",
"fix": "eslint src --fix"
}
You can set up the PUBLIC_URL, such as:
...
"build": "PUBLIC_URL=https://fe.wxpay.oa.com/dv node scripts/build.js",
"build-windows": "set PUBLIC_URL=https://fe.wxpay.oa.com/dv&& node scripts/build.js",
...
Switch omi, omio and reomi
Add or remove the alias config in package.json to switch omi and omio:
"alias": {
"omi": "omio"
}
Project Template
Template Type | Command | Describe |
---|---|---|
Base Template(v3.3.0+) | omi init my-app |
Basic omi or omio(IE8+) project template. |
Base Template with snapshoot | omi init-snap my-app |
Basic omi or omio(IE8+) project template with snapshoot prerendering. |
TypeScript Template(omi-cli v3.3.0+) | omi init-ts my-app |
Basic template with typescript. |
Mobile Template | omi init-weui my-app |
Mobile web app template with weui and omi-router. |
omi-mp Template(omi-cli v3.0.13+) | omi init-mp my-app |
Developing web with mini program template. |
The base Template(omi init my-app
) is based on a single-page create-react-app to be converted into a multi-page one, with configuration issues to see create-react-app user guide
Hello Element
Define a custom element by extending WeElement
base class:
import { define, WeElement } from 'omi'
define('hello-element', class extends WeElement {
onClick = evt => {
// trigger CustomEvent
this.fire('abc', { name: 'dntzhang', age: 12 })
evt.stopPropagation()
}
//If you need to use <hello-element></hello-element> directly in html, you must declare propTypes
static propTypes = {
msg: String
}
static css = `
div {
color: red;
cursor: pointer;
}`
render(props) {
return (
<div onClick={this.onClick}>
Hello {props.msg}
<div>Click Me!</div>
</div>
)
}
})
Using hello-element
:
import { define, render, WeElement } from 'omi'
import './hello-element'
define('my-app', class extends WeElement {
data = { abc: 'abc' }
// define CustomEvent Handler
onAbc = evt => {
// get evt data by evt.detail
this.data.abc = ' by ' + evt.detail.name
this.update()
}
static css = `
div{
color: green;
}`
}
render(props, data) {
return (
<div>
Hello {data.abc}
<hello-element
onAbc={this.onAbc}
msg="WeElement"
/>
</div>
)
}
})
render(<my-app name="Omi v4.0" />, 'body')
Tell Babel to transform JSX into Omi.h()
call:
{
"presets": ["env", "omi"]
}
The following two NPM packages need to be installed to support the above configuration:
"babel-preset-env": "^1.6.0",
"babel-preset-omi": "^0.1.1",
If you use babel7, you can also use the following packages and configuration:
npm install --save-dev @babel/preset-env
npm install --save-dev @babel/preset-react
{
"presets": [
"@babel/preset-env",
[
"@babel/preset-react",
{
"pragma": "Omi.h"
}
]
]
}
If you don't want to write CSS in JS, you can use to-string-loader of webpack, For example, the following configuration:
{
test: /[\\|\/]_[\S]*\.css$/,
use: [
'to-string-loader',
'css-loader'
]
}
If your CSS file starts with "_
", CSS will use to-string-loader
., such as:
import { tag, WeElement render } from 'omi'
define('my-app', class extends WeElement {
css = require('./_index.css')
...
...
...
You can also forget the tedious configuration and use omi-cli directly, no need to configure anything.
TodoApp
Here is a relatively complete example of TodoApp:
import { define, render, WeElement } from 'omi'
define('todo-list', class extends WeElement {
static propTypes = {
items: Array
}
render(props) {
return (
<ul>
{props.items.map(item => (
<li key={item.id}>{item.text}</li>
))}
</ul>
)
}
})
define('todo-app', class extends WeElement {
static observe = true
data = { 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 />, 'body')
TypeScript Auto Complete
import { h, WeElement, tag, classNames } from 'omi';
import * as styles from './_index.less';
interface ButtonProps {
href?: string,
disabled?: boolean,
type?: 'default' | 'primary' | 'danger',
htmltype?: 'submit' | 'button' | 'reset',
onClick?: (e: any) => void
}
const TAG = 'o-button'
declare global {
namespace JSX {
interface IntrinsicElements {
[TAG]: Omi.Props & ButtonProps
}
}
}
@tag(TAG)
export default class oButton extends WeElement<ButtonProps, {}> {
...
...
...
Lifecycle
Lifecycle method | When it gets called |
---|---|
install |
before the component gets mounted to the DOM |
installed |
after the component gets mounted to the DOM |
uninstall |
prior to removal from the DOM |
beforeUpdate |
before update |
updated |
after update |
beforeRender |
before render() |
receiveProps |
parent element re-render will trigger it, return false will prevent update action |
Debugging
Easy to debug via Omi DevTools Extension [Install from Chrome WebStore], using Omi DevTools you can simply debug and manage your UI without any configuration. Just install and debug.
Since Omi uses Web Components and Shadow-DOM, it doesn't need to have another elements panel such as React has. It just adds a panel to the Elements' sidebar and it's powerful as much as React DevTools.
View registered elements
console.log(Omi.elements)
Browsers Support
Omio - Omi for old browsers(IE8+)
Omis - Functional Component + Store + Scoped Style(IE9+)
Omi 4.0+ works in the latest two versions of all major browsers: Safari 10+, IE 11+, and the evergreen Chrome, Firefox, and Edge.
<script src="https://unpkg.com/@webcomponents/webcomponentsjs@2.0.0/webcomponents-bundle.js"></script>
Contribution
Build a example:
npm start example_name
Build omi:
npm run build
Unit testing
npm run test
Contributors
Core Maintainers
Please contact us for any questions. Also, Add Omi QQ Group.
Thanks
License
MIT © Tencent