Vue+koa2开发一款全栈小程序(8.图书列表页)
1.图书列表页获取数据
1.在server/routes/index.js中新增路由
router.get('/booklist',controllers.booklist)
2.在server/controllers下新增booklist.js
const {mysql}=require('../qcloud')
module.exports=async(ctx)=>{
const books=await mysql('books').select('*').orderBy('id','desc')
ctx.state.data={
list:books
}
}
3.在mydemo/src/pages/books/index.vue中
<template>
<div>
<div :key="book.id" v-for="book in books">{{book.title}}</div>
</div>
</template>
<script>
import {get} from '@/until' export default {
data(){
return {
books:[]
}
}, methods:{
async getList(){
const books=await get('/weapp/booklist') this.books=books.data.list
}
}, mounted(){
this.getList()
} }
</script>
<style> </style>
效果图

2.图书卡片显示数据
1.在src/components目录下新建组件BookList.vue
<template>
<div class='book-card'>
<div class="thumb">
<img :src="book.image" class="img" mode="aspectFit">
</div>
<div class="detail">
<div class="row">
<div class="right">
{{book.rate}}
</div>
<div class="left">
{{book.title}}
</div>
</div> <div class="row">
<div class="right">
浏览量
</div>
<div class="left">
{{book.author}}
</div>
</div> <div class="row">
<div class="right">
添加人
</div>
<div class="left">
{{book.publisher}}
</div>
</div>
</div>
</div>
</template> <script>
export default {
props:['book'] }
</script> <style lang='scss' scoped>
.book-card{
padding: 5px;
overflow: hidden;
margin-top: 5px;
margin-bottom: 5px;
font-size: 14px;
.thumb{
width: 90px;
height: 90px;
float: left;
margin: 0 auto;
overflow: hidden;
.img{
max-width: 100%;
max-height: 100%;
}
}
.detail{
margin-left: 100px;
.row{
line-height: 20px;
margin-bottom: 3px;
}
.right{
float: right;
}
.left{
margin-right: 80px;
}
}
} </style>
2.在src/pages/books/index.vue中
<template>
<div>
<BookList :key='book.id' v-for='book in books' :book='book'></BookList> </div>
</template>
<script>
import {get} from '@/until'; import BookList from'@/components/BookList' export default {
components:{
BookList
}, data(){
return {
books:[]
}
}, methods:{
async getList(){
const books=await get('/weapp/booklist') this.books=books.data.list
}
}, mounted(){
this.getList()
} }
</script>
<style> </style>
效果图

3.星级显示组件的实现
1.在src/components目录下新建组件Rate.vue
<template>
<div class="rate">
<span>☆☆☆☆☆</span>
<div class="hollow" :style='style'>★★★★★</div>
</div>
</template>
<script>
export default {
props:{
value:{type:[Number,String],default:'0'}
},
computed:{
style(){
return `width:${this.value/2}em`
}
}, }
</script>
<style lang='scss'>
.rate{
position: relative;
display: inline-block;
.hollow{
position: absolute;
display: inline-block;
top:0;
left: 0;
width: 0;
overflow: hidden;
}
}
</style>
2.在src/components目录下修改BookList.vue
<template>
<div class='book-card'>
<div class="thumb">
<img :src="book.image" class="img" mode="aspectFit">
</div>
<div class="detail">
<div class="row">
<div class="right">
{{book.rate}}<Rate :value='book.rate'></Rate>
</div>
<div class="left">
{{book.title}}
</div>
</div> <div class="row">
<div class="right">
浏览量
</div>
<div class="left">
{{book.author}}
</div>
</div> <div class="row">
<div class="right">
添加人
</div>
<div class="left">
{{book.publisher}}
</div>
</div>
</div>
</div>
</template> <script>
import Rate from '@/components/Rate'
export default {
components:{
Rate
},
props:['book'] }
</script> <style lang='scss' scoped>
.book-card{
padding: 5px;
overflow: hidden;
margin-top: 5px;
margin-bottom: 5px;
font-size: 14px;
.thumb{
width: 90px;
height: 90px;
float: left;
margin: 0 auto;
overflow: hidden;
.img{
max-width: 100%;
max-height: 100%;
}
}
.detail{
margin-left: 100px;
.row{
line-height: 20px;
margin-bottom: 3px;
}
.right{
float: right;
}
.left{
margin-right: 80px;
}
}
} </style>
效果图

