美食杰-菜谱详情

本文介绍了如何使用Vue.js将菜谱详情页拆分为Header、Content和Comment三个子组件,通过props传递数据,实现各部分的渲染。在detail组件中监听路由变化获取菜谱信息,子组件中接收并展示数据,包括收藏功能的实现以及评论的获取与提交。详细阐述了各个组件的逻辑和渲染过程。
摘要由CSDN通过智能技术生成

一、介绍

菜谱详情分成了三个子组件来进行渲染,在父组件中获取数据,通过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('请输入内容')
      }
    }

总结:

到这里菜谱详情就介绍完了,祝大家生活愉快

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值