在 Weex 中使用 Vue.js
- 只含有运行时的构建版本
如果你熟悉 Vue.js,你应该知道 Vue.js 有两种构建版本: 运行时 + 编译器 与 只包含运行时。它们之间的区别在于编译器是否需要能够在运行时编译
template
选项。由于运行时构建版本比完整版本的构建版本轻约 30%(Vue 官方估算),为了更好的性能和更小的代码体积,Weex 集成的是运行时版本的 Vue。具体来说,差异如下:
- 定义组件时不支持
template
选项。 - 不支持使用
x-templates
。 - 不支持使用
Vue.compile
。
平台的差异
Vue.js 最初是为 Web 平台设计的。虽然可以基于Weex开发原生应用程序,但是仍然存在许多。
与 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 来实现它。
WARNING
vue-render-for-apache-weex
是三方插件,不由 Apache Weex 开发或维护。vue-render-for-apache-weex
是 Vue DSL 的 Web 渲染器, 它在 Web 上实现了 Weex 的内置组件和内置模块。详情请参阅这里。单文件组件
Vue 中的单文件组件(即
*.vue
文件)是一种特殊的文件格式,扩展名为.vue
。这个模板会在构建时编译到render
函数里。此外,所有的编辑器里都支持一个好的语法高亮插件。
在 Weex 中使用单个文件组件语法是一种很好的做法。
TIP
在 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 文件。{ entry: './path/to/entry.js' }
TIP
无论什么情况下都使用 javascript 文件作为入口文件。
使用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 “全局”配置只会影响 Weex 上的单一页面,配置不会在不同的 Weex 页面之间共享。
Vue 全局配置 是否支持 说明 Vue.config.silent 支持 - Vue.config.optionMergeStrategies 支持 - Vue.config.devtools 不支持 只在 Web 环境下支持 Vue.config.errorHandler 支持 - Vue.config.warnHandler 支持 - Vue.config.ignoredElements 支持 不推荐 Vue.config.keyCodes 不支持 在移动端无用 Vue.config.performance 不支持 与 devtools 一样 Vue.config.productionTip 支持 - 全局 API
Vue 全局 API 是否支持 说明 Vue.extend 支持 - Vue.nextTick 支持 - Vue.set 支持 - Vue.delete 支持 - Vue.directive 支持 - Vue.filter 支持 - Vue.component 支持 - Vue.use 支持 - Vue.mixin 支持 - Vue.version 支持 - Vue.compile 不支持 Weex 用的是 只包含运行时构建 选项
Vue 选项 是否支持 说明 data 支持 - props 支持 - propsData 支持 - computed 支持 - methods 支持 - watch 支持 - el 支持 在移动端 el
的值是无意义的template 不支持 Weex 用的是 只包含运行时构建 render 支持 不推荐 renderError 支持 - directives 支持 - filters 支持 - components 支持 - parent 支持 不推荐 mixins 支持 - extends 支持 - provide/inject 支持 不推荐 name 支持 - delimiters 支持 不推荐 functional 支持 - model 支持 - inheritAttrs 支持 - comments 不支持 - 生命周期钩子
Vue 组件的实例生命周期钩子将在特定的阶段发出,详情请参考 Vue 组件的生命周期图示。
Vue 生命周期钩子 是否支持 说明 beforeCreate 支持 - created 支持 - beforeMount 支持 - mounted 支持 和 Web 端不完全一样(下文有详解) beforeUpdate 支持 - updated 支持 - activated 不支持 不支持 <keep-alive>
deactivated 不支持 不支持 <keep-alive>
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 指令 是否支持 说明 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 支持 - - 定义组件时不支持