美食杰 菜谱详情(效果介绍)

实现效果:

    在detail组件中:
       1.根据menuld请求数据(查看数据结构),渲染页面(如果没有menuld,提示框请登录)
              注意:数据结构过多,在保存到组件中时,提前写好默认值。避免在异步请求返回数据之前找下到属性。
     头部:

       1.根据数据,逐个渲染头部页面。用户信息中,query传入用户id,跳转个人空间
       2.收藏按钮:判断是否本人登录再显示
       3..收藏功能:I判断是否登录,再请求,否则提示框,请先登录

     菜谱做法的顺序
       1.逐个渲染数据中,菜品的步骤:编号使用数组下标+1即可(index)
     评论:

        1.获取菜品本来的评论

        2.输入评论点击提交可以发送

        3.未登录账号时显示不能评论需要登录

效果显现方式

        使用vue脚手架搭建项目完成效果

        使用element组件库

        使用vue-router路由

        vuex库

        等...

 效果图

 

 

 

 登陆时评论区的状态

 

 未登录时状态

   当前菜品有评论时会显示 但是不能提交评论

 

说明各个组件负责的块 以及实现代码说明

 

detail.vue                获取所有数据

detail-header.vue   获取头部数据 块(第一张图)

detail-content.vue  菜品制作过程

comment.vue         评论区块

 detail中代码

<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'; //   从menuInfo中获取数据 数据从后端拿
export default {
  components: {DetailHeader, DetailContent, Comment},
  data(){
    return {
      menuInfo:{//获取数据给menuInfo 下面是我们需要数据的解构进行一下声明
         userInfo:{},
         raw_material:{
           accessories_material:[],
           main_material:[]
         },
         steps:[]
      },
    }
  },
//获取数据
  watch:{
     $route:{
        handler(){
          let {menuId} = this.$route.query;
             //判断进入的query的路径,路径不对需要重新进入
            if(menuId){//发请求
               menuInfo({menuId}).then(({data})=>{
                   this.menuInfo=data.info
                   console.log(data)
               })
            }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" >
        <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.userId}}" 
        >
          <img :src="info.userInfo.avatar">
        </router-link>
        <div class="info">
          <h4>
            <router-link id="tongji_author"   
               :to="{name:'space', query:{userId:info.userId}}" tag="em"
            >
                {{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(){
判断账号是否登陆 没登陆不能收藏 登陆之后才可以收藏菜谱
       if(!this.$store.getters.isLogin){
           this.$message({
             showClose:true,
             message:'请先登陆,在收藏',
             type:'warning'
           });
           return 
       }
       const data = await toggleCollection({menuId:this.info.menuId})
       console.log(data)
       this.info.isCollection = data.data.isCollection;
     }
  }
}
</script>

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="(proc,index) in info.steps"
             :key="index" 
      >
             <!--key值标记当前数量 index+1所以下一步就是index+1-->
        <em class="detail-number">{{index+1}}.</em>、
        <div class="detail-explain-desc">
          <p>{{proc.describe}}</p>
          <img class="conimg" :src="proc.img_url" v-if="proc.img_url.length" 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        评论区块代码

<template>
  <div class="comment-box">
    <h2>{{info.title}}的讨论</h2>
    <div class="comment-text">
      <!--img 用户头像显示-->
      <a href="javascript:;" class="useravatar">
        <img :src="userInfo.avatar">
      </a>
      <div  v-if="!isLogin">请先登录后,再评论<router-link :to="{name:'space'}">登录</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>
          <!--send点击提交的事件-->
        </div>
      </div>
    </div>
    <div class="comment-list-box">
      <ul class="comment-list">
        <li
         v-for="item in comments"
         :key="item.commentId"
        >
          <a target="_blank" href="https://i.meishi.cc/cook.php?id=14026963" class="avatar">
           
          </a>
          <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} from '@/service/api';
export default {
  name: 'Comment',
//获取父元素传的值
  props:{
    info: {
      type: Object,
      default: () => ({})
    }
  },
  data(){
    return {
       commentText:'',
       comments:[]

    }
  },

  computed: {
//判断用户是否登陆账号
      isLogin(){
        return this.$store.getters.isLogin
      },
//获取头像
      userInfo(){
        return this.$store.state.userInfo
      }
  },
//提交评论
  methods:{
     async send(){
       let data = await postComment({menuId:this.info.menuId,commentText:this.commentText});//获取输入评论点击的数据
            console.log(data)
            this.comments.unshift(data.data.comments)//向前添加数据
            this.commentText = ""//添加后清空
     }
  },
//获取当前菜谱的历史评论
  async mounted(){
      let {menuId} = this.$route.query;
      if(menuId){
         let {data} = await getComments({menuId:menuId})
         this.comments=data.comments;
        //  console.log(data)
        //  console.log(this.comments)
      }
  },
 
}
</script>

以上效果的代码展示完毕

下次见

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值