微信小程序之小豆瓣圖書

本文發(fā)表至今已有一段時(shí)間奋姿,錯(cuò)別字多锄开、文筆混亂、內(nèi)容過于陳舊称诗。本人建議讀者不必細(xì)究萍悴,大概瀏覽即可,最新的開發(fā)指南還是以官方文檔為準(zhǔn),該博文的示例代碼經(jīng)過了重構(gòu)癣诱,已經(jīng)與官方文檔同步计维,可能與文章中的代碼有較大差異,請(qǐng)以 Github 倉庫上的代碼為準(zhǔn)撕予。

最近微信小程序被炒得很火熱鲫惶,本人也抱著試一試的態(tài)度下載了微信web開發(fā)者工具,開發(fā)工具比較簡(jiǎn)潔实抡,功能相對(duì)比較少欠母,個(gè)性化設(shè)置也沒有。了解完開發(fā)工具之后吆寨,順便看了一下小程序的官方開發(fā)文檔赏淌,大概了解了小程序的開發(fā)流程和一些常用的API。

了解了小程序之后啄清,自己就有了想要做一個(gè)小demo的沖動(dòng)六水,雖然自己對(duì)小程序還沒有做過很多實(shí)踐,只是在官方例子上徘徊辣卒,但是還是想做出點(diǎn)小東西缩擂。既然要做一個(gè)demo,自然需要到數(shù)據(jù)添寺,自己有又不想獨(dú)自搭建服務(wù)端,所以在網(wǎng)上搜索可以用來提供測(cè)試數(shù)據(jù)的免費(fèi)api懈费,最后我選擇了豆瓣圖書计露。豆瓣圖書提供的api功能比較少,加上不開放appkey申請(qǐng)憎乙,所以無法操作用戶數(shù)據(jù)票罐。只能做點(diǎn)簡(jiǎn)單的圖書查詢和圖書詳細(xì)信息展示,這個(gè)demo只有兩個(gè)頁面泞边,非常之簡(jiǎn)單该押。

豆瓣圖書API

demo中用到的豆瓣圖書api只有兩個(gè),一個(gè)是圖書搜索阵谚,另一個(gè)是獲取圖書詳情蚕礼。

搜索圖書

GET https://api.douban.com/v2/book/search

參數(shù) 意義 備注
q 查詢關(guān)鍵字 q和tag必傳其一
tag 查詢的tag q和tag必傳其一
start 取結(jié)果的offset 默認(rèn)為0
count 取結(jié)果的條數(shù) 默認(rèn)為20,最大為100

返回status=200

{
  "start": 0,
  "count": 10,
  "total": 30,
  "books" : [Book, ...]
}

獲取圖書詳情

GET https://api.douban.com/v2/book/:id

參數(shù) 意義
:id 圖書id

以下是具體圖書的詳情信息梢什,部分demo中用不到的信息省略

{
    "id":"1003078",
    "title":"小王子",
    "alt":"https:\/\/book.douban.com\/subject\/1003078\/",
    "image":"https://img3.doubanio.com\/mpic\/s1001902.jpg",
    "author":[
        "(法)圣暗斓牛克蘇佩里"
        ],
    "publisher":"中國(guó)友誼出版公司",
    "pubdate":"2000-9-1",
    "rating":{"max":10,"numRaters":9438,"average":"9.1","min":0},
    "author_intro":"圣埃克蘇佩里(1900-1944)1900年嗡午,瑪雅·戴斯特萊姆......",
    "catalog":"序言:法蘭西玫瑰\n小王子\n圣岸谠辏克蘇佩里年表\n"
}

Demo編寫

創(chuàng)建項(xiàng)目

項(xiàng)目取名為DouBanBookApp,項(xiàng)目的結(jié)構(gòu)小程序默認(rèn)的結(jié)構(gòu)一樣

