本篇文章主要实现的是App.vue组件、头部组件header、蒙层组件detal和Modal以及路由切换router

文章目录

  • 一、App.vue组件
    • 1、重点说明
    • 2、具体实现
      • (1)、整体布局
      • (2)、数据获取
    • 3、源码
  • 二、header.vue组件
    • 1、重点说明
    • 2、具体实现
      • (1)、整体布局
      • (2)、父子组件传值
      • (3)、商家头像展示
      • (4)、商家内容展示
      • (5)、字体图标的使用
    • 3、源码
  • 三、蒙层组件
    • 1、detal组件
    • 2、Modal组件
      • (1)、整体布局
    • 3、蒙层的展示和隐藏
    • 4、源码
  • 四、路由切换

一、App.vue组件

1、重点说明

App组件是整个项目的大的组件,其中可以划分为头部组件、导航栏切换、以及对应的导航栏内容显示。

2、具体实现

(1)、整体布局
<template><div id="app"><Header :seller="seller"></Header><div class="tab"><div class="tab-item"><router-link :to="{name:'goods'}">商品</router-link></div><div class="tab-item"><router-link :to="{name:'ratings'}">评价</router-link></div><div class="tab-item"><router-link :to="{name:'seller'}">商家</router-link></div></div><keep-alive><router-view :seller="seller"></router-view></keep-alive></div>
</template>
(2)、数据获取

本次项目中主要使用的是axios实现与后端的数据交互
引入axios

import axios from 'axios'

数据获取 获取的数据使用seller接收

<script>
// eslint-disable-next-line no-unused-vars
import Header from '@/components/header/header'
import axios from 'axios'
const ERR_OK = 0
export default {data () {return {seller: {}}},created () {axios.get('/api/seller').then((response) => {response = response.dataif (response.errno === ERR_OK) {this.seller = response.data}})},components: {Header},name: 'App'
}
</script>

3、源码

<template><div id="app"><Header :seller="seller"></Header><div class="tab"><div class="tab-item"><router-link :to="{name:'goods'}">商品</router-link></div><div class="tab-item"><router-link :to="{name:'ratings'}">评价</router-link></div><div class="tab-item"><router-link :to="{name:'seller'}">商家</router-link></div></div><keep-alive><router-view :seller="seller"></router-view></keep-alive></div>
</template>
<script>
// eslint-disable-next-line no-unused-vars
import Header from '@/components/header/header'
import axios from 'axios'
const ERR_OK = 0
export default {data () {return {seller: {}}},created () {axios.get('/api/seller').then((response) => {response = response.dataif (response.errno === ERR_OK) {this.seller = response.data}})},components: {Header},name: 'App'
}
</script>
<style scoped>
/* 评论商家商品使用flex布局 */
.tab{display: flex;width: 100%;/* 展示的高度是height的两倍 */height: 40px;line-height: 40px;
}
.tab .tab-item{flex: 1;text-align: center;
}
.tab .tab-item ::after{display: block;content: ' ';border-top: 1px solid #ddd ;left: 0;right: 0;width: 100%;
}
.tab .tab-item router-link{display: block;font-size:14px;color: rgb(77,85,93);
}
.tab .tab-item .router-link-exact-active{/*  选中时样式 */color: rgb(240,20,20);
}
</style>>

二、header.vue组件

1、重点说明

header组件主要实现的是商家的名称和公告的展示,并且商家的公告在展示过程中要做到单行展示,超出部分缩略的效果。通过文字超出部分隐藏三要素实现

  // 文字超出部分隐藏三要素white-space: nowrap;// // 消除子元素之间的空白间隙 或者可以删掉span标签之间的空格// font-size:0;overflow: hidden;text-overflow: ellipsis;

背景图片模糊效果 使用通过设置背景图片撑满整个header,将背景图片的z-index设置为-1,使用CSS3中的filter: blur(10px);实现

2、具体实现

