Weex 初探
Weex 介紹
Weex 是阿里於 2016 年開源的一款開發框架,它的介紹是:
Weex 是一個使用 Web 開發體驗來開發高性能原生應用的框架。
它使用了 Web 技術來開發 Android、IOS 應用,從而達到更快的迭代速度,同時降低了開發原生應用的門檻,
達到生產力和性能共存。
Weex 項目結構
Weex 設計之初是為了和原有應用進行兼容開發,和 NativeScript 不同,它只需要在項目中添加 Weex 的 SDK 即可使用。
它的定位不是全部應用,目標是針對部分變動頻繁的應用。它是一種解耦的應用,每個頁面相對獨立,通過路由的方式對調用各頁面,
通過 API 的方式與設備進行交互。所以可以看到官網上 Weex 的結構圖:
使用 Weex 構建一個簡單的應用
Weex 做一個簡單一些的例子還是比較合適的。本文以仿開眼部分功能為例做一小應用。先看下效果圖:
項目搭建前准備工作
首先需要准備好 npm 環境、Android 環境,IOS 環境,由於在 mac 下直接安裝 xcode 就具備 IOS 環境了,且 npm 是前端必備開發環境的,就無需再安裝了。Android 環境的安裝可以直接安裝 Android Studio,一鍵配置好環境。
打開控制台,全局安裝 weex
npm i -g weex-toolkit weex weex-debugger
創建項目:
weex create weex-kaiyan
cd weex-kaiyan
weex platform add android
weex platform add ios
按照提示操作即可。安裝速度都不是很快,需要耐心等候。為了方便開發,我們采用 airbnb 的代碼規范,先在 devDependencies 安裝相關依賴(或者全局安裝eslint,用 eslint 的init 功能也可以):
"eslint": "^4.13.1",
"eslint-config-airbnb-base": "^12.1.0",
"eslint-friendly-formatter": "^3.0.0",
"eslint-import-resolver-webpack": "^0.8.3",
"eslint-loader": "^1.7.1",
"eslint-plugin-import": "^2.8.0",
"eslint-plugin-vue": "^4.0.0",
在 .eslintrc.js 中添加
extends: ['plugin:vue/recommended', 'airbnb-base'],
在 vscode 中啟用 lint 功能:
"eslint.validate": [
"javascript",
"javascriptreact",
"html",
"vue"
],
"eslint.options": {
"plugins": ["html"]
},
然后准備好要訪問的 api (https://github.com/kaikaixue/Eyepetizer/blob/master/app/src/main/java/com/xk/eyepetizer/api),這樣做完了准備工作,可以開始開發了。
目錄結構大概是這樣子:
├── README.md
├── android.config.json
├── configs
│ ├── config.js
│ ├── helper.js
│ ├── logo.png
│ ├── plugin.js
│ ├── utils.js
│ ├── vue-loader.conf.js
│ ├── webpack.common.conf.js
│ ├── webpack.dev.conf.js
│ ├── webpack.prod.conf.js
│ └── webpack.test.conf.js
├── ios.config.json
├── npm-shrinkwrap.json
├── package.json
├── platforms
│ ├── android
│ ├── ios
│ └── platforms.json
├── plugins
│ └── plugins.json
├── src
│ ├── api
│ │ └── index.js
│ ├── components
│ │ ├── card-list-scroller.vue
│ │ ├── card-video-no-author.vue
│ │ ├── card-video.vue
│ │ └── tab.vue
│ ├── entry.js
│ ├── index.vue
│ ├── mixin-common.js
│ ├── mixin-preload.js
│ ├── mixin-router.js
│ ├── router.js
│ └── views
│ ├── categories.vue
│ ├── categoryHome.vue
│ ├── home.vue
│ ├── rank.vue
│ └── videoDetail.vue
├── web
│ ├── assets
│ │ ├── preview.css
│ │ └── qrcode.js
│ ├── index.html
│ └── preview.html
└── webpack.config.js
其中 config 文件下是用於放 webpack 打包的配置, src 就是我們的代碼目錄,platform 里面放 native 代碼,
web 文件夾是我們的 web 的 html 模板。
項目配置
要實現三端開發,默認的 weex 項目模板是不行的,它的設計是為 Native 准備的,不考慮單頁應用的方式。
雖然不推薦三端同時開發(兼容三端效率會比較低),但為研究怎么實現我們還是做一下。先安裝單頁應用必備 vue-router
修改 entry.js
然后修改 src/entry.js ,添加手動掛載 vue 的代碼,假定我們 src 目錄下有個 router.js,
還有一個所有文件用的mixin,修改完成后的代碼如下:
import Vue from 'vue';
import weex from 'weex-vue-render';
import App from './index.vue';
import router from './router';
import mixin from './mixin-router';
weex.init(Vue);
Vue.mixin(mixin);
App.el = '#root';
App.router = router;
const app = new Vue(App);
export default app;
在 native 端這個 entry.js 是沒用的,native 端是直接使用由 weex 打包生成的 js 文件,
包括掛載都是框架做的,我們不需要處理,所以它只是給 web 使用的。
設置入口
然后設置主入口:build/webpack.common.conf.js中webEntry為固定值:
const webEntry = {
'index': helper.rootNode(config.entryFilePath)
};
同時注釋掉讀取文件內容並注入entry中
// if (extname === '.vue') {
// const entryFile = path.join(vueWebTemp, dir, path.basename(file, extname) + '.js');
// fs.outputFileSync(path.join(entryFile), getEntryFileContent(entryFile, fullpath));
// webEntry[name] = path.join(entryFile) + '?entry=true';
// }
添加代理
在 webpack 中添加代理,由於 web 端有跨域問題,我們在 configs/config.js 中添加
proxyTable: {
'/api': {
target: 'https://baobab.kaiyanapp.com/',
changeOrigin: true,
}
},
編寫代碼
公用模塊
現在開始像正常寫 vue 一樣開始碼代碼吧。要先注意的一點是 native 端不支持 vue-router 的特性,
需要使用 navigator 模塊進行 push 操作,所以我們需要單獨寫個模塊,通過 mixin 方式進行兼容 頁面跳轉,
參考 https://www.jianshu.com/p/497f1a9ff33f:
const isWeex = weex.config.env.platform.toLowerCase() !== 'web';
const nav = weex.requireModule('navigator');
export default {
methods: {
push(path, option = {}) {
if (isWeex) {
const toUrl = weex.config.bundleUrl.split('/').slice(0, -1).join('/') + '/' + path.replace(/^\//, '') + '.js';// 將a.js的絕對地址轉為b.js的絕對地址
nav.push({
url: toUrl,
animated: option.animated || 'true',
});
} else {
this.$router.push(path);// 使用vue-router
}
},
pop(option = {}) {
if (isWeex) {
nav.pop({
animated: option.animated || 'true',
});
} else {
window.history.back();
}
},
},
};
這樣我們在寫跳轉時候就可以寫成:
this.push('/videoDetail')
同時准備好你需要的 api 庫模塊(我用的 axios),以及其他公眾模塊,比如說 storage 。Weex 中的 Storage 模塊是為了兼容 web 版本,接口和 web 版本的 LocalStorage 比較類似,只是異步形式。為方便,我們可以將回調式轉為 Promise 式:
function callStorage(type) {
return function callMethod(...args) {
const storage = this.$storage;
return new Promise((resolve, reject) => {
const callback = (e) => {
if (e && e.result === 'success') {
resolve(e.data);
} else {
reject(e);
}
};
storage[type].call(storage, ...args, callback);
});
};
}
class Storage {
constructor() {
this.$storage = weex.requireModule('storage');
}
setItem = callStorage('setItem')
getItem = callStorage('getItem')
removeItem = callStorage('removeItem')
}
然后在 Mixin 中使用它即可。如果你有精力的話,可以設計一個基於 storage 的數據傳遞模塊。
開發頁面
開發頁面就和寫 vue 一樣啦,只是要注意一些點:
- Weex 支持的元素類型是有限的,用到哪種需要到官網手冊中去查詢
- 每個頁面是獨立,一定要記住這一點,因此 mixin 之類的公用庫,需要手動引入到頁面中
- css 選擇器只支持一級,比如 .classA 不支持 .classA .classB 這種類型,你需要為設置樣式的每個元素添加 className,需要防止變量沖突(web 端是單頁應用,可能會有問題)
Native 端配置
包括在開發階段,我們也是需要對 native 端進行效果驗證的。Weex 提供了一個簡單的命令:
weex run android
weex run ios
npm run dev
如果已經配置了 IOS 環境,直接運行命令就可以了。不過默認的主頁是 index.js,
可以在 android.config.json 和 ios.config.json 中分別配置 WeexBundle 選項即可。
需要注意的是,運行狀態下默認是打開本地文件的,而運行命令是不會放 views 文件夾目錄過去,
需要手動拷貝一下。安卓下面由於訪問本地文件的接口在 7.0 下有問題,
建議在 app_config.xml 中修改 launch_locally 為 false, 並指定好遠程地址。
調試沒問題后,我們按照 Android 和 IOS 各自的方案進行打包即可.
總結
由於自己對 Native 開發了解得不多,所以好多東西一知半解,而且 Weex 的包總能發現各種小問題,
需要強大的耐心去解決或者規避這些問題,只能祝使用的人好運吧。新出的 weex-ui 雖然已經開源好久了,
有時間可以嘗試下,不過由於核心模塊沒有開源,好多組件不能使用,先觀望一段時間,等有好的點子再試試。