Omi入门实战教程 - 仿淘票票

官网 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
Omi入门实战教程 - 仿淘票票_第1张图片
自动启动3000端口
├─ 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)
Omi入门实战教程 - 仿淘票票_第2张图片
底部三个按钮可以点击

由于多入口间的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}
...
Omi入门实战教程 - 仿淘票票_第3张图片
点击底部按钮,可以打开路由内指定组件

实现具体页面

  1. 热映影片
// 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) => )}
    ) } })
    Omi入门实战教程 - 仿淘票票_第4张图片
    购票按钮还不能点
    1. 加入分页
    // 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) => )}
    ) } })
    1. 影院页
      影院页同理,不再上代码。
    2. 我的
      在我的中添加两个比较丑的添加修改页
      在影院、电影列表上绑定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(我不知道,望指正),从优势来讲

    1. 包更小,但与vue、react比没有小到让人拍案惊呼咱换框架的程序
    2. 多入口,vue、react其实也能配,我比较不懂它这个多入口优势在哪里(望指正)
    3. 小程序框架、native支持,这确实是个优势,一套代码多处复用,但没有上过项目,它的功是不是盖的住它的坑还不好定定论

    你可能感兴趣的:(Omi入门实战教程 - 仿淘票票)