3.优化UI页面
在src/App.vue中的<style>标签内,加全局样式
.text-primary{
color: #EA5149;
}
在src/components/BookList.vue中给row加上text-primary类
<div class="row text-primary">
<div class="right">
{{book.rate}}<Rate :value='book.rate'></Rate>
</div>
<div class="left">
{{book.title}}
</div>
</div>
效果图

4.获取添加人(连表查询)
1.在server/controllers/booklist.js中
const {mysql}=require('../qcloud')
module.exports=async(ctx)=>{
const books=await mysql('books')
.select('books.*','csessioninfo.user_info')
.join('csessioninfo','books.openid','csessioninfo.open_id')
.orderBy('books.id','desc')
ctx.state.data={
list:books.map(v=>{
const info=JSON.parse(v.user_info)
return Object.assign({},v,{
user_info:{
nickName:info.nickName
}
})
})
}
}
2.在src/components/BookList.vue中将原来添加人的位置,替换为
<div class="row">
<div class="right">
{{book.user_info.nickName}}
</div>
<div class="left">
{{book.publisher}}
</div>
</div>
效果图

5.下拉刷新
1.多添加几本图书入库
2.在src/pages/books目录下,新建main.json
{
"enablePullDownRefresh":true
}
3.在src/pages/books/index.vue中
<template>
<div>
<BookList :key='book.id' v-for='book in books' :book='book'></BookList> </div>
</template>
<script>
import {get} from '@/until'; import BookList from'@/components/BookList' export default {
components:{
BookList
}, data(){
return {
books:[]
}
}, methods:{
async getList(){
wx.showNavigationBarLoading()
const books=await get('/weapp/booklist')
this.books=books.data.list
wx.stopPullDownRefresh()
wx.hideNavigationBarLoading()
}
}, onPullDownRefresh(){
// console.log('下拉')
this.getList()
}, mounted(){
this.getList()
} }
</script>
<style> </style>
6.图书滚动加载功能实现(包含了下拉加载和上拉加载)
1.在server/controllers/booklist.js中修改代码为
const {mysql}=require('../qcloud')
module.exports=async(ctx)=>{
const {page}=ctx.request.query
const size=10
const books=await mysql('books')
.select('books.*','csessioninfo.user_info')
.join('csessioninfo','books.openid','csessioninfo.open_id')
.limit(size)
.offset(Number(page)*size)
.orderBy('books.id','desc')
ctx.state.data={
list:books.map(v=>{
const info=JSON.parse(v.user_info)
return Object.assign({},v,{
user_info:{
nickName:info.nickName
}
})
})
}
}
2.在src/pages/books/index.vue中修改为
<template>
<div>
<BookList :key='book.id' v-for='book in books' :book='book'></BookList>
<p class="text-footer" v-if='!more'>没有更多数据</p>
</div>
</template>
<script>
import {get} from '@/until'; import BookList from'@/components/BookList' export default {
components:{
BookList
}, data(){
return {
books:[],
page:0,
more:true
}
}, methods:{
async getList(){ wx.showNavigationBarLoading()//显示加载中菊花动画
const books=await get('/weapp/booklist',{page:this.page})
if(books.data.list.length<10&&this.page>0){
this.more=false
}
this.books=this.books.concat(books.data.list)//下拉刷新,不能直接覆盖books,而是累加
wx.hideNavigationBarLoading()//隐藏加载中菊花动画
wx.stopPullDownRefresh()//停止下拉状态
}
}, onPullDownRefresh(){
// console.log('下拉')
this.page+=1
this.getList(true)
},
onReachBottom(){
//上拉(向下到底)
if(!this.more){
// 没有更多了
return false
}
this.page+=1
this.getList()
}, mounted(){
this.getList()
} }
</script>
<style> </style>
3.在App.vue中增加样式
.text-footer{
text-align: center;
font-size: 15px;
margin-bottom: 15px;
}
7.图书访问次数统计
1.在src/components/BookList.vue中,修改代码,加上a标签,以及配置
<template>
<a :href="detailUrl">
<div class='book-card'>
<div class="thumb">
<img :src="book.image" class="img" mode="aspectFit">
</div>
<div class="detail">
<div class="row text-primary">
<div class="right">
{{book.rate}}<Rate :value='book.rate'></Rate>
</div>
<div class="left">
{{book.title}}
</div>
</div> <div class="row">
<div class="right">
浏览量:{{book.count}}
</div>
<div class="left">
{{book.author}}
</div>
</div> <div class="row">
<div class="right">
{{book.user_info.nickName}}
</div>
<div class="left">
{{book.publisher}}
</div>
</div>
</div>
</div>
</a>
</template> <script>
import Rate from '@/components/Rate'
export default {
components:{
Rate
},
props:['book'], computed:{
detailUrl(){
return '/pages/detail/main?id='+this.book.id
}
} }
</script> <style lang='scss' scoped>
.book-card{
padding: 5px;
overflow: hidden;
margin-top: 5px;
margin-bottom: 5px;
font-size: 14px;
.thumb{
width: 90px;
height: 90px;
float: left;
margin: 0 auto;
overflow: hidden;
.img{
max-width: 100%;
max-height: 100%;
}
}
.detail{
margin-left: 100px;
.row{
line-height: 20px;
margin-bottom: 3px;
}
.right{
float: right;
}
.left{
margin-right: 80px;
}
}
} </style>
2.在src/pages目录下新建detail目录,新建index.vue和main.js
1.main.js
import Vue from 'vue'
import App from './index' const app = new Vue(App)
app.$mount()
2.index.vue
<template>
<div>图书id:{{bookid}}</div>
</template>
<script> import {get} from '@/until' export default {
data(){
return{
bookid:''
}
}, methods:{
async getDetail(){
const info=await get('/weapp/bookdetail',{id:this.bookid})
}
}, mounted(){
this.bookid=this.$root.$mp.query.id //this.$root.$mp.query获取跳转链接传过来的对象集合
this.getDetail()
}
}
</script>
<style> </style>
3.在src/app.json中加入
"pages/detail/main"

