目录
detail.vue
detail-header.vue
detail-content.vue
comment.vue
注意:
因为用到了element-ui组件,所以需要先安装element-ui组件,进入项目根目录后
执行
npm i element-ui
思路:
detail.vue:
1.根据menuId请求数据(查看数据结构),渲染页面(如果没有menuId),提示框请登录
注意:数据结构过多,在保存到组件中时,提前写好默认值,避免在异步请求返回数据之前找不到属性
detail-header.vue(头部页):
1.根据数据,逐个渲染头部数据,用户信息通过query传入用户id,跳转个人空间
2.收藏按钮:判断是否本人登录再显示
3.收藏功能:判断是否登录,再请求,否则提示框弹出‘请先登录’
detail-content.vue (内容):
1.逐个渲染数据中,菜品的步骤:编号使用数组下标+1即可
1.效果展示
2.视图页面:views
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: {
handler() {
//通过query拿到menuId的数据
let { menuId } = this.$route.query;
if (menuId) {
//发送请求
menuInfo({ menuId }).then(({ data }) => {
console.log(data);
this.menuInfo = data.info;
});
} else {
this.$message({
showClose: true,
message: "重进",
type: "warrning",
});
}
},
immediate: true,//立即执行
},
},
};
</script>
detail-header.vue
通过收藏点击事件 toggleCollection()判断 点no-collection-at为灰色是收藏,点info.isCollection是红色是取消收藏,通过isOnwer()方法进行判断是否是本人登录
<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">
<a
href="javascript:;"
class="collection-at"
:class="{ 'no-collection-at': info.isCollection }"
@click="toggleCollection">
{{ info.isCollection ? "已收藏" : "收藏" }}
</a>
</div>
</div>
<ul class="detail-property clearfix">
<li v-for="item in info.properties_show" :key="item.type">
<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;
},
},
methods: {
async toggleCollection() {//通过async等待异步渲染的数据
if (!this.$store.getters.isLogin) {
this.$message({
showClose: true,
message: "请登录再收藏",
type: "warrning",
});
return ;
}
// 收藏菜品的接口
const data = await toggleCollection({ menuId: this.info.menuId });
console.log(data);
// 返回值有两种 true 未收藏转为已收藏的
// flase 已收藏的转为未收藏的
this.info.isCollection = data.data.isCollection;
},
},
};
</script>
detail-content.vue
通过父组件props来接受子组件的信息。
逐个渲染数据,在菜品编号时使用数组下标{{index+1}}.
<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.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>
<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>
comment.vue
通过postComment给后端发送请求,再通过send()方法提交评论
<template>
<div class="comment-box">
<h2>{{ info.title }}的讨论</h2>
<div class="comment-text">
<a href="javascript:;" class="useravatar" v-if="isLogin">
<img :src="userInfo.avatar" />
</a>
<div v-if="!isLogin">
请先登录后,再评论<router-link
:to="{name:'login',query:{userId: info.userInfo.userId}}">登录</router-link>
</div>
<!-- 输入内容需要做一个双向数据绑定 -->
<div class="comment-right" v-if="isLogin">
<el-input
type="textarea"
:rows="5"
:cols="50"
placeholder="请输入内容"
v-model="commentText">
</el-input>
<div class="comment-button" v-if="isLogin">
<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.userInfo.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 ,menuId} from "@/service/api";
export default {
name: "Comment",
props: {//接收数据
info: {
type: Object,
default: () => ({}),
},
},
data() {
return {
comments: [],//空的变量
commentText: "",//评论的内容
};
},
computed: {
userInfo() {
// vuex里面拿
return this.$store.state.userInfo;
},
isLogin(){
return this.$store.getters.isLogin;
}
},
async mounted() {
if (menuId) {
console.log(data);
//向后端发送请求 评论内容
let data = await getComments({ menuId: menuId });
console.log(data);
this.comments = data.data.comments;//存在组件当中
}
},
methods: {
async send() {
// 发送数据 (两种方式)
// 1.query中获取 2.父组件传入的info
let data= await postComment({menuId: this.info.menuId,commentText:this.commentText});
console.log(data)
this.comments.unshift(data.data.comments);//向前添加数据
this.commentText='';//清除上次里面的评论
},
},
};
</script>
总结
今天的内容就先到这里 因为还有一些没完善所以不是很好 后面再继续改进!