在學習微信小程式開發過程中,一部分的難點是前端邏輯的處理,也就是對前端JS的代碼編輯;一部分的難點是前端界面的設計展示;本篇隨筆基於一個豆瓣電影介面的小程式開源項目進行重新調整,把其中遇到的相關難點和改進的地方進行討論介紹,希望給大家提供一個參考的思路,本篇隨筆是基於前人小程式的項目基礎上進行的改進... ...
在學習微信小程式開發過程中,一部分的難點是前端邏輯的處理,也就是對前端JS的代碼編輯;一部分的難點是前端界面的設計展示;本篇隨筆基於一個豆瓣電影介面的小程式開源項目進行重新調整,把其中遇到的相關難點和改進的地方進行討論介紹,希望給大家提供一個參考的思路,本篇隨筆是基於前人小程式的項目基礎上進行的改進,因此在開篇之前首先對原作者的辛勞致敬及感謝。
1、豆瓣電影介面的小程式項目情況
豆瓣電影介面提供了很多相關的介面給我們使用,豆瓣電影介面的API地址如下所示:https://developers.douban.com/wiki/?title=movie_v2
在GitHub的開源庫裡面,可以搜索到很多關於豆瓣電影介面的小程式,我本篇隨筆是基於 weapp-douban-movie 這個小程式進行的改造處理,後來找到了原作者的項目地址:wechat-weapp-movie,原作者對版本做了一次升級,後來我對照我的調整和作者最新版本的源碼,發現有些地方改造的思路有些類似,如對於URL地址外放到統一的配置文件中的處理,不過還是有很多地方改造不同。
本篇隨筆的改造方案是基於小程式項目 weapp-douban-movie 的,因此對比的代碼也是和這個進行比較,不知道這個版本是不是原作者的舊版本,不過這個版本對文件目錄的區分已經顯得非常乾凈利落了,對電影信息的展示也統一到了模板裡面,進行多次的重覆利用,整體的佈局和代碼都做的比較好,看得出是花了不少功夫進行整理優化的了。
小程式主界面效果如下所示:
小程式源碼目錄結構如下所示:
不過每個人都有不同的經驗和看法,對於開發小程式來說,我側重於使用配置文件減少硬編碼的常量,使用Promise來優化JS代碼的使用,將獲取和提交JSON數據的方法封裝到輔助類,以及使用地理位置介面動態獲取當前城市名稱和坐標等等。
本篇隨筆下麵的部分就是介紹使用這些內容進行代碼優化的處理過程。
1、使用配置文件定義常量內容
我們在使用任何代碼開發程式的時候,我們都是非常註意一些變數或常量的使用,如果能夠統一定義那就統一定義好了,這種在小程式的JS代碼裡面也是一樣,我們儘可能抽取一些如URL,固定參數等信息到獨立的配置文件中,這樣在JS代碼引入文件,使用變數來代替
例如原來的config.js文件裡面,只是定義了一個地址和頁面數量的大小常量,如下所示
module.exports = { city: '杭州', count: 20 }
原來的小程式代碼在獲取待映的電影內容時候,部分源碼如下所示
其他頁面JS代碼也和這個類似,頭部依舊有很多類似這樣URL地址,這個是我希望統一到config.js文件的地方,另外這個調用的函數是使用回調函數的處理方式,如下所示。
douban.fetchFilms.call(that, url, config.city, that.data.start, config.count)
其實我認為這裡面既然是定義的外部函數,那麼這裡面的url, city, config.city, config.cout都不需要這裡,在封裝函數內部使用這些常量即可,因此可以對他們進行改造,如下我們統一抽取各個文件裡面的URL,以及一些常見變數到config.js裡面。
下麵代碼是我優化整理後的配置參數信息。
module.exports = { city: '', location:'0,0', count: 20, coming_soon_url: 'https://api.douban.com/v2/movie/coming_soon', in_theaters_url: 'https://api.douban.com/v2/movie/in_theaters', top_url: 'https://api.douban.com/v2/movie/top250', search_url: 'https://api.douban.com/v2/movie/search?tag=', detail_url: 'https://api.douban.com/v2/movie/subject/', //?id= celebrity_url: 'https://api.douban.com/v2/movie/celebrity/', baidu_ak:'6473aa8cbc349933ed841467bf45e46b', baidu_movie:'https://api.map.baidu.com/telematics/v3/movie', hotKeyword: ['功夫熊貓', '烈日灼心', '擺渡人', '長城', '我不是潘金蓮', '這個殺手不太冷', '驢得水', '海賊王之黃金城', '西游伏妖片', '我在故宮修文物', '你的名字'], hotTag: ['動作', '喜劇', '愛情', '懸疑'], }
上面的配置文件config.js裡面,我統一抽取了各個頁面的URL地址、關鍵詞和標簽(hotKeyword和hotTag)、城市及地址(city和location後面動態獲取)、頁面數量count等參數信息。
另外由於部分參數統一通過config.js獲取,就不需要再次在調用的時候傳入了,因此簡化調用代碼的參數傳入,如下代碼所示。
douban.fetchComming(that, that.data.start)
對於原先的代碼
douban.fetchFilms.call(that, url, config.city, that.data.start, config.count)
簡化的雖然不多,但是儘可能的保持乾凈簡單的介面是我們的目標,而且這裡把常規的URL等參數提取到函數裡面,更加符合我們編碼的習慣。
這裡定義的douban.fetchComming(that, that.data.start) 使用了Promise來簡化代碼,傳入的that參數是因為需要在函數體裡面設置該頁面裡面的Data等處理。
關於Promise的相關處理,我們在下麵進行介紹。
2、使用Promise來優化JS代碼
關於Promise的好處和如何使用Promise插件介紹,我在隨筆《在微信小程式的JS腳本中使用Promise來優化函數處理》中已有介紹,我很喜歡使用這種Promise的風格代碼,而且可以定義一些常用的輔助類來提高代碼的重用。在我參考的這個豆瓣電影小程式還是使用常規回調的函數,對比原作者最新版本的 wechat-weapp-movie 小程式,也依舊使用回調函數模式來處理,有點奇怪為什麼不引入Promise插件來開發。
原來的小程式,電影介面的相關處理,統一在fetch.js裡面進行處理,這裡封裝對各種豆瓣API介面的調用。
這裡我們來看看原來程式沒有採用Promise的回調函數處理代碼
var config = require('./config.js') var message = require('../../component/message/message') module.exports = { fetchFilms: function(url, city, start, count, cb) { var that = this if (that.data.hasMore) { wx.request({ url: url, data: { city: config.city, start: start, count: count }, method: 'GET', header: { "Content-Type": "application/json,application/json" }, success: function(res){ if(res.data.subjects.length === 0){ that.setData({ hasMore: false, }) }else{ that.setData({ films: that.data.films.concat(res.data.subjects), start: that.data.start + res.data.subjects.length, showLoading: false }) } wx.stopPullDownRefresh() typeof cb == 'function' && cb(res.data) }, fail: function() { that.setData({ showLoading: false }) message.show.call(that,{ content: '網路開小差了', icon: 'warning', duration: 3000 }) } }) } },
這個函數是一個通用的函數,用來獲取待映、熱映、top250口碑的記錄信息,不過它把參數拋給調用者傳入,因此顯得調用比較複雜一些,我們經過使用Promise優化代碼處理,並對介面的參數進行簡化,代碼改造如下所示。
var config = require('./config.js') var message = require('../../component/message/message') var app = getApp()//獲取應用實例 module.exports = { //待映 fetchComming : function(page, start) { return this.fetchFilms(page, config.coming_soon_url, config.city, start, config.count); }, //熱映 fetchPopular : function(page, start) { return this.fetchFilms(page, config.in_theaters_url, config.city, start, config.count); }, //top250口碑 fetchTop : function(page, start) { return this.fetchFilms(page, config.top_url, config.city, start, config.count); }, //通用的熱映、待映的獲取方式 fetchFilms: function(page, url, city, start, count) { return new Promise((resolve, reject) => { var that = page; var json = {city: city, start: start, count: count }; var type = "json";//特殊設置,預設是application/json if (that.data.hasMore) { app.utils.get(url, json, type).then(res => { if(res.subjects.length === 0){ that.setData({ hasMore: false, }) }else{ that.setData({ films: that.data.films.concat(res.subjects), start: that.data.start + res.subjects.length, showLoading: false }) } wx.stopPullDownRefresh(); resolve(res); }) } }) },
最終的請求介面參數只有兩個,一個是頁面對象,一個是請求的起始位置,如下代碼所示
function(page, start)
另外我們使用了代碼
app.utils.get(url, json, type)
來對wx.request方法的統一封裝,直接使用工具類裡面的方法即可獲取結果,不需要反覆的、臃腫的處理代碼。這就是我們使用Promise來優化JS,並抽取常用代碼到工具類裡面的做法。
我們再來對比一下獲取電影詳細信息的介面函數封裝,原來代碼如下所示。
fetchFilmDetail: function(url, id, cb) { var that = this; wx.request({ url: url + id, method: 'GET', header: { "Content-Type": "application/json,application/json" }, success: function(res){ that.setData({ filmDetail: res.data, showLoading: false, showContent: true }) wx.setNavigationBarTitle({ title: res.data.title }) wx.stopPullDownRefresh() typeof cb == 'function' && cb(res.data) }, fail: function() { that.setData({ showLoading: false }) message.show.call(that,{ content: '網路開小差了', icon: 'warning', duration: 3000 }) } }) },
我改造後的函數代碼如下所示。
//獲取電影詳細信息 fetchFilmDetail: function(page, id) { return new Promise((resolve, reject) => { var that = page; var url = config.detail_url + id; var type = "json";//特殊設置,預設是application/json app.utils.get(url, {}, type).then(res => { that.setData({ filmDetail: res, showLoading: false, showContent: true }); wx.setNavigationBarTitle({ title: res.title }); wx.stopPullDownRefresh(); resolve(res); }); }) },
通過對fetch.js函數代碼的改造處理,可以看到調用的JS代碼參數減少了很多,而且頁面也不用保留那麼多連接等參數常量信息了。
onLoad: function() { var that = this douban.fetchComming(that, that.data.start) },
3、使用地理位置介面動態獲取當前城市名稱和坐標
原來程式使用硬編碼的方式設置當前城市,如下腳本所示
module.exports = { city: '杭州', count: 20 }
不過我們不同地方的人員使用的時候,這個城市名稱肯定需要變化的,因此可以使用微信的地理位置介面動態獲取當前位置信息,然後寫入到配置文件裡面即可。
//獲取當前位置信息 function getLocation (type) { return new Promise((resolve, reject) => { wx.getLocation({ type: type, success: resolve, fail: reject }) }) } //根據坐標獲取城市名稱 function getCityName (latitude = 39.90403, longitude = 116.407526) { var data = { location: `${latitude},${longitude}`, output: 'json', ak: '6473aa8cbc349933ed841467bf45e46b' }; var url = 'https://api.map.baidu.com/' + 'geocoder/v2/'; var type = 'json'; return this.get(url, data, type).then(res => res.result.addressComponent.city); }
然後我們在app.js裡面編寫代碼,在app啟動的時候,動態獲取城市名稱、坐標信息然後寫入配置文件即可,這裡使用的還是Promise的函數調用實現。
const utils = require('./comm/script/util.js') const config = require('./comm/script/config.js') App({ onLaunch: function() { utils.getLocation() .then(res=>{ const { latitude, longitude } = res; config.location = `${longitude},${latitude}`;//當前坐標 console.log(`currentLocation : ${config.location}`); return utils.getCityName(latitude, longitude) }) .then(name=>{ config.city = name.replace('市', ''); //當前城市名稱 console.log(`currentCity : ${config.city}`) }) .catch(err => { config.city = '廣州' console.error(err) }) }, ...
最後呈上改造過代碼的運行界面,還是保留原來的功能正常使用。
以上就是我對這個小程式進行不同方面的調整思路和經驗總結,希望大家有所收益或者建議,感謝閱讀支持。