4.在server/routes/index.js中加入路由
router.get('/bookdetail',controllers.bookdetail)
5.在server/controllers目录下新建bookdetail.js
const {mysql}=require('../qcloud')
module.exports=async(ctx)=>{
const {id}=ctx.request.query
await mysql('books')
.where('id',id)
.increment('count',1)
}
6.因为新增了page,所以要重新启动项目
npm run dev


8.排行榜轮播图
1.点击排行榜的获取
1.在src/pages/books/index.vue中增加getTop方法,并在相关位置调用
async getTop(){
const tops=await get('/weapp/top')
this.tops=tops.data.list
}

2.在server/router/index.js中增加路由
router.get('/top',controllers.top)
3.在server/controllers目录下新建top.js
const {mysql} =require('../qcloud')
module.exports=async (ctx)=>{
const top=await mysql('books')
.select('id','title','image','count')
.orderBy('count','desc')
.limit(9)
ctx.state.data={
list:top
}
}
2.排行榜轮播图的基本实现
1.在src/components目录下新建组件TopSwiper.vue
<template>
<div class='swiper'>
<swiper
:indicator-dots='true'
indicator-color='#EA5A49'
:autoplay='true'
:interval='6000'
:duration='1000'
:circular='true'
> <div :key='imgindex' v-for='(top,imgindex) in tops'> <swiper-item>
<img class='slide-image' mode='aspectFit' :src='top.image'>
</swiper-item> </div> </swiper>
</div>
</template>
<script>
export default {
props:['tops'] }
</script>
<style> </style>
2.在src/pages/books/index.vue中导入TopSwiper组件
<template>
<div>
<TopSwiper :tops='tops'></TopSwiper>
<BookList :key='book.id' v-for='book in books' :book='book'></BookList>
<p class="text-footer" v-if='!more'>没有更多数据</p>
</div>
</template>
<script>
import {get} from '@/until'; import BookList from'@/components/BookList'
import TopSwiper from '@/components/TopSwiper' //...
效果图

