在微信小程序開發中,我們可以根據不同的業務場景,開發不同的業務應用,可以基於自身域名服務接口,也可以基於第三方的域名接口進行處理(如果被禁用除外),本篇隨筆介紹使用小程序來實現我博客(http://wuhuacong.cnblogs.com)的文章閱讀功能,這個小程序主要用來介紹使用介紹基於Javascript的正則表達式的處理應用,和常規在C#里面使用正則表達式有一些差異,因此可以作為后續使用正則表達式處理業務數據的一個練兵吧。
1、Request接口合法域名配置
一般情況下,我們知道微信的Request請求是需要配置合法的域名的,這種安全性可以是微信攔截有潛在危險的或者不喜歡的域名接口,Request合法域名配置界面如下所示。
一般情況下,我們在上面增加合法域名即可,這樣小程序發布后,就可以順利通過檢查並獲取數據了,本篇隨筆由於想讀取博客園個人博客園的文章,因此需要配置博客園的域名,不過很不幸,博客園的域名上了黑名單被禁用了。
如果我們在開發環境,我們可以通過不包含對合法域名的檢驗處理,不過在開發環境必須取消勾選“不校驗”。
2、小程序功能設計
首先我們來看看主體界面的效果圖,然后在進行分析具體的功能實現,具體界面效果如下所示。
博客文章列表內容如下所示:
文章詳細界面效果如下所示:
這些文章直接都是從博客園頁面中獲取,並通過Javascript的正則表達式進行提取,然后展示在小程序上的,對於HTML內容的展示我們還是使用了WxParse的這個HTML解析組件,具體功能和使用過程可以參考我之前的隨筆《在微信小程序中使用富文本轉化插件wxParse 》進行詳細了解。對於Javascript函數的封裝,我們還是使用比較方便的Promise進行封裝處理,具體知識可以參考我隨筆《在微信小程序的JS腳本中使用Promise來優化函數處理 》進行詳細了解。
一般我們也准備把公用方法提取出來,放到工具類Utils/util.js里面,配置統一放到utils/config.js里面,這樣方便小程序的模塊化處理。
項目的文件目錄如下所示。
在Utils/util.js里面,我們封裝了wx.request的獲取內容方法如下所示。
//封裝Request請求方法 function request(url,method,data = {},type='application/json'){ wx.showNavigationBarLoading(); return new Promise((resove,reject) => { wx.request({ url: url, data: data, header: {'Content-Type': type}, method: method.toUpperCase(), // OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT success: function(res){ wx.hideNavigationBarLoading() resove(res.data) }, fail: function(msg) { console.log('reqest error',msg) wx.hideNavigationBarLoading() reject('fail') } }) }) }
而在Config.js里面,我們主要定義好一些常用的參數,如URL等
在列表頁面,我們主要是展示文字標題和日期等信息,而列表是需要滾動翻頁的,因此我們使用微信界面組件 scroll-view 來展示,具體界面代碼如下所示。
<block wx:if="{{showLoading}}"> <view class="loading">玩命加載中…</view> </block> <block wx:else> <scroll-view scroll-y="true" style="height: {{windowHeight}}rpx" scroll-top="{{scrollTop}}" bindscroll="scroll" bindscrolltolower="scrolltolower"> <view class="blog"> <block wx:for="{{blogs}}" wx:for-index="blogIndex" wx:for-item="blogItem" wx:key="blog"> <view data-id="{{blogItem.id}}" catchtap="viewBlogDetail" class="flex box box-lr item"> <view class="flex item_left"> <view><text class="title">{{blogItem.title}}</text></view> <view><text class="sub_title">{{blogItem.date}}</text></view> </view> </view> </block> <block wx:if="{{hasMore}}"> <view class="loading-tip">拼命加載中…</view> </block> <block wx:else> <view class="loading-tip">沒有更多內容了</view> </block> </view> </scroll-view> </block>
通過綁定向下滑動的事件 bindscrolltolower="scrolltolower" 我們可以實現列表內容的滾動刷新。
我們通過前面介紹的封裝Request方法,可以獲取到HTML內容,如下函數所示。
//獲取博客文章列表 getList:function(start =1) { return new Promise((resolve, reject) => { var that = this; var data = {}; var type = "text/html"; var url = config.mainblog_url + start; if (that.data.hasMore) { app.utils.get(url, data, type).then(res => {
通過指定type = "text/html",並且傳入對應的起始位置,可以獲取到對應頁面的內容。
在博客園里面,【我的隨筆】里面的標准URL地址為:http://www.cnblogs.com/wuhuacong/p/?page=n,其中 n 是當前的頁碼。
頁面上的頁碼效果如下所示:
分析頁面源碼,可以看到頁碼標簽的源碼如下所示。
因此我們對HTML源碼進行正則表達式的匹配即可獲取對應的內容(關鍵是獲取多少頁,為后面循環獲取文章列表做准備)。
關於正則表達式的測試,建議使用RegExBuilder(http://www.jb51.net/softs/389196.html)進行測試,其實我之前傾向於使用The Regulator 2.0這個很好的程序測試正則表達式,不過這個軟件經常性的不能啟動使用。
不過后來測試使用RegExBuilder,也覺得非常不錯,其中勾選ECMAScript是為了我們在Javascript使用正則表達式的選項,畢竟和在C#里面使用正則標識還是有一些差異,如不支持單行選擇,以及一些微小差異。
對於在Javascript中使用正則標識,建議大家溫習下下面幾篇隨筆,有所幫助:
《使用javascript正則表達式實現遍歷html字符串》
以及一個常見的坑,在HTML內容匹配的時候,不支持.*這種很普通的模式,這種由於不能選擇單行模式導致的,變通的方式是使用[\s\S]來實現匹配所有字符處理。
可以參考文章:https://stackoverflow.com/questions/1068280/javascript-regex-multiline-flag-doesnt-work 了解下。
另外對於Javascript的正則書寫,經常看到i,g,m的結束符
修飾符 描述
i (ignore case)
執行對大小寫不敏感的匹配。
g (global search)
執行全局匹配(查找所有匹配而非在找到第一個匹配后停止)。
m (multiline)
執行多行匹配。
它的意思你參考文章了解:
https://zhidao.baidu.com/question/620656820875333772.html
Javascript的正則匹配處理,支持正則表達式的String對象的方法可以使用search()方法、match()方法、replace()方法、split()方法、
而RegExp對象方法包括:test()方法、exec()方法。
具體Javascript的正則表達式使用,可以好好學習下《深入淺出的javascript的正則表達式學習教程》,就很清晰了。
例如對於我們這篇小程序,我們獲取頁碼的js代碼如下所示。
var reg = /共(\d{0,})頁/g; var pageNum = reg.exec(html)[1]; //console.log(pageNum); that.setData({ end:pageNum, //設置最大頁碼 });
在獲取每篇隨筆文章的標題、URL、日期等信息,我編寫了一個正則表達式來匹配,如下所示。
var regContent=/class=\"postTitl2\">.*?href=\"(.*?)\">(.*?)<\/a>.*?class=\"postDesc2\">(.*?)\s*閱讀:.*?<\/div>/igm;
正則表達式的內容,在使用前,一定需要在這個工具上測試,測試通過了我們再在代碼上使用,減少調試錯誤的時間。
下面的測試結果如下所示。
獲取文章列表信息的小程序js代碼如下所示。
在之前介紹的列表展示界面代碼里面,我們綁定了單擊連接的事件,如下界面所示標注所示。
這個事件就是觸發導航到詳細界面,如下所示,我們把URL作為id傳入到詳細的界面里面。
viewBlogDetail: function(e) { var data = e.currentTarget.dataset; var url = data.id; // console.log(url); wx.navigateTo({ url: "../details/details?id=" + data.id }) },
在文章詳細界面展示里面,界面的代碼如下所示。
<import src="../../utils/wxParse/wxParse.wxml" /> <view class="flex box box-lr item"> <view class="flex item_left"> <view> <text class="title">{{detail.title}}</text> </view> </view> </view> <view class="page"> <view class="page__bd"> <view class="weui-article"> <view class="weui-article__p"> <template is="wxParse" data="{{wxParseData:article.nodes}}"/> </view> </view> </view> </view>
這里引入了WxParse作為HTML內容解析的組件,我們在頁面代碼頂部引入組件代碼
<import src="../../utils/wxParse/wxParse.wxml" />
具體處理的內容在JS代碼里面,我們的JS代碼如下所示。
//獲取文章詳細內容 getDetail(url) { var that = this; var type = "text/html"; app.utils.get(url, {}, type).then(res => { // console.log(res); var html = res; var regContent = /id=\"cb_post_title_url\".*?>([\s\S]*?)<\/a>[\s\S]*?id=\"cnblogs_post_body\">([\s\S]*?)<\/div><div\s*id=\"MySignature\">/igm var matchArr; if ((matchArr = regContent.exec(html))) { var detail = { id: url, title : matchArr[1], //titile content : matchArr[2], //content }; that.setData({ detail:detail }); WxParse.wxParse('article', 'html', detail.content, that, 5); }; }); },
其中的Javascript的正則表達式如下:
var regContent = /id=\"cb_post_title_url\".*?>([\s\S]*?)<\/a>[\s\S]*?id=\"cnblogs_post_body\">([\s\S]*?)<\/div><div\s*id=\"MySignature\">/igm
我們在工具上測試,得到相關的效果后再在代碼上使用。
最后就可以獲得詳細的展示效果了,文章詳細界面效果如下所示: