系列文章的目录在 这里
在配置完开发环境之后,就可以开始写应用了。在写应用之前,肯定会先划分好页面,一个一个独立着写的。
不过,首先要明确的是,使用 Weex 写出来的是原生应用,页面的概念还和 Web 上一样吗?
Weex 里“页面”的概念
写的有些乱,与下边内容关系不太,不理解可以忽略。
Weex 的实例在 Web 上是和“浏览器页签”的概念相对应的,通常一个 Weex 实例就是一个“页面”。
在 Web 上,只要没有新开页签,网页中的各种跳转,都是记录在 History
对象中的,对于 Weex 而言,这些都相当与在一个“页面”之内。在 Native 上,页面的跳转是记录在 Navigator
中的,内部也有一个栈来存储跳转记录,可以 push
、 pop
。
要想在原生页面之间(Weex 多实例之间)跳转,可以使用 navigator
模块,也可以看看 weex-router。
想深入理解这方面的概念,还需要了解一些 Native 开发的知识。原生开发里边,页面是个比较上层的概念,可以来回切换和销毁,在背后还有生命周期更长程序在运行,Weex Runtime 就运行在这一层里,多个 Weex 的实例会共用一个 Runtime。
因为 vue-router 的设计和实现都是在同一个页面内的,是 SPA 概念里的产物。其实前端路由也是基于 SPA 产生的概念,在 Weex 或者原生应用这种多页跳转的场景里可能并不合适,慎重使用。虽然 weex-hackernews 项目里用了 vue-router ,但是依然在同一个 Weex 实例中。相关话题我在 《使用 vue-router》这篇文章里详细再说。
编写入口文件
以 weex-hackernews 为例,看 webpack.config.js
中的配置,src/entry.js 就是入口文件。项目代码中因为用了 Vuex 和 vue-router,入口文件还有点长,其实只需要引入口组件,配置挂载点,然后初始化 Vue 实例就行了。
import Vue from 'vue'
import App from './App.vue'
// 将 App 组件挂载到 #root 之上,生成的 DOM 节点会替换 #root 标签
App.el = '#root'
// 创建 Vue 实例
new Vue(App)
这还要求你在 Web 入口 HTML 文件里手动写上 #root
的标签:
<div id="root"></div>
至于 Android 和 iOS 平台,只要指定了 el
属性即可,属性值就无所谓了,Weex 会默认将其挂载到容器根视图中(可由 Native 端配置)。
使用单文件组件
在配置好入口文件之后,就可以开始写组件了,推荐写单文件组件,也就是 .vue
文件。语法就不再重复介绍,官方文档中写得很详细,能支持 ES6+,甚至可以配置 TypeScript 、Sass 、Stylus 、PostCSS 、Jade 等语法。
需要注意的是,针对 Web 平台,依然使用 Webpack + vue-loader
的方式编译 .vue
文件,但是针对 Android 和 iOS 平台,你必须使用 Webpack + weex-loader
才可以。也就是说,针对 Web 和 Native 平台要分别生成两份不同的 js bundle,具体的配置参考 webpack.config.js。
只使用 Vue Runtime 的功能
Weex 已经将 Vue Runtime 的代码整合进了 SDK 中,Vue 中支持的语法特性也能用在 Weex 中。注意,是 Vue Runtime (运行时构建)。如果你下载过 Vue 2.0 对外发布的版本,应该能发现除了区分产品版和开发版,既区分 “Standalone” 版本和 “Runtime-only” 版本,具体的差异可以看官方安装指南(其实有些名词不太好翻译,看英文原版文档或许能理解得更准确一些)。
简单来说,Vue 在 Weex 中使用的是“预编译”模式,只保留了运行时,不支持实时编译模板。简单来说,就是不支持下边几个特性:
- 定义组件时不支持使用
template
属性。 - 不支持使用
x-templates
。 - 不支持使用
Vue.compile
。
如何做到跨平台?
写代码的过程和写其他 Vue 2.0 项目是一样的,没什么可说的。但是既然说了是写原生应用,就要注意跨平台的问题,虽然 Weex 抹平了很多差异,但是平台差异是客观存在的。Web 和 Android 和 iOS 毕竟都不相同,想写跨平台的应用,了解平台差异还是很有必要的。
了解平台差异
推荐阅读官方文档:
大概摘录一下是这样的:
-
Weex 环境中没有 DOM
- 不支持 DOM 操作,原生平台没有 DOM 概念。
- 并不支持 Web 中所有的事件类型,详情请参考《通用事件》。
- 不区分事件的捕获阶段和冒泡阶段,相当于 DOM 0 级事件。
-
Weex 环境中没有 BOM
- 没有 window 、screen 对象,可以通过
WXEnvironment
获取设备环境信息。 - 没有 document 对象,没有选择器方法。
- 没有 history 、location 、navigator 对象,有 navigator 模块。
- 没有 window 、screen 对象,可以通过
-
能够调用移动设备原生 API
- 可以通过模块调用设备原生 API,如 clipboard 、 navigator 、storage 等。
使用通用组件
为了保证三端可用,不能使用浏览器提供的标签,只能用 Weex 提供的标签(组件)。如果你写了 <figure>
或者 <menu>
这类组件,在 Web 端可以看到效果,但是在客户端上渲染效果是不确定的。而且,客户端上没有 SEO 和语义化的需求,HTML5 中的大多数标签都可以通过别名实现(参考 weex-component-alias)。
具体组件的使用方法参考官方文档。
使用通用样式
CSS 的属性特别多,写法也特别多,能力很强大,也有很多坑。一方面新标准在不断的提出,像 CSS Grid 和 Houdini 这些概念也逐渐受到关注;另一方面旧标准是很难再废除的,新旧语法总能摩擦出各种奇葩的行为,CSS 也是容易滋生“奇技淫巧”的地方,也有各种关于“最佳实践”的话题,很多人乐于此道。浏览器内部为了处理这些边界情况肯定用了大量“特殊技巧”。
然而在实际使用中,绝大多数的网页只用了其中很少一部分属性(参考 Global CSS property usage)。Weex 是由 Native 平台解析的样式,Android 和 iOS 本身并不支持 CSS ,所有解析都是原生渲染器实时计算的,所以必然要再性能和可用性之间做平衡。既然不能支持、也不打算支持所有 CSS 特性,那就必然要分清主次,优先支持常用样式。
Weex 对 CSS 样式的支持情况,可以参考这篇文档。简单概括下边几点:
- 支持基本的盒模型。
- 支持
position
定位布局。 - 支持使用
flexbox
布局。 -
使用限制
- 只支持单个类名选择器,不支持关系选择器,也不支持属性选择器。
- 默认是组件级别的作用域,没有全局样式。
- 不支持样式继承(因为有作用域隔离)。
- 考虑到样式的数据绑定,样式属性暂不支持简写。