3.排行榜轮播图完善实现
1.修改在src/components目录下的组件TopSwiper.vue
<template>
<div class='swiper'>
<swiper
:indicator-dots='true'
indicator-color='#EA5A49'
:autoplay='true'
:interval='6000'
:duration='1000'
:circular='true'
> <div :key='imgindex' v-for='(top,imgindex) in imgUrls'> <swiper-item>
<img
@click="bookDetail(img)"
class='slide-image'
mode='aspectFit'
v-for="img in top"
:key="img.id"
:src='img.image'>
</swiper-item> </div> </swiper>
</div>
</template>
<script>
export default {
props:['tops'],
computed:{
imgUrls(){
// 如果通用 请用chunk函数 比如lodash的chunk方法
let res=this.tops
return [res.slice(0,3),res.slice(3,6),res.slice(6)]
}
},
methods:{
bookDetail(item){
wx.navigateTo({
url:'/pages/detail/main?id='+item.id
})
}
} }
</script>
<style lang='scss'>
.swiper{
margin-top: 5px;
.slide-image{
width: 33%;
height: 250rpx;
}
}
</style>
效果图


2.点击图片预览功能,点击缩略图不会跳转,而是图片预览效果
1.修改在src/components目录下的组件BookList.vue
<template>
<a :href="detailUrl">
<div class='book-card'>
<div class="thumb" @click.stop="preview">
<img :src="book.image" class="img" mode="aspectFit">
</div>
<div class="detail">
<div class="row text-primary">
<div class="right">
{{book.rate}}<Rate :value='book.rate'></Rate>
</div>
<div class="left">
{{book.title}}
</div>
</div> <div class="row">
<div class="right">
浏览量:{{book.count}}
</div>
<div class="left">
{{book.author}}
</div>
</div> <div class="row">
<div class="right">
{{book.user_info.nickName}}
</div>
<div class="left">
{{book.publisher}}
</div>
</div>
</div>
</div>
</a>
</template> <script>
import Rate from '@/components/Rate'
export default {
components:{
Rate
},
props:['book'], computed:{
detailUrl(){
return '/pages/detail/main?id='+this.book.id
}
},
methods:{
preview(){
wx.previewImage({
current:this.book.image,
urls:[this.book.image]//轮播图列表
})
}
} }
</script> <style lang='scss' scoped>
.book-card{
padding: 5px;
overflow: hidden;
margin-top: 5px;
margin-bottom: 5px;
font-size: 14px;
.thumb{
width: 90px;
height: 90px;
float: left;
margin: 0 auto;
overflow: hidden;
.img{
max-width: 100%;
max-height: 100%;
}
}
.detail{
margin-left: 100px;
.row{
line-height: 20px;
margin-bottom: 3px;
}
.right{
float: right;
}
.left{
margin-right: 80px;
}
}
} </style>
效果图

