今天要讲的是美食杰详情页面,这个页面主要讲述的是菜品制作的详细步骤,其中分为三部分:
头部,内容和评价。
思路:
根据menuId 请求数据(查看数据结构),渲染页面(如果没有menuld,提示框请登录)
注意:数据结构过多,在保存到组件中时,提前写好默认值。避免在异步请求返回数据之前找不到属性。
头部:
1.根据数据,逐个渲染头部页面。用户信息中,query传入用户id,跳转个人空间。
2收藏按钮:判断是否本人登录再显示。
3.收藏功能:判断是否登录,再请求,否则提示框,请先登录。
内容:
1.逐个渲染数据中,菜品的步骤:编号使用数组下标+1即可(index) 。
评论:
1.在输入框里绑定v-model,实现双向数据绑定。
2.在提交框里写一个点击事件,在评论完之后提交数据。
下面展示效果图:
头部:
内容:
评论:
展示代码:
detail.vue:
<template>
<div class="menu-detail">
<detail-header :info="menuInfo"></detail-header>
<detail-content :info="menuInfo"></detail-content>
<Comment :info="menuInfo"></Comment>
</div>
</template>
<script>
import DetailHeader from "./detail-header";
import DetailContent from "./detail-content";
import Comment from "./comment";
import { menuInfo } from "@/service/api";
export default {
components: { DetailHeader, DetailContent, Comment },
data() {
return {
menuInfo: {
userInfo: {},
raw_material: {
main_material: [],
accessories_material: [],
},
steps: [],
},
};
},
watch: {
$route: {
async handler() {
//来判断路由是否有信息
let { menuId } = this.$route.query;
if (menuId) {
menuInfo({ menuId }).then(({ data }) => {
this.menuInfo = data.info;
});
} else {
this.$message({
showClose: true,
message: "请重新进入",
type: "warning",
});
}
},
immediate: true,
},
},
};
</script>
detail-header.vue:
<template>
<section class="detail-header">
<img class="detail-img" :src="info.product_pic_url" />
<div class="detail-header-right">
<div class="detail-title clearfix">
<h1 class="title">{{ info.title }}</h1>
<!--
1. 不显示,这个菜谱是当前用户发布的
2. 显示,后端返回一个是否收藏的字段
-->
<div class="detail-collection" v-if="!isOnwer">
<!-- collection-at no-collection-at-->
<a
href="javascript:;"
class="collection-at"
:class="{ 'no-collection-at': info.isCollection }"
@click="toggleCollection"
>
{{ info.isCollection ? "已收藏" : "收藏" }}
</a>
</div>
</div>
<ul
class="detail-property clearfix"
v-for="item in info.properties_show"
:key="item.parent_type"
>
<li>
<strong>{{ item.parent_name }}</strong>
<span>{{ item.name }}</span>
</li>
</ul>
<div class="user">
<router-link
id="tongji_author_img"
class="img"
:to="{ name: 'space', query: { userId: info.userInfo.userId } }"
>
<img :src="info.userInfo.avatar" />
</router-link>
<div class="info">
<h4>
<router-link
id="tongji_author"
:to="{ name: 'space', query: { userId: info.userInfo.userId } }"
>{{ info.userInfo.name }}
</router-link>
</h4>
<span
>菜谱:{{ info.userInfo.work_menus_len }}/ 关注:{{
info.userInfo.following_len
}}
/ 粉丝:{{ info.userInfo.follows_len }}</span
>
<strong>{{ info.userInfo.createdAt }}</strong>
</div>
</div>
</div>
</section>
</template>
<script>
import { toggleCollection } from "@/service/api";
export default {
props: {
info: {
type: Object,
default: () => ({}),
},
},
computed: {
isOnwer() {
return this.info.userInfo.userId === this.$store.state.userInfo.userId;//判断这个作品是否是本人发布的
},
},
data() {
return {};
},
methods: {
async toggleCollection() {
//先判断一下是否登录
if (!this.$store.getters.isLogin) {
this.$message({
showClose: true,
message: "请先登录,再收藏",
type: "warning",
});
return;
}
const data = await toggleCollection({ menuId: this.info.menuId });
this.info.isCollection = data.data.isCollection;
},
},
};
</script>
<style lang="stylus">
.detail-header
margin-top 40px
display flex
background-color #fff
.detail-img
width 328px
.detail-header-right
width 662px
.detail-title
box-sizing border-box
width 100%
padding-left: 25px;
border-bottom: 1px solid #eee;
.title
max-width: 288px;
height: 44px;
padding: 28px 0px;
line-height: 44px;
font-size: 36px;
color: #333;
float left
.collected
background: #999;
.collecte
background: #ff3232;
.detail-collection
float right
display block
height: 50px;
line-height: 44px;
color #fff
padding: 0px 14px;
text-align center
margin-top 25px
cursor pointer
a
display: inline-block;
padding: 3px 0;
width: 50px;
color: #fff;
text-align: center;
line-height 20px
.collection-at
background-color: #ff3232;
.no-collection-at
background-color: #999;
.detail-property
margin-left 2px
overflow hidden
display inline-block
li
width 199px
float left
height 48px
border-right 1px solid #eee
padding 18px 0px 18px 20px
border-bottom 1px solid #eee
strong
color #999
line-height 18px
display block
height 18px
span
display block
font-size 24px
color #ff3232
line-height 30px
width 100px
.user
height 70px
padding 20px 0px 20px 20px
overflow hidden
font-size 12px
a.img
display block
height 70px
width 70px
float left
position relative
border-radius 35px
overflow hidden
img
display block
height 70px
width 70px
.info
float left
padding-left 10px
height 70px
h4
height 22px
line-height 22px
font-size 14px
color #ff3232
position relative
a
color #ff3232
display inline-block
vertical-align top
padding-right 0px
height 22px
span
line-height 24px
display block
color #666
padding-top 4px
strong
line-height 22px
color #999
</style>
detail-content.vue:
<template>
<section class="detail-content">
<div class="detail-materials">
<p class="">
<strong>“</strong>{{ info.product_story }}<strong>”</strong>
</p>
<h2>用料</h2>
<div
class="detail-materials-box clearfix"
v-if="info.raw_material.main_material.length"
>
<h3>主料</h3>
<ul>
<li
class=""
v-for="item in info.raw_material.main_material"
:key="item._id"
>
{{ item.name }}
<span>{{ item.specs }}</span>
</li>
</ul>
</div>
<div
class="detail-materials-box clearfix"
v-if="info.raw_material.accessories_material.length"
>
<h3>辅料</h3>
<ul>
<li
class=""
v-for="item in info.raw_material.accessories_material"
:key="item._id"
>
{{ item.name }}
<span>{{ item.specs }}</span>
</li>
</ul>
</div>
</div>
<div class="detail-explain">
<h2>{{ info.title }}的做法</h2>
<section
class="detail-section clearfix"
v-for="(item, index) in info.steps"
:key="item._id"
>
<em class="detail-number">{{ index + 1 }}</em>
<div class="detail-explain-desc">
<p>{{ item.describe }}</p>
<img class="conimg" :src="item.img_url" v-if="item.img_url" alt="" />
</div>
</section>
<div class="skill">
<h2>烹饪技巧</h2>
<p>{{ info.skill }}</p>
</div>
</div>
</section>
</template>
<script>
export default {
name: "DetailContent",
props: {
info: {
type: Object,
default: () => ({}),
},
},
};
</script>
<style lang="stylus">
.detail-content
margin-top 20px
h2
font-size 24px
color #333
height 66px
line-height 66px
border-bottom 1px solid #eee
text-indent 24px
font-family Microsoft Yahei
display block
.detail-materials
background-color #fff
> p
line-height 24px
font-size 14px
padding 20px 24px 10px
color #666
.detail-materials-box
margin-bottom 20px
h3
width 48px
height 22px
color #999
background #f5f5f5
border 1px solid #ddd
text-align center
line-height 24px
margin 14px 5px 14px 25px
float left
ul
float left
width 910px
li
float left
box-sizing border-box
height 54px
line-height 54px
margin 0 5px 5px 5px
padding 0 10px
border 1px solid #eee
.detail-explain
background-color #fff
padding-bottom 20px
.detail-section
.detail-number
font-size 50px
color #ff3232
font-style italic
text-align center
font-family arial
height 50px
width 100px
display block
float left
line-height 50px
.detail-explain-desc
float left
width 650px
overflow hidden
p
line-height 24px
color #666
padding 10px 20px 10px 0px
position relative
font-size 14px
img
max-width 550px
.skill
p
font-size 12px
padding-left 100px
padding-top 10px
</style>
comment.vue:
<template>
<div class="comment-box">
<h2>{{ info.title }}的讨论</h2>
<div class="comment-text">
<a href="javascript:;" class="useravatar">
<img :src="userInfo.avatar" />
</a>
<!-- <div v-if="!isLogin">
请先登录后,再评论<router-link to="">登录</router-link>
</div> -->
<div class="comment-right">
<el-input
type="textarea"
:rows="5"
:cols="50"
placeholder="请输入内容"
v-model="commentText"
>
</el-input>
<div class="comment-button">
<el-button
class="send-comment"
type="primary"
size="medium"
@click="send"
>提交</el-button
>
</div>
</div>
</div>
<div class="comment-list-box">
<ul class="comment-list">
<li v-for="item in comments" :key="item.commentId">
<router-link
:to="{ name: 'space', query: { userId: item.userId } }"
class="avatar"
>
<img :src="item.userInfo.avatar" />
<h5>{{ item.userInfo.name }}</h5>
</router-link>
<div class="comment-detail">
<p class="p1">{{ item.commentText }}</p>
<div class="info clearfix">
<span style="float: left;">{{ item.createdAt }}</span>
</div>
</div>
</li>
</ul>
</div>
</div>
</template>
<script>
import { getComments, postComment } from "@/service/api";
export default {
name: "Comment",
props: {
info: {
type: Object,
default: () => ({}),//获取数据
},
},
data() {
return {
comments: [],//创建一个空数组,保存数据
commentText: "",//初始值为空
};
},
computed: {
userInfo() {
return this.$store.state.userInfo;
},
},
async mounted() {
let { menuId } = this.$route.query;
if (menuId) {
let data = await getComments({ menuId: menuId });
console.log(data);
this.comments = data.data.comments;
}
},
methods: {
async send() {
//console.log('发送');
let data = postComment({//发送数据到后端
menuId: this.info.menuId,
commentText: this.commentText,
});
//console.log(data)
this.comments.unshift(data.data.comments);//在数组开头添加元素
this.commentText = "";//让评论的内容为空
},
},
};
</script>
<style lang="stylus">
.comment-box
background-color #ffffff
margin-top 20px
padding 0 20px
h2
font-size 24px
color #333
height 66px
line-height 66px
border-bottom 1px solid #eee
.comment-text
margin-top 20px
.useravatar
margin-right 20px
img
vertical-align top
width 36px
height 36px
.comment-right
display inline-block
width 80%
.comment-button
text-align right
margin-top 10px
.send-comment
background #ff3232
border none
.comment-list-box
border-top 1px solid #eee
margin-top 20px
padding-top 30px
ul li
border-bottom 1px solid #eee
margin-bottom 20px
.avatar
height 82px
width 50px
overflow hidden
display inline-block
h5
white-space nowrap
img
height 50px
width 50px
.comment-detail
display inline-block
vertical-align top
margin-left 20px
width 80%
p
margin 0
font-size 14px
.info
margin-top 10px
color #999
.thumbs
cursor pointer
font-size 18px
.thumbs-actve
color red
</style>
看到这里就结束了,本篇主要讲述的是美食杰---详情页,这个效果大多以渲染数据为主,谢谢大家观看!!!