自打出生的那一天起,WEEX就免不了被拿來同React Native「一決高下」的命運。React Native宣稱「Learn Once, Write Anywhere」,而WEEX宣稱「Write Once, Run Everywhere」。在我看來,並無誰更好,只有誰更合適。下面我將圍繞WEEX入門進行講解。 (若是你尚不瞭解React Native,並想簡單入門,能夠閱讀【整理】ReactNative快速入門筆記)javascript
什麼都不說,先給你感覺下weex的效果。如下就是我使用weex,4*8h(不連續)作出來的demo,其中還包括素材收集,踩坑總結等時間。css
此處是github源碼地址: github.com/zwwill/yanx… 感謝【Star】【Fock】支持隨便搞html
不得不說,使用Weex開發App對於咱們純前端人員來講,是件***很爽***的事情,只要你熟悉了他的語法,基本能夠作到一週上手寫app。極其適合交互要求不高,時間緊迫,人手不足的同構開發需求。前端
可是,固然有可是,若是你想寫出一個完美的app,你就須要在性能優化上下很大的功夫,包括動畫的優化,過場的優化,圖片的優化,細節的打磨等等,在這就是你須要掌握或者「能寫」一些原生的代碼,否則有些功能你是 實現不了的,好比status bar的屬性更改,開場動畫的製做,內存的回收,webview的監聽等等。vue
下面咱們具體講講入門知識html5
Weex 提供了多端一致的技術方案。java
在同構這條路上,WEEX比ReactNative作得更完全,他「幾乎」作到了,「你來使用vue寫一個webapp,我順便給你編譯成了ios和android的原生app」node
至於爲何要造這個輪子,官方給瞭如下說法android
一、今天在技術社區有大量的 web 開發者,Weex 能夠賦能更多的 web 開發者構建高性能和高體驗的移動應用。 二、Web 開發自己具備很是強的高效率和靈活性,這和 Weex 想解決的移動端動態性問題不謀而合。 三、Web 標準和開發體驗是不少頂尖而優秀的科技公司共同討論和建設的結果,自己的設計和理念都有極高的 四、品質保障,同時 Weex 也但願能夠藉此機會努力爲標準貢獻一點本身的微薄之力。 五、Web 是一種標準化的技術,標準自己就是一種力量,基於標準、尊重標準、貼近標準都意味着擁有更多的可能性。 六、Web 今天的生態和社區是很是繁榮的,有不少成熟的工具、庫、工程體系、最佳實踐可使用、引入和借鑑。webpack
在我看來,WEEX實際上是alibaba團隊提升生產效率的產物,在淘寶這類要求多端統一迭代快速的部門,三端約定一種便於統一的規範,在加上時間的發酵,漸漸的就有了此類腳手架的雛形,同時在臉書ReactNative開源帶來的極大轟動後,本身也坐不住了吧^_^
好了,閒話就說到這,下面就來讓咱們解剖一下WEEX的優劣良莠。
入門Weex前須要瞭解如下知識,這樣能幫助你更快的掌握 Node:Node.js 教程 Vue:《Vue.js官方教程》 ES6:《ECMAScript 6 入門》 再者就是ios和android開發語法的入門和編輯器的使用,固然
IOS : MacOS
, 黑蘋果
Android :MacOS
, Linux
, Windows
你能夠參考官方文檔安裝必須的依賴環境weex.apache.org/cn/guide/se…, 也能夠直接安裝如下環境
下載必須的插件: a) JDK1.8+ b) Show Package Details c) Android SDK Build Tools d) Android Support Repository
配置基礎環境: a) ANDROID_HOME (如運行是遇到問題可參考此文www.jianshu.com/p/a77396301…) b) JAVA_HOME
官方文檔上的入門Hello world是web端的,緊接着介紹瞭如何集成 Weex 到已有應用
可是,身爲一個web前端開發者,若是你不懂原生語音的話,介紹這些並不能起到很好的引導做用,由於web前端開發者都有***一統前端界***的野心(Web+Android+IOS),「寄人籬下」只能是暫時的。
因此快速建立並運行一個純Weex App纔是有意義的事兒。
若是你在官方教程裏沒有找到建立工程的教程,能夠閱讀此文《WEEX快速建立工程 Hello World》
Weex在迭代的過程當中選擇了於Vue2.0握手,由於該版本的Vue加入了 Virtual-DOM 和預編譯器的設計,使得該框架在運行時可以脫離 HTML 和 CSS 解析,只依賴 JavaScript,如此,Vue在和WEEX合做後,便得到了使用JS預編譯原生的組件UI的能力。
同React Native同樣,有人也將WEEX叫作Vue Native。
若是你對Vue還不瞭解,能夠先學習【預科】部分推薦的《Vue.js官方教程》。
那麼接下來咱們講講,Vue在WEEX中的不一樣
雖然說WEEX使用vue語言寫的,但畢竟是須要在不一樣平臺間運行的,雖然大部分語法都有支持,可是依然有部分語法是不一樣的
目前 Weex 支持了基本的容器 (div)、文本 (text)、圖片 (image)、視頻 (video) 等組件,注意是組件,而不是標籤,雖然使用起來跟html標籤很像,至於其餘標籤基本可使用以上組件組合而成。
由於Weex解析vue獲得的並非dom,而是原生布局樹
並不支持 Web 中全部的事件類型,詳情請參考《通用事件》
在 Weex 中可以調用移動設備原生 API,使用方法是經過註冊、調用模塊來實現。其中有一些模塊是 Weex 內置的,如 clipboard 、 navigator 、storage 等。 《clipboard 剪切板》 《navigator 導航控制》 《storage 本地存儲 》 爲了保持框架的通用性,Weex 內置的原生模塊有限,不過 Weex 提供了橫向擴展的能力,能夠擴展原生模塊,具體的擴展方法請參考《iOS 擴展》 和《Android 擴展》。
Weex 中的樣式是由原生渲染器解析的,出於性能和功能複雜度的考慮,Weex 對 CSS 的特性作了一些取捨 一、Weex 中只支持單個類名選擇器,不支持關係選擇器,也不支持屬性選擇器。 二、組件級別的做用域,爲了保持web和 Native 的一致性,須要<style scoped>
寫法 三、支持了基本的盒模型和 flexbox 佈局,詳情可參考Weex 通用樣式文檔。可是須要注意的是,
display: none;
舉個栗子,如下是嚴選App Demo首頁的簡化代碼
<template>
<div class="wrapper">
<text class="iconfont"></text>
<home-header></home-header>
<scroller class="main-list" offset-accuracy="300px">
<refresher></refresher>
<div class="cell-button" @click="jumpWeb('https://m.you.163.com')">
<yx-slider :imageList="YXBanners" ></yx-slider>
</div>
<div class="cell-button">
<block-1 :title="block1.title" :items="block1.items"></block-1>
</div>
</scroller>
</div>
</template>
<style scoped>
.iconfont { font-family:iconfont; }
.main-list{ position: fixed; top: 168px; bottom: 90px; left: 0; right: 0; }
</style>
<script>
var navigator = weex.requireModule('navigator');
import util from '../../src/assets/util';
import Header from '../components/Header.vue';
import refresher from '../components/refresh.vue';
import YXSlider from '../components/YXSlider.vue';
import Block1 from '../components/Block1.vue';
export default {
components: {
'home-header': Header,
'refresher': refresher,
'yx-slider': YXSlider,
'block-1': Block1
},
data () {
return {
YXBanners: [
{ title: '', src: 'http://doc.zwwill.com/yanxuan/imgs/banner-1.jpg'},
{ title: '', src: 'http://doc.zwwill.com/yanxuan/imgs/banner-2.jpg'},
{ title: '', src: 'http://doc.zwwill.com/yanxuan/imgs/banner-3.jpg'}
]
}
},
methods: {
jumpWeb (_url) {
const url = this.$getConfig().bundleUrl;
navigator.push({
url: util.setBundleUrl(url, 'page/web.js?weburl='+_url) ,
animated: "true"
});
}
}
}
</script>
複製代碼
若是以上代碼脫離工程單獨出現,基本上是沒法得知他是weex工程。此處可切實感覺到weex的web開發體驗
<template>
<div>
<text v-for="(v, i) in list" class=「text」>{{v}}</text>
<image style="" src=「"></image> <video class="video" :src="src" autoplay controls @start="onstart" @pause="onpause" @finish="onfinish" @fail="onfail"></video> </div> </template> 複製代碼
weex工程中經常使用的標籤有<div/>
,<text/>
,<image/>
,<video/>
(組件另算),由此四種標籤基本能夠知足絕大多數場景的需求,雖然說此標籤同web工程下的標籤用法一致,但此處的標籤已再也不是咱們前端口中常提的html標籤,並且名不副實的weex標籤,確切講是weex組件。
經過weex-loader、vue-loader、weex-vue-render的解析最終轉換輸出的即是實際的組件,有此設計只是爲了完成**「web開發體驗」**的目標。可是咱們身爲上層的開發人員要清楚本身天天「把玩」的究竟是個什麼「鬼」。
其實用閹割版來形容 weex 的 css 支持度並不合適,但若是從「web開發體驗」的角度來衡量,那麼這個形容詞也是能夠理解的。(此處對weex寄有厚望^_^)
weex 中的全部 css 屬性值的單位均爲 px
,也可省略不寫,系統會默認爲 px
單位。
Weex 中只支持單個類名選擇器,不支持關係選擇器,也不支持屬性選擇器。
/* 支持單個類名選擇器 */
.one-class {
font-size: 36px;
}
/* 不支持關係選擇器 */
.parent > .child {
padding-top: 10px;
}
/* 不支持屬性選擇器,不支持 v-cloak指令 */
[v-cloak] {
color: #FF6600;
}
複製代碼
這個只是對樣式定義的限制,不影響樣式類名的使用,在標籤中能夠添加多個樣式類名,如:
<template>
<div class="one two three"><div>
</template>
複製代碼
weex支持css基本的盒模型結構,但須要注意的是
box-sizing
屬性值默認爲 border-box
margin
,padding
,border
等屬性暫不支持合併簡寫weex中對flexbox佈局支持度很高,但依然有部分屬性並不支持,如 align-items:baseline;
、align-content:space-around;
、align-self:wrap_reverse;
等。
具體weex對flexbox的支持和佈局算法,可經過此文進行了解由FlexBox算法強力驅動的Weex佈局引擎,此處便再也不贅述。
在 weex 的 ios 和 android 端,並不支持 display
屬性。
所以,不能使用 display:none;
來控制元素的顯隱性,所以vue語法中的 v-show
條件渲染是不生效的。
咱們可使用 v-if
代替,或者用 opacity:0;
來模擬。
須要注意的是,ios和android端並不能使用 opacity:0;
來徹底模擬 visibility: hidden;
,由於,當opacity的只小於等於0.01時,native控件便會消失,佔位空間還在,但用戶沒法進行交互操做,點擊時會發生點透效果。
Weex支持css3屬性,雖然支持並不夠,但相較RN的「不能用」已是強大不少了。
如下幾種屬性咱們在開發前須要知道她的支持度
animation
實現動畫交互因爲使用了加強版的webpak打包工具weexpack,支持第三方框架也是件天然而然的事情。
經常使用的有 vuex
、vue-router
等,可根據項目實際狀況引入須要的第三方工具庫
npm 包管理是前端開發朋友們再熟悉不過的包管理方式了。這也是爲何ReactNative和Weex都選擇這種管理方式的緣由。
如下是本工程的 package.json 文件,這裏就不作講解了,不熟悉的朋友點這裏->NPM 使用介紹
{
"name": "yanxuan-weex",
"version": "1.0.0",
"description": "a weex project",
"main": "index.js",
"scripts": {
"build": "webpack",
"build_plugin": "webpack --config ./tools/webpack.config.plugin.js --color",
"dev": "weex-builder src dist -w",
"serve": "webpack-dev-server --config webpack.dev.js -p --open"
},
"keywords": ["weex"],
"author": "zwwill",
"license": "MIT",
"dependencies": {
"vue": "^2.4.2",
"vue-router": "^2.7.0",
"vuex": "^2.1.1",
"vuex-router-sync": "^4.3.0",
"weex-html5": "^0.4.1",
"weex-vue-render": "^0.11.2"
},
"devDependencies": {
"babel-core": "^6.21.0",
"babel-loader": "^6.2.4",
"babel-plugin-add-module-exports": "^0.2.1",
"babel-plugin-transform-runtime": "^6.9.0",
"babel-preset-es2015": "^6.9.0",
"babel-runtime": "^6.9.2",
"css-loader": "^0.26.1",
"history": "^4.7.2",
"quick-local-ip": "^1.0.7",
"vue-loader": "^13.0.4",
"vue-template-compiler": "^2.4.2",
"webpack": "^2.7.0",
"webpack-dev-server": "^2.4.2",
"weex-builder": "^0.2.7",
"weex-loader": "^0.4.5",
"weex-router": "0.0.1"
}
}
複製代碼
Weex 容器默認的顯示寬度 (viewport) 是 750px,頁面中的全部組件都會以 750px 做爲滿屏寬度。
這很像移動設備的邏輯像,好比iPhone 6的物理像素寬爲750,邏輯像素
Type | iPhone 3G | iPhone 4 | iPhone 6 | iPhone 6Plus |
---|---|---|---|---|
物理像素 | 320x480 | 640x960 | 750x1134 | 1080x1920 |
邏輯像素 | 320x480 | 320x480 | 375x667 | 414x736 |
像素比 | @1x | @2x | @2x | @3x |
類比在Weex中,若是全部的顯示寬度都是用默認值750,那麼顯示出來的實際像素信息爲
Type | iPhone 3G | iPhone 4 | iPhone 6 | iPhone 6Plus |
---|---|---|---|---|
物理像素 | 320x480 | 640x960 | 750x1134 | 1080x1920 |
顯示像素 | 750x1125 | 750x1125 | 750x1134 | 750x1333 |
像素比 | @0.427x | @0.85x | @1x | @1.44x |
因此咱們在使用weex作UI適配時就沒有所謂的@2x圖和@3x圖,全部的尺寸都是Weex幫咱們根據750做爲基數寬作的縮放。
固然,Weex 提供了改變此顯示寬度的API,setViewport
,經過此方法能夠改變頁面的顯示寬度,能夠實現每一個頁面根據本身的需求改變基數邏輯尺寸
所以對於一些固定的icon,不建議使用普通的靜態圖片或者雪碧圖,這裏建議使用矢量的字體圖片,有如下優勢:
Weex的調試方式有多種,若是說RN的調試模式是解放了原生開發的調試,那麼weex的調試方式能夠說是賦予了web模式調試原生應用的能力。
此方法多用於解決bug,檢測控件的佈局問題
# 調試單個頁面
$ weex debug your_weex.vue
# 調試整個工程
$ weex debug your/path -e App.vue
複製代碼
執行調試命令後,會將指定的文件打包成 JSBundle,並啓動一個 weex Devtool 服務(http://localhost:8088可訪問,以下圖),同時將 JSBundle 文件傳遞至該服務跟路徑下的weex文件夾內(http://localhost:8088/weex/App.js,實際是下圖右邊二維碼的的內容)。
使用Weex Playground App掃下左二維碼進入調試模,見下圖
再次掃碼右方二維碼,點擊【inspector】便可進入調試模式。
每個控件都是相同的數據結構
<view class="WXText" frame="{{0,0},{414,736}}" hidden="NO" alpha="1" opaque="YES"></view>
複製代碼
此方法多用於開發調試,試試觀察結果
$ weex your_weex.vue
複製代碼
若是出現access權限報錯,使用管理員指令
$ sudo weex your_weex.vue
複製代碼
此時本地同時啓動一個watch的服務器用於檢查代碼變動,自動從新構建JSBundle,視覺同步刷新。
上圖看到的效果即爲H5頁面的效果,咱們通常在整個單頁編寫完成後在使用 Weex Playground App 掃碼查看真機效果,或者你也能夠在編寫的同時使用真機觀察代碼的運行效果,每次從新構建包到重繪的速度仍是很快的。
但前提是你要保證,你的手機和電腦的連在同一個局域網下,而且使用IP訪問。
熟悉RN的人都知道,RN的發佈實際上就是發佈一個JSBundle,Weex也是這樣,但不一樣的是,Weex將工程進行分包,發佈多個JSBundle。由於weex是單頁獨立開發的,每一個頁面都將經過weex打包器將vue/we頁面打包成一個單獨的JSBundle,這樣的好處在於減小單個bundle包的大小,使其變的足夠小巧輕量,提升增量更新的效率。
# 僅打包
$ npm run build
# 打包+構建
$ weex build ios
# 打包+構建+安裝執行
$ weex run ios
複製代碼
以上三種均會觸發weex對工程進行打包。 在咱們執行了以上打包命令後,全部的工程文件將被單獨打成一個獨立的JSBundle,以下:
打包後的JSBundle有兩種格式# 由.vue文件打包出來的包格式(簡寫),使用vue2.0語法編寫
// { "framework": "Vue"}
/******/ (function(modules) {
.......
/******/ })
複製代碼
# 由.we文件打包出來的包格式(簡寫),使用weex語法編寫
// { "framework": "Weex" }
/******/ (function(modules) {
.......
/******/ })
複製代碼
不一樣的頭部是要告訴使用什麼語法解析此JSBundle。
至此,咱們準備「熱更新的包」就已經準備完畢了,接下就是發包執行了。
打包後的 JSBundle 通常發佈到發包服務器上,客戶端從服務器更新包後便可在下次啓動執行新的版本,而無需從新下載 app,由於運行依賴的 WeexSDK 已經存在於客戶端了,除非新包依賴於新的 SDK,這也是熱更新的基本原理。
【WeexSDK】包括
- 【JS Framework】JSBundle 的執行環境
- 【JS-Native Bridge】中間件或者叫通信橋樑,也叫【Weex Runtime】
- 【Native Render Engine】解析 js 端發出的指令作原生控件佈局渲染
Weex 的 iOS 和 Android 客戶端的【JSFramework】中都會運行一個 JavaScript 引擎,來執行 JS bundle,同時向各端的渲染層發送規範化的指令,調度客戶端的渲染和其它各類能力。iOS 下選擇了 JavaScriptCore 內核,而在 Android 下選擇了 UC 提供的 v8 內核(RN兩端都是JavaScriptCore 內核)。
JSBundle被push到客戶端後就會在JSFramework中執行,最終輸出三端可讀性的VNode節點,數據結構簡化以下:
{
tag: 'div',
data: {
staticStyle: { justifyContent: 'center' }
},
children: [{
tag: 'text',
data: {
staticClass: 'txt'
},
context: {
$options: {
style: {
freestyle: {
textAlign: 'center',
fontSize: 200
}
}
}
},
children: [{
tag: '',
text: '文字'
}]
}]
}
複製代碼
有了統一的VNode節點,各端便可根據本身的方法解析渲染原生UI了,以前的全部操做都是一致的,包括文件格式、打包編譯過程、模板指令、組件的生命週期、數據綁定等。
然而因爲目標執行環境不一樣(瀏覽器和 Weex 容器),在渲染真實原生UI的時候調用的接口也不一樣。
此過程發生在【Weex SDK】的【Weex Runtime】中。
最總【Weex Runtime】發起渲染指令callNative({...})
有RenderEngine完成渲染
官方配圖:
擴充配圖:
目前支持單頁使用或整個App使用Weex開發(還不完善,須要開發Router和生命週期管理)。
本文先行的嚴選demo即是使用第二種全屏模式,使用Weex開發整個App,期間觸碰到Weex的在此模式下諸多不足,如StatusBar控制、Tab切換、開場動畫自定義、3DTouch、 Widget等等原生的特點功能沒有現成的API,須要咱們本身擴展,甚至擴展不了。所以並不能徹底「滅掉」原生。
因此,目前在阿里內部使用較多的是此模式中的單頁模式,這也是爲何官方文檔在介紹原理後就直接奔入集成到原生應用的主題上去了。
把Weex看成一個iOS/Android組件來使用,類比ImageView。這類需求遍及手淘主鏈路,如首頁、主搜結果、交易組件化等,這類Native頁面主體已經很穩定,可是局部動態化需求旺盛致使頻繁發版,解決這類問題也是Weex的重點。
在H5種使用Weex,類比WVC。一些較複雜或特殊的H5頁面短時間內沒法徹底轉爲Weex全頁模式(或RN),好比互動類頁面、一些複雜頻道頁等。這個痛點的解決辦法是:在現有的H5頁面上作微調,引入Native解決長列表內存暴增、滾動不流暢、動畫/手勢體驗差等問題。
另外,WVC將會融入到Weex中,成爲Weex的H5 Components模式。
因爲Weex沒有封裝Tab的組件,所以筆者使用了不少方法來實現Tab切換的功能。
一、vue-router:router思想方便管理,可是每次切換都是新的實例,沒有tab模式 二、opacity、visablity:此處須要注意,Weex的渲染機制和web是有區別的,對夫層設置opacity或者visiablity隱藏是沒法同時隱藏定位爲position:fixed;
的子元素。 三、position、transform:改變tab層的位置,此方法在定位爲position:fixed;
的子元素上依然無效。
Weex中全部的靜態資源基本都是網絡資源,包括圖片、字體圖片等,因此使用iconfont圖標是再合適不過的了。
此demo中全部的icon均使用的iconfont。
此處強烈推薦一個站點www.iconfont.cn。
在此平臺你能夠找到幾乎全部你須要的icon,你也能夠上傳本身的icon到本身建立的項目中。同時該系統還提供生成ttf、woff資源,而且作了cdn加速和gzip壓縮,是否是跟weex很配呢?
不過也有風險,就是,若是哪天阿里不在維護並回收該平臺的資源了,你的app可能就會變成這樣,全是方框,或者padding掉你H5的頁面
固然,這種及狀況出現的概率很小,若是你是一個大公司,你手上有更好的資源急速方案,那就本身保存吧。
UIWebView是咱們開發App經常使用的一個控件,不過Weex幫咱們封裝好的API明顯時不夠用的,目前只有pagestart
、pagefinish
、error
,並無封裝像RN那樣的onShouldStartLoadWithRequest
攔截地址請求的API,在我看來,這有些不合理,並不清楚輪子的製造者是什麼意圖。
性能是一個大課題,在此就不作展開了,只稍微說起一些咱們開發須要注意的幾點
腳本語言天生自帶「熱更新」,Weex針對RN的熱更新策略作了優化,將WeexSDK事先綁到了客戶端上,而且對JSBundle進行分包增量更新,大大提升了熱更新的效率。
但優勢也是缺點,若是新包依賴於心的SDK,此狀況下,咱們須要發佈還有新SDK的app到應用市場,用戶也須從市場更新此app。不夠隨着WeexSDK版本的穩定後,相信此策略的優點就會凸顯出來。
Weex是一種輕量級、可擴展、高性能框架。集成也很方便,能夠直接在HTML5頁面嵌入,也可嵌在原生UI中。因爲和ReactNative同樣,都會調用Native端的原生控件,因此在性能上比Hybrid高出一個層次。
雖然說這是一個大膽的實踐,但對於大前端社區的統一有着推進做用,顯然阿里在這一方面已經邁出了第一步。基本解決了三端同等需求致使資源浪費的痛點。
但後期可能會出現這種現象,開發一個三端的App會從原來的我的變成四我的,多出來的那一我的負責開發Weex單頁。
意思就是,三端統一的不夠完全,但就目前的環境下,這一句是最優方案了,倒是提升了開發效率。大前端未來將如何一統三國咱們且行且觀望吧。
對於一些交互視覺統一且沒有很大的性能需求的遊戲,Weex仍是能夠勝任的。
近期筆者將嘗試發佈一款純Weex構建的益智小遊戲,敬請期待。
朋友們能夠用這個demo體驗下Weex 版掃雷遊戲開發
雖說大一統事件百利的事,但並不是無一害。
對於一些有差別化完美體驗追求的項目就只能收斂或者放棄了。
對於三端同時上線,一端存在bug的狀況,Weex並不能保證作到牽一髮而不動全身。
好比安卓的波紋按鈕、3DTouch、 Widget、iWatch版本等,目前這些功能仍是沒有的,不知道之後Weex是否將其加入到官方文檔中。
以上均爲我的看法,不表明官方。若有不當之處還望指正。
[ 1 ] Weex官方文檔 - weex.apache.org/cn/referenc… [ 2 ] 場景研讀 - Native 性能穩定性極致優化 - https://yq.aliyun.com/articles/69005 [ 3 ] 門柳 - 詳解 Weex JS Framework 的編譯過程 - https://yq.aliyun.com/articles/59935?spm=5176.8067842.tagmain.66.1QA1fL [ 4 ] 阿里百川 - 深度揭祕阿里移動端高性能動態化方案Weex - https://segmentfault.com/a/1190000005031818 [ 5 ] 一縷殤流化隱半邊冰霜 - Weex 是如何在 iOS 客戶端上跑起來的 - http://www.jianshu.com/p/41cde2c62b81