Vue+koa2开发一款全栈小程序(8.图书列表页)的更多相关文章
- Vue+koa2开发一款全栈小程序(9.图书详情页)
1.获取图书详情 1.修改server/controllers/bookdetail.js为 const {mysql}=require('../qcloud') module.exports=asy ...
- Vue+koa2开发一款全栈小程序(7.图书录入功能)
1.图书录入功能 1.获取图书信息 1.在mydemo/src/until.js中封装工具函数post和get // 工具函数 import config from './config' // htt ...
- Vue+koa2开发一款全栈小程序(1.课程介绍+2.ES6入门)
1.课程介绍 1.课程概述 1.做什么? Vue+koa2开发一款全栈小程序 2.哪些功能? 个人中心.图书列表.图书详情.图书评论.个人评论列表 3.技术栈 小程序.Vue.js.koa2.koa- ...
- Vue+koa2开发一款全栈小程序(5.服务端环境搭建和项目初始化)
1.微信公众平台小程序关联腾讯云 腾讯云的开发环境是给免费的一个后台,但是只能够用于开发,如果用于生产是需要花钱的,我们先用开发环境吧 1.用小程序开发邮箱账号登录微信公众平台 2.[设置]→[开发者 ...
- Vue+koa2开发一款全栈小程序(3.vue入门、Mpvue入门)
1.Vue-cli 1.新建一个vue项目 打开cmd 官方命令行工具 npm install -g vue-cli //安装脚手架 cd到你想要存放demo的目录下,然后 vue init webp ...
- Vue+koa2开发一款全栈小程序(6.个人中心)
1.用户信息的获取和展示 1.初始化数据库 cd到server目录下,执行 node tools/initdb.js 登录mysql控制界面,查看初始化以后生成的表 show databases; u ...
- Vue+koa2开发一款全栈小程序(4.Koa入门)
1.Koa是什么? 基于nodejs平台的下一代web开发框架 1.Express原班人马打造,更精简 2.Async+await处理异步 3.洋葱圈型的中间件机制 新建一个koa项目 1.打开cmd ...
- 微信小程序云开发-从0打造云音乐全栈小程序
第1章 首门小程序“云开发”课程,你值得学习本章主要介绍什么是小程序云开发以及学习云开发的重要性,并介绍项目的整体架构,真机演示项目功能,详细介绍整体课程安排.课程适用人群以及需要掌握的前置知识.通过 ...
- 从零开发一款自己的小程序UI组件库(一)
写在前面:有开发过小程序的朋友肯定知道组件化开发的特性,高内聚与低耦合.使用已有的UI组件库,诸如:vantUI-weapp.minUI-weapp等UI组件库的诞生使我们的开发速度大大的加快,丰富的 ...
随机推荐
- 测者的性能测试手册:快速安装LoadRunner Linux上的Generator
安装和初始化 安装包 上传Linux.zip(LoadRunner Generator for Linux.zip,后台回复loadrunner获取下载地址),然后通过如下命令: unzip Linu ...
- 获取spring security用户相关信息
在JSP中获得 使用spring security的标签库 在页面中引入标签 <%@ taglib prefix="sec" uri="http://www.spr ...
- PHAR系列之导言
由于之前都是在现成的PHP框架下写web项目,一般都只专注于框架内部的使用跟优化.但是对于一些PHP很有特色的功能跟特性很少过多的深入了解.最近做项目调研的时候偶尔注意到一个PHP中一个比较常见的概念 ...
- crosstool-ng-1.22.0搭建开发环境
Ubuntu16.04无法安装libtool,只能在Ubuntu14.04以下版本安装. cp 下载/crosstool-ng-1.22.0.tar.bz2 /home/hou/ tar -x ...
- SQLServer之视图简介
视图定义 视图是一个虚拟表,其内容由查询定义. 同表一样,视图包含一系列带有名称的列和行数据. 视图在数据库中并不是以数据值存储集形式存在,除非是索引视图. 行和列数据来自由定义视图的查询所引用的表, ...
- LeetCode算法题-Longest Uncommon Subsequence I(Java实现)
这是悦乐书的第252次更新,第265篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第119题(顺位题号是521).给定一组两个字符串,您需要找到这组两个字符串中最长的不同 ...
- EXTJS的使用
最近一段时间一直使用Extjs作为前端,通过HTTP与.net后端进行交互,今天总结一下EXTJS,方便以后复习. 1.概念: ExtJS可以用来开发RIA也即富客户端的AJAX应用,是一个用java ...
- 腾讯大数据平台Oceanus: A one-stop platform for real time stream processing powered by Apache Flink
January 25, 2019Use Cases, Apache Flink The Big Data Team at Tencent In recent years, the increa ...
- react组件之间的通信
通过props传递 共同的数据放在父组件上, 特有的数据放在自己组件内部(state),通过props可以传递一般数据和函数数据, 只能一层一层传递 一般数据-->父组件传递数据给子组件--&g ...
- hbase 迁库移库步骤
1 将数据导出 hbase org.apache.hadoop.hbase.mapreduce.Export t_zyzx_grzyfwtjxxb /hbase/data_backup/2018103 ...