一、介紹
weex 是阿里出品的一個類似RN的框架,可以使用前端技術來開發移動應用,實現一份代碼支持H5,IOS和Android。最新版本的weex已默認將vue.js作為前端框架,而weex-hacknews則是weex官方出品的,首個使用 Weex 和 Vue 開發的 Hacker News 原生應用,在項目中使用了 Vuex 和 vue-router等官方組件 。因此這個應用可以作為weex-vue開發的典范,分析該項目代碼可以了解如何使用weex技術棧進行開發,實現同一份代碼在 iOS、Android、Web 下都能完整地工作。
1、下載
下載地址:https://github.com/weexteam/weex-hackernews
使用git clone項目或者直接下載zip包
2、安裝
安裝依賴:
npm install
編譯代碼:
npm run build
啟動 Web 服務
npm run serve
3、訪問
啟動服務后會監聽 1337 端口,訪問 http://127.0.0.1:1337/index.html 即可在瀏覽器中預覽頁面。
Chrome瀏覽器打開,F12進入開發者模式,啟用手機模擬,可以看到如下的效果
3.1 首頁
3.2 評論頁
更多的請自行安裝體驗。
二、代碼分析
將項目里的src導入到IDE里,可以看到代碼結構如下:
1、簡單說明
- components ——vue組件
- views ——視圖
- store ——Vuex
- mixins——擴展
- filters——vue.js 的filter
- App.vue 主UI界面
- entry.js 入口程序
- router.js ——vue-router
2、入口程序
上代碼:
該段代碼主要實現將各個組件和擴展導入,執行各種初始化工作,包括view、store、router等核心功能。暫且說這么多,后面再詳說。
3、vue-router
3.1 vue-router介紹
vue-router (https://github.com/vuejs/vue-router)是vue.js生態里重要的一環,是vue.js官方router ,它與Vue.js核心深度集成,使得使用Vue.js構建單頁面應用程序變得輕而易舉,包含如下特性:
- 嵌套路由/視圖映射
- 基於組件的路由器配置
- 路由參數,查詢,通配符
- 集成Vue.js頁面過渡效果
- 導航控制
- 歷史記錄:HTML5 history mode 或者 hash mode
我們從hackernews項目來看如何使用vue-router:
3.2 代碼分析
- 首先,需要import Router from 'vue-router',導入Router,然后Vue.use(Router)
- rourter是基於組件的路由配置,所以還需要導入各種View
-
最重要的,router需要返回Router的實例對象,關鍵是配置routes,如代碼所示,routes是一個json-array,里面的每一個json-object包含了path和component
- path支持字符串、通配符
- component返回一個View
- 看到這里大概就理解了router的原理,通過path去匹配,然后返回匹配的View,比如訪問主頁,route里配置的是redirect:'/top', 則會跳轉到top
- 項目里,top,new,show等都是StoriesView,只是類型不同,所以createStoriesView函數用於實例化不同類型的StoriesView
-
路由跳轉
-
跳轉:包含兩種方式,聲明和編程。
- <router-link :to="...">
-
router.push(...)
- router.push({ path: 'home' })
- router.push('home')
- router.push({ name: 'user', params: { userId: 123 }})
- 這里順帶提一下mixins,在入口代碼里有
// register global mixins.
Vue.mixin(mixins)
我們來看mixins
- Vue.mixin 混合是一種靈活的分布式復用 Vue 組件的方式,所有混合對象的選項將被混入該組件本身的選項,因此上述代碼實現為Vue組件增加jump方法,而jump的核心就是路由的跳轉。mixin后,可以在vue組件里使用jump方法。例如:<div class="link" @click="jump('/top')">
4、vuex
4.1 vuex介紹
Vuex 是一個專為 Vue.js 應用程序開發的狀態管理模式。它采用集中式存儲管理應用的所有組件的狀態,並以相應的規則保證狀態以一種可預測的方式發生變化。Vuex 也集成到 Vue 的官方調試工具 devtools extension,提供了諸如零配置的 time-travel 調試、狀態快照導入導出等高級調試功能。
狀態管理模式,開發中大型單頁應用時需要使用到,Vuex 借鑒了 Flux、Redux等成熟框架的思想開發而成。什么是"狀態管理模式"呢,我們來看官方的說明:
讓我們從一個簡單的 Vue 計數應用開始:
new Vue({
// state
data () {
return {
count: 0
}
},
// view
template: `
<div>{{ count }}</div>
`,
// actions
methods: {
increment () {
this.count++
}
}
})這個狀態自管理應用包含以下幾個部分:
- state,驅動應用的數據源;
- view,以聲明方式將state映射到視圖;
- actions,響應在view上的用戶輸入導致的狀態變化。
以下是一個表示"單向數據流"理念的極簡示意:
但是,當我們的應用遇到多個組件共享狀態時,單向數據流的簡潔性很容易被破壞:
- 多個視圖依賴於同一狀態。
- 來自不同視圖的行為需要變更同一狀態。
我們可以把組件的共享狀態抽取出來,以一個全局單例模式管理。這樣組件樹構成了一個巨大的"視圖",不管在樹的哪個位置,任何組件都能獲取狀態或者觸發行為。另外,通過定義和隔離狀態管理中的各種概念並強制遵守一定的規則,代碼將會變得更結構化且易維護。
Vuex包含State,Getters,Mutations ,Actions 和Modules 五大核心概念
- State : Vuex 使用 單一狀態樹,State是全局唯一數據源,可以理解為state為數據庫
- Getters可以認為是 store 的計算屬性,類似面向對象類里的get,set
- mutation:更改 Vuex 的 store 中的狀態的唯一方法是提交 mutation,每個 mutation 都有一個字符串的 事件類型 (type) 和 一個 回調函數 (handler)
-
Actions Action 類似於 mutation,不同在於:
- Action 提交的是 mutation,而不是直接變更狀態
- Action 可以包含任意異步操作
-
Modules : 使用單一狀態樹,導致應用的所有狀態集中到一個很大的對象。但是,當應用變得很大時,store 對象會變得臃腫不堪,Vuex 允許將 store 分割到模塊(module),每個模塊擁有自己的 state、mutation、action、getters
再來看下面的圖,Sate作為全局數據源,可以通過Action提交Mutation來改變State,State改變后自動Render到Vue的component,同時可以安裝vue.js提供的devtools查看mutation變更記錄。
-
4.2 代碼分析
4.2.1 導入Vuex
import Vuex from 'vuex'
4.2.2 定義Store,實例化Vuex.Store
4.2.3 定義state 和getters
state是全局唯一數據,定義了包含items,lists等需要展示到UI上的數據,getters可以理解為state的一個切片或者視圖函數,返回符合條件的特定數據。
4.2.4 mutation
回顧下前面說的,state的所有改變必須是通過mutation,我們來看實現:
每個mutation是一個函數,第一個參數是state,第二個是所謂的載荷,理解為變化的數據
mutation如何調用的呢?
- store.commit('mutation名稱')
-
store.commit('mutation名稱', {
參數: 參數值
})
Vuex 規定mutation必須是同步函數,不能為異步。
4.2.5 數據API
store最主要的功能就是獲取和存儲數據,如何獲取數據呢?
weex中通過stream提供網絡訪問功能,通過stream.fetch獲取,注意fetch.js里fetch函數返回的是一個Promise對象
關於Promise,不了解的可以查看(https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise)
store/fetch.js
4.2.6 action
進入store/action.js
看code:
export function FETCH_LIST_DATA({commit,dispatch,state},{type}){
commit('SET_ACTIVE_TYPE',{type})
return fetchIdsByType(type)
.then(ids=>commit('SET_LIST',{type,ids}))
.then(()=>dispatch('ENSURE_ACTIVE_ITEMS'))
}
- 定義了一個名為FETCH_LIST_DATA的action
- Action 函數接受一個與 store 實例具有相同方法和屬性的 context 對象,可以調用 context.commit 提交一個 mutation,或者通過 context.state 和 context.getters 來獲取 state 和 getters
- 為什么FETCH_LIST_DATA的第一個參數是{commit,dispatch,state}?因為使用了ES2015 的 參數解構 來簡化代碼
- commit('SET_ACTIVE_TYPE',{type}) 實現調用名為SET_ACTIVE_TYPE 的mutation,傳遞的參數為type,可以回過頭去看下mutation的定義
- fetchIdsByType返回的是Promise對象,后面兩個then理解為異步結果回調函數,則調用SET_LIST Mutation
5、filters過濾器
filter是vue.js的一個特性,
過濾器是一個通過輸入數據,能夠及時對數據進行處理並返回一個數據結果的簡單函數。Vue有很多很便利的過濾器,可以參考官方文檔, http://cn.vuejs.org/api/#過濾器 ,過濾器通常會使用管道標志 " | ", 比如:
{{ msg | capitalize }}
// 'abc' => 'ABC'
項目里的定義如下:
提供了獲取host,以及格式化時間的filter
看下如何使用過濾器
<text class="text-cellsmall-text">|{{comment.time|timeAgo}} ago</text>
第二部分見: