2018-10-28 21:39:27 +08:00
|
|
|
|
[English](./main-concepts.md) | 简体中文 | [한국어](./main-concepts.kr.md)
|
2018-10-18 10:27:55 +08:00
|
|
|
|
|
|
|
|
|
## Omi 文档
|
2018-10-18 08:22:41 +08:00
|
|
|
|
|
2018-10-22 03:50:09 +08:00
|
|
|
|
- [Omi 文档](#omi-文档)
|
2018-10-25 21:30:18 +08:00
|
|
|
|
- [My First Element](#my-first-element)
|
|
|
|
|
- [Props](#props)
|
|
|
|
|
- [Event](#event)
|
|
|
|
|
- [Custom Event](#custom-event)
|
|
|
|
|
- [CSS](#css)
|
|
|
|
|
- [Ref](#ref)
|
|
|
|
|
- [Store](#store)
|
|
|
|
|
- [Slot](#slot)
|
2018-10-28 18:35:11 +08:00
|
|
|
|
- [Observe](#observe)
|
2018-10-25 21:30:18 +08:00
|
|
|
|
- [SSR](#ssr)
|
2018-10-18 08:22:41 +08:00
|
|
|
|
|
2018-10-26 16:11:59 +08:00
|
|
|
|
[→ Omi Simple Examples](https://github.com/Tencent/omi/tree/master/packages/omi/examples)
|
|
|
|
|
|
2018-10-18 08:22:41 +08:00
|
|
|
|
### My First Element
|
|
|
|
|
|
|
|
|
|
```js
|
2018-10-30 07:18:59 +08:00
|
|
|
|
import { WeElement, define, render } from 'omi'
|
2018-10-18 08:22:41 +08:00
|
|
|
|
|
2018-10-30 07:18:59 +08:00
|
|
|
|
define('my-first-element', class extends WeElement {
|
2018-10-22 03:50:09 +08:00
|
|
|
|
render() {
|
|
|
|
|
return (
|
|
|
|
|
<h1>Hello, world!</h1>
|
|
|
|
|
)
|
|
|
|
|
}
|
2018-10-18 08:22:41 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
render(<my-first-element></my-first-element>, 'body')
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
在 HTML 开发者工具里看看渲染得到的结构:
|
|
|
|
|
|
|
|
|
|
![fe](../assets/first-element.jpg)
|
|
|
|
|
|
|
|
|
|
除了渲染到 body,你可以在其他任意自定义元素中使用 `my-first-element`。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### Props
|
|
|
|
|
|
|
|
|
|
```js
|
2018-10-30 07:18:59 +08:00
|
|
|
|
import { WeElement, define, render } from 'omi'
|
2018-10-18 08:22:41 +08:00
|
|
|
|
|
2018-10-30 07:18:59 +08:00
|
|
|
|
define('my-first-element', class extends WeElement {
|
2018-10-22 03:50:09 +08:00
|
|
|
|
render(props) {
|
|
|
|
|
return (
|
|
|
|
|
<h1>Hello, {props.name}!</h1>
|
|
|
|
|
)
|
|
|
|
|
}
|
2018-10-18 08:22:41 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
render(<my-first-element name="world"></my-first-element>, 'body')
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
你也可以传任意类型的数据给 props:
|
|
|
|
|
|
|
|
|
|
```js
|
2018-10-30 07:18:59 +08:00
|
|
|
|
import { WeElement, define, render } from 'omi'
|
2018-10-18 08:22:41 +08:00
|
|
|
|
|
2018-10-30 07:18:59 +08:00
|
|
|
|
define('my-first-element', class extends WeElement {
|
2018-10-22 03:50:09 +08:00
|
|
|
|
render(props) {
|
|
|
|
|
return (
|
|
|
|
|
<h1>Hello, {props.myObj.name}!</h1>
|
|
|
|
|
)
|
|
|
|
|
}
|
2018-10-18 08:22:41 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
render(<my-first-element my-obj={{ name: 'world' }}></my-first-element>, 'body')
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
`my-obj` 将映射到 myObj,驼峰的方式。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### Event
|
|
|
|
|
|
|
|
|
|
```js
|
2018-10-30 07:18:59 +08:00
|
|
|
|
define('my-first-element', class extends WeElement {
|
2018-10-22 03:50:09 +08:00
|
|
|
|
onClick = (evt) => {
|
|
|
|
|
alert('Hello Omi!')
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
render() {
|
|
|
|
|
return (
|
2018-10-30 07:18:59 +08:00
|
|
|
|
<h1 onClick={this.onClick}>Hello, world!</h1>
|
2018-10-22 03:50:09 +08:00
|
|
|
|
)
|
|
|
|
|
}
|
2018-10-30 07:18:59 +08:00
|
|
|
|
})
|
2018-10-18 08:22:41 +08:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Custom Event
|
|
|
|
|
|
|
|
|
|
```js
|
2018-10-30 07:18:59 +08:00
|
|
|
|
define('my-first-element', class extends WeElement {
|
2018-10-22 03:50:09 +08:00
|
|
|
|
onClick = (evt) => {
|
|
|
|
|
this.fire('myevent', { name: 'abc' })
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
render(props) {
|
|
|
|
|
return (
|
|
|
|
|
<h1 onClick={this.onClick}>Hello, world!</h1>
|
|
|
|
|
)
|
|
|
|
|
}
|
2018-10-30 07:18:59 +08:00
|
|
|
|
})
|
2018-10-18 08:22:41 +08:00
|
|
|
|
|
|
|
|
|
render(<my-first-element onMyEvent={(evt) => { alert(evt.detail.name) }}></my-first-element>, 'body')
|
|
|
|
|
```
|
|
|
|
|
|
2018-10-18 10:22:50 +08:00
|
|
|
|
通过 `this.fire` 触发自定义事件,fire 第一个参数是事件名称,第二个参数是传递的数据。通过 `evt.detail` 可以获取到传递的数据。
|
2018-10-18 08:22:41 +08:00
|
|
|
|
|
2018-10-23 09:18:59 +08:00
|
|
|
|
### CSS
|
|
|
|
|
|
|
|
|
|
```js
|
2018-10-30 07:18:59 +08:00
|
|
|
|
define('my-first-element', class extends WeElement {
|
2018-10-23 09:18:59 +08:00
|
|
|
|
css() {
|
|
|
|
|
return `h1 { color: red; }`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
render(props) {
|
|
|
|
|
return (
|
|
|
|
|
<h1>Hello, world!</h1>
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
render(<my-first-element onMyEvent={(evt) => { alert(evt.detail.name) }}></my-first-element>, 'body')
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
你也可以在 JS 里动态拼接 CSS:
|
|
|
|
|
|
|
|
|
|
```js
|
|
|
|
|
css() {
|
|
|
|
|
return `h1 { color: ${Math.random() > 0.5 ? "red" : "blue"}; }`
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
你也可以另起一个文件用来写 CSS,但是需要配置一下 webpack [to-string-loader](https://www.npmjs.com/package/to-string-loader):
|
|
|
|
|
|
|
|
|
|
```js
|
|
|
|
|
{
|
|
|
|
|
test: /[\\|\/]_[\S]*\.scss$/,
|
|
|
|
|
use: [
|
|
|
|
|
'to-string-loader',
|
|
|
|
|
'css-loader',
|
|
|
|
|
'sass-loader'
|
|
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
然后:
|
|
|
|
|
|
|
|
|
|
```js
|
2018-10-30 07:18:59 +08:00
|
|
|
|
import { define, WeElement } from 'omi'
|
2018-10-23 09:18:59 +08:00
|
|
|
|
import style from '../style/_button.scss'
|
|
|
|
|
|
2018-10-30 07:18:59 +08:00
|
|
|
|
define('el-button', class extends WeElement {
|
|
|
|
|
static pure = true
|
2018-10-23 09:18:59 +08:00
|
|
|
|
|
|
|
|
|
css() {
|
|
|
|
|
return style
|
|
|
|
|
}
|
|
|
|
|
...
|
|
|
|
|
...
|
|
|
|
|
```
|
|
|
|
|
|
2018-10-18 08:22:41 +08:00
|
|
|
|
### Ref
|
|
|
|
|
|
|
|
|
|
```js
|
2018-10-30 07:18:59 +08:00
|
|
|
|
define('my-first-element', class extends WeElement {
|
2018-10-22 03:50:09 +08:00
|
|
|
|
onClick = (evt) => {
|
|
|
|
|
console.log(this.h1)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
render(props) {
|
|
|
|
|
return (
|
|
|
|
|
<div>
|
|
|
|
|
<h1 ref={e => { this.h1 = e }} onClick={this.onClick}>Hello, world!</h1>
|
|
|
|
|
</div>
|
|
|
|
|
)
|
|
|
|
|
}
|
2018-10-30 07:18:59 +08:00
|
|
|
|
})
|
2018-10-18 08:22:41 +08:00
|
|
|
|
|
|
|
|
|
render(<my-first-element></my-first-element>, 'body')
|
|
|
|
|
```
|
|
|
|
|
|
2018-10-18 11:19:30 +08:00
|
|
|
|
在元素上添加 `ref={e => { this.anyNameYouWant = e }}` ,然后你就可以 JS 代码里使用 `this.anyNameYouWant` 访问该元素。
|
|
|
|
|
|
|
|
|
|
### Store
|
|
|
|
|
|
|
|
|
|
```js
|
2018-10-30 07:18:59 +08:00
|
|
|
|
define('my-first-element', class extends WeElement {
|
2018-10-22 03:50:09 +08:00
|
|
|
|
//You must declare data here for view updating
|
|
|
|
|
static get data() {
|
|
|
|
|
return { name: null }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
onClick = () => {
|
|
|
|
|
//auto update the view
|
|
|
|
|
this.store.data.name = 'abc'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
render(props, data) {
|
2018-10-30 07:18:59 +08:00
|
|
|
|
//data === this.store.data when using store system
|
2018-10-22 03:50:09 +08:00
|
|
|
|
return (
|
|
|
|
|
<h1 onClick={this.onClick}>Hello, {data.name}!</h1>
|
|
|
|
|
)
|
|
|
|
|
}
|
2018-10-30 07:18:59 +08:00
|
|
|
|
})
|
2018-10-18 11:19:30 +08:00
|
|
|
|
|
|
|
|
|
const store = {
|
2018-10-22 03:50:09 +08:00
|
|
|
|
data: { name: 'Omi' }
|
2018-10-18 11:19:30 +08:00
|
|
|
|
}
|
|
|
|
|
render(<my-first-element name="world"></my-first-element>, 'body', store)
|
|
|
|
|
```
|
|
|
|
|
|
2018-10-19 14:19:44 +08:00
|
|
|
|
当非纯 Element 使用 store 体系时,`static get data` 就仅仅被用来声明依赖,举个例子:
|
2018-10-18 11:19:30 +08:00
|
|
|
|
|
|
|
|
|
```js
|
|
|
|
|
static get data() {
|
2018-10-22 03:50:09 +08:00
|
|
|
|
return {
|
|
|
|
|
a: null,
|
|
|
|
|
b: null,
|
|
|
|
|
c: { d: [] },
|
|
|
|
|
e: []
|
|
|
|
|
}
|
2018-10-18 11:19:30 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
会被转换成:
|
|
|
|
|
|
|
|
|
|
```js
|
|
|
|
|
{
|
|
|
|
|
a: true,
|
|
|
|
|
b: true,
|
|
|
|
|
'c.d':true,
|
|
|
|
|
e: true
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
举例说明 Path 命中规则:
|
|
|
|
|
|
2018-10-22 03:50:09 +08:00
|
|
|
|
| Proxy Path | updatePath | 是否更新 |
|
|
|
|
|
| ---------- | ---------- | -------- |
|
|
|
|
|
| abc | abc | 更新 |
|
|
|
|
|
| abc[1] | abc | 更新 |
|
|
|
|
|
| abc.a | abc | 更新 |
|
|
|
|
|
| abc | abc.a | 不更新 |
|
|
|
|
|
| abc | abc[1] | 不更新 |
|
|
|
|
|
| abc | abc[1].c | 不更新 |
|
|
|
|
|
| abc.b | abc.b | 更新 |
|
2018-10-18 11:19:30 +08:00
|
|
|
|
|
|
|
|
|
以上只要命中一个条件就可以进行更新!
|
|
|
|
|
|
|
|
|
|
总结就是只要等于 updatePath 或者在 updatePath 子节点下都进行更新!
|
|
|
|
|
|
|
|
|
|
看可以看到 store 体系是中心化的体系?那么怎么做到部分组件去中心化?使用 tag 的第二个参数:
|
|
|
|
|
|
|
|
|
|
```js
|
|
|
|
|
@tag('my-first-element', true)
|
|
|
|
|
```
|
|
|
|
|
|
2018-10-18 15:53:33 +08:00
|
|
|
|
纯元素!不会注入 store!
|
2018-10-19 15:47:18 +08:00
|
|
|
|
|
2018-10-19 19:24:08 +08:00
|
|
|
|
### Slot
|
|
|
|
|
|
2018-10-19 19:27:41 +08:00
|
|
|
|
HTML`<slot>`元素(Web组件技术套件的一部分)是Web组件内部的占位符,您可以用自己的标记填充该占位符,该标记允许您创建单独的DOM树并将它们一起呈现。
|
2018-10-19 19:24:08 +08:00
|
|
|
|
|
2018-10-19 19:26:27 +08:00
|
|
|
|
```jsx
|
2018-10-30 07:18:59 +08:00
|
|
|
|
define('hello-element', class extends WeElement {
|
2018-10-22 03:50:09 +08:00
|
|
|
|
render() {
|
|
|
|
|
return (
|
|
|
|
|
<div onClick={this.onClick}>
|
|
|
|
|
<p><slot name="my-text">My default text</slot></p>
|
|
|
|
|
</div>
|
|
|
|
|
)
|
|
|
|
|
}
|
2018-10-30 07:18:59 +08:00
|
|
|
|
})
|
2018-10-19 19:24:08 +08:00
|
|
|
|
|
2018-10-30 07:18:59 +08:00
|
|
|
|
define('my-app', class extends WeElement {
|
2018-10-22 03:50:09 +08:00
|
|
|
|
render() {
|
|
|
|
|
return (
|
|
|
|
|
<div >
|
|
|
|
|
<hello-element>
|
|
|
|
|
<span slot="my-text">Let's have some different text!</span>
|
|
|
|
|
</hello-element>
|
|
|
|
|
</div>
|
|
|
|
|
)
|
|
|
|
|
}
|
2018-10-19 19:24:08 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
render(<my-app></my-app>, 'body')
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
[→ Slot MDN](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_templates_and_slots#Adding_flexibility_with_slots)
|
|
|
|
|
|
2018-10-28 18:35:11 +08:00
|
|
|
|
### Observe
|
|
|
|
|
|
|
|
|
|
#### Omi Observe
|
|
|
|
|
|
|
|
|
|
你可以为那些不需要 store 的自定义元素使用 observe 创建响应式视图,比如:
|
2018-10-26 16:00:52 +08:00
|
|
|
|
|
|
|
|
|
```js
|
2018-10-30 07:18:59 +08:00
|
|
|
|
define("my-app", class extends WeElement {
|
|
|
|
|
static observe = true
|
2018-10-28 18:35:11 +08:00
|
|
|
|
|
|
|
|
|
install() {
|
|
|
|
|
this.data.name = "omi"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
onClick = () => {
|
|
|
|
|
this.data.name = "Omi V4.0"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
render(props, data) {
|
|
|
|
|
return (
|
|
|
|
|
<div onClick={this.onClick}>
|
|
|
|
|
<h1>Welcome to {data.name}</h1>
|
|
|
|
|
</div>
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-10-26 16:00:52 +08:00
|
|
|
|
```
|
|
|
|
|
|
2018-10-28 18:35:11 +08:00
|
|
|
|
如果你想要兼容 IE11,请使用 `omi-mobx` 代替 omi 自带的 obersve,往下看..
|
|
|
|
|
|
|
|
|
|
#### Omi Mobx
|
2018-10-26 16:00:52 +08:00
|
|
|
|
|
|
|
|
|
```js
|
2018-10-28 18:35:11 +08:00
|
|
|
|
import { tag, WeElement } from "omi"
|
|
|
|
|
import { observe } from "omi-mobx"
|
|
|
|
|
|
|
|
|
|
@observe
|
|
|
|
|
@tag("my-app")
|
|
|
|
|
class MyApp extends WeElement {
|
|
|
|
|
install() {
|
|
|
|
|
this.data.name = "omi"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
onClick = () => {
|
|
|
|
|
this.data.name = "Omi V4.0"
|
|
|
|
|
}
|
2018-10-26 16:00:52 +08:00
|
|
|
|
|
2018-10-28 18:35:11 +08:00
|
|
|
|
render(props, data) {
|
|
|
|
|
return (
|
|
|
|
|
<div onClick={this.onClick}>
|
|
|
|
|
<h1>Welcome to {data.name}</h1>
|
|
|
|
|
</div>
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
2018-10-26 16:00:52 +08:00
|
|
|
|
|
2018-10-19 15:47:18 +08:00
|
|
|
|
### SSR
|
|
|
|
|
|
|
|
|
|
推荐尝试的框架:
|
|
|
|
|
|
|
|
|
|
* https://github.com/skatejs/skatejs/tree/master/packages/ssr
|
2018-10-23 22:11:03 +08:00
|
|
|
|
* https://www.youtube.com/watch?v=yT-EsESAmgA
|