DouBanBookApp
    pages
        index 首頁
            index.js
            index.wxml
            index.wxss
        detail 詳情頁
            detail.js
            detail.wxml
            detail.wxss
    requests 
        api.js API地址
        request.js 網(wǎng)絡(luò)請(qǐng)求
    utils
        util.js 工具
    app.js
    app.json
    app.wxss

應(yīng)用的主調(diào)色參考了豆瓣app的色調(diào),采用了偏綠色狸演。

首頁

首頁頂部展示搜索輸入框言蛇,用戶輸入圖書名稱,點(diǎn)擊搜索按鈕宵距,展示圖書列表腊尚。圖書可能會(huì)很多,不能一下子全部展示消玄,需要用到分頁跟伏,app上最常見的列表分頁就是上拉加載模式,根據(jù)小程序提供的組件中翩瓜,找到了一個(gè)比較符合場(chǎng)景的scroll-view組件受扳,這個(gè)組件有一個(gè)下拉到底部自動(dòng)觸發(fā)的bindscrolltolower事件。

先制作出界面的靜態(tài)效果兔跌,之后再整合API勘高,由于本人對(duì)界面設(shè)計(jì)不敏感,所以隨便弄了一個(gè)粗糙的布局坟桅,看得過去就行了华望,嘿嘿~~

index.wxml

<view class="search-container">
  <input type="text" placeholder="輸入書名搜索"></input><icon type="search" size="20"/>
</view>

<scroll-view scroll-y="true" style="width:100%;position:relative;top:40px;height:200px">

    <view style="text-align:center;padding-top:50rpx;">
      <icon type="cancel" color="red" size="40" />
      <view><text>沒有找到相關(guān)圖書</text></view>
    </view>

    <view style="text-align:center;padding-top:50rpx;">
      <icon type="search" size="60" />
      <view><text>豆瓣圖書</text></view>
    </view>
    
    <view class="header">
      <text>圖書 10本圖書</text>
    </view>

    <view class="common-list">

    <view class="list-item">
      <view class="index-list-item">
        <view class="cover">
          <image class="cover-img" src="images/demo.png"></image>
        </view>
        <view class="content">
          <view class="title">圖書標(biāo)圖</view>
          <text class="desc">9.0/oopsguy/2016-07-08</text>
        </view>
      </view>
    </view>

    </view>

    <view class="refresh-footer">
      <icon type="waiting" size="30" color="reed"  />
    </view>

</scroll-view>

index.wxss

page {
  background: #F2F1EE;
}

/*seach*/
.search-container {
  position: fixed;
  top: 0;
  right: 0;
  left: 0;
  background-color: #42BD56;
  color: #FFF;
  height: 40px;
  padding: 0 10rpx;
  z-index: 100;
}
.search-container input {
  background: #FFF;
  color: #AAA;
  margin-top: 5px;
  padding: 5px 10rpx;
  height: 20px;
  border-radius: 8rpx;
}
.search-container icon {
  position: absolute;
  top: 10px;
  right: 20rpx;
}

/*header*/
.header {
  padding: 20rpx 30rpx;
}
.header text {
  color: #A6A6A6;
}

/*common list*/
.list-item {
  position: relative;
  overflow: hidden
}

