接上篇,vue项目美食杰菜谱大全已经实现,今天来说一下菜单详情的实现

分析:

这个菜单详情页面,考验的知识很少,基本都是拿数据渲染

分为4大部分,四个组件:

1.detail:

detail组价:

根据menuld请求数据(查看数据结构),渲染页面(如果没有menuld,提示框请登录)

注意事项:数据结构过多,在保存到组件中,提前写好默认值。避免在异步请求返回数据之前查找不到属性。

2.菜谱头部:

detail-header组件:

1.根据数据,逐个渲染头部页面。用户信息中国,query传入用户id,跳转个人空间

2.收藏按钮:判断是否是本人登录再显示

3.收藏功能:判断是否登录,再请求,否则提示框,请先登录....

3.菜的内容(用料,做法):

detail-content组件:

1.根据数据,逐个渲染页面,菜品的步骤:编号使用数组下标+1即可(index)

2.注意事项,一定要接收父组件传的数据props:{}接收

4.评论:

comment组价:

1.拿数据根据数据,逐个渲染页面

2.点击提交添加数据 向后端请求  评论内容,然后添加到页面

3.注意:请先登录,再评论

写完评论后,文本为空

接下来按照步骤一步一步实现

首先在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';
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>

watch监听一下获取数据通过后端api提供的方法用.then()异步获取数据,赋值给menuInfo,然后在data中存一下menuInfo,判断一下menuld,如果没有menuld,提示框请登录,重新进入。这一页主要是获取数据,然后子组件通过props接收数据。

打印一下可以获取到的数据

然后写菜谱头部

先props接收一下info,是一个对象形式,空对象

props:{info:{type: Object,default: () => ({})}
},

接着渲染数据

接着

<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>

然后是否是是本人

