一、介绍
菜谱详情分成了三个子组件来进行渲染,在父组件中获取数据,通过props传给子组件。
二、过程
1.首先在父组件detail里面通过监听路由,路由改变时通过menuInfo调用后端获取到数据,赋值给创建的空对象info。并把它赋值给子组件,在info里面为了防止在子组件里找不到属性,所以在里面初始化上属性:
<template>
<div class="menu-detail">
<detail-header :info='info'></detail-header>
<detail-content :info='info'></detail-content>
<Comment :info='info'></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 {
info:{
userInfo:{
userId:0
},
raw_material:{
main_material:[],
accessories_material:[]
}
}
}
},
watch:{
$route:{
handler(){
let {menuId}=this.$route.query
menuInfo({menuId:menuId}).then(({data})=>{
this.info=data.info
})
},
immediate:true
}
}
}
</script>
数据:
2.在子组件detail-header里面通过props对象的方法获取到数据,detail-header组件渲染的是头部:
props:{
info: {
type: Object,
default: () => ({})
}
}
接着进行渲染:
<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"
@click="collect"
:class="{'no-collection-at':info.isCollection}"
>
{{info.isCollection?'已收藏':'未收藏'}}
</a>
</div>
</div>
<ul class="detail-property clearfix">
<li v-for="item in info.properties_show" :key='item.parent_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>
在头部有一个收藏按钮,给收藏添加一个点击事件collect,在事件里面判断是否已经登录,如果登录通过toggleCollection来进行收藏和取消收藏并且把data下的data里面的isCollection赋值给info里面的isCollection来给收藏添加高亮显示,并切换文字:
async collect(){//collect收藏
if(this.$store.getters.isLogin){
let data=await toggleCollection({menuId:this.$route.query.menuId}).then((data)=>{
console.log(data);
this.info.isCollection=data.data.isCollection
})
}else{
alert('请登录')
}
}
3.在子组件detail-content里面渲染内容,同样是用props的对象方法来获取数据进行渲染,detail-content渲染的是菜谱的基本信息和步骤:
props:{
info: {
type: Object,
default: () => ({})
}
}
在这个组件里不需要实现功能,所以只需要进行渲染就可以了:
<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" alt="">
</div>
</section>
<div class="skill">
<h2>烹饪技巧</h2>
<p>{{info.skill}}</p>
</div>
</div>
</section>
4.在子组件comment里通过props的对象方法获取传递的数据,comment渲染的是下面的评论:
props:{
info: {
type: Object,
default: () => ({})
}
},
首先是在计算属性里通过获取vuex里面的isLogin来判断是否已经登录,如果登录正常显示,如果没有登录显示请登录:
computed:{
isLogin(){
return this.$store.getters.isLogin
}
},
通过getComments向后端获取当前菜谱的评论赋值给comments来进行渲染,调用comments需要通过对象传递一个参数menuId:
async show(){//显示
let {menuId}=this.$route.query
if(menuId){
await getComments({menuId}).then(({data})=>{
this.comments=data.comments
})
}
}
在声明周期mounted里面调用show,是页面刚加载就有评论显示:
mounted(){
this.show()
}
给提交绑定一个post方法,通过v-model获取当前输入的值,并把它当做对象里面的commentText的属性值,把当前路由下的query里面的menuId单做对象里menuId的属性值。把这个对象当做参数通过postComment来调用后端添加评论:
async post(){
if(this.value){
await postComment({commentText:this.value,menuId:this.$route.query.menuId})
this.show()
this.value=''
}else{
alert('请输入内容')
}
}
总结:
到这里菜谱详情就介绍完了,祝大家生活愉快