/*index list*/
.index-list-item {
  background: #FFF;
  padding: 15rpx 30rpx;
  overflow: hidden;
}
.index-list-item::active {
  background: #EEE;
}
.index-list-item .cover {
  float: left;
  width: 120rpx;
  height: 160rpx;
  overflow: hidden
}
.index-list-item .cover image.cover-img {
  width: 120rpx;
  height: 160rpx;
}
.index-list-item .content {
  margin-left: 140rpx;
}
.index-list-item .title {
  display: inline-block;
  height: 90rpx;
  padding-top: 20rpx;
  overflow: hidden;
}
.index-list-item .desc  {
  display: block;
  font-size: 30rpx;
  padding-top: 10rpx;
  color: #AAA;
  white-space:nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.refresh-footer {
  text-align: center;
  padding: 10rpx 0;
}

圖書詳細(xì)頁面

圖書詳細(xì)頁面就是展示具體的圖書信息,通用首頁穿過了的圖書id來獲取圖書信息之后在展示出來仅乓,獲取的過程中可能有延遲赖舟,需要一個(gè)加載效果來過渡。

detail.wxml

<view>
    <view class="cover-container">
        <image src="images/demo.png"></image>
    </view>

    <view class="book-meta">
        <view class="meta-info">
            <text class="book-title">圖書標(biāo)題</text>
            <text class="other-meta">作者:作者名稱</text>
            <text class="other-meta">出版社:xxx出版社</text>
            <text class="other-meta">出版日期:2010-05-07</text>
        </view>
        <view class="range">
            <text class="score">0</text>
            <text class="viewers">0</text>
        </view>
    </view>

    <view class="book-intro">
        <view class="intro-header"><text>簡(jiǎn)介</text></view>
        <text class="intro-content">
            這是圖書簡(jiǎn)介
        </text>
    </view>

    <view class="book-intro">
        <view class="intro-header"><text>作者</text></view>
        <text class="intro-content">
            這是作者簡(jiǎn)介
        </text>
    </view>
</view>

<loading>
    加載中...
</loading>

detail.wxss

page {
    background: #EEE;
}
.cover-container {
    background: #42BD56;
    text-align: center;
    padding: 50rpx 0;
}
.cover-container image {
    display: inline-block;
    width: 300rpx;
    height: 400rpx;
}

.book-meta {
    position: relative;
    padding: 20rpx;
    overflow: hidden;
}
.book-meta .range {
    position: absolute;
    top: 30rpx;
    right: 20rpx;
    width: 180rpx;
    background: #FFF;
    padding: 20rpx 10rpx;
    text-align: center;
    box-shadow: 2px 2px 10px #CCC;
}
.book-meta .meta-info {
    margin-right: 200rpx;
}
.meta-info text {
    display: block
}
.book-title {
    font-weight: bold;
    font-size: 50rpx;
}
.other-meta {
    padding-top: 10rpx;
    color: #888;
    font-size: 30rpx;
}
.range text {
    display: block;
}
.range .score {
    font-size: 50rpx;
    font-weight: bold;
}
.range .starts {
    font-size: 40rpx;
}
.range .viewers {
    font-size: 30rpx;
}

.book-intro {
    padding: 20rpx;
    font-size: 40rpx;
}
.book-intro .intro-header {
    color: #888
}
.book-intro .intro-content {
    font-size: 35rpx;
    line-height: 45rpx;
}

做好了首頁和詳細(xì)頁的靜態(tài)頁面夸楣,接下來就是通過網(wǎng)絡(luò)請(qǐng)求api來獲取數(shù)據(jù)宾抓,并顯示到頁面上來。

網(wǎng)絡(luò)請(qǐng)求和數(shù)據(jù)處理

為了更好的管理api豫喧,我把a(bǔ)pi專門放到了一個(gè)單獨(dú)的api.js文件中

api.js

const API_BASE = "https://api.douban.com/v2/book";

module.exports = {
  API_BOOK_SEARCH: API_BASE + "/search",
  API_BOOK_DETAIL: API_BASE + "/:id"
}

有些經(jīng)常用到的工具函數(shù)放到了util.js中

util.js

function isFunction( obj ) {
  return typeof obj === 'function';
}

module.exports = {
  isFunction: isFunction
}

微信小程序提供了一個(gè)用于網(wǎng)絡(luò)請(qǐng)求的api:wx.request(OBJECT)石洗,具體的參數(shù)跟jquery的ajax方法差不多,為了方便調(diào)用紧显,我把網(wǎng)絡(luò)請(qǐng)求放到了request.js中

request.js

var api = require('./api.js');
var utils = require('../utils/util.js');

/**
 * 網(wǎng)路請(qǐng)求
 */
function request(url, data, successCb, errorCb, completeCb) {
    wx.request({
        url: url,
        method: 'GET',
        data: data,
        success: function(res) {
            utils.isFunction(successCb) && successCb(res.data);
        },
        error: function() {
            utils.isFunction(errorCb) && errorCb();
        },
        complete: function() {
            utils.isFunction(completeCb) && completeCb();
        }
    });
}

/**
 * 搜索圖書
 */
function requestSearchBook(data, successCb, errorCb, completeCb) {
    request(api.API_BOOK_SEARCH, data, successCb, errorCb, completeCb);
}

/**
 * 獲取圖書詳細(xì)信息
 */
function requestBookDokDetail(id, data, successCb, errorCb, completeCb) {
    request(api.API_BOOK_DETAIL.replace(':id', id), data, successCb, errorCb, completeCb);
}

module.exports = {
  requestSearchBook: requestSearchBook,
  requestBookDokDetail: requestBookDokDetail
}

首頁有圖書搜索和列表展示讲衫,上拉加載的效果。微信小程序中沒有了DOM操作的概念孵班,一切的界面元素的改變都要通過數(shù)據(jù)變化來改變涉兽,所以需要在js中的Page中的data中聲明很多數(shù)據(jù)成員。

用戶在輸入數(shù)據(jù)時(shí)重父,輸入框的input綁定了searchInputEvent事件花椭,就回捕獲到輸入的數(shù)據(jù),把輸入的數(shù)據(jù)更新的data中的searchKey中房午。

searchInputEvent: function( e ) {
    this.setData( { searchKey: e.detail.value });
}

當(dāng)點(diǎn)擊搜索按鈕是矿辽,觸發(fā)tap事件,其綁定了searchClickEvent

searchClickEvent: function( e ) {
    if( !this.data.searchKey )
      return;
    this.setData( { pageIndex: 0, pageData: [] });
    requestData.call( this );
}

requestData中封裝了請(qǐng)求圖書列表的方法

/**
 * 請(qǐng)求圖書信息
 */
function requestData() {
  var _this = this;
  var q = this.data.searchKey;
  var start = this.data.pageIndex;

  this.setData( { loadingMore: true, isInit: false });
  updateRefreshBall.call( this );

  requests.requestSearchBook( { q: q, start: start }, ( data ) => {
    if( data.total == 0 ) {
      //沒有記錄
      _this.setData( { totalRecord: 0 });
    } else {
      _this.setData( {
        pageData: _this.data.pageData.concat( data.books ),
        pageIndex: start + 1,
        totalRecord: data.total
      });
    }
  }, () => {
    _this.setData( { totalRecord: 0 });
  }, () => {
    _this.setData( { loadingMore: false });
  });
}

上拉加載的效果是一個(gè)小球不停的變換顏色,需要一個(gè)顏色列表

//刷新動(dòng)態(tài)球顏色
var iconColor = [
  '#353535', '#888888'
];

然后用一個(gè)定時(shí)器來動(dòng)態(tài)改變小球圖標(biāo)的顏色

/**
 * 刷新上拉加載效果變色球
 */
function updateRefreshBall() {
  var cIndex = 0;
  var _this = this;
  var timer = setInterval( function() {
    if( !_this.data[ 'loadingMore' ] ) {
      clearInterval( timer );
    }
    if( cIndex >= iconColor.length )
      cIndex = 0;
    _this.setData( { footerIconColor: iconColor[ cIndex++ ] });
  }, 100 );
}

詳細(xì)頁面的顯示需要到首頁點(diǎn)擊了具體圖書的id袋倔,所以需要首頁傳值過來雕蔽,這里用到了小程序的wx.navigateTo方法,給其指定的url參數(shù)后面帶以查詢字符串格式形式的參數(shù)宾娜,被跳轉(zhuǎn)的頁面就會(huì)在onLoad方法中得到值批狐。

//跳轉(zhuǎn)到詳細(xì)頁面
toDetailPage: function( e ) {
    var bid = e.currentTarget.dataset.bid; //圖書id [data-bid]
    wx.navigateTo( {
      url: '../detail/detail?id=' + bid
    });
}

detail.js中接受參數(shù)

onLoad: function( option ) {
    this.setData({
      id: option.id
    });
}

其實(shí)小程序的頁面制作跟平時(shí)的html和css差不多,只是頁面中不能用傳統(tǒng)的html標(biāo)簽前塔,而是改用了小程序提供的自定義標(biāo)簽嚣艇,小程序?qū)ss的支持也有限制,注意哪些寫法不兼容也差不多懂了华弓。操作頁面變化是通過數(shù)據(jù)變化來表現(xiàn)出來的食零,這點(diǎn)有點(diǎn)像react和vue。以上的demo用到的知識(shí)點(diǎn)并不多寂屏,主要是頁面的數(shù)據(jù)綁定贰谣、事件綁定、模版知識(shí)和網(wǎng)絡(luò)請(qǐng)求等相關(guān)api迁霎。仔細(xì)看看文檔也差不多可以做出一個(gè)小例子吱抚。
qi