(1)、整体布局
<template><div class="header"><div class="content-wrapper"><!-- 头像 --><div class="avatar"><img :src="seller.avatar" width="64" height="64" alt=""></div><!-- 内容 --><div class="content"><div class="title"><span class="brand"></span><span class="name">{{ seller.name }}</span></div><div class="description">{{ seller.description }}/{{ seller.deliveryTime }}分钟送达</div><div v-if="seller.supports" class="support"><span class="icon" :class="classMap[seller.supports[0].type]"></span><span class="text">{{seller.supports[0].description}}</span></div><div v-if="seller.supports" class="support-count" @click="handleClick"><span class="count">{{seller.supports.length}}个</span><i class="iconfont icon-moreinfo-copy"></i></div></div></div><!-- 详情简介 --><div class="bulletin-wrapper" @click="handleClick"><span class="bulletin-title"></span><span class="bulletin-text">{{seller.bulletin}}</span><i class="iconfont icon-moreinfo-copy"></i></div><!-- 背景 --><div class="background"><img :src="seller.avatar" width="100%" height="100%" alt=""></div><!-- 弹层 --><Detal ref="child" :seller="seller" :classMap="classMap"/></div>
</template>
(2)、父子组件传值

在父组件中通过<Header :seller="seller"></Header>将数据传递给header组件,在header组件中通过prop属性接收seller数据

 props: {seller: {type: Object}},
(3)、商家头像展示

商家头像展示通过动态绑定img的src属性获取商家的图片

<div class="avatar"><img :src="seller.avatar" width="64" height="64" alt="">
</div>
(4)、商家内容展示

