在 WeexSDK v0.10.0 以及后续的版本中,集成了 v2 版本的 Vue.js。Vue 是一套构建用户界面的渐进式框架,截止于作者发文, Weex 官方没有对 Vue3 提供支持。
内置构建版本
Vue.js 有两种构建版本: 运行时+编译器 与 只包含运行时。它们之间的区别在于编译器是否需要能够在运行时编译 template 选项。由于运行时构建版本比完整版本的构建版本轻约 30%(Vue 官方估算),为了更好的性能和更小的代码体积,Weex 集成的是运行时版本的 Vue。
具体来说,差异如下:
- 定义组件时不支持 template 选项。
- 不支持使用 x-templates。
- 不支持使用 Vue.compile。
平台的差异
Vue.js 最初是为 Web 平台设计的。虽然可以基于Weex开发原生应用程序,但是仍然存在许多Weex 与 Web 平台的差异。
与 Web 平台的主要差异是: 执行环境、DOM、样式和事件。
-
执行环境
Weex 主要用于编写多页的应用程序,每个页面都对应了原生开发中的 View 或者 Activity,并且保持自己的上下文。即使 Weex 的所有页面都使用的都是同一个 Javascript 引擎的实例(virtual machine),每个页面是执行环境也是互相隔离的(基于 Sandbox 技术)。使用 BroadcastChannel 可以实现跨页通信。
具体来讲,每个页面的 Vue 变量都是不同的实例,即使是写在 Vue 上的“全局”配置(Vue.config.xxx)也只会影响 Weex 上的单个页面。
在此基础上,一些 Vue 的 SPA (单页面应用)技术,如 Vuex 和 vue-router 也将单页内生效。更通俗地说,“页面”概念在 SPA 技术中是虚拟的,但在 Weex 上却是真实的。即便如此,Vuex 和 vue-router 都是独立的库,都有自己的概念和使用场景,仍然可以在 Weex 里使用 Vuex 和 vue-router。
-
DOM
因为在 Android 和 iOS 上没有 DOM(Document Object Model),如果需要手动操作和生成 DOM 元素的话可能会遇到一些兼容性问题。在使用现代前端框架的情况下,操作数据与组件而不是生成的元素是一个比较好的做法。
一些与 DOM 相关的特性,比如 v-html,vm.$el,template 选项,在不同的平台上可能无法获得相同的反应。准确来说,vm.$el属性类型在web环境下是HTMLElement,但是在移动端并没有这个类型。实际上,它是一个由 Weex 文档对象模型 定义的特殊数据结构。
-
样式
样式表和 CSS 规则是由 Weex js 框架和原生渲染引擎管理的。要实现完整的 CSS 对象模型(CSSOM:CSS Object Model)并支持所有的 CSS 规则是非常困难的,而且没有这个必要。出于性能考虑,Weex 目前只支持单个类选择器,并且只支持 CSS 规则的子集。
在 Weex 里, 每一个 Vue 组件的样式都是 scoped。 -
事件
目前在 Weex 里不支持事件冒泡和捕获,因此 Weex 原生组件不支持事件修饰符,例如.prevent,.capture,.stop,.self 。此外,按键修饰符以及系统修饰键 例如 .enter,.tab,.ctrl,.shift 在移动端基本没有意义,在 Weex 中也不支持。
Web 渲染器
如果想在网络上呈现页面,需要第三方插件 vue-render-for-apache-weex 来实现。
vue-render-for-apache-weex是 Vue DSL 的 Web 渲染器, 它在 Web 上实现了 Weex 的内置组件和内置模块。
单文件组件
Vue 中的单文件组件(即*.vue文件)是一种特殊的文件格式,扩展名为.vue。这个模板会在构建时编译到render函数里。
在 Weex 中使用单个文件组件语法是一种很好的做法。
在 Weex 中使用 Vue 的单个文件组件语法是一种最佳实践。
因为针对 Weex 的 Web 平台的编译工具并不一样,如果直接写的 render 函数,则绕过了 weex-loader 编译模板的过程,这样的话就需要自行处理平台差异的细节。
-
编译目标
因为平台的差异以及为了提高网络性能,* .vue文件需要用两种不同的方式来编译:
对于 Web 平台来说,可以用任何正式的方式来编译源文件,例如 使用 Webpack + vue-loader 或者 Browserify + vueify 来编译 * .vue文件。
对于安卓与 iOS 平台来说, 你需要使用 weex-loader 来编译*.vue文件。
不同的平台使用不同的bundles,可以充分利用平台原有的特性,减少构建时的兼容性代码。但是源代码仍然是一样的,唯一的区别是编译的方法。 -
使用weex-loader
weex-loader 是一个 webpack 的 loader,它能把*.vue文件转化为简单的javascript 模块用于安卓以及 iOS 平台。所有的特性和配置都是跟 vue-loader 一样的。
需要注意的是,如果 Webpack 的 entry 配置项是一个 *.vue 文件的话,仍需要传递一个额外的 entry 参数作为标记。
const webpackConfig = {
// Add the entry parameter for the .vue file
entry: './path/to/App.vue?entry=true'
/* ... */
use: {
loaders: [{
// matches the .vue file path which contains the entry parameter
test: /\.vue(\?^^]+)?$/,
loaders: ['weex-loader']
}]
}
}
如果用的是.js文件做入口文件,就不需要写那些额外的参数。 推荐 webpack 配置的入口文件使用 javascript 文件。无论什么情况下都使用 javascript 文件作为入口文件。
{
entry: './path/to/entry.js'
}
使用weex-loader单文件编译示例
- 执行npm init
- 修改package.json文件,添加:
"dependencies": {
"babel-loader": "^8.0.6",
"weex-loader": "^0.7.12",
"webpack": "^2.2.1"
},
"scripts": {
"build": "webpack --config webpack.config.js"
},
- 创建webpack.config.js,按照需要更改。
const webpack = require('webpack');
const path = require('path');
module.exports = {
entry: '<your-input-file>',
output: {
path: path.resolve(__dirname, './'),
filename: <your-output-file>
},
module: {
rules: [
{
test: /\.vue(\?[^?]+)?$/,
loaders: ['weex-loader']
},
{
test: /\.js$/,
loaders: ['babel-loader']
}
]
},
plugins: [
new webpack.BannerPlugin({
raw: true ,
banner: '// { "framework": "Vue" }\n'
})
]
}
- 执行npm run build。
使用weex compile编译
- 安装weex-cli:npm install weex-toolkit -g
- 执行weex compile [资源文件] [产物地址]命令
生命周期钩子
Vue 组件的实例生命周期钩子将在特定的阶段发出,详情参考 Vue 组件的生命周期图示。
Vue 全局配置 | 是否支持 | 说明 |
---|---|---|
beforeCreate | 支持 | - |
created | 支持 | - |
beforeMount | 支持 | - |
mounted | 支持 | 和 Web 端不完全一样(下文有详解) |
beforeUpdate | 支持 | - |
updated | 支持 | - |
activated | 不支持 | 不支持 |
deactivated | 不支持 | 不支持 |
beforeDestroy | 支持 | - |
destroyed | 支持 | - |
errorCaptured | 支持 | 在 Vue 2.5.0+, Weex SDK 0.18+ 中新增 |
- 关于 “mounted” 生命周期
和浏览不同的是,Weex 的渲染流程是异步的,而且渲染出来的结果都是原生系统中的 View,这些数据都无法被 javascript 直接获取到。因此在 Weex 上,Vue 的 mounted 生命周期在当前组件的 virtual-dom (Vue 里的 VNode) 构建完成后就会触发,此时相应的原生视图未必渲染完成。
实例属性
Vue实例属性 | 是否支持 | 说明 |
---|---|---|
vm.$data | 支持 | - |
vm.$props | 支持 | - |
vm.$el | 支持 | 移动端没有HTMLElement |
vm.$options | 支持 | - |
vm.$parent | 支持 | - |
vm.$root | 支持 | - |
vm.$children | 支持 | - |
vm.$slots | 支持 | - |
vm.$scopedSlots | 支持 | - |
vm.$refs | 支持 | - |
vm.$isServer | 支持 | 永远是false |
vm.$attrs | 支持 | - |
vm.$listeners | 支持 | - |
实例方法
Vue实例方法 | 是否支持 | 说明 |
---|---|---|
vm.$watch() | 支持 | - |
vm.$set() | 支持 | - |
vm.$delete() | 支持 | - |
vm.$on() | 支持 | - |
vm.$once() | 支持 | - |
vm.$off() | 支持 | - |
vm.$emit() | 支持 | - |
vm.$mount() | 不支持 | 不需要手动安装 Vue 实例 |
vm.$forceUpdate() | 支持 | - |
vm.$nextTick() | 支持 | - |
vm.$destroy() | 支持 | - |
模板指令
Vue 指令 | 是否支持 | 说明 |
---|---|---|
centered 文本居中 | right-aligned 文本居右 | |
v-text | 支持 | - |
v-html | 不支持 | Weex 中没有 HTML 解析器,这不是很好的实现 |
v-show | 不支持 | 不支持 display: none; |
v-if | 支持 | - |
v-else | 支持 | - |
v-else-if | 支持 | - |
v-for | 支持 | - |
v-on | 支持 | 不支持事件修饰符 |
v-bind | 支持 | - |
v-model | 支持 | - |
v-pre | 支持 | - |
v-cloak | 不支持 | 只支持单类名选择器 |
v-once | 支持 | - |
特殊属性
Vue特殊属性 | 是否支持 | 说明 |
---|---|---|
key | 支持 | - |
ref | 支持 | - |
slot | 支持 | - |
slot-scope | 支持 | 在 Vue 2.5.0+, Weex SDK 0.18+ 中新增 |
scope | 支持 | 不推荐 |
is | 支持 | - |
内置组件
Vue内置组件 | 是否支持 | 说明 |
---|---|---|
component | 支持 | - |
transition | 不支持 | 在移动端 enter 与 leave 的概念有点不同,并且 Weex 不支持display: none; |
transition-group | 不支持 | 跟 transition 一样 |
keep-alive | 不支持 | 移动端的原生组件不能被前端缓存 |
slot | 支持 | - |
注意:Weex不支持Vue.compile、template,因为Weex 用的是只包含运行时构建,也不支持comments。