最終效果圖

總體來說,Demo很簡(jiǎn)單考廉,只有兩個(gè)頁面秘豹,界面也是丑丑的T_T,算是我入門小程序的第一課吧昌粤。

DouBanBookApp效果圖

計(jì)劃后續(xù)會(huì)有更多小例子

正在編寫中的Demo憋肖,不久將完成,敬請(qǐng)期待

知乎日?qǐng)?bào)微信小程序版本

代碼存在

https://github.com/oopsguy/WechatSmallApps

http://git.oschina.net/oopsguy/WechatSmallApps

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末婚苹,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子鸵膏,更是在濱河造成了極大的恐慌膊升,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,378評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件谭企,死亡現(xiàn)場(chǎng)離奇詭異廓译,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)债查,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門非区,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人盹廷,你說我怎么就攤上這事征绸。” “怎么了?”我有些...
    開封第一講書人閱讀 152,702評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵管怠,是天一觀的道長(zhǎng)淆衷。 經(jīng)常有香客問我,道長(zhǎng)渤弛,這世上最難降的妖魔是什么祝拯? 我笑而不...
    開封第一講書人閱讀 55,259評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮她肯,結(jié)果婚禮上佳头,老公的妹妹穿的比我還像新娘。我一直安慰自己晴氨,他們只是感情好康嘉,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評(píng)論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著瑞筐,像睡著了一般凄鼻。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上聚假,一...
    開封第一講書人閱讀 49,036評(píng)論 1 285
  • 那天块蚌,我揣著相機(jī)與錄音,去河邊找鬼膘格。 笑死峭范,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的瘪贱。 我是一名探鬼主播纱控,決...
    沈念sama閱讀 38,349評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼菜秦!你這毒婦竟也來了甜害?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,979評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤球昨,失蹤者是張志新(化名)和其女友劉穎尔店,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體主慰,經(jīng)...
    沈念sama閱讀 43,469評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡嚣州,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了共螺。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片该肴。...
    茶點(diǎn)故事閱讀 38,059評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖藐不,靈堂內(nèi)的尸體忽然破棺而出匀哄,到底是詐尸還是另有隱情秦效,我是刑警寧澤,帶...
    沈念sama閱讀 33,703評(píng)論 4 323
  • 正文 年R本政府宣布拱雏,位于F島的核電站棉安,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏铸抑。R本人自食惡果不足惜贡耽,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望鹊汛。 院中可真熱鬧蒲赂,春花似錦、人聲如沸刁憋。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽至耻。三九已至若皱,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間尘颓,已是汗流浹背走触。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留疤苹,地道東北人互广。 一個(gè)月前我還...
    沈念sama閱讀 45,501評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像卧土,于是被迫代替她去往敵國(guó)和親惫皱。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容