介绍
weex是阿里出品的一个类似RN的框架,可以使用前端技术来开发移动应用,实现一份代码支持H5,iOS和Android。最新版本的weex已默认将Vue.js作为前端框架,而wisdom-medical-hardware则是我第一次使用Weex和Vue开发的原生应用,在项目中使用了vue-router等官方组件。下面我们以该项目代码为例,具体了解如何使用weex技术栈进行开发,实现同一份代码在 iOS、Android下都能完整地工作。
这是我Weex开发初体验,其中难免出现常识性的纰漏,还请各位指正~
效果
代码分析
将项目里的src导入到IDE里,可以看到代码结构如下:
简单说明
- components —— vue组件
- views —— 视图
- mixins —— 扩展
- filters —— vue.js 的filter
- App.vue —— 主UI界面
- entry.js —— 入口程序
- router.js —— vue-router
入口程序
import App from './App.vue'
import router from './router'
import * as filters from './filters'
import mixins from './mixins'
// register global utility filters.
Object.keys(filters).forEach(key => {
Vue.filter(key, filters[key])
})
// register global mixins.
Vue.mixin(mixins)
new Vue(Vue.util.extend({ el: '#root', router }, App))
router.push('/')
该段代码主要实现将各个组件和扩展导入,执行各种初始化工作,包括view、router等核心功能。暂且说这么多,后面再详说。
vue-router (https://github.com/vuejs/vue-router) 是vue.js生态里重要的一环,是vue.js官方router它与Vue.js核心深度集成,使得使用Vue.js构建单页面应用程序变得轻而易举,包含如下特性:
- 嵌套路由/视图映射
- 基于组件的路由器配置
- 路由参数,查询,通配符
- 集成Vue.js页面过渡效果
- 导航控制
- 历史记录:HTML5 history mode 或者 hash mode
我们本项目项目来看如何使用vue-router:
// import Vue from 'vue'
import Router from 'vue-router'
import MineDeviceView from './views/MineDeviceView.vue'
import AddDeviceView from './views/AddDeviceView.vue'
import BloodSugarResultView from './views/BloodSugarResultView.vue'
import BloodSugarRunView from './views/BloodSugarRunView.vue'
import BlueToothPreView from './views/BlueToothPreView.vue'
import BlueToothRunView from './views/BlueToothRunView.vue'
import BlueToothErrorView from './views/BlueToothErrorView.vue'
import BloodPressureResultView from './views/BloodPressureResultView.vue'
import BloodPressureRunView from './views/BloodPressureRunView.vue'
Vue.use(Router)
export default new Router({
// mode: 'abstract',
routes: [
{ path: '/device-mine', component: MineDeviceView },
{ path: '/device-add', component: AddDeviceView },
{ path: '/blood-sugar-result', component: BloodSugarResultView },
{ path: '/blood-sugar-run', component: BloodSugarRunView },
{ path: '/bluetooth-pre', component: BlueToothPreView },
{ path: '/bluetooth-run', component: BlueToothRunView },
{ path: '/bluetooth-error', component: BlueToothErrorView },
{ path: '/blood-press-result', component: BloodPressureResultView },
{ path: '/blood-press-run',component: BloodPressureRunView },
{ path: '/', redirect: '/device-mine' }
]
})
- 首先,需要import Router from 'vue-router',导入Router,然后Vue.use(Router)
- rourter是基于组件的路由配置,所以还需要导入各种View
- 最重要的,router需要返回Router的实例对象,关键是配置routes,如代码所示,routes是一个json-array,里面的每一个json-object包含了path和component
- path支持字符串、通配符
- component返回一个View
- 看到这里大概就理解了router的原理,通过path去匹配,然后返回匹配的View,比如访问主页,route里配置的是redirect:'/device-mine', 则会跳转到device-mine
- 项目里,top,new,show等都是StoriesView,只是类型不同,所以createStoriesView函数用于实例化不同类型的StoriesView
- 路由跳转
- 跳转:包含两种方式,声明和编程。
router.push(...)
router.push({ path: 'home' })
router.push('home')
router.push({ name: 'user', params: { userId: 123 }})
声明式 | 编程式 |
---|---|
router.push(...) |
- mixins,在入口代码里有
Vue.mixin(mixins)
export default {
methods: {
jump (to) {
if (this.$router) {
this.$router.push(to)
}
}
}
}
- Vue.mixin 混合是一种灵活的分布式复用 Vue 组件的方式,所有混合对象的选项将被混入该组件本身的选项,因此上述代码实现为Vue组件增加jump方法,而jump的核心就是路由的跳转。mixin后,可以在vue组件里使用jump方法。例如:
这是抄袭自weex官方demo
filters过滤器
filter是vue.js的一个特性,过滤器是一个通过输入数据,能够及时对数据进行处理并返回一个数据结果的简单函数。Vue有很多很便利的过滤器,可以参考官方文档, http://cn.vuejs.org/api/#过滤器 ,过滤器通常会使用管道标志 " | ", 比如:
{{ msg | capitalize }} // 'abc' => 'ABC'
项目里的定义如下:
export function timeAgo (time) { const between = Date.now() / 1000 - Number(time) if (between < 3600) { return pluralize(~~(between / 60), ' minute') } else if (between < 86400) { return pluralize(~~(between / 3600), ' hour') } else { return pluralize(~~(between / 86400), ' day') } }
格式化时间的filter
使用过滤器
{{comment.time|timeAgo}} ago App.vue
定义了一个div作为body容器,transition 作为过渡动画容器,router-view作为component容器
这里存在一个问题是似乎transition过渡动画的存在是个然并暖
-
@androidback="back"
处理了Android返回按钮点击事件,点击返回按钮时,router执行back回退。 - 通过
Vue.util.extend
,将router注入到所有子组件,这样就可以使用this.$router
来访问路由。
new Vue(Vue.util.extend({ el: '#root', router }, App)) router.push('/')
代码最后一行,router.push('/') , 跳转到'/', 根据上篇的内容,会跳转到/device-mine
export default new Router({ // mode: 'abstract', routes: [ { path: '/device-mine', component: MineDeviceView }, { path: '/device-add', component: AddDeviceView }, { path: '/blood-sugar-result', component: BloodSugarResultView }, { path: '/blood-sugar-run', component: BloodSugarRunView }, { path: '/bluetooth-pre', component: BlueToothPreView }, { path: '/bluetooth-run', component: BlueToothRunView }, { path: '/bluetooth-error', component: BlueToothErrorView }, { path: '/blood-press-result', component: BloodPressureResultView }, { path: '/blood-press-run',component: BloodPressureRunView }, { path: '/', redirect: '/device-mine' } ] })
MineDeviceView.vue(我的设备)
目前尚未使用任何设备 请点击屏幕右上角添加设备 {{ item.title }} {{ item.time }}使用 上次测量结果 {{ item.lastValue }} 组件通过props属性传递数据
MineDeviceView
HeaderNor组件
Vue.js可以使用 props 把数据传给子组件,prop 是父组件用来传递数据的一个自定义属性,子组件需要显式地用 props 选项声明 "prop":
{{ title }} 子组件
在MineDeviceView中,包含子组件HeaderNor,使用时需要import
import HeaderNor from '../components/HeaderNor.vue'
{{ title }} 两个关键点
- @click 处理点击事件,jump是在入口程序里mixin的router跳转函数
- weex里,text用于显示文本元素,可以理解为html里的span
谈一谈使用Vue.js开发Weex的一些体验
Weex 可以让前端开发人员开发native app程序,值得点赞
缺点是目前坑还比较多,开源社区资源也较少
在开发过程中遇到一些情况
- Weex 盒模型基于 CSS 盒模型,每个 Weex 元素都可视作一个盒子。本项目中绝大多数布局,都基于「盒模型」概念。但是,Weex目前对盒模型的支持并不完全。
- Weex 对于长度值目前只支持像素值,不支持相对单位(em、rem)
- 设定边框,border 目前不支持类似这样 border: 1 solid #ff0000; 的组合写法
.button-choice { border-radius: 110px; height: 221px; width: 221px; border-color: #B4B4B4; border-width: 1px; border-style: solid; background-color: #5A33BE; }
写出来的CSS很多时候都是这个样子的,在web可以一行带带吗搞定的问题,在这个可能需要3行或者4行,并且,weex是不支持全局样式的,所在在style标签中
scoped
是必须的。- style选择器只支持class
这个在上面的MineDeviceView代码中有所体现,写到最后会发现满屏幕的class。。。
- 令人困惑的官方文档
以下代码来自于官方手册
https://weex.incubator.apache.org/cn/v-0.10/guide/syntax/style-n-class.html
Alibaba Weex Team class="large {{textClass}}"
style="font-size: {{fontSize}};"
这样的写法我相信写过vue的人都知道是不可以的,但是,weex手册中出现了,那么在weex中支持这样的写法吗?答案是不支持
。反正我被文档骗了一整天。
正确的写法是使用v-bind指令:v-bind:style="..."
,那么v-bind:class="..."
应该也是支持的吧?结果是不支持
- 生命周期,到底是ready还是mounted?
官方手册,Weex 和 Vue 2.x 的语法差异
https://weex.incubator.apache.org/cn/references/migration/difference.html
weex vue 生命周期 ready: function() {} mounted: function() {} ……
实际情况当然是mounted
,被骗一天+1对动画的支持
weex提供了animation模块,我们可以很方便的在页面中加入动画,利用相关的API,可以设置动画对象、动画类型、持续时间、回调函数,但是我们无法手动结束动画
。本地存储
相比较动画,weex的storage做的还是不错的。
storage 是一个在前端比较常用的模块,可以对本地数据进行存储、修改、删除,并且该数据是永久保存的,除非手动清除或者代码清除。但是,storage 模块有一个限制就是浏览器端(H5)只能存储小于5M的数据,因为在 H5/Web 端的实现是采用 HTML5 LocalStorage API。而 Android 和 iOS 这块是没什么限制的。
storage.setItem('bloodPress', vm.data.jsonString, event => { console.log('set success') })
很容易就可以保存相关的数据,和使用h5的localStorage很相似。
-