[使用 Weex 和 Vue 開發原生應用] 4 使用 Weex 平臺的功能

系列文章的目錄在 ? 這裏html

除了 Vue 框架提供的功能覺得,Weex 平臺自己也提供了不少功能,這些功能比前端框架更底層一些,並且是跨框架通用的,在 VueRax 裏均可以用。本文的幾個例子愈來愈偏底層,最後一個例子還須要寫 java 代碼。前端

使用 Weex 的模塊

Weex 模塊的文檔vue

經過 weex.requireModule 便可引入 weex 的模塊。java

const modal = weex.requireModule('modal')

modal.toast({
  message: 'native toast'
})

Weex 的模塊究竟是什麼東西?

模塊的用法很簡單,像普通 js 模塊同樣調接口就好了,看起來挺像一個 npm 模塊的,可是在 Weex 模塊內部會調用原生接口,最終調用的都是原平生臺提供的功能。Weex 的模塊提供了使用原生功能的能力。android

例如 modal 模塊能夠彈出 toastalertconfirmprompt 等各類彈窗,這些彈窗都是原生彈窗,在 Android 和 iOS 下的風格和行爲是由各自的系統決定的。Weex 的模塊在 js 這一層只負責向原生環境裏傳遞數據,通知 native 去執行某些操做。ios

storagenavigatorclipboard 這種依賴平臺特性的功能,須要調用平臺原生接口才能實現,因此只能寫成模塊。git

模塊的同步和異步

通常來講,都是調用模塊的功能,並不會依賴模塊返回值的,可是像 dom 模塊中的 getComponentRect 接口是用來計算組件的寬高和位置的,必須得從原生端獲取值。可是在 Weex 最初設計的版本里,模塊都是異步返回值的,也就是說,只能經過回調函數的方式拿到真正的佈局信息(也能夠本身封裝成 Promise)。如今 Weex 已經支持了模塊的同步返回值,可是爲了保持原先版本中接口的行爲一致,getComponentRect 這個方法依然是異步的。github

const dom = weex.requireModule('dom')

const returns = dom.getComponentRect(this.$refs.box, option => {
  console.log(option) // { result: true, size: { ... } }
})

console.log(returns) // undefined

上邊的代碼中,會先執行 console.log(returns) 再執行 console.log(option),而且 getComponentRect 方法沒有返回值,因此 returns 的值是 undefined,option 中才是真正的原生端返回的佈局信息。web

擴展 Weex 的模塊

Weex 自己內置了不少模塊,出於通用性考慮,咱們只會把最基礎的模塊打包進 SDK。其餘個性化的模塊能夠本身來實現,或者從社區中找。Weex Market 將會是一個收集這些擴展模塊(組件、插件)的地方,結合 weex-pack 能夠實現方便的安裝和擴展。(目前來講,Weex Market 中仍是基於舊版 .we語法的模塊比較多,不適用於 Vue,在使用前要看準適用的框架)vue-router

具體的擴展 Weex 模塊的方法,參考:

獲取平臺環境數據

Weex 的運行環境有好幾種,在寫代碼的時候,有些狀況下須要獲取環境數據。Weex 提供了 weex.config 變量能夠獲取配置信息。

  • bundleUrl: 當前 js bundle 的 URL 地址。

  • env: 環境對象。

    • weexVersion: WeexSDK 的版本。

    • appName: 應用名字。

    • appVersion: 應用版本。

    • platform: 平臺信息,目前是 "iOS""Android""Web" 之一。

    • osVersion: 系統版本。

    • deviceModel: 設備型號 (僅限 iOS 和 Android)。

    • deviceWidth: 設備寬度。

    • deviceHeight: 設備高度。

此外其實還有一個全局的 WXEnvironment 變量,它和 weex.config.env 的屬性是同樣的。

下邊是一個獲取環境數據的二維碼(支持拷貝):

圖片描述

寫三端不一致的代碼

只針對 native 平臺註冊 Vuex

由於在瀏覽器環境中,Vuex 是會自動註冊的,只須要引入庫文件就好了,若是重複註冊,Vuex 會拋出警告的。(下邊這段代碼摘自 Vuex)

// auto install in dist mode
if (typeof window !== 'undefined' && window.Vue) {
  install(window.Vue)
}

可是在 native 環境中沒有 window 變量,就須要再手動調用 Vue.use(Vuex) 註冊 Vuex 插件,在註冊前判斷當前運行的平臺。

