微信小程序之图书管理系统(wepy版)

2016年小程序的推出,刷爆了朋友圈。作为一名好奇的程序猿,当然是要学习一下。于是就在2个月前在小黄象发了个demo 图书管理系统(社区API版).个人在写这个demo的时候发现小程序有一些不方便的地方: 
  • 不能使用promise(后来发现手动引用第三方promise库还是可以的)
    不能使用promise意味着一定要使用回调这种写法,当回调的层次深了后,代码的可读性将大幅下降,日后维护也麻烦。
  • 开发模式不利于代码的重复利用
 后来发现Gcaufy大神有开发了一个wepy框架,能解决小程序的一些问题。以下摘自于wepy的介绍.
主要解决的问题
  • 开发模式转换
  • 支持组件化开发
  • 支持加载外部NPM包
  • 单文件模式,使得目录结构更加清晰
  • 默认使用babel编译,支持ES6/7的一些新特性
  • 针对原生API进行优化
  • (更详细的内容请点击这里
 在学习了一波wepy后,于是有了今天的微信小程序之图书管理系统(wepy版),数据的存储还是使用社区的API,大家可以直接把源码下载下来运行。本demo在外观和功能上与图书管理系统(社区API版)没有多大的区别,更多的是一种组件化的开发思路(本文不对样式进行介绍)。好了,开始进入正题。 

完成效果图


index页面分析index页面其实很简单,就包含两个组件,分别是searchbar 和 booklist。我们只需通过css控制这两个组件的布局就可以。剩下的就是searchbar 和 booklist的开发。
 
searchbar组件searchbar组件的功能也很单纯,只是需要告诉父组件用户输入了什么信息。看一下代码
  • // searchbar.vue
  • <template>
  • <view class="search-bar">
  •     <input placeholder="请输入书名" bindinput="inputChange" />
  •     <button type="primary" bindtap="queryBooks">查詢</button>
  • </view>
  • </template>
  • <script>
  • import wepy from 'wepy';
  • export default class SearchBar extends wepy.component {
  •     props = {};
  •     data = {};
  •     events = {
  •         'index-broadcast': ($event, ...args) => {
  •             console.log(`${this.name} receive ${$event.name} from ${$event.source.name}`);
  •         }
  •     };
  •     methods = {
  •         inputChange(e) {
  •             this.$emit('inputChange', e.detail.value);
  •         },
  •     };
  • }
  • </script>
当用户在输入的时候会触发inputChange事件,而inputChange会emit一个叫“inputChange”的事件。在父组件中(page也是组件,这里指index页面),会监听inputChange事件,从而获取到从子组件传递出来的数据,继而过滤数据。 
  • // index.vue
  •     events = {
  •         // 监听searchbar emit出来的事件,从而获得searchbar的输入
  •         'inputChange': ($event, ...args) => {
  •             this.searchFilter = args[0];
  •             let filterBooks = [];
  •             if (this.searchFilter.trim().length === 0) {
  •                 filterBooks = this.booksCopy;
  •             } else {
  •                 this.books.forEach((book) => {
  •                     if (this.searchFilter.trim() &&
  •                         book.title.toUpperCase().indexOf(this.searchFilter.toUpperCase()) >= 0) {
  •                         filterBooks.push(book);
  •                     }
  •                 });
  •             }
  •             this.books = filterBooks;
  •             this.$apply();
  •         },
  •         // 点击book list组件时候转跳到明细页面,book list组件把被点击的book传递出来
  •         'goToDetailPage': ($event, ...args) => {
  •             let book = args[0];
  •             wx.navigateTo({
  •                 url: 'bookdetail?book=' + JSON.stringify(book),
  •             });
  •         },
  •     };
booklist组件booklist组件接收一个book数组,然后for循环把book的概要信息显示出来.父组件(index)需要在onLoad的时候发起请求获取book信息,然后通过props把信息传递给booklist。index页面在发起请求的时候使用了wepy封装后的wx.request,返回promise。然后利用async/await可以让异步请求看起来像同步,是不是很爽!!
  • // index
  •     async onShow() {
  •         var op1 = {
  •             url: Config.clubApi.list,
  •             data: {
  •                 appkey: Config.appKey,
  •                 type: 'bookLibrary'
  •             }
  •         };
  •         let res = await wx.request(op1);
  •         let clubBooks = res.data.result;
  •         let clubBooksArray = [];
  •         if (clubBooks.length > 0) {
  •             try{
  •                 clubBooks.forEach((clubBook) => {
  •                     clubBooksArray.push(clubBook.value);
  •                 });
  •                 this.books = clubBooksArray;
  •                 this.booksCopy = this.books;
  •             }catch(err){
  •                 this.books=[];
  •                 this.booksCopy=[];
  •             }
  •         }
  •         this.$apply();
  •     }
  • //booklist组件 ,通过props获取从父组件传递过来的数据
  • <template>
  • <view class="book-content">
  •     <view wx:for="{{books}}" wx:key="isbn13" id="{{item.isbn13}}" data-qty="{{item.qty}}" bindtap="goToDetailPage({{item}})">
  •         <view class="book-list">
  •             <view class="book-image">
  •                 <image src="{{item.image}}" mode="aspectFit"></image>
  •             </view>
  •             <view class="book-info">
  •                 <view class="book-info-style">
  •                     <view>书名:{{item.title}}</view>
  •                     <view>作者:{{item.author}}
  • </view>
  •                     <view>价格:{{item.price}}
  • </view>
  •                     <view>出版信息:{{item.publisher}}
  • </view>
  •                     <view>可借数量:{{item.qty}}
  • </view>
  •                 </view>
  •             </view>
  •         </view>
  •         <view class="line"></view>
  •     </view>
  • </view>
  • </template>
  • props = {
  • // 接收父组件传递的books数组
  •   books: {},
  • };
然后,我们回到index页面,把两个组件引用进来就可以了,index页面完成!
  • <view class="main-wrapper">
  •     <view class="search-bar-wrapper">
  •         <component id="searchBar"></component> //searchbar组件
  •     </view>
  •     <view class="book-list-wrapper">
  •         <component id="bookList" :books.sync="books"></component> //booklist组件
  •     </view>
  • </view>
book detail页面接着我们再看看book detail 页面的结构。其实也是由3部分组成。最上方是booklist 组件,中间是book info组件,最下面是btn wrapper,如下图。大家可以发现,这个页面也是有book list的,那我们是否需要把代码copy过来的。No!我们只需要引用过来就好了,这个是组件化开发的好处之一,重用性高。

以下是book detail的页面结构,非常的简单。
  • <view class="main-wrapper">
  •     <view class="book-list-wrapper">
  •         <component id="bookList" :books.sync="book"></component>
  •     </view>
  •     <view class="book-detail-wrapper">
  •         <component id="bookInfo" :books.sync="bookInfo" :height.sync="windowHeight"></component>
  •     </view>
  •     <view class="control-btn-wrapper">
  •         <button type="primary" wx:if="{{bookInfo.qty > 0}}" bindtap="borrowBook"> 借阅 </button>
  •         <button type="primary" wx:if="{{bookInfo.qty === 0}}"> 预约 </button>
  •         <button type="primary" wx:if="{{showAddBook}}"> 录入 </button>
  •     </view>
  • </view>
现在我们还差一个book info组件,now,一起来把它撸出来。
book info 组件其实book info组件的功能也很单纯。把“内容推荐”,“作者简介”和“目录”信息显示出来就可以。看以下页面结构:
  • // book info组件
  • <view class="book-info">
  •     <scroll-view scroll-y="true" style="height:{{height}}px;" >
  •         <view class="book-intro">
  •             <text class="book-title">内容推荐</text>
  •             <text class="book-msg">{{books.summary}}</text>
  •         </view>
  •         <view class="space-line-30"></view>
  •         <view class="book-intro">
  •             <text class="book-title">作者简介</text>
  •             <text class="book-msg">{{books.author_intro}}</text>
  •         </view>
  •         <view class="space-line-30"></view>
  •         <view class="book-intro">
  •             <text class="book-title">目录</text>
  •             <text class="book-msg">{{books.catalog}}</text>
  •         </view>
  •     </scroll-view>
  • </view>
这里使用到scroll view,小程序的scroll view是需要指定高度的,否则无法滚动。所以我们要动态计算中间那部分的高度。但是,组件本身是不知道它的容器的有多高的,所以需要父组件通过props告诉组件。
  • // book info 组件
  •     props = {
  •         books: {},//接收要显示的书本的信息
  •         height:Number,//接收scroll view的高度
  •     };
  • //book detail 组件
  •     async onLoad(options) {
  •         this.book = [];
  •         this.book.push(JSON.parse(options.book));
  •         this.bookInfo = JSON.parse(options.book);
  •         if (this.windowHeight === 0) {
  •             // 获取设备的高度,然后减去book list组件的高度,减去btn wrapper的高度再减去margin top 的高度
  •             let res = await wx.getSystemInfo();
  •             this.windowHeight = res.windowHeight - 66 - 136 - 10;
  •             this.$apply();
  •         }

原文链接:http://bbs.jointforce.com/topic/25380

展开阅读全文

没有更多推荐了,返回首页