[English](./main-concepts.md) | 简体中文 | [한국어](./main-concepts.kr.md)
## Omi 文档
- [Omi 文档](#omi-文档)
- [My First Element](#my-first-element)
- [Props](#props)
- [Event](#event)
- [Custom Event](#custom-event)
- [CSS](#css)
- [Ref](#ref)
- [Store](#store)
- [Slot](#slot)
- [Observe](#observe)
- [Use](#use)
- [SSR](#ssr)
[→ Omi Simple Examples](https://github.com/Tencent/omi/tree/master/packages/omi/examples)
### My First Element
```js
import { WeElement, define, render } from 'omi'
define('my-first-element', class extends WeElement {
render() {
return (
Hello, world!
)
}
})
render(, 'body')
```
在 HTML 开发者工具里看看渲染得到的结构:
![fe](../assets/first-element.jpg)
除了渲染到 body,你可以在其他任意自定义元素中使用 `my-first-element`。
### Props
```js
import { WeElement, define, render } from 'omi'
define('my-first-element', class extends WeElement {
render(props) {
return (
Hello, {props.name}!
)
}
})
render(, 'body')
```
你也可以传任意类型的数据给 props:
```js
import { WeElement, define, render } from 'omi'
define('my-first-element', class extends WeElement {
render(props) {
return (
Hello, {props.myObj.name}!
)
}
})
render(, 'body')
```
`my-obj` 将映射到 myObj,驼峰的方式。你可以通过静态属性 `props` 来设置默认值:
```js
import { WeElement, define, render } from 'omi'
define('my-first-element', class extends WeElement {
static defaultProps = {
name: 'Omi',
myAge: 18
}
render(props) {
return (
Hello, {props.name}! Age {props.myAge}
)
}
})
render(, 'body')
```
### Event
```js
define('my-first-element', class extends WeElement {
onClick = (evt) => {
alert('Hello Omi!')
}
render() {
return (
Hello, world!
)
}
})
```
### Custom Event
```js
define('my-first-element', class extends WeElement {
onClick = (evt) => {
this.fire('myevent', { name: 'abc' })
}
render(props) {
return (
Hello, world!
)
}
})
```
然后在你的自定义元素上绑定事件:
```js
{ alert(evt.detail.name) }}>
```
通过 `this.fire` 触发自定义事件,fire 第一个参数是事件名称,第二个参数是传递的数据。通过 `evt.detail` 可以获取到传递的数据。
### CSS
```js
define('my-first-element', class extends WeElement {
css() {
return `h1 { color: red; }`
}
render(props) {
return (
Hello, world!
)
}
})
render( { alert(evt.detail.name) }}>, '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
import { define, WeElement } from 'omi'
import style from '../style/_button.scss'
define('el-button', class extends WeElement {
static pure = true
css() {
return style
}
...
...
```
### Ref
```js
define('my-first-element', class extends WeElement {
onClick = (evt) => {
console.log(this.h1)
}
render(props) {
return (
{ this.h1 = e }} onClick={this.onClick}>Hello, world!
)
}
})
render(, 'body')
```
在元素上添加 `ref={e => { this.anyNameYouWant = e }}` ,然后你就可以 JS 代码里使用 `this.anyNameYouWant` 访问该元素。
### Store
```js
define('my-first-element', class extends WeElement {
//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) {
//data === this.store.data when using store system
return (
Hello, {data.name}!
)
}
})
const store = {
data: { name: 'Omi' }
}
render(, 'body', store)
```
当非纯 Element 使用 store 体系时,`static get data` 就仅仅被用来声明依赖,举个例子:
```js
static get data() {
return {
a: null,
b: null,
c: { d: [] },
e: []
}
}
```
会被转换成:
```js
{
a: true,
b: true,
'c.d':true,
e: true
}
```
举例说明 Path 命中规则:
| 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 | 更新 |
以上只要命中一个条件就可以进行更新!
总结就是只要等于 updatePath 或者在 updatePath 子节点下都进行更新!
看可以看到 store 体系是中心化的体系?那么怎么做到部分组件去中心化?为自定义元素加上静态属性 pure 并设置为 ture:
```js
static pure = true
```
纯元素!不会注入 store!
### Slot
HTML``元素(Web组件技术套件的一部分)是Web组件内部的占位符,您可以用自己的标记填充该占位符,该标记允许您创建单独的DOM树并将它们一起呈现。
```jsx
define('hello-element', class extends WeElement {
render() {
return (
)
}
})
define('my-app', class extends WeElement {
render() {
return (
Let's have some different text!
)
}
})
render(, 'body')
```
[→ Slot MDN](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_templates_and_slots#Adding_flexibility_with_slots)
### Observe
#### Omi Observe
你可以为那些不需要 store 的自定义元素使用 observe 创建响应式视图,比如:
```js
define("my-app", class extends WeElement {
static observe = true
install() {
this.data.name = "omi"
}
onClick = () => {
this.data.name = "Omi V4.0"
}
render(props, data) {
return (
Welcome to {data.name}
)
}
})
```
如果你想要兼容 IE11,请使用 `omi-mobx` 代替 omi 自带的 obersve,往下看..
#### Omi Mobx
```js
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"
}
render(props, data) {
return (
Welcome to {data.name}
)
}
}
```
### Use
```js
import { define, render } from 'omi'
define('my-counter', function() {
const [count, setCount] = this.use({
data: 0,
effect: function() {
document.title = `The num is ${this.data}.`
}
})
const [items, setItems] = this.use({
data: [{ text: 'Omi' }],
effect: function() {
console.log(`The items count is ${this.data.length}.`)
}
})
return (
{count}
{items.map(item => {
return - {item.text}
})}
)
})
render(, 'body')
```
### SSR
推荐尝试的框架:
* https://github.com/skatejs/skatejs/tree/master/packages/ssr
* https://www.youtube.com/watch?v=yT-EsESAmgA