去年年末 o2 开源了 Taro,一直手痒痒没去玩。考虑到 wx 的审核制度,因此决定写个工具类小程序。赶在 Taro 喜提第 2000 个 issues 之际,Natsuha 也终于上线了。源码所有释出(除涉及私钥部分,GitHub有说明),文章后面会贴出一些仍需优化的点,欢迎你们一块儿讨论。
Natsuha Weather 已开源,欢迎你们一块儿折腾,给个 star 也是极好的~ GitHub Repocss
技术栈是 Taro + mobx + TypeScript
,接口来自 Yahoo Weather API,固然设计也是参 (chao) 考 (xi) 的 Yahoo Weather. 接口有时会访问失败,尤为是晚上,我也没办法啊。🤷html
因为众所周知的缘由,wx 小程序没法调用未 bei an 的接口,哪怕是在开发环境。因此咱们用云开发的云函数来 “反代” 接口,下面经过一个例子说一下技术要点。前端
首先在根目录的 project.config.json
文件里添加 "cloudfunctionRoot": "functions/"
,而后在根目录建立文件夹 functions
. 并点击右键建立一个新的云函数,好比咱们叫 getRegion
。webpack
由于咱们的目标是经过云函数请求一个未 bei an 的接口,因此为了更方便的处理异步请求,咱们引入 request-promise
这个库。git
经过硬盘打开
进入到这个云函数的文件夹,而后安装依赖:github
yarn add request request-promise
接下来咱们在 index.js
中写逻辑,直接上代码。云函数经过 event
对象来获取前端传过来的参数,而后经过 Promise 对象将结果返回。这个例子中咱们须要拿到region
,web
// 云函数入口文件 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>
查了一下官方文档,必须将 Input
和 Button
包裹在一个 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>;
大可能是编译问题和它 webpack 配的问题,相应的我都提了 issue,有兴趣的话能够跟进。
举个例子,<Text>day - night</Text>
,能够正常编译,页面能够正常看到 day - night
,可是假如是变量,就会被编译成 day- night
,注意,空格被吃掉了。
const day = 'day' const night = 'night' <Text>{day} - {night}</Text>
我提了个 issue #2261,然并没人鸟我,有兴趣能够跟进一下。
wx
由于用到了云开发,而 Taro 现阶段尚未Taro.cloud(...)
,因此在使用原生的wx.cloud(...)
时,
ts 确定会报错。
一开始用的import
来引入静态文件,但报“找不到路径”,能够看下图(但不影响使用)。提了个 issue #2213,
按照大佬的回复修改也没解决问题,实在受不了一片红,索性改为了commonJS
.
下面是项目中存在的一些问题,有兴趣的话欢迎你们一块儿讨论。
接口图片的 url 来自aws
,由于众所周知的缘由,图片常常会挂掉,
因此有必要在图片挂掉的时候触发onError
事件,而后给用户一个提示。
由于小程序不支持new Image()
,因此只能用官方提供的Image
组件,幸亏这个
组件支持onLoad
和onError
事件。
加载失败的问题解决了,但由于aws
的速度太慢,因此正常加载时也很不友好(能够自行体会)
作了一些尝试,好比先加载缩略图,再展现完整图片,但接口提供的最小尺寸的图片也已经达到了
70 多 k,而且该死的 Yahoo 刚好将图片 url 控制大小的那段用了加密,因此这个方式 pass 掉了。
如今的作法是在 store 的 构造器加个节流,但不知道这样合不合理。
construtor() { this.getRegion = _.debounce(this.getRegion, 150); }
老子不再写小程序了!