computed: {isOnwer(){//是否是本人return this.info.userInfo.userId === this.$store.state.userInfo.userId;}
},

接着写上边的收藏,已收藏

判断       1.先判断是否是是登录状态

2.有两个返回值

返回值:true 未收藏的转化已收藏

false已收藏转化未收藏

 methods:{async collection(){//先判断是否是是登录状态if(!this.$store.getters.isLogin){this.$message({showClose:true,message:'请先登录,再收藏',type:'warning'});return;}//收藏菜品的接口const data= await toggleCollection({menuId:this.info.menuId});//返回值:true 未收藏的转化已收藏//        false已收藏转化未收藏// console.log(data);this.info.isCollection = data.data.isCollection;}},

头部就这些效果了:

头部整体代码

<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="!isOwner"><!-- collection-at  no-collection-at--><a href="javascript:;" class="collection-at":class="{ 'no-collection-at' :info.isCollection}"@click="collection"> {{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>
</template>
<script>
import {toggleCollection} from '@/service/api'
export default {data(){return {isOwner:false,userInfo:[]}},props:{info:{type: Object,default: () => ({})}},computed: {isOnwer(){//是否是本人return this.info.userInfo.userId === this.$store.state.userInfo.userId;}},methods:{async collection(){//先判断是否是是登录状态if(!this.$store.getters.isLogin){this.$message({showClose:true,message:'请先登录,再收藏',type:'warning'});return;}//收藏菜品的接口const data= await toggleCollection({menuId:this.info.menuId});//返回值:true 未收藏的转化已收藏//        false已收藏转化未收藏this.info.isCollection = data.data.isCollection;}},
}
</script><style lang="stylus">
.detail-headermargin-top 40pxdisplay flexbackground-color #fff.detail-imgwidth 328px.detail-header-rightwidth 662px.detail-titlebox-sizing border-boxwidth 100%padding-left: 25px;border-bottom: 1px solid #eee;.titlemax-width: 288px;height: 44px;padding: 28px 0px;line-height: 44px;font-size: 36px;color: #333;float left.collectedbackground: #999;.collectebackground: #ff3232;.detail-collectionfloat rightdisplay blockheight: 50px;line-height: 44px;color #fffpadding: 0px 14px;text-align centermargin-top 25pxcursor pointera display: inline-block;padding: 3px 0;width: 50px;color: #fff;text-align: center;line-height 20px.collection-atbackground-color: #ff3232;.no-collection-atbackground-color: #999;.detail-propertymargin-left 2pxoverflow hiddenli width 200pxfloat leftheight 48pxborder-right 1px solid #eeepadding 18px 0px 18px 20pxborder-bottom 1px solid #eeestrong color #999line-height 18pxdisplay blockheight 18pxspan display blockfont-size 24pxcolor #ff3232line-height 30pxwidth 100px.userheight 70pxpadding 20px 0px 20px 20pxoverflow hiddenfont-size 12pxa.imgdisplay blockheight 70pxwidth 70pxfloat leftposition relativeborder-radius 35pxoverflow hiddenimgdisplay blockheight 70pxwidth 70px.infofloat leftpadding-left 10pxheight 70pxh4height 22pxline-height 22pxfont-size 14pxcolor #ff3232position relativeacolor #ff3232display inline-blockvertical-align toppadding-right 0pxheight 22pxspan line-height 24pxdisplay blockcolor #666padding-top 4pxstrong line-height 22pxcolor #999</style>

接着写 菜的内容(用料,做法):

这页就比较简单了

通过props接收数据:根据数据,逐个渲染页面,菜品的步骤:编号使用数组下标+1即可(index)

效果:

全部代码实现:

<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>菜的做法</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="" 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-contentmargin-top 20pxh2 font-size 24pxcolor #333height 66pxline-height 66pxborder-bottom 1px solid #eeetext-indent 24pxfont-family Microsoft Yaheidisplay block.detail-materialsbackground-color #fff> p line-height 24pxfont-size 14pxpadding 20px 24px 10pxcolor #666.detail-materials-boxmargin-bottom 20pxh3 width 48pxheight 22pxcolor #999background #f5f5f5border 1px solid #dddtext-align centerline-height 24pxmargin 14px 5px 14px 25pxfloat leftul float leftwidth 910pxli float leftbox-sizing border-boxheight 54pxline-height 54pxmargin 0 5px 5px 5pxpadding 0 10pxborder 1px solid #eee.detail-explainbackground-color #fffpadding-bottom 20px.detail-section.detail-numberfont-size 50pxcolor #ff3232font-style italictext-align centerfont-family arialheight 50pxwidth 100pxdisplay blockfloat leftline-height 50px.detail-explain-descfloat leftwidth 650pxoverflow hiddenp line-height 24pxcolor #666padding 10px 20px 10px 0pxposition relativefont-size 14pximg max-width 550px.skillp font-size 12pxpadding-left 100pxpadding-top 10px
</style>

最后写评论页,个人评论,用户评论中间用路由跳转,个人评论请先登录,再评论

1.拿数据根据数据,逐个渲染页面

2.点击提交添加数据 向后端请求  评论内容,然后添加到页面

3.注意:请先登录,再评论

写完评论后,文本为空

接收:

props:{info:{type: Object,default: () => ({})}
},

发送获取menuId 有两种方法1.从query中获取 2.父组件传递info ,我这用的是父组件传递info

点击事件提交

向后端请求  评论内容

基本效果就这些了

评论页全部代码

<template><div class="comment-box"><h2>{{info.title}}的讨论</h2><div class="comment-text"><a href="javascript:;" class="useravatar"><img :src="info.userInfo.avatar"></a><div v-if="!isLogin">请先登录后,再评论<router-link :to="{name:'login',query:{userId: info.userInfo.userId}}">登录</router-link></div><!-- 输入内容需要做一个双向数据绑定 --><div class="comment-right"><el-inputtype="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"><a target="_blank" href="https://i.meishi.cc/cook.php?id=14026963" class="avatar"></a><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;},isLogin(){return this.$store.getters.isLogin;}},async mounted(){//有两种情况let {menuId}=this.$route.query;if(menuId){// 向后端请求  评论内容let data=await getComments({menuId:menuId})this.comments=data.data.comments// console.log(this.comments)}},methods:{// 发送async send(){//获取menuId   1.从query中获取 2.父组件传递infolet data=await postComment({menuId:this.info.menuId,commentText:this.commentText})//  console.log(data)this.comments.unshift(data.data.comments)//添加数据this.commentText=''// 写完评论后,文本为空if(!this.$store.getters.isLogin){this.$message({showClose:true,message:'请先登录,再评论',type:'warning'});return;}}}
}
</script>
<style lang="stylus">
.comment-boxbackground-color #ffffffmargin-top 20pxpadding 0 20pxh2font-size 24pxcolor #333height 66pxline-height 66pxborder-bottom 1px solid #eee.comment-textmargin-top 20px.useravatarmargin-right 20pximg vertical-align topwidth 36pxheight 36px.comment-right display inline-blockwidth 80%.comment-buttontext-align right margin-top 10px.send-commentbackground #ff3232border none.comment-list-boxborder-top 1px solid #eeemargin-top 20pxpadding-top 30pxul li border-bottom 1px solid #eeemargin-bottom 20px.avatarheight 82pxwidth 50pxoverflow hiddendisplay inline-blockh5white-space nowrapimg height 50pxwidth 50px.comment-detaildisplay inline-blockvertical-align topmargin-left 20pxwidth 80%p margin 0font-size 14px.infomargin-top 10pxcolor #999.thumbscursor pointerfont-size 18px.thumbs-actvecolor red</style>

总结:
写的时候一定要注意接收值,这个菜详情,没什么太难的问题,就拿数据渲染,判断。别的也没什么,要懂得分析,其实所有组件实现效果是一样的,都是通过拿到的数据,拿到之后获取数据渲染到页面上,然后再一步一步实现效果,
每天及时更新项目,喜欢的话,点赞,关注,收藏。

感谢观看!

散会!

vue项目美食杰菜谱大全实现(三)相关推荐

  1. vue项目美食杰菜谱大全实现(二)

    接上篇,vue项目美食杰菜谱大全实现 效果图 分析: 整体分为三大部分 1.先实现菜谱分类头部实现 (1)先实现家常菜谱中华菜系和各地小吃的实现,通过后端获取到数据,渲染页面(2)再实现第一部中的每一 ...

  2. vue项目美食杰--菜谱大全

    项目已经接近尾声了,难度也随之增加,不过,世上无难事,只要肯登攀,遇到困难,打倒它,然后在遇到更大的困难..当然了,在这个过程中我们的技术和心理素质也会逐步的提高..今天分享一个小小难度的部分,菜谱大 ...

  3. vue项目美食杰菜谱大全实现

    效果图 分析 1.先实现菜谱分类头部实现 (1)先实现家常菜谱中华菜系和各地小吃的实现 (2)再实现第一部中的每一项 2.实现左边筛选中的功能 (1)先实现工艺,口味,难度,人数 (2)实现第一步中包 ...

  4. 美食杰----菜谱大全(二)

    这篇文章接着续写上一篇菜谱大全,这篇文章主要写的是右边的侧栏部分. 一.思路:1.首先布局,要用到Element Ui组件来布局. 2.然后从后端获取数据. 3.将调用到的数据进行解构,再创建个空数组 ...

  5. 美食杰-菜谱大全(一)

    一,效果展示 二,效果概要 tab切换 获取api中的数据 点击换css样式 渲染页面 三,技术要求 熟悉element组件库 掌握vue-cli脚手架 掌握vue-router路由 掌握vuex库 ...

  6. vue项目美食杰 -- 发布菜谱

    不知不觉间,vue美食杰项目已经实现了很多了,我都有点始料未及呢,今天进行的部分呢,是项目中的发布菜谱功能,在这个页面中,我们会学习到前后端的交互,Element-ui的使用等等... 先看下效果图: ...

  7. 美食杰----菜谱大全

    今天我们来写美食杰的菜谱大全页面,首先要讲的是实现这个页面的流程: 拿到数据----渲染数据----监听路由传参----判断----写点击事件 1.在api里面拿到数据getClassify, get ...

  8. 美食杰-菜谱大全右侧主体

    根据用户的选择,展示不同的数据 分页 在data中定义需要的数组 data() {return {classify: [],property: [],propertype: {}, //存储分类的属性 ...

  9. 美食杰--------菜谱大全

    话不多说,直接看效果图: HTML: <template><div class="recipe"><!-- v-model="activeN ...

最新文章

  1. iframe怎么用_怎么样减少无效URL的爬行和索引
  2. TensorRT是NVIDIA开发的深度学习推理工具,只支持推理,不支持训练 引
  3. 如何在IE/Edge浏览器中巧妙地传输HTA文件?
  4. 让atmega8可以和飞思卡尔xs128一样对IO引脚进行定义
  5. 软工Hello World!团队第二周博客汇总
  6. 普林斯顿微积分读本篇六:求解微分问题
  7. 单片机入门学习十五 STM32单片机学习十二 电容触摸按键
  8. 录制软件Bandicam安装教程
  9. 虚拟机安装Mac OS系统
  10. 初试 Coding.net 在线IDE——WebIDE
  11. 前端获取文件的MD5值
  12. Regulator的使用
  13. Incorrect string value: '\xF0\x9F\x98\x84\xF0\x9F
  14. php汽车租赁网站_ThinkPHP实战开发汽车租赁网站项目教程
  15. C语言/C++编程学习:栈的代码实现之数组方案
  16. Drupal - 制作首页
  17. git命令解决冲突解决
  18. 期货交易怎么买空(期货怎么买做空)
  19. ping 加上时间信息
  20. 小米扫地机器人充电座指示灯不亮_扫地机器人常见问题及故障排除

热门文章

  1. 北大最会读书的人《何帆的读书笔记》-推荐200本书籍清单,让你快速提高阅读能力
  2. ContextCapture系列教程(四):新建工程、添加照片、相机参数设置、选择坐标系统
  3. 曝切尔西3000万清洗奥斯卡 一举动证他定离队
  4. API安全接口安全设计
  5. 大数据:数据采集平台之Fluentd
  6. iPhone各机型的屏幕比例
  7. 职校电子计算机专业高考分数线,2015年重庆高考分数线
  8. WPF教程(十五)MVVM框架
  9. 【已解决】联想小新Pro14适配器打感叹号(代码56)无法上网原因解决!亲测有效
  10. 传腾讯拟入股绝地求生开发商;刘若英回应《后来》退票异常;蓝色起源成功发射火箭丨价值早报...