官网 https://github.com/Tencent/omi
以下代码基于omi 6.0.3,omio 2.1.0,omi-router 2.0.10
初始化项目
$ npm i omi-cli -g # 全局安装脚手架
$ omi init my-app # 初始化项目
$ cd my-app
$ npm start # 不用npm install
├─ config
├─ public
├─ scripts
├─ src
│ ├─ assets
│ ├─ elements //存放所有 custom elements
│ ├─ store //存放所有页面的 store
│ │ ├─ admin-store.js
│ ├─ admin.js //入口文件,会 build 成 admin.html
│ └─ index.js //入口文件,会 build 成 index.html
// 改造入口文件 index.js
import { define, render, WeElement } from 'omi'
import './assets/index.css'
define('my-app', class extends WeElement {
data = { tabbar: 'list-movie' }
changeTabber = e => {
this.data.tabbar = e.target.dataset.tab
this.update() // 更新视图
}
render(props, data) {
return (
)
}
})
render( , '#root', store)
由于多入口间的store(中的值)不可以共用,所以我们使用路由。又由于omi的根部注入只能注入store,所以我们把路由放进store里
// 在src目录下创建router文件夹
// 创建 router.js (存放路由数组)
export default [
{
path: '',
redirect: '/movie'
},
{
path: '/movie',
name: 'list-movie',
component: () => require('../elements/list_movie') // 创建目录和(空)文件
},
{
path: '/cinema',
name: 'list-cinema',
component: () => require('../elements/list_cinema') // 同上
},
{
path: '/my',
name: 'my',
component: () => require('../elements/My') // 同上
}
]
// 创建 index.js (启用路由,封闭 router-view)
import { define, WeElement } from 'omi'
import routerList from './router'
import 'omi-router' // 引入了route对象
define('router-view', class extends WeElement {
static observe = true // 封闭的router-view公共组件,用observe(不用手动update)
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
}
})
// 改造 store/admin-store.js
import axios from 'axios'
import route from 'omi-router'
import '../router'
route.view = // 封装自己的router-view
export default {
Post (method, data) { ... }, // 我自己封装的调用后台接口的方法,也可以直接读本地文件
$route: route // 把路由放进store里
}
// 入口文件 index.js
...
changeTabber = e => {
this.data.tabbar = e.target.dataset.tab
this.store.$route.to('/' + e.target.dataset.tab)
this.update()
}
...
{this.store.$route.view}
...
实现具体页面
- 热映影片
// elements/list_movie/item.js (创建 单个影片封闭成一个组件)
import { define, WeElement } from 'omi'
define('item-movie', class extends WeElement {
css = require('./_index.css')
render(props, data) {
let item = props.data // 组件间传值
return (
{item.name}
{item.ThrD ? '3D' : '2D'}
IMAX
淘票票评分 {item.point}
导演:{item.maker}
主演:{item.actor.replace(',',' ')}
)
}
})
// elements/list_movie/index.js
import { define, WeElement } from 'omi'
import './item'
define('list-movie', class extends WeElement {
css = require('./_index.css')
data = {
list: []
}
installed() {
this.store.Post('piaopiao/getall', {}).then(res => { // 调用store中的Post方法
this.data.list = res
this.update()
})
}
render(props, data) {
return (
妈妈的淘票票
{data.list.map((item, index) =>
)}
)
}
})
- 加入分页
// elements/list_movie/index.js
import { define, WeElement } from 'omi'
import './item'
define('list-movie', class extends WeElement {
css = require('./_index.css')
// data = { list: [] }
data = { list: [], page_index: 1, loading: false }
installed() {
// this.store.Post('piaopiao/getall', {}).then(res => { // 调用store中的Post方法
// this.data.list = res
// this.update()
// })
this.getList()
}
getList () {
if (this.data.loading) return; // 正在加载
else this.data.loading = true
this.store.Post('piaopiao/movie_get_all', { pindex: this.data.page_index, psize: 5 }).then(res => {
this.data.loading = false
this.data.page_index++
this.data.list.push(...res )
this.update()
})
}
nextPage = (e) => {
// 已经滑动到最底部了
// 监听div滚动到底部方法,网上很多,不重要
common.ScrollToBottom(e.target, 30).then(res => this.getList())
}
render(props, data) {
return (
妈妈的淘票票
{data.list.map((item, index) =>
)}
)
}
})
- 影院页
影院页同理,不再上代码。 - 我的
在我的中添加两个比较丑的添加修改页
在影院、电影列表上绑定onTouchMove事件,用于触发修改事件
// elements/My/index.js
import { define, WeElement } from 'omi'
define('my', class extends WeElement {
static observe = true
data = { tabbar: 0, update_obj: {} }
installed() {
if (route.query.type) {
// 修改电影|影院
// ?type=cinema&obj={电影|影院对像字符串}
let temp = ['movie', 'cinema']
this.data.tabbar = temp.indexOf(route.query.type)
this.data.update_obj = JSON.parse(route.query.obj)
console.info(this.data.update_obj)
}
}
AddMoive = e => {
let params = {
name: document.querySelector('#name').value,
maker: document.querySelector('#maker').value,
actor: document.querySelector('#actor').value,
ThrD: document.querySelector('#is3d').checked,
IMax: document.querySelector('#isimax').checked,
point: document.querySelector('#point').value,
img: document.querySelector('#img').value
}
if (!params.name) { alert('电影总要有个名字吧'); return }
if (this.data.update_obj._id) {
// 修改
params = { keyid: this.data.update_obj._id, sets: params }
this.store.Post('piaopiao/movie_update', params).then(res => {
console.info(res)
this.store.$route.to('/movie')
})
} else {
// 添加
this.store.Post('piaopiao/movie_add', params).then(res => {
console.info(res)
this.store.$route.to('/movie')
})
}
}
AddCinema = e => {
let params = {
cinema: document.querySelector('#cinema').value,
address: document.querySelector('#address').value,
nearby: ''
}
// console.info(document.querySelectorAll('input:checked[name="nearby"]'))
document.querySelectorAll('input:checked[name="nearby"]').forEach(item => {
// console.info(item.nextSibling.nodeValue)
params.nearby += ',' + item.nextSibling.nodeValue
})
if (params.nearby != '') params.nearby = params.nearby.substr(1)
if (!params.address) { alert('影院总要有地址吧'); return }
if (this.data.update_obj._id) {
// 修改
params = { keyid: this.data.update_obj._id, sets: params }
this.store.Post('piaopiao/cinema_update', params).then(res => {
console.info(res)
this.store.$route.to('/cinema')
})
} else {
// 添加
this.store.Post('piaopiao/cinema_add', params).then(res => {
console.info(res)
this.store.$route.to('/cinema')
})
}
}
render(props, data) {
return (
this.data.tabbar = 0}>添加电影
this.data.tabbar = 1}>添加影院
电影名:
导演:
演员:
3D:
IMAX:
评分:
海报:
影院:
地址:
{data.update_obj.nearby &&
周边设施:
}
)
}
})
// elements/list_movie/index.js
onUpdate = ({detail}) => {
let obj = this.data.list.find(item => item._id == detail)
route.to('/My?type=movie&obj=' + JSON.stringify(obj)) // 传参给my,用于回显
}
...
做到现在发现,底部tabber高亮没有跟上,在“传参给my,用于回显”后根组件没有对路由的变化进行处理
omi-router有钩子函数(也叫路由守卫),分别是before和after。在api上并没有写(它github上的 README.md,不知道以后会不会有一个正式点的api),但源码里有,before钩子返回false可以阻止路由跳转
import { define, render, WeElement } from 'omi'
import './assets/index.css'
define('my-app', class extends WeElement {
data = { tabbar: 'list-movie' }
install () {
// 添加路由钩子函数,路由变化时,及时修改底部tabbar高亮状态
// { newURL, oldURL ... }
route.before = e => {
let path = e.newURL.split('?')[0].split('/')
this.data.tabbar = path[path.length - 1]
this.update()
return true
}
}
...
嗯,route这个变量好像直接就能用,不用每个组件引用,也不用this.store.$router,嗯...大家就假装没看到这一part,就先这样吧
现状?
目前不知道有哪些站是用的omi(我不知道,望指正),从优势来讲
- 包更小,但与vue、react比没有小到让人拍案惊呼咱换框架的程序
- 多入口,vue、react其实也能配,我比较不懂它这个多入口优势在哪里(望指正)
- 小程序框架、native支持,这确实是个优势,一套代码多处复用,但没有上过项目,它的功是不是盖的住它的坑还不好定定论