Natsuha - 用Taro寫個天氣微信小程序

去年年末 o2 開源了 Taro,一直手癢癢沒去玩。考慮到 wx 的審覈制度,因此決定寫個工具類小程序。趕在 Taro 喜提第 2000 個 issues 之際,Natsuha 也終於上線了。源碼所有釋出(除涉及私鑰部分,GitHub有說明),文章後面會貼出一些仍需優化的點,歡迎你們一塊兒討論。

前言

Natsuha Weather 已開源,歡迎你們一塊兒折騰,給個 star 也是極好的~ GitHub Repocss

Scan the QR Code by WeChat

技術棧是 Taro + mobx + TypeScript,接口來自 Yahoo Weather API,固然設計也是參 (chao) 考 (xi) 的 Yahoo Weather. 接口有時會訪問失敗,尤爲是晚上,我也沒辦法啊。🤷html

功能

  • 下拉刷新
  • 華氏溫度、攝氏溫度切換
  • 分時展現一天的天氣預報
  • 展現將來10天的天氣預報
  • 展現當前風向、風速
  • 展現日出日落、月相等信息
  • 展現一天內的降水預報
  • 城市天氣檢索
  • 顯示檢索記錄

踩坑

小程序篇

雲開發解決 Bei An 問題

因爲衆所周知的緣由,wx 小程序沒法調用未 bei an 的接口,哪怕是在開發環境。因此咱們用雲開發雲函數來 「反代」 接口,下面經過一個例子說一下技術要點。前端

首先在根目錄的 project.config.json 文件裏添加 "cloudfunctionRoot": "functions/",而後在根目錄建立文件夾 functions. 並點擊右鍵建立一個新的雲函數,好比咱們叫 getRegionwebpack

雲函數開發

由於咱們的目標是經過雲函數請求一個未 bei an 的接口,因此爲了更方便的處理異步請求,咱們引入 request-promise 這個庫。git

經過硬盤打開進入到這個雲函數的文件夾,而後安裝依賴:github

yarn add request request-promise

接下來咱們在 index.js 中寫邏輯,直接上代碼。雲函數經過 event 對象來獲取前端傳過來的參數,而後經過 Promise 對象將結果返回。這個例子中咱們須要拿到regionweb

// 雲函數入口文件
const cloud = require('wx-server-sdk')
const rp = require('request-promise')

cloud.init()

exports.main = async (event, context) => {
  const region = event.region;
  const res = await rp({
    method: 'get',
    uri: `https://www.yahoo.com/news/_tdnews/api/resource/WeatherSearch;text=${region}`,
    json: true
  }).then((body) => {
    return {
      regionList: body
    }
  }).catch(err => {
    return err;
  })
  return res;
}

接下來是前端發請求了,注意這裏不能再用 Taro.request(), 而是雲函數獨有的 wx.cloud.callFunction(), 由於我如今的 Taro 版本還沒有實現 Taro.cloud.callFunction(),因此直接用 wx 打頭便可。json

首先封裝一下 wx.cloud.callFunction(),其實感受什麼卵用🤪:小程序

export const httpClient = (url: string, data: any) => new Promise((resolve, reject): void => {
  wx.cloud.callFunction({
    name: url,
    data,
  }).then(res => {
    resolve(res.result);
  }).catch(e => {
    reject(e)
  });
});

而後咱們在 store 裏面寫邏輯,這樣基本上就解決了數據請求的坑。api

public getRegion = (text: string) => {
    httpClient('getRegion', {
        region: encodeURI(text),
      })
      .then((res: any) => {
        runInAction(() => {
          if (res.regionList) {
            this.regionList = res.regionList;
          }
        });
      })
      .catch(() => {
        setToast(toastTxt.cityFail);
      });
  };

🔔題外話:由於當前版本還沒有實現 Taro.cloud.callFunction(),因此 lint 會報錯,雖然不影響使用,你們有什麼好的方法,能夠說一下。

地理信息受權問題

在這個項目裏,咱們須要經過小程序拿到的經緯度來反查城市信息,而小程序獲取經緯度須要用戶受權。這裏有個坑,當用戶拒絕受權後,小程序默認詢問受權的 dialog 在一段時間內不會重複彈出,因此咱們必須手動將用戶引導到受權頁面。

