他山之石可以攻玉。
本文作为小程序的最后一篇文章,介绍学习大神的代码实现的豆瓣图书搜索功能。采用了网络请求功能,这也是大部分小程序需要的一个功能模块。
注:豆瓣图书代码忘记博客出处了,求大神原谅。
涉及知识
1、布局、数据绑定、模板
2、调用API——wx.request,豆瓣图书接口
3、跳转豆瓣图书详情页
实现效果如下:
粗鲁的我,直接进入主题吧。
首先介绍目录结构,如下图。
目录结构
接下来贴上所有代码和图片。
app.js
//app.js App({ onLaunch: function () { //调用API从本地缓存中获取数据 var logs = wx.getStorageSync('logs') || [] logs.unshift(Date.now()) wx.setStorageSync('logs', logs) }, getUserInfo:function(cb){ var that = this if(this.globalData.userInfo){ typeof cb == "function" && cb(this.globalData.userInfo) }else{ //调用登录接口 wx.login({ success: function () { wx.getUserInfo({ success: function (res) { that.globalData.userInfo = res.userInfo typeof cb == "function" && cb(that.globalData.userInfo) } }) } }) } }, globalData:{ userInfo:null } })
app.json
{ "pages": [ "pages/index/index", "pages/detail/detail" ], "window": { "backgroundTextStyle": "light", "navigationBarBackgroundColor": "#42BD56", "navigationBarTitleText": "豆瓣图书", "navigationBarTextStyle": "white" } }
app.wxss
page { font-family: 'microsoft yahei'; height: 100%; } /*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 { font-size: 35rpx; 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; }
util.js
function formatTime( date ) { var year = date.getFullYear() var month = date.getMonth() + 1 var day = date.getDate() var hour = date.getHours() var minute = date.getMinutes() var second = date.getSeconds() return [ year, month, day ].map( formatNumber ).join( '/' ) + ' ' + [ hour, minute, second ].map( formatNumber ).join( ':' ) } function formatNumber( n ) { n = n.toString() return n[ 1 ] ? n : '0' + n } function isFunction( obj ) { return typeof obj === 'function'; } function parseInteger(val) { if (isNaN(val)) return 0; return parseInt(val); } module.exports = { formatTime: formatTime, isFunction: isFunction, parseInteger: parseInt }
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" }
request.js
var api = require('./api.js'); var utils = require('../utils/util.js'); /** * 网路请求 */ function request(url, data, successCb, errorCb, completeCb) { wx.request({ url: url, method: 'GET', data: data, success: function(res) { if (res.statusCode == 200) utils.isFunction(successCb) && successCb(res.data); else console.log('请求异常', res); }, 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); } /** * 获取图书详细信息 */ function requestBookDokDetail(id, data, successCb, errorCb, completeCb) { request(api.API_BOOK_DETAIL.replace(':id', id), data, successCb, errorCb, completeCb); } /** * 关键字是否是tag */ function requestHasTag(tag, successCb, errorCb, completeCb) { request(api.API_BOOK_SEARCH, {tag: tag, count: 1}, successCb, errorCb, completeCb); } module.exports = { requestSearchBook: requestSearchBook, requestBookDokDetail: requestBookDokDetail }
index.js
var requests = require('../../requests/request.js'); var utils = require('../../utils/util.js'); //刷新动态球颜色 var iconColor = [ '#42BD56', '#31A040' ]; Page({ data: { scrollHeight: 0, //scroll-view高度 pageIndex: 0, //页码 totalRecord: 0, //图书总数 isInit: true, //是否第一次进入应用 loadingMore: false, //是否正在加载更多 footerIconColor: iconColor[0], //下拉刷新球初始颜色 pageData: [], //图书数据 searchKey: null //搜索关键字 }, //页面显示获取设备屏幕高度,以适配scroll-view组件高度 onShow: function () { wx.getSystemInfo({ success: (res) => { console.log(res) this.setData({ scrollHeight: res.windowHeight - (100 * res.windowWidth / 750) //80为顶部搜索框区域高度 rpx转px 屏幕宽度/750 }); } }) }, //搜索输入框输入取值 searchInputEvent: function (e) { this.setData({ searchKey: e.detail.value }); }, //搜索按钮点击事件 searchClickEvent: function (e) { if (!this.data.searchKey) { return; } this.setData({ pageIndex: 0, pageData: [] }); requestData.call(this); }, //下拉请求数据 scrollLowerEvent: function (e) { if (this.data.loadingMore) return; requestData.call(this); }, //跳转到详细页面 toDetailPage: function (e) { var bid = e.currentTarget.dataset.bid; //图书id [data-bid] wx.navigateTo({ url: '../detail/detail?id=' + bid }); } }); /** * 请求图书信息 */ function requestData() { var _this = this; var q = this.data.searchKey; var start = this.data.pageIndex; this.setData({ loadingMore: true, isInit: false }); updateRefreshBall.call(this); console.log(start) 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 }); }); } /** * 刷新下拉效果变色球 */ 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); }
index.wxml
<view class="search-container"> <input type="text" bindinput="searchInputEvent" placeholder="输入书名搜索"></input><icon bindtap="searchClickEvent" type="search" size="20"/> </view> <scroll-view scroll-y="true" style="height:{{scrollHeight}}px" bindscrolltolower="scrollLowerEvent"> <view class="logo" wx:if="{{!loadingMore && totalRecord == 0 && !isInit}}"> <icon type="cancel" color="#B0AAAA" size="50" /> <view><text>没有找到相关图书</text></view> </view> <view class="logo" wx:if="{{isInit}}"> <image src="../../images/book.png" /> <view><text>豆瓣图书</text></view> <text style="font-size:30rpx;">Designed by Oopsguy</text> </view> <view class="header" wx:if="{{totalRecord > 0 && !isInit}}"> <text>图书 {{totalRecord}}本图书</text> </view> <view class="common-list" wx:if="{{totalRecord > 0}}"> <block wx:for="{{pageData}}"> <view class="list-item" data-bid="{{item.id}}" bindtap="toDetailPage"> <view class="index-list-item"> <view class="cover"> <image class="cover-img" src="{{item.image}}"></image> </view> <view class="content"> <view class="title">{{item.title}}</view> <text class="desc">{{item.rating.average == '0.0' ? '无' : item.rating.average}}/<block wx:for="{{item.author}}" wx:for-item="it" wx:key="*this">{{it}}/</block>{{item.pubdate}}</text> </view> </view> </view> </block> </view> <view class="refresh-footer" wx:if="{{loadingMore}}"> <icon type="waiting" size="30" color="{{footerIconColor}}" /> </view> </scroll-view>
index.wxss
page { background: #F2F1EE; } .logo { text-align:center; padding-top:50rpx; font-size: 40rpx; font-weight: bold; color: #AAA } .logo image { width: 250rpx; height: 250rpx; } .search-container { position: relative; display: flex; justify-content: center; align-items: center; background-color: #42BD56; color: #FFF; height: 80rpx; padding: 10rpx 20rpx; z-index: 100; } .search-container input { background: #FFF; color: #AAA; padding: 5px 10rpx; height: 40rpx; width: 100%; border-radius: 8rpx; } .search-container icon { position: absolute; z-index: 10; top: 50%; margin-top: -20rpx; right: 40rpx; } /*header*/ .header { padding: 20rpx 30rpx; } .header text { color: #A6A6A6; font-size: 35rpx }
detail.js
var requests = require( '../../requests/request.js' ); var utils = require( '../../utils/util.js' ); Page( { data: { id: null, loadidngHidden: false, bookData: null }, onLoad: function( option ) { console.log(option) this.setData({ id: option.id }); }, onReady: function() { var id = this.data.id; var _this = this; requests.requestBookDokDetail( id, {fields: 'image,summary,publisher,title,rating,pubdate,author,author_intro,catalog'}, ( data ) => { console.log(data) _this.setData({ bookData: data }); }, () => { wx.navigateBack(); }, () => { _this.setData( { loadidngHidden: true }); }); } });
detail.wxml
<view wx:if="{{bookData}}"> <view class="cover-container"> <image src="{{bookData.image}}"></image> </view> <view class="book-meta"> <view class="meta-info"> <text class="book-title">{{bookData.title}}</text> <text class="other-meta">作者:<block wx:for="{{bookData.author}}" wx:for-item="it" wx:key="*this">{{it}} </block></text> <text class="other-meta">出版社:{{bookData.publisher}}</text> <text class="other-meta">出版日期:{{bookData.pubdate}}</text> </view> <view class="range"> <text class="score">{{bookData.rating.average}}</text> <text class="viewers">{{bookData.rating.numRaters ? bookData.rating.numRaters : 0}}参与</text> </view> </view> <view class="book-intro" wx:if="{{bookData.summary}}"> <view class="intro-header"><text>简介</text></view> <text class="intro-content">{{bookData.summary}}</text> </view> <view class="book-intro" wx:if="{{bookData.author_intro}}"> <view class="intro-header"><text>作者</text></view> <text class="intro-content">{{bookData.author_intro}}</text> </view> </view> <loading hidden="{{loadidngHidden}}"> 加载中... </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: 40rpx; } .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 { margin-bottom: 40rpx; padding: 20rpx; background: #FAFAFA; } .book-intro .intro-header { color: #888; font-weight: bold; padding: 40rpx 0; } .book-intro .intro-content { font-size: 35rpx; line-height: 2; text-align: justify }
作者:爱情小傻蛋
链接:https://www.jianshu.com/p/6e3074fa0d32
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。