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>

效果图

原文地址:https://www.cnblogs.com/xuepangzi/p/9796048.html

时间: 2024-10-24 05:24:54

Vue+koa2开发一款全栈小程序(8.图书列表页)的相关文章

Vue+koa2开发一款全栈小程序(1.课程介绍+2.ES6入门)

1.课程介绍 1.课程概述 1.做什么? Vue+koa2开发一款全栈小程序 2.哪些功能? 个人中心.图书列表.图书详情.图书评论.个人评论列表 3.技术栈 小程序.Vue.js.koa2.koa-router.mysql 2.课程亮点 1.项目前后端分离开发 Vue+koa2开发一款全栈小程序 2.完整流程,一步不少 注册小程序账号,前后端开发,打包,正式上线 2.小程序环境搭建 1.后台地址: https://mp.weixin.qq.com/ 2.文档地址: https://develo

Vue+koa2开发一款全栈小程序(5.服务端环境搭建和项目初始化)

1.微信公众平台小程序关联腾讯云 腾讯云的开发环境是给免费的一个后台,但是只能够用于开发,如果用于生产是需要花钱的,我们先用开发环境吧 1.用小程序开发邮箱账号登录微信公众平台 2.[设置]→[开发者工具]→第一次是git管理,开启腾讯云关联 3.会一路跳转到腾讯云的[开通开发环境]的流程要走 1.已经完成 2.下载安装微信开发者工具,也已经下载安装了 3.下载Node.js版本Demo 将demo中的server文件夹,复制到mpvue项目中 在项目下的project.config.json中

微信小程序云开发-从0打造云音乐全栈小程序

第1章 首门小程序“云开发”课程,你值得学习本章主要介绍什么是小程序云开发以及学习云开发的重要性,并介绍项目的整体架构,真机演示项目功能,详细介绍整体课程安排.课程适用人群以及需要掌握的前置知识.通过本章的学习,能够使大家对本门课程有一个整体的了解.... 第2章 云开发介绍以及从0构建项目本章会详细介绍小程序云开发与Serverless,并介绍如何开通小程序云开发及控制台的功能,并且初始化项目代码,讲解airbnb/javascript代码规范. 第3章 播放列表功能实现本章完成歌单列表与歌曲

从零开发一款自己的小程序UI组件库(二)

写在前面:从零开发一款自己的小程序UI组件库(一) 上节我们讲到初始化组件库模板.模板文件概述.模板上传npm以及npm包文件下载至本地并运用到项目.这节我们继续,内容主要有基础UI组件库的搭建(button组件的实例)以及如何在本地使用npm link调试npm包项目. 本节所用到的物料:mineui-weapp组件库v1.1.weapp-for-mineui程序v1.1 1.开发基础组件button 我们上节有提到,要开发组件库的话,需要在官方单组件模板的基础上,①修改tools目录下的co

云开发初探 —— 更简便的小程序开发模式

欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由李成熙heyli发表于云+社区专栏 李成熙,腾讯云高级工程师.2014年度毕业加入腾讯AlloyTeam,先后负责过QQ群.花样直播.腾讯文档等项目.2018年加入腾讯云云开发团队.专注于性能优化.工程化和小程序服务. 小程序诞生以来,业界关注小程序前端的技术演进较多,因此众多小程序前端的框架.工具也应运而生,前端开发效率大大提高,而后台的开发技术则关注不多,痛点不少,具体痛在哪里呢? 小程序后台开发之痛 第一个是脑袋瓜疼,怎么疼

如何快速开发一套微信商城小程序?

小程序的价值相信已经不用我多说,未来大部分应用场景都将使用微信小程序进行研发.开发一套商城小程序需要哪些步骤,怎么开通?快搞定小编来为大家解疑. 第一步:确定商城小程序产品功能.UI风格 在设计小程序的时候一定要符合"轻便.即用即走"的定位,小程序只是场景化的产品,功能不宜过多,更多的是起到平台覆盖和完善用户使用场景的作用. 第二步:注册微信小程序并申请微信支付 进入微信公众平台mp.weixin.qq.com,按提示注册即可.需注意的是,个人暂时不能注册小程序,注册时必须提供企业营业

【转】两天快速开发一个自己的微信小程序 悬笔e绝 www.xuanbiyijue.com

文章出处:https://www.cnblogs.com/xuanbiyijue/p/7980010.html 作者: 悬笔e绝 www.xuanbiyijue.com 两天快速开发一个自己的微信小程序 一.写在前面 1.为什么要学小程序开发? 对于前端开发而言,微信小程序因为其简单快速.开发成本低.用户流量巨大等特点,也就成了前端开发工程师必会的一个技能. 2.先放上我做的小程序 可以在微信小程序搜索“悬笔e绝”,或者用微信扫描下面的二维码哦 (1)欢迎页:这个logo是当年念大学给社团做的l

基于Taro与Typescript开发的网易云音乐小程序

基于Taro与网易云音乐api开发,技术栈主要是:typescript+taro+taro-ui+redux,目前主要是着重小程序端的展示,主要也是借此项目强化下上述几个技术栈的使用,通过这个项目也可以帮助你快速使用Taro开发一个属于你自己的小程序- 源码地址:taro-music,感兴趣的话可以star关注下,功能会进行持续完善 快速开始 首先需要在src目录下创建一个config.ts,可以根据自己的需要将其替换成线上地址,接口服务是使用的NeteaseCloudMusicApi expo

微信小程序,我的英雄列表

最近微信小程序炒得火热,就跟成都的这个房价一样.昨天我也尝试了一下,做了一个自己的英雄列表.今天将自己的制作过程记录于此. 1.下载微信开发者工具 官网链接:https://mp.weixin.qq.com/debug/wxadoc/dev/devtools/download.html?t=1475052055364,下载完成之后默认安装即可 2.新建项目 打开微信开发者工具,(首次需要微信扫码登录),如下图所示,点击添加项目,然后依次输入APPID,项目名称,并选择你的项目所在的目录(本地目录