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组件库的诞生使我们的开发速度大大的加快,丰富的 ...
随机推荐
- 从0开始的Python学习008变量
局部变量 在我们定义函数的过程中,函数内外具有相同名称的变量是没有任何关系的.变量的名称对于函数来说是局部的,而它所在的代码块就是它的作用域. 使用局部变量 #局部变量 def func(x): pr ...
- Highcharts入坑记
第一次用Highcharts画一个温度湿度变化的图片,因为不熟悉跳了好多坑,特记录下: 一.JS引用 <script src="~/Scripts/jquery.min.js" ...
- Eclipse链接数据库
在eclipse中找到数据库 选择数据库 然后点击next 填写数据库信息 选择需要执行的SQL语句 ALT+X 或者 右键点击execute selected text: 执行结果: 有问题请在评论 ...
- Java实现Sunday百万级数据量的字符串快速匹配算法
背景 在平时的项目中,几乎都会用到比较两个字符串时候相等的问题,通常是用==或者equals()进行,这是在数据相对比较少的情况下是没问题的,当数据库中的数据达到几十万甚至是上百万千万的数 ...
- day 6 - 1 知识点小节
python2 与 python3 的区别 1. print.input.生成器 #python2 print() print 'abc' range() xrange() 生成器 raw_input ...
- Django-CRM项目学习(三)-stark的页面展示
开始今日份整理,主要为stark组件的增删改以及model_form组件的使用以及form组件的回顾 1.list_display_link功能 功能:客制化字段进行跳转到指定的页面(编辑页面) 1. ...
- ansible 与 Jinja2的结合
1.文件架构 [root@master template]# tree . ├── jinj2_test.yml ├── meta ├── tasks ├── templates │ └── te ...
- Elasticsearch 通关教程(二): 索引映射Mapping问题
数据库建表的时候,我们的DDL语句一般都会指定每个字段的存储类型,例如:varchar,int,datetime等等,目的很明确,就是更精确的存储数据,防止数据类型格式混乱. CREATE TABLE ...
- HTML页面全屏/退出全屏
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- centos6.8 配置mysql赋予mysql远程连接权限
1.关掉防火墙 2.检查3306端口是否开放 3.修改用户用户权限 GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY '您的数据库密码' ...