Vue+koa2开发一款全栈小程序(9.图书详情页)
1.获取图书详情
1.修改server/controllers/bookdetail.js为
const {mysql}=require('../qcloud') module.exports=async(ctx)=>{
const {id}=ctx.request.query
const detail=await mysql('books')
.select('books.*','csessioninfo.user_info')
.join('csessioninfo','books.openid','csessioninfo.open_id')
.where('id',id)
.first()
const info=JSON.parse(detail.user_info)
ctx.state.data=Object.assign({},detail,{
user_info:{
name:info.nickName,
image:info.avatarUrl
}
}) }
2.在mydemo/src/components/BookInfo.vue
<template>
<div class="bookinfo">
<div class="thumb">
<img class="back"
:src="info.image"
mode="aspectFull">
<img class="img"
:src="info.image"
mode="aspectFit">
<div class="info">
<div class="title">
{{info.title}}
</div>
<div class="author">
{{info.author}}
</div>
</div>
</div>
<div class="detail">
<img :src="userinfo.image" class="avatar" mode="aspectFit">
{{userinfo.name}}
<div class="right text-primary">
{{info.rate}}分<Rate :value='info.rate'></Rate>
</div>
</div>
<div class="detail">
{{info.publisher}}
<div class="right">
{{info.price}}
</div> </div>
</div>
</template>
<script>
import Rate from '@/components/Rate'
export default {
components:{
Rate
}, props:['info'], computed:{
userinfo(){
return this.info.user_info||{}
}
} }
</script>
<style lang="scss">
.bookinfo{
font-size: 14px;
.right{
float: right;
}
.detail{
padding: 5px 10px;
.avatar{
width: 20px;
height: 20px;
border-radius: 50%;
vertical-align: middle;
}
}
.thumb{
width: 750rpx;
height: 500rpx;
overflow: hidden;
position: relative;
.back{
filter: blur(15px);
width: 100%;
}
.img{
position: absolute;
width: 100%;
height: 300rpx;
left: 0;
top:30rpx;
}
.info{
color: white;
position:absolute;
width: 100%;
left: 0;
top: 330rpx;
text-align: center;
.title{
font-size: 20px;
}
.author{
font-size: 14px;
}
}
}
} </style>
3.在src/pages/detail/index.vue中,加入代码,才可以有分享转发功能
onShareAppMessage: (res) => {
if (res.from === 'button') {
console.log("来自页面内转发按钮");
console.log(res.target);
}
else {
console.log("来自右上角转发菜单")
}
return {
// title: '',
// path: '/pages/share/share?id=123',
// imageUrl: "/images/1.jpg",
success: (res) => {
console.log("转发成功", res);
},
fail: (res) => {
console.log("转发失败", res);
}
}
}
index.vue
<template>
<div> <BookInfo :info='info'></BookInfo>
</div>
</template>
<script> import {get} from '@/until' import BookInfo from '@/components/BookInfo' export default {
components:{
BookInfo
}, data(){
return{
bookid:'',
info:{}
}
}, methods:{
async getDetail(){
const info=await get('/weapp/bookdetail',{id:this.bookid})
wx.setNavigationBarTitle({title:info.data.title})
this.info=info.data
}
}, mounted(){
this.bookid=this.$root.$mp.query.id //this.$root.$mp.query获取跳转链接传过来的对象集合
this.getDetail()
}, onShareAppMessage: (res) => {
if (res.from === 'button') {
console.log("来自页面内转发按钮");
console.log(res.target);
}
else {
console.log("来自右上角转发菜单")
}
return {
// title: '',
// path: '/pages/share/share?id=123',
// imageUrl: "/images/1.jpg",
success: (res) => {
console.log("转发成功", res);
},
fail: (res) => {
console.log("转发失败", res);
}
}
} }
</script>
<style> </style>
2.图书tags和简介显示
1.在server/controllers/bookdetail.js中修改代码,增添返回tag和简介的代码
const {mysql}=require('../qcloud') module.exports=async(ctx)=>{
const {id}=ctx.request.query
const detail=await mysql('books')
.select('books.*','csessioninfo.user_info')
.join('csessioninfo','books.openid','csessioninfo.open_id')
.where('id',id)
.first()
const info=JSON.parse(detail.user_info)
ctx.state.data=Object.assign({},detail,{
tags:detail.tags.split(','),
summary:detail.summary.split('\n'),
user_info:{
name:info.nickName,
image:info.avatarUrl
}
}) }
2.在mydemo/src/components/BookInfo.vue
<template>
<div class="bookinfo">
<div class="thumb">
<img class="back"
:src="info.image"
mode="aspectFull">
<img class="img"
:src="info.image"
mode="aspectFit">
<div class="info">
<div class="title">
{{info.title}}
</div>
<div class="author">
{{info.author}}
</div>
</div>
</div>
<div class="detail">
<img :src="userinfo.image" class="avatar" mode="aspectFit">
{{userinfo.name}}
<div class="right text-primary">
{{info.rate}}分<Rate :value='info.rate'></Rate>
</div>
</div>
<div class="detail">
{{info.publisher}}
<div class="right">
{{info.price}}
</div>
</div>
<div class="tags">
<div class="badge" :key="tag" v-for="tag in info.tags">{{tag}}</div>
</div>
<div class="summary">
<p :key="i" v-for="(sum,i) in info.summary">{{sum}}</p>
</div>
</div>
</template>
<script>
import Rate from '@/components/Rate'
export default {
components:{
Rate
}, props:['info'], computed:{
userinfo(){
return this.info.user_info||{}
}
} }
</script>
<style lang="scss">
.bookinfo{
font-size: 14px;
.right{
float: right;
}
.detail{
padding: 5px 10px;
.avatar{
width: 20px;
height: 20px;
border-radius: 50%;
vertical-align: middle;
}
}
.thumb{
width: 750rpx;
height: 500rpx;
overflow: hidden;
position: relative;
.back{
filter: blur(15px);
width: 100%;
}
.img{
position: absolute;
width: 100%;
height: 300rpx;
left: 0;
top:30rpx;
}
.info{
color: white;
position:absolute;
width: 100%;
left: 0;
top: 330rpx;
text-align: center;
.title{
font-size: 20px;
}
.author{
font-size: 14px;
}
}
}
.badge{
display: inline-block;
margin:5px;
padding: 5px;
border-radius: 10px;
border:1px #EA5A49 solid;
color: #EA5A49;
}
.summary{
padding: 0 15px;
margin-top: 10px;
p{
text-indent: 2em;
font-size: 14px;
margin-top: 5px;
}
}
} </style>
效果图
3.获取手机型号、地理位置,用户评论功能
1.评论框和获取用户手机型号,在src/pages/detail/index.vue中
<template>
<div> <BookInfo :info='info'></BookInfo> <div class="comment">
<textarea v-model="comment"
class="textarea"
:maxlength="100"
placeholder="请输入图书短评"></textarea>
<div class="location">
地理位置:
<switch color='#EA5A49' :checked='location' @change="getGeo"></switch>
<span class="text-primary">{{location}}</span>
</div>
<div class="phone">
手机型号:
<switch color='#EA5A49' :checked='phone' @change="getPhone"></switch>
<span class="text-primary">{{phone}}</span>
</div>
</div> </div>
</template>
<script> import {get} from '@/until' import BookInfo from '@/components/BookInfo' export default {
components:{
BookInfo
}, data(){
return{
bookid:'',
info:{},
comment:'',
location:'',
phone:''
}
}, methods:{
async getDetail(){
const info=await get('/weapp/bookdetail',{id:this.bookid})
wx.setNavigationBarTitle({title:info.data.title})
this.info=info.data
}, getGeo(){},
getPhone(e){
if(e.target.value){
const phoneInfo=wx.getSystemInfoSync()
console.log(phoneInfo)
this.phone=phoneInfo.model
}else{
// 没选中
this.phone=''
}
}
}, mounted(){
this.bookid=this.$root.$mp.query.id //this.$root.$mp.query获取跳转链接传过来的对象集合
this.getDetail()
}, onShareAppMessage: (res) => {
if (res.from === 'button') {
console.log("来自页面内转发按钮");
console.log(res.target);
}
else {
console.log("来自右上角转发菜单")
}
return {
// title: '',
// path: '/pages/share/share?id=123',
// imageUrl: "/images/1.jpg",
success: (res) => {
console.log("转发成功", res);
},
fail: (res) => {
console.log("转发失败", res);
}
}
} }
</script>
<style lang='scss'>
.comment{
margin-top: 10px;
.textarea{
width: 730rpx;
height: 200rpx;
background: #eee;
padding: 10rpx; }
.location{
margin-top: 10px;
}
.phone{
margin-top:10px;
}
}
</style>
2.获取经纬度 在src/pages/detail/index.vue中
<template>
<div> <BookInfo :info='info'></BookInfo> <div class="comment">
<textarea v-model="comment"
class="textarea"
:maxlength="100"
placeholder="请输入图书短评"></textarea>
<div class="location">
地理位置:
<switch color='#EA5A49' :checked='location' @change="getGeo"></switch>
<span class="text-primary">{{location}}</span>
</div>
<div class="phone">
手机型号:
<switch color='#EA5A49' :checked='phone' @change="getPhone"></switch>
<span class="text-primary">{{phone}}</span>
</div>
</div> </div>
</template>
<script> import {get} from '@/until' import BookInfo from '@/components/BookInfo' export default {
components:{
BookInfo
}, data(){
return{
bookid:'',
info:{},
comment:'',
location:'',
phone:''
}
}, methods:{
async getDetail(){
const info=await get('/weapp/bookdetail',{id:this.bookid})
wx.setNavigationBarTitle({title:info.data.title})
this.info=info.data
}, getGeo(e){
if(e.target.value){
wx.getLocation({
success:geo=>{
console.log(geo)
}
})
}else{
this.location=''
}
},
getPhone(e){
if(e.target.value){
const phoneInfo=wx.getSystemInfoSync()
console.log(phoneInfo)
this.phone=phoneInfo.model
}else{
// 没选中
this.phone=''
}
}
}, mounted(){
this.bookid=this.$root.$mp.query.id //this.$root.$mp.query获取跳转链接传过来的对象集合
this.getDetail()
}, onShareAppMessage: (res) => {
if (res.from === 'button') {
console.log("来自页面内转发按钮");
console.log(res.target);
}
else {
console.log("来自右上角转发菜单")
}
return {
// title: '',
// path: '/pages/share/share?id=123',
// imageUrl: "/images/1.jpg",
success: (res) => {
console.log("转发成功", res);
},
fail: (res) => {
console.log("转发失败", res);
}
}
} }
</script>
<style lang='scss'>
.comment{
margin-top: 10px;
.textarea{
width: 730rpx;
height: 200rpx;
background: #eee;
padding: 10rpx; }
.location{
margin-top: 10px;
}
.phone{
margin-top:10px;
}
}
</style>
效果图
3.通过配合百度地图的api,通过经纬度获取地理位置
1.百度地图开放平台网址:
http://lbsyun.baidu.com/apiconsole/key
2.服务文档和使用方法网址:
http://lbsyun.baidu.com/index.php?title=webapi/guide/webservice-geocoding
根据使用指南,注册,申请百度开发者,获取服务秘钥(AK)
部分过程图
3.全球逆地理编码(给经纬度输出地点名称)文档地址:
http://lbsyun.baidu.com/index.php?title=webapi/guide/webservice-geocoding-abroad
4.在src/pages/detail/index.vue中
<template>
<div> <BookInfo :info='info'></BookInfo> <div class="comment">
<textarea v-model="comment"
class="textarea"
:maxlength="100"
placeholder="请输入图书短评"></textarea>
<div class="location">
地理位置:
<switch color='#EA5A49' :checked='location' @change="getGeo"></switch>
<span class="text-primary">{{location}}</span>
</div>
<div class="phone">
手机型号:
<switch color='#EA5A49' :checked='phone' @change="getPhone"></switch>
<span class="text-primary">{{phone}}</span>
</div>
</div> </div>
</template>
<script> import {get} from '@/until' import BookInfo from '@/components/BookInfo' export default {
components:{
BookInfo
}, data(){
return{
bookid:'',
info:{},
comment:'',
location:'',
phone:''
}
}, methods:{
async getDetail(){
const info=await get('/weapp/bookdetail',{id:this.bookid})
wx.setNavigationBarTitle({title:info.data.title})
this.info=info.data
}, getGeo(e){
const ak='你的ak'
let url='http://api.map.baidu.com/geocoder/v2/'
if(e.target.value){
wx.getLocation({
success:geo=>{
wx.request({
url,
data:{
ak,
location:`${geo.latitude},${geo.longitude}`,
output:'json'
},
success:res=>{
// console.log(res)
if(res.data.status==0){
this.location=res.data.result.addressComponent.city
}else{
// console.log('出错了')
this.location='未知地点'
}
}
})
// console.log(geo)
}
})
}else{
this.location=''
}
},
getPhone(e){
if(e.target.value){
const phoneInfo=wx.getSystemInfoSync()
console.log(phoneInfo)
this.phone=phoneInfo.model
}else{
// 没选中
this.phone=''
}
}
}, mounted(){
this.bookid=this.$root.$mp.query.id //this.$root.$mp.query获取跳转链接传过来的对象集合
this.getDetail()
}, onShareAppMessage: (res) => {
if (res.from === 'button') {
console.log("来自页面内转发按钮");
console.log(res.target);
}
else {
console.log("来自右上角转发菜单")
}
return {
// title: '',
// path: '/pages/share/share?id=123',
// imageUrl: "/images/1.jpg",
success: (res) => {
console.log("转发成功", res);
},
fail: (res) => {
console.log("转发失败", res);
}
}
} }
</script>
<style lang='scss'>
.comment{
margin-top: 10px;
.textarea{
width: 730rpx;
height: 200rpx;
background: #eee;
padding: 10rpx; }
.location{
margin-top: 10px;
}
.phone{
margin-top:10px;
}
}
</style>
效果图,emmmm,通过经纬度这么定位,而且还是wifi的经纬度,除了城市是准的,其他偏差还挺大的,感觉还是通过ip定位比较靠谱一点,嗯。
4.点击评论发起请求
1.功能定义:
一个用户只能评论一次
如果已经评论过了,再次访问就看到评论列表,而不是评论输入框
2.在mydemo/src/pages/detail/index/vue中,增加button评论按钮,样式,以及addComment方法
<template>
<div> <BookInfo :info='info'></BookInfo> <div class="comment">
<textarea v-model="comment"
class="textarea"
:maxlength="100"
placeholder="请输入图书短评"></textarea>
<div class="location">
地理位置:
<switch color='#EA5A49' :checked='location' @change="getGeo"></switch>
<span class="text-primary">{{location}}</span>
</div>
<div class="phone">
手机型号:
<switch color='#EA5A49' :checked='phone' @change="getPhone"></switch>
<span class="text-primary">{{phone}}</span>
</div>
<button class="btn" @click="addComment">
评论
</button>
</div> </div>
</template>
<script> import {get,post,showModal} from '@/until' import BookInfo from '@/components/BookInfo' export default {
components:{
BookInfo
}, data(){
return{
userinfo:'',
bookid:'',
info:{},
comment:'',
location:'',
phone:''
}
}, methods:{
async getDetail(){
const info=await get('/weapp/bookdetail',{id:this.bookid})
wx.setNavigationBarTitle({title:info.data.title})
this.info=info.data
}, getGeo(e){
const ak='5hvI2CGwH5YO4ZT85MjpxXgk01WWSGOi'
let url='http://api.map.baidu.com/geocoder/v2/'
if(e.target.value){
wx.getLocation({
success:geo=>{
wx.request({
url,
data:{
ak,
location:`${geo.latitude},${geo.longitude}`,
output:'json'
},
success:res=>{
// console.log(res)
if(res.data.status==0){
this.location=res.data.result.addressComponent.city
}else{
// console.log('出错了')
this.location='未知地点'
}
}
})
// console.log(geo)
}
})
}else{
this.location=''
}
},
getPhone(e){
if(e.target.value){
const phoneInfo=wx.getSystemInfoSync()
// console.log(phoneInfo)
this.phone=phoneInfo.model
}else{
// 没选中
this.phone=''
}
}, async addComment(){
// 评论内容 手机型号 地理位置 图书id 用户的openid
const data={
openid:this.userinfo.openId,
bookid:this.bookid,
comment:this.comment,
phone:this.phone,
location:this.location
}
// console.log(data)
if(!this.comment){
return
}
try{
await post('/weapp/addcomment',data)
this.comment=''
}catch(e){
showModel('失败',e.msg)
} }
}, mounted(){
this.bookid=this.$root.$mp.query.id //this.$root.$mp.query获取跳转链接传过来的对象集合
this.getDetail()
const userinfo=wx.getStorageSync('userinfo')
// console.log(888,userinfo)
if(userinfo){
this.userinfo=userinfo
}
}, onShareAppMessage: (res) => {
if (res.from === 'button') {
console.log("来自页面内转发按钮");
console.log(res.target);
}
else {
console.log("来自右上角转发菜单")
}
return {
// title: '',
// path: '/pages/share/share?id=123',
// imageUrl: "/images/1.jpg",
success: (res) => {
console.log("转发成功", res);
},
fail: (res) => {
console.log("转发失败", res);
}
}
} }
</script>
<style lang='scss'>
.comment{
margin-top: 10px;
.textarea{
width: 730rpx;
height: 200rpx;
background: #eee;
padding: 10rpx; }
.location{
margin-top: 10px;
}
.phone{
margin-top:10px;
margin-bottom: 10px;
}
}
</style>
效果图
5.后台接口的实现
1.打开mysql数据库对话框,新建评论表comments
show databases; /*查看数据库列表*/
use cauth; /* 使用cAuth数据库*/ CREATE TABLE `comments` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`openid` varchar(100) NOT NULL,
`bookid` varchar(100) NOT NULL,
`comment` varchar(200) NOT NULL,
`phone` varchar(20) DEFAULT NULL,
`location` varchar(20) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
/*创建comments表*/ desc comments; /* 查看comments表的字段*/ select * from comments; /*查看comments的记录*/
2.在server/routes/index.js内增加路由
router.post('/addcomment',controllers.addcomment)
3.在server/controllers目录下新建addComment.js
const {mysql} =require('../qcloud') module.exports=async (ctx)=>{
const {bookid,comment,openid,location,phone}=ctx.request.body
console.log(bookid,comment,openid,location,phone)
try{
await mysql('comments').insert({bookid,comment,openid,location,phone})
ctx.state.data={
msg:'succcess'
}
}catch(e){
ctx.state={
code:-1,
data:{
msg:'评论失败:'+e.sqlMessage
}
}
}
}
效果图
4.评论列表实现
1.在mydemo/src/pages/detail/index/vue中的mounted中增加获取评论列表this.getComments()方法,在methods中编写
<template>
<div> <BookInfo :info='info'></BookInfo> <div class="comment">
<textarea v-model="comment"
class="textarea"
:maxlength="100"
placeholder="请输入图书短评"></textarea>
<div class="location">
地理位置:
<switch color='#EA5A49' :checked='location' @change="getGeo"></switch>
<span class="text-primary">{{location}}</span>
</div>
<div class="phone">
手机型号:
<switch color='#EA5A49' :checked='phone' @change="getPhone"></switch>
<span class="text-primary">{{phone}}</span>
</div>
<button class="btn" @click="addComment">
评论
</button>
</div> </div>
</template>
<script> import {get,post,showModal} from '@/until' import BookInfo from '@/components/BookInfo' export default {
components:{
BookInfo
}, data(){
return{
userinfo:'',
bookid:'',
info:{},
comment:'',
comments:[],
location:'',
phone:''
}
}, methods:{
async getDetail(){
const info=await get('/weapp/bookdetail',{id:this.bookid})
wx.setNavigationBarTitle({title:info.data.title})
this.info=info.data
}, getGeo(e){
const ak='5hvI2CGwH5YO4ZT85MjpxXgk01WWSGOi'
let url='http://api.map.baidu.com/geocoder/v2/'
if(e.target.value){
wx.getLocation({
success:geo=>{
wx.request({
url,
data:{
ak,
location:`${geo.latitude},${geo.longitude}`,
output:'json'
},
success:res=>{
// console.log(res)
if(res.data.status==0){
this.location=res.data.result.addressComponent.city
}else{
// console.log('出错了')
this.location='未知地点'
}
}
})
// console.log(geo)
}
})
}else{
this.location=''
}
},
getPhone(e){
if(e.target.value){
const phoneInfo=wx.getSystemInfoSync()
// console.log(phoneInfo)
this.phone=phoneInfo.model
}else{
// 没选中
this.phone=''
}
}, async addComment(){
// 评论内容 手机型号 地理位置 图书id 用户的openid
const data={
openid:this.userinfo.openId,
bookid:this.bookid,
comment:this.comment,
phone:this.phone,
location:this.location
}
// console.log(data)
if(!this.comment){
return
}
try{
await post('/weapp/addcomment',data)
this.comment=''
}catch(e){
showModel('失败',e.msg)
} }, async getComments(){
const comments=await get('/weapp/commentlist',{bookid:this.bookid})
this.comments=comments
}
}, mounted(){
this.bookid=this.$root.$mp.query.id //this.$root.$mp.query获取跳转链接传过来的对象集合
this.getDetail()
const userinfo=wx.getStorageSync('userinfo')
// console.log(888,userinfo)
if(userinfo){
this.userinfo=userinfo
}
this.getComments()
}, onShareAppMessage: (res) => {
if (res.from === 'button') {
console.log("来自页面内转发按钮");
console.log(res.target);
}
else {
console.log("来自右上角转发菜单")
}
return {
// title: '',
// path: '/pages/share/share?id=123',
// imageUrl: "/images/1.jpg",
success: (res) => {
console.log("转发成功", res);
},
fail: (res) => {
console.log("转发失败", res);
}
}
} }
</script>
<style lang='scss'>
.comment{
margin-top: 10px;
.textarea{
width: 730rpx;
height: 200rpx;
background: #eee;
padding: 10rpx; }
.location{
margin-top: 10px;
}
.phone{
margin-top:10px;
margin-bottom: 10px;
}
}
</style>
2.在server/router/index.js中增加路由
router.get('/commentlist',controllers.commentlist)
3.在server/controllers目录下新建commentlist.js
const {mysql}=require('../qcloud') module.exports=async(ctx)=>{
const {bookid}=ctx.request.query
const comments=await mysql('comments')
.select('comments.*','cSessionInfo.user_info')
.join('cSessionInfo','comments.openid','cSessionInfo.open_id')
.where('bookid',bookid)
ctx.state.data={
list:comments.map(v=>{
const info=JSON.parse(v.user_info)
return Object.assign({},v,{
title:info.nickName,
image:info.avatarUrl
})
})
}
}
效果图
5.评论列表封装成一个组件
1.在src/components目录下新建CommentList.vue
<template>
<div class="comment-list">
<div class="page-title" v-if="comments.length">
我的评论
</div>
<div class="comment" v-for="comment in comments" :key="comment.id">
<div class="user">
<div class="inline">
<img class="avatar" :src="comment.image" mode='aspectFit'>
{{comment.title}}
</div>
<div class="right">
{{comment.location||'未知地点'}}
<span class="text-primary">--</span>
{{comment.phone||'未知型号'}}
</div>
</div>
<div style="clear:both;"></div>
<div class="content">
{{comment.comment}}
</div>
</div>
</div>
</template>
<script>
export default {
props:['comments']
}
</script> <style lang='scss'>
.comment-list{
background: #eee;
font-size: 14px;
.page-title{
padding-left: 20px;
background: #eee;
line-height: 40px;
font-size: 16px;
}
.comment{
background: white;
margin-bottom: 10px;
padding: 5px 20px;
.content{
margin: 10px;
}
.user{
.inline{
float: left;
}
.right{
float:right;
}
.avatar{
width:20px;
height: 20px;
border-radius: 50%;
}
}
} }
</style>
2.在src/pages/detail/index.vue中修改增加代码
<template>
<div> <BookInfo :info='info'></BookInfo> <CommentList :comments="comments"></CommentList> <div class="comment" v-if="showAdd">
<textarea v-model="comment"
class="textarea"
:maxlength="100"
placeholder="请输入图书短评"></textarea>
<div class="location">
地理位置:
<switch color='#EA5A49' :checked='location' @change="getGeo"></switch>
<span class="text-primary">{{location}}</span>
</div>
<div class="phone">
手机型号:
<switch color='#EA5A49' :checked='phone' @change="getPhone"></switch>
<span class="text-primary">{{phone}}</span>
</div>
<button class="btn" @click="addComment">
评论
</button>
</div> <div v-else class="text-footer">
未登录或者已经评论过啦
</div> <button class="btn" open-type="share">分享给好友</button> </div>
</template>
<script> import {get,post,showModal} from '@/until' import BookInfo from '@/components/BookInfo' import CommentList from '@/components/CommentList' export default {
components:{
BookInfo,
CommentList
}, data(){
return{
userinfo:'',
bookid:'',
info:{},
comment:'',
comments:[],
location:'',
phone:''
}
}, methods:{
async getDetail(){
const info=await get('/weapp/bookdetail',{id:this.bookid})
wx.setNavigationBarTitle({title:info.data.title})
this.info=info.data
}, getGeo(e){
const ak='5hvI2CGwH5YO4ZT85MjpxXgk01WWSGOi'
let url='http://api.map.baidu.com/geocoder/v2/'
if(e.target.value){
wx.getLocation({
success:geo=>{
wx.request({
url,
data:{
ak,
location:`${geo.latitude},${geo.longitude}`,
output:'json'
},
success:res=>{
// console.log(res)
if(res.data.status==0){
this.location=res.data.result.addressComponent.city
}else{
// console.log('出错了')
this.location='未知地点'
}
}
})
// console.log(geo)
}
})
}else{
this.location=''
}
},
getPhone(e){
if(e.target.value){
const phoneInfo=wx.getSystemInfoSync()
// console.log(phoneInfo)
this.phone=phoneInfo.model
}else{
// 没选中
this.phone=''
}
}, async addComment(){
// 评论内容 手机型号 地理位置 图书id 用户的openid
const data={
openid:this.userinfo.openId,
bookid:this.bookid,
comment:this.comment,
phone:this.phone,
location:this.location
}
// console.log(data)
if(!this.comment){
return
}
try{
await post('/weapp/addcomment',data)
this.comment=''
this.getComments()
}catch(e){
showModel('失败',e.msg)
} }, async getComments(){
const comments=await get('/weapp/commentlist',{bookid:this.bookid})
// console.log(11111,comments.data.list[0])
this.comments=comments.data.list }
}, computed:{
showAdd(){
// 没登录
if(!this.userinfo.openId){
return false
}
if(this.comments.filter(v=>v.openid==this.userinfo.openId).length){
return false
}
return true
}
}, mounted(){
this.bookid=this.$root.$mp.query.id //this.$root.$mp.query获取跳转链接传过来的对象集合
this.getDetail()
const userinfo=wx.getStorageSync('userinfo')
// console.log(888,userinfo)
if(userinfo){
this.userinfo=userinfo
}
this.getComments() }, onShareAppMessage: (res) => {
if (res.from === 'button') {
console.log("来自页面内转发按钮");
console.log(res.target);
}
else {
console.log("来自右上角转发菜单")
}
return {
// title: '',
// path: '/pages/share/share?id=123',
// imageUrl: "/images/1.jpg",
success: (res) => {
console.log("转发成功", res);
},
fail: (res) => {
console.log("转发失败", res);
}
}
} }
</script>
<style lang='scss'>
.comment{
margin-top: 10px;
.textarea{
width: 730rpx;
height: 200rpx;
background: #eee;
padding: 10rpx; }
.location{
margin-top: 10px;
}
.phone{
margin-top:10px;
margin-bottom: 10px;
}
}
</style>
效果图
6.修整代码格式
打开cmd,cd到项目目录mydemo下,执行
npm run lint
发现有四处代码不规范,去改正
应该是三个等号写成了两个等号,showModal写错了,写成了showModel
Vue+koa2开发一款全栈小程序(9.图书详情页)的更多相关文章
- Vue+koa2开发一款全栈小程序(8.图书列表页)
1.图书列表页获取数据 1.在server/routes/index.js中新增路由 router.get('/booklist',controllers.booklist) 2.在server/co ...
- 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组件库的诞生使我们的开发速度大大的加快,丰富的 ...
随机推荐
- Linux 安装 powershell
linux 安装 powershell Intro powershell 已经推出了一个 Powershell Core, 版本号对应 Powershell 6.x,可以跨平台,支持 Linux 和 ...
- (办公)面试java设计模式
1.单例模式: 程序开发的时候,有些对象只能有一个.有实例,且只有一个,比如工具类. 修改构造方法为私有的. 饿汉模式: 线程安全 创建一个实例 Private Static 实例; 提供一个静态 ...
- asp.net core自定义端口
asp.net Core 自定义端口 官方文档 aspnet内库源码: https://github.com/aspnet dotnet系统内库源码:https://github.com/dotnet ...
- python3操作MySQL数据库,一次插入多条记录的方法
这里提供一个思路,使用字符串拼接的方法,将sql语句拼接出来,然后去执行: l = ["] s = '-' print(s.join(l))
- 利用java实现excel转pdf文件
在有些需求当中我们需要抓取字段并且填充到excel表格里面,最后将excel表格转换成pdf格式进行输出,我第一次接触这个需求时,碰到几个比较棘手的问题,现在一一列出并且提供解决方案. 1:excel ...
- SQLServer之创建主XML索引
创建主XML索引注意事项 若要创建主 XML 索引,请使用 CREATE INDEX (Transact-SQL) Transact-SQL DDL 语句. XML 索引不完全支持可用于非 XML 索 ...
- 新数据革命: 开源C#图形化爬虫引擎Hawk5发布
https://ferventdesert.github.io/Hawk/ Hawk是一款由沙漠之鹰历时五年个人业余时间开发的,开源图形化爬虫和数据清洗工具,GitHub Star超过2k+,前几代版 ...
- 需求规格说明书(SRS)特点
需求说明书的7大特征: 完整性 正确性 可行性 必要性 划分优先级 无二义性 可验证性 每条需求规格说明书的4大特点: 完整性 一致性 可修改性 可跟踪性 需求管理就是一种获取.组织并记录系统需求的系 ...
- springMVC实现登陆
页面打开跳转到登陆页面 登陆成功跳转到成功页面 登陆失败再次返回登录页面,并增加提示信息 1.首页跳转到登陆页面 Tomcat服务器启动时默认加载WEB-INF下的index.jsp,可以通过修改xm ...
- Linux内存管理 (7)VMA操作
专题:Linux内存管理专题 关键词:VMA.vm_area_struct.查找/插入/合并VMA.红黑树. 用户进程可以拥有3GB大小的空间,远大于物理内存,那么这些用户进程的虚拟地址空间是如何管理 ...