官网 https://github.com/Tencent/omi
此文主要是对omi的一个初步了解,详细入门见手把手教程:Omi入门实战教程 - 仿淘票票
新概念
- 深入浅出 Shadow Dom
- HTM - JSX ?(why take react so close, but not vue)
- css3transform(我们反应快,我们经过了海量项目洗礼,虽然还是css3,但我们是鹅厂的,so)
- Native 方案(看,h5、小程序、原生app我全包了)
- css变量
- 我们用了requestIdleCallback
- ...
Let's Coding
$ npm i omi-cli -g # 全局安装脚手架
$ omi init my-app # 初始化项目
$ cd my-app
$ npm start # 不用npm install
项目目录结构
package.json:很多babel配置项、eslint配置项,webpack用的4.x,呃,等...
官网给出的目录说明
├─ config
├─ public
├─ scripts
├─ src
│ ├─ assets
│ ├─ elements //存放所有 custom elements
│ ├─ store //存放所有页面的 store
│ ├─ admin.js //入口文件,会 build 成 admin.html
│ └─ index.js //入口文件,会 build 成 index.html
嗯,没有路由,但有两个入口文件,看来它是一个多入口框架?
我讨厌过年我讨厌过年我讨厌过年,凭什么凭什么为什么
在index.js下面新添加一个usercenter.js文件,在elements中添加usercenter文件夹 -> index.js
## usercenter.js
import { render } from 'omi'
import './elements/usercenter'
import store from './store/admin-store'
render( , '#root', store)
## elements/usercenter/index.js
import { define, WeElement } from 'omi'
define('hello-element', class extends WeElement {
render(props, data) {
return (
个人中心 - {this.store.name}
これは嫌な世界です.
)
}
})
重启服务后(怎么还要手动重启),访问http://localhost:3000/usercenter.html渲染出了个人中心
组件间传值
Cli 自动创建的项目脚手架是基于单页的 create-react-app 改造成多页的(能不能改为成vue呢,还要熟悉react语法)
import { define, render, WeElement } from 'omi'
define('hello', function(props) {
onClick = evt => {
// trigger CustomEvent
this.fire('say', { name: 'dntzhang', age: 12 }) ## 触发父组件事件
evt.stopPropagation()
}
render(props) {
return (
Hello {props.msg} {props.propFromParent} ## 父组件传来的值
Click Me!
)
}
})
define('my-app', class extends WeElement {
data = { abc: 'abc', passToChild: 123 }
// define CustomEvent Handler
onSay = evt => {
// get evt data by evt.detail
this.data.abc = ' by ' + evt.detail.name + ', he is ' + evt.detail.age
this.data.passToChild = 1234
this.update()
}
handleChange = e => {
this.data.val = e.target.value
}
handleSubmit = e => {
this.data.items.push({id: this.data.items.length + 1, text: this.data.val})
this.update() ## 不加这句页面不刷新渲染
}
render(data) {
return (
Hello {data.abc}
-- TODO --
{data.items.map(item => ( ## map
- {item.text}
))}
)
}
})
再来看OMI的store
## store/admin-store.js
export default {
name: 'I am admin page',
rename(name) {
this.name = name
}
}
## index.js
render( , '#root', store) // 根部注入,其后的子组件可this.store调用
由于omi是多入口,所以store中的状态不可在页面间共用
Omi Observe
你可以为那些不需要 store 的自定义元素使用 observe 创建响应式视图:
install、installed、uninstall、beforeUpdate、updated、beforeRender、receiveProps
define("my-app", class extends WeElement {
static observe = true ## 启用 Omi Observe
install() {
this.data.name = "omi"
}
...
这是什么意思,不启用生命周期钩子就不能用?启用了就不能用store???
它也有路由
API,与vue路由大不相同,似乎和组件化结合的不够
import 'omi-router' // 引入
import './elements/list_movie'
import './elements/list_cinema'
import './elements/My'
define('my-app', class extends WeElement {
static observe = true
data = { tabbar: 'list-movie' }
install () {
route('/movie', () => {
this.data.tabbar = 'list-movie'
})
route('/cinema', (evt) => {
this.data.tabbar = 'list-cinema'
})
route('/my', (evt) => {
this.data.tabbar = 'my'
})
}
下面尝试懒加载(结束不如人意,感觉只能懒执行,加载一点都不懒)
import 'omi-router'
define('my-app', class extends WeElement {
static observe = true
data = { tabbar: 'list-movie' }
install () {
route('/movie', () => {
require('./elements/list_movie')
this.data.tabbar = 'list-movie'
})
route('/cinema', (evt) => {
require('./elements/list_cinema')
this.data.tabbar = 'list-cinema'
})
route('/my', (evt) => {
require('./elements/My')
this.data.tabbar = 'my'
})
}
changeTabber = e => {
route.to('/' + this.data.tabbar.replace('list-', ''))
}
...
尝试做根部注入,发现在只能注入store,看来这个框架是个偏向多页的框架,对于SPA支持的并不好,但多页都用在什么场景下呢?
// src/router/router.js
// 路由数据
export default [
{
path: '',
redirect: '/movie'
},
{
path: '/movie',
name: 'movie',
component: () => require('../elements/movie')
},
{
path: '/my',
name: 'my',
component: () => require('../elements/My')
}
]
// src/router/index.js
// 封装 router-view 及路由处理
import { define, WeElement } from 'omi'
import routerList from '../router/router'
import 'omi-router'
define('router-view', class extends WeElement {
static observe = true
data = { router_view: '' }
install () {
routerList.forEach(item => {
route(item.path, () => {
if (item.redirect) {
route.to('#' + item.redirect)
} else {
item.component()
this.data.router_view = item.name
}
})
})
}
render(props, data) {
return data.router_view ? ( ) : null
}
})
// src/store/admin-store.js
// 由于根部注入只能注入store,所有在store中添加route模块
$route: {
to: route.to,
view:
}
// 使用
import { define, render, WeElement } from 'omi'
import store from './store/admin-store'
define('my-app', class extends WeElement {
changeTabber = e => {
this.store.$route.to('/' + e.target.dataset.tab) // 跳转
this.update()
}
render(props, data) {
return (
{this.store.$route.view}
)
}
})
render( , '#root', store)
调试工具
下载地址:https://github.com/f/omi-devtools
下载下来是个.crx文件,装不上打开开发者模式多试几次~