在商家内容展示中,难点就是商家会有不同的折扣方式,不同的折扣方式对应着不同的折扣图片和文字信息。定义一个classMap用来存储折扣方式

  created () {// 定义一个数组用来存储折扣的图标this.classMap = ['decrease', 'discount', 'special', 'invoice', 'guarantee']},

通过:class="classMap[seller.supports[0].type]"绑定对应的折扣图标通过{{seller.supports[0].description}}展示文字信息

(5)、字体图标的使用
<div v-if="seller.supports" class="support-count" @click="handleClick"><span class="count">{{seller.supports.length}}个</span><i class="iconfont icon-moreinfo-copy"></i>
</div>
 <div class="bulletin-wrapper" @click="handleClick"><span class="bulletin-title"></span><span class="bulletin-text">{{seller.bulletin}}</span><i class="iconfont icon-moreinfo-copy"></i></div>

3、源码

<template><div class="header"><div class="content-wrapper"><!-- 头像 --><div class="avatar"><img :src="seller.avatar" width="64" height="64" alt=""></div><!-- 内容 --><div class="content"><div class="title"><span class="brand"></span><span class="name">{{ seller.name }}</span></div><div class="description">{{ seller.description }}/{{ seller.deliveryTime }}分钟送达</div><div v-if="seller.supports" class="support"><span class="icon" :class="classMap[seller.supports[0].type]"></span><span class="text">{{seller.supports[0].description}}</span></div><div v-if="seller.supports" class="support-count" @click="handleClick"><span class="count">{{seller.supports.length}}个</span><i class="iconfont icon-moreinfo-copy"></i></div></div></div><!-- 详情简介 --><div class="bulletin-wrapper" @click="handleClick"><span class="bulletin-title"></span><span class="bulletin-text">{{seller.bulletin}}</span><i class="iconfont icon-moreinfo-copy"></i></div><!-- 背景 --><div class="background"><img :src="seller.avatar" width="100%" height="100%" alt=""></div><!-- 弹层 --><Detal ref="child" :seller="seller" :classMap="classMap"/></div>
</template>
<script>
import '../../common/stylus/mixin.styl'
// import Modal from '@/components/Modal/Modal.js'
import Detal from '@/components/detal/detal'
export default {// 父组件使用:seller='seller'将数据传给子组件,子组件使用props接收props: {seller: {type: Object}},created () {// 定义一个数组用来存储折扣的图标this.classMap = ['decrease', 'discount', 'special', 'invoice', 'guarantee']},components: {Detal},methods: {handleClick () {// 父组件修改子组件数据this.$refs.child.detailShow = true}}
}
</script><style scoped lang="stylus" rel="stylesheet/stylus">
.header{color: #fff;background: rgba(7,17,27,0.5);position: relative;overflow: hidden;
}
.header .content-wrapper{padding: 24px 12px 18px 24px;font-size: 0;position: relative;
}
.header .content-wrapper .avatar{display: inline-block;// 顶部对齐vertical-align: top;
}
.header .content-wrapper .avatar img{border-radius:2px;
}
.header .content-wrapper .content{display: inline-block;margin-left: 16px;// font-size: 14px;
}
.header .content-wrapper .content .title{margin: 2px 0 8px 0;
}
.header .content-wrapper .content .title .brand{width: 30px;height: 18px;vertical-align: top;display: inline-block;// bg-image('brand');background-image :url('./brand@2x.png')background-size :30px 18px;background-repeat : no-repeat;
}
.header .content-wrapper .content .title .name{margin-left: 6px;font-size: 16px;line-height: 18px;font-weight: bold;
}
.header .content-wrapper .content .description{margin-bottom: 10px;line-height: 12px;font-size: 12px;
}
.header .content-wrapper .content .support .icon{display: inline-block;width: 12px;height: 12px;margin-right: 4px;background-size: 12px 12px;background-repeat: no-repeat;
}
.header .content-wrapper .content .support .decrease{background-image: url('./decrease_1@2x.png')
}
.header .content-wrapper .content .support .discount{background-image: url('./discount_1@2x.png')
}
.header .content-wrapper .content .support .guarantee{background-image: url('./guarantee_1@2x.png')
}
.header .content-wrapper .content .support .invoice{background-image: url('./invoice_2@2x.png')
}
.header .content-wrapper .content .support .special{background-image: url('./special_1@2x.png')
}
.header .content-wrapper .content .support .text{line-height: 12px;font-size: 12px;vertical-align: top;
}
.header .content-wrapper .support-count{position: absolute;right: 12px;bottom: 18px;padding: 0 8px;height: 24px;line-height: 24px;border-radius: 14px;background: rgba(0,0,0,0.2);text-align: center;
}
.header .content-wrapper .support-count .count,
.header .content-wrapper .support-count .iconfont{vertical-align: top;font-size: 10px;
}
.header .bulletin-wrapper{height: 28px;line-height: 28px;position: relative;padding: 0 22px 0 12px;// 文字超出部分隐藏三要素white-space: nowrap;// // 消除子元素之间的空白间隙 或者可以删掉span标签之间的空格// font-size:0;overflow: hidden;text-overflow: ellipsis;background: rgba(7,17,27,0.2);
}
.header .bulletin-wrapper .bulletin-title{display: inline-block;width: 22px;height: 12px;background-image: url('./bulletin@2x.png');background-size: 22px 12px;background-repeat: no-repeat;vertical-align: top;margin-top: 7px;
}
.header .bulletin-wrapper .bulletin-text{font-size: 10px;margin: 0 4px;vertical-align: top;
}
.header .bulletin-wrapper .iconfont{position: absolute;font-size: 10px;right: 12px;
}
.header .background{//背景图片position: absolute;top:0;left:0;width:100%;height:100%;z-index:-1;// 模糊效果filter: blur(10px);
}
</style>

三、蒙层组件

1、detal组件

<template><transition name="slide-fade"><div class="detail" v-if="detailShow"><Modal :seller="seller" :classMap="classMap" @hide-detail="changeDetail"></Modal></div></transition>
</template>

默认detal组件是不显示的,因此在data中定义detailShow,通过改变detal的值来控制蒙层。

  data () {return {detailShow: false}},

类似的子组件通过定义prop属性来接收父组件传过来的值

   props: {seller: {type: Object},classMap: {type: Array}},

2、Modal组件

Modal组件主要实现蒙层的内容展示

(1)、整体布局
<template><div class="modal"><div class = "detail-wrapper  clearfix"><div class = "detail-main"><div class="detail-content"><h1 class="name">{{seller.name}}</h1><div class="star-wrapper"><Star :score="seller.score"></Star></div><div class="title"><div class="line"></div><div class="text">优惠信息</div><div class="line"></div></div><ul v-if="seller.supports" class="supports"><li class="supports-item" v-for="(item,index) in seller.supports" :key="index"><span class="icon" :class="classMap[seller.supports[index].type]"></span><span class="text">{{seller.supports[index].description}}</span></li></ul><div class="title"><div class="line"></div><div class="text">商家公告</div><div class="line"></div></div><div class="bulletin"><p class="content">{{seller.bulletin}}</p></div></div></div><div class = "detail-close" @click="hideDetail"><i class="iconfont icon-quxiao"></i></div></div></div>
</template>

3、蒙层的展示和隐藏

展示
在header组件中通过给

<div v-if="seller.supports" class="support-count" @click="handleClick"><span class="count">{{seller.supports.length}}个</span><i class="iconfont icon-moreinfo-copy"></i>
</div>
 <div class="bulletin-wrapper" @click="handleClick"><span class="bulletin-title"></span><span class="bulletin-text">{{seller.bulletin}}</span><i class="iconfont icon-moreinfo-copy"></i></div>

绑定点击事件handleClick事件来控制蒙层的展示
由于控制蒙层的展示数据在detal组件中,detal组件是header的子组件,父组件想要修改子组件的数据可以通过

  methods: {handleClick () {// 父组件修改子组件数据this.$refs.child.detailShow = true}}

修改。
隐藏
在Modal组件中通过点击

<div class = "detail-close" @click="hideDetail"><i class="iconfont icon-quxiao"></i>
</div>

可以实现隐藏,由于控制蒙层的隐藏数据在detal组件中,Modal组件是detal组件的子组件,子组件无法直接修改父组件的元素,因此子组件可以抛出一个emit事件(触发事件)

  methods: {hideDetail () {this.$emit('hide-detail')}}

父组件detal为子组件设置事件处理程序(注册事件)

 <Modal :seller="seller" :classMap="classMap" @hide-detail="changeDetail"></Modal>
  methods: {changeDetail () {this.detailShow = false}}

4、源码

detal.vue

<template><transition name="slide-fade"><div class="detail" v-if="detailShow"><Modal :seller="seller" :classMap="classMap" @hide-detail="changeDetail"></Modal></div></transition>
</template>
<script>
import Modal from '@/components/Modal/Modal.vue'
export default {props: {seller: {type: Object},classMap: {type: Array}},components: {Modal},data () {return {detailShow: false}},methods: {changeDetail () {this.detailShow = false}}
}
</script><style >
.detail{position: fixed;z-index: 100;top:0;left:0;width: 100%;height: 100%;/* overflow: auto 可以当内容超过屏幕高度时可以实现屏幕滚动*/overflow: auto;background: rgba(7, 17, 27, 0.8);
}
.slide-fade-enter-active {transition: all .3s ease;
}
.slide-fade-leave-active {transition: all .3s cubic-bezier(1.0, 0.5, 0.8, 1.0);
}
.slide-fade-enter, .slide-fade-leave-to {transform: translateX(10px);opacity: 0;
}
</style>

Modal.vue

<template><div class="modal"><div class = "detail-wrapper  clearfix"><div class = "detail-main"><div class="detail-content"><h1 class="name">{{seller.name}}</h1><div class="star-wrapper"><Star :score="seller.score"></Star></div><div class="title"><div class="line"></div><div class="text">优惠信息</div><div class="line"></div></div><ul v-if="seller.supports" class="supports"><li class="supports-item" v-for="(item,index) in seller.supports" :key="index"><span class="icon" :class="classMap[seller.supports[index].type]"></span><span class="text">{{seller.supports[index].description}}</span></li></ul><div class="title"><div class="line"></div><div class="text">商家公告</div><div class="line"></div></div><div class="bulletin"><p class="content">{{seller.bulletin}}</p></div></div></div><div class = "detail-close" @click="hideDetail"><i class="iconfont icon-quxiao"></i></div></div></div>
</template><script>
import Star from '@/components/Star/star'
export default {props: {seller: {type: Object},classMap: {type: Array}},components: {Star},methods: {hideDetail () {this.$emit('hide-detail')}}
}
</script><style scoped>
/* .clearfix{display: inline-block;
} */
.clearfix ::after{display: table;content: ' ';clear: both;
}
.detail-wrapper{position: fixed;width: 100%;height: 100%;z-index: 100;left: 0;top: 0;overflow: auto;
}
.detail-wrapper .detail-main{display: inline-block;min-height: 100%;width: 100%;
}
.detail-wrapper .detail-main .detail-content{margin-top: 64px;padding-bottom: 64px;/**撑开高度 给按钮留出位置 */
}
.detail-wrapper .detail-main .detail-content .name{line-height: 16px;text-align: center;font-size: 16px;font-weight: 700;
}
.detail-wrapper .detail-main .detail-content .star-wrapper{margin-top:18px;padding: 2px 0;text-align: center;
}
.detail-wrapper .detail-main .detail-content .title{display: flex;width: 80%;margin: 28px auto 24px;
}
.detail-wrapper .detail-main .detail-content .title .line{flex: 1;position: relative;top: -6px;border-bottom: 1px solid rgba(255, 255, 255, 0.2);
}
.detail-wrapper .detail-main .detail-content .title .text{padding: 0 12px;font-size: 14px;font-weight: 700;
}
.detail-wrapper .detail-main .detail-content .supports{width: 80%;margin: 0 auto;
}
.detail-wrapper .detail-main .detail-content .supports .supports-item{padding: 0 12px;margin-bottom: 12px;font-size: 0;
}
.detail-wrapper .detail-main .detail-content .supports .supports-item .icon{display: inline-block;width: 16px;height: 16px;vertical-align: top;margin-right: 6px;background-size: 16px 16px;background-repeat: no-repeat;
}
.detail-wrapper .detail-main .detail-content .supports .supports-item .decrease{background-image: url('./decrease_2@2x.png')
}
.detail-wrapper .detail-main .detail-content .supports .supports-item .discount{background-image: url('./discount_2@2x.png')
}
.detail-wrapper .detail-main .detail-content .supports .supports-item .guarantee{background-image: url('./guarantee_2@2x.png')
}
.detail-wrapper .detail-main .detail-content .supports .supports-item .invoice{background-image: url('./invoice_2@2x.png')
}
.detail-wrapper .detail-main .detail-content .supports .supports-item .special{background-image: url('./special_2@2x.png')
}
.detail-wrapper .detail-main .detail-content .supports .supports-item .text{line-height: 16px;font-size: 12px;
}
.detail-wrapper .detail-main .detail-content .bulletin{width: 80%;margin: 0 auto;
}
.detail-wrapper .detail-main .detail-content .bulletin .content{padding: 0 12px;line-height: 24px;font-size: 12px;
}
.detail-close{position: relative;width: 32px;height: 32px;margin: -64px auto 0 auto;clear: both;font-size: 32px;
}
</style>

四、路由切换

在这里使用了页面懒加载,当我们执行这个函数的时候再加载页面

import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
export default new Router({mode: 'history',routes: [{ // 定义首页path: '',redirect: {name: 'goods'}},{path: '/goods',name: 'goods',// 这里使用了Webpack的页面懒加载,当我们运行到这个函数的时候再加载这个页面component: () => import('@/components/goods/goods')},{path: '/ratings',name: 'ratings',component: () => import('@/components/ratings/ratings')},{path: '/seller',name: 'seller',component: () => import('@/components/seller/seller')}]
})

Vue.js仿饿了么外卖App--(2)头部相关的组件的实现相关推荐

  1. Vue.js仿饿了么外卖App--(4)商品详情页实现

    文章目录 一.内容介绍 1.内容 2.效果 二.具体实现 1.组件传值 2.点击事件 3.图片展示 4.加入购物车 5.分隔条组件 6.评价展示 布局 评价筛选组件 时间展示 三.源码 一.内容介绍 ...

  2. Vue.js仿饿了么外卖App--(5)评价列表页实现

    文章目录 一.内容介绍 1.内容 2.效果 二.具体实现 1.数据的获取 2.具体布局 3.star组件 4.ratingSelect组件 三.源码 一.内容介绍 1.内容 本篇文章主要介绍的是评价列 ...

  3. Vue.js仿饿了么外卖App--(6)商家详情页实现

    文章目录 一.内容介绍 1.内容 2.效果 二.具体实现 1.布局 2.滚动实现 三.源码 一.内容介绍 1.内容 商家详情页主要包括商家的具体信息.公告与活动.商家实景和商家信息.其中商家实景这里实 ...

  4. Vue.js高仿饿了么外卖App学习记录

    (给达达前端加星标,提升前端技能) 开发一款vue.js开发一款app,使用vue.js是一款高效的mvvm框架,它轻量,高效,组件化,数据驱动等功能便于开发.使用vue.js开发移动端app,学会使 ...

  5. vue结合饿了么_Vue.js 高仿饿了么外卖app 全套_IT教程网

    资源名称:Vue.js  高仿饿了么外卖app  全套 资源目录: vue仿饿了么视频全套 全套 资源 │ files.txt │ project.zip │ resource.zip │ ├─第01 ...

  6. 项目:Vue.js高仿饿了吗外卖APP(一)

    Vue.js高仿饿了吗外卖APP核心知识 使用Vue.js作为项目的技术栈!这是目前最火的MVVM框架(之一),轻量.简洁.高效.数据驱动.组件化的优点,被大家称为"简单却不失优雅,小巧而不 ...

  7. vue + vue-router + vue-resource + es6 + stylus + webpack 高仿饿了么外卖App商家详情

    VUE高仿饿了么app 本项目github地址:https://github.com/motysla/eleme.git VUE 搭建简介 刚学习了VUE高仿饿了么app课,记录课的要点,巩固知识. ...

  8. Vue.js 高仿饿了么外卖APP

    第1章 课程简介 介绍课程的学习目标和学习内容. 1-1 课程简介 1-2 课程安排 第2章 Vuejs介绍 从前端开发趋势分析开始,引入 MVVM 开发框架和 Vue.js,接着对比流行框架Angu ...

  9. 【慕课网实战课程笔记】Vue.js高仿饿了么外卖App

    写在前面:该课程为慕课网付费课程,笔记内容代码居多.内容简略,仅供自己日后翻阅.如有疑问或者不妥,欢迎提出指正,我看到了会回复,谢谢! 第1章:课程简介 第2章:Vuejs介绍 Ctrl+Alt+l ...

最新文章

  1. java 生成校验验证码_java 验证码生成与校验
  2. Oracle - 新装数据库、新建用户注意事项
  3. Identity Server4学习系列四之用户名密码获得访问令牌
  4. LeetCode-69 x的平方根
  5. E. Sergey and Subway
  6. freeRADIUS下EAP测试
  7. uni-app:uni.navigateTo 封装页面跳转传参
  8. 机器学习加速器文献整理
  9. 用计算机收传真,使用计算机发送和接收传真.doc
  10. Debian/Ubuntu系统命令终端提示无法定位软件包解决方法
  11. android 图标 自定义,巧用 Drawable 之实现一个最简单的自定义电池图标
  12. problem 1148
  13. jdon的设计模式详细解读
  14. 企业简介和公司介绍快闪PPT模板
  15. VS2015远程白屏的解决办法——亲测可用
  16. ToF相机从Camera2 API中获取DEPTH16格式深度图
  17. MII与RMII接口的区别
  18. DataGrip如何将创建的console保存路径设置到指定目录?
  19. wordpress编辑器遇到了未知错误
  20. 大吉大利,今晚吃鸡!

热门文章

  1. 安兔兔html5测试排名,10部手机安兔兔跑分测试:都是骁龙865处理器,差距比想象要大...
  2. EASEUS partition Manager磁盘分割大师
  3. 工作 — 您确定是在招前端工程师职位么?
  4. 雅特丽单片机学习——时钟配置
  5. 小程序开发,小程序代理,小程序加盟,小程序创业
  6. 一篇文章带你详解HTTP协议(1)
  7. IEDA超实用插件,开启这些功能,提高工作效率、提高code容错 ❤️【建议收藏】
  8. 我的世界光影mod怎么用_我的世界电脑版光影怎么用
  9. Table打印 根据高度自动分页
  10. 帆软如何把两个表格分页显示