import Vue from 'vue'
import Vuex from 'vuex'

// Vuex is auto installed on the web
if (WXEnvironment.platform !== 'Web') {
  Vue.use(Vuex)
}

不一樣的連接跳轉行爲

若是你在不一樣端上運行了 weex-hackernews 裏的項目,會發如今瀏覽器上點擊文章連接是會新開一個頁籤的,可是在客戶端上點擊連接就不會新開視圖,而是在當前視圖裏跳轉。

圖片描述

這種不一樣的行爲體如今 story.vue 文件裏,這裏的跳轉連接並非直接使用的 Weex 裏的 <a> 標籤,而是自定義了一個 <external-link> 的組件,把 url 參數傳過去。

<external-link :url="story.url">
  <text>{{story.title}}</text>
  <text v-if="story.url">({{ story.url | host }})</text>
</external-link>

頁面跳轉邏輯是在 external-link.vue 裏組件實現的:

<template>
  <div @click="open">
    <slot></slot>
  </div>
</template>

<script>
  export default {
    props: ['url'],
    methods: {
      open () {
        const env = weex.config.env || WXEnvironment

        // open a new window (tab) on the web
        if (env.platform === 'Web') {
          window.open(this.url)
          return
        }

        // change router path on native (Android & iOS)
        this.jump(`/article/${this.url}`)
      }
    }
  }
</script>

該組件監聽了 click 事件,在點擊時會首先判斷當前運行的平臺,若是是 Web ,則使用 window.open 新開頁面,不然(在原平生臺中)就默認使用 vue-router 進行跳轉,這個「跳轉」其實只是更新了當前的視圖,其實還在同一個原生頁面內。

透傳原生事件

若是你看了 src/App.vue 中的代碼,會發現裏邊用了一個 androidback 的事件。它實現的效果是綁定了 Android 中的「返回」事件,點擊返回按鈕就會退回上一個視圖。

<template>
  <div @androidback="back">
    <router-view></router-view>
  </div>
</template>

<script>
  export default {
    methods: {
      back () {
        this.$router.back()
      }
    }
  }
</script>

這個事件並非 Vue.js 自己提供的,也不是 Web 標準裏的,在瀏覽器上確定不會給你提供一個以 android 開頭的事件名。在 vue-router 裏也不會加這樣的東西。甚至若是你去翻 Weex 的文檔,也找不到這個事件類型,它也不是 Weex 默認提供的。

想要實現 Android 特有的功能,就得在 Android 項目裏的代碼,在「前端」層面是解決不了這個問題的,要寫 java

在 Android 中派發原生事件

首先,在 Android 裏確定是能夠監聽到「返回」按鈕的點擊事件的,其實只要實現 Activity 裏的 onBackPressed 接口就能夠了,它會在當前視圖裏點擊返回按鈕時執行。在 weex-hackernews Andorid 項目裏的 MainActivity.java 中,就實現了 onBackPressed 接口:

public void onBackPressed() {
    Log.e("USER ACTION", "BACK");
    WXSDKManager.getInstance().fireEvent(mWXSDKInstance.getInstanceId(), "_root", "androidback");
}

在這個方法裏,經過 WXSDKManager.getInstance() 取到了當前頁面的實例,而後調用 fireEvent 接口給根視圖派發 androidback 事件,事件名是能夠自定義的。在 Weex Runtime 中會接收到這個事件,會傳遞給 Vue.js 框架,而且觸發最外層組件的 androidback 事件,最終會找到 back 方法並執行。(這裏說的 Weex Runtime 是前端代碼實現的,比 Vue.js 更底層一些)。

小結

除了 Vue.js 自己的特性之外,Weex 還提供了不少平臺化的特性,這些特性比前端框架更底層,也更通用一些。即便你用的不是 Vue.js 而是 Rax,或者是舊版的 .we 的語法,Weex 裏的這些特性也都是能夠用的。

雖然同一份代碼能夠運行在三端,可是 iOS 和 Android 和 Web 都有各自的優點和缺陷,若是你想實現一些平臺特有的功能,Weex 也是支持的。若是你想要體現平臺特有的優點,就得針對某個平臺寫一下原生代碼。在寫 iOS 或者 Android 代碼的時候,確定能確保在其餘平臺中不會執行到;可是在寫 js 代碼的時候,若是使用了只在 Web 上纔有的特性,就得注意一些,不要讓 iOS 和 Android 執行到這些代碼。

相關文章
相關標籤/搜索