之前小程序有個接口叫作 wx.openSetting(),但 tx 把它廢掉了,如今只能讓用戶點擊一個特定的按鈕。

爲此我作了一個 modal,這裏貼出關鍵代碼。

<Button openType='openSetting' onOpenSetting={() => this.onOpenSetting()}>
  OK
</Button>

首先咱們必須給按鈕聲明 openType='openSetting',這樣當用戶點擊了以後就會跳轉到設置頁面。

其次,咱們須要在用戶離開受權頁面時,也就是點擊了左上角那個返回按鈕時,再次去檢查一下用戶的受權狀況。因此咱們要添加
onOpenSetting={() => this.onOpenSetting(),不得不吐槽這個事件命名,明明應該叫作 onLeaveSetting才合理。

onOpenSetting() 方法中咱們再次執行判斷用戶是否受權的方法,未受權的話接着彈 modal,不然放行請求相應的數據接口。

文字有些累,直接看圖。

受權圖解

沒法用傳統方式清空文本框文字

當用戶關閉搜索 dialog 時,文本框的文字應當被清空,因此一開始寫成下面的這樣,即點擊關閉按鈕時將 inputValue = '' ,然而發現不行。

<Input
  type='text'
  value={inputValue}
  placeholder='Enter City or ZIP code'
  onInput={e => handleInputTextChange(e)}
/>

<Button onClick={() => hideSearchDialog()}>Close</Button>

查了一下官方文檔,必須將 InputButton 包裹在一個 Form 下,且要給關閉按鈕加上 formType='reset',最後給 Form 添加 onReset 事件指向關閉 dialog 的方法。

<Form onReset={() => hideSearchDialog()}>
  <Input
    className={styles.input}
    type='text'
    placeholder='Enter City or ZIP code'
    onInput={e => handleInputTextChange(e)}
  />
  <Button formType='reset'>Close</Button>
</Form>;

Taro篇

大可能是編譯問題和它 webpack 配的問題,相應的我都提了 issue,有興趣的話能夠跟進。

Taro 編譯會忽略模版兩個之間的空格

舉個例子,<Text>day - night</Text>,能夠正常編譯,頁面能夠正常看到 day - night,可是假如是變量,就會被編譯成 day- night,注意,空格被吃掉了。

const day = 'day'
const night = 'night'

<Text>{day} - {night}</Text>

我提了個 issue #2261,然並沒人鳥我,有興趣能夠跟進一下。

ts 不能識別wx

由於用到了雲開發,而 Taro 現階段尚未Taro.cloud(...),因此在使用原生的wx.cloud(...)時,
ts 確定會報錯。

css module 等靜態文件 找不到路徑

一開始用的import來引入靜態文件,但報「找不到路徑」,能夠看下圖(但不影響使用)。提了個 issue #2213,
按照大佬的回覆修改也沒解決問題,實在受不了一片紅,索性改爲了commonJS.

找不到模塊

Problem

下面是項目中存在的一些問題,有興趣的話歡迎你們一塊兒討論。

圖片加載不友好

接口圖片的 url 來自aws,由於衆所周知的緣由,圖片常常會掛掉,
因此有必要在圖片掛掉的時候觸發onError事件,而後給用戶一個提示。

由於小程序不支持new Image(),因此只能用官方提供的Image組件,幸虧這個
組件支持onLoadonError事件。

加載失敗的問題解決了,但由於aws的速度太慢,因此正常加載時也很不友好(能夠自行體會)

作了一些嘗試,好比先加載縮略圖,再展現完整圖片,但接口提供的最小尺寸的圖片也已經達到了
70 多 k,而且該死的 Yahoo 剛好將圖片 url 控制大小的那段用了加密,因此這個方式 pass 掉了。

搜索輸入框加個節流

如今的作法是在 store 的 構造器加個節流,但不知道這樣合不合理。

construtor() {
    this.getRegion = _.debounce(this.getRegion, 150);
  }

TODO

  • 國際化
  • 性能優化
  • 圖片加載優化
  • Jest 搞起來(初始化已搭好)
  • Travis CI 搞起來(初始化已搭好)
  • 將搜索模塊放到一個新頁面(強行加個路由😂)

最後

老子不再寫小程序了!

老子不再寫小程序了!

相關文章
相關標籤/搜索