跟我一起做一个vue的小项目(APPvue2.5完结篇)
先放一下这个完结项目的整体效果
下面跟我我一起进行下面项目的进行吧~~~
接下来我们进行的是实现header的渐隐渐显效果,并且点击返回要回到首页
我们先看效果
在处理详情页向下移动过程中,header页出现,我们使用的是监听滚动的方法,然后动态传入样式
//src\pages\detail\components\Header.vue
<template>
<div>
<router-link
class="header-abs"
tag="div"
to="/"
v-show="showAbs"
>
<div class="iconfont header-abs-back">
</div>
</router-link>
<div
class="header-fixed"
v-show="!showAbs"
:style="opacityStyle"
>
<router-link to="/">
<div class="iconfont header-icon-back"></div>
</router-link>
景点详情
</div>
</div>
</template>
<script>
export default {
name: 'DetailHeader',
data () {
return {
showAbs: true,
opacityStyle: {
opacity: 0
}
}
},
methods: {
handleScroll () {
console.log('滾動艦艇', document.documentElement.scrollTop)
const top = document.documentElement.scrollTop
if (top > 60) {
let opacity = top / 140
opacity = opacity > 1 ? 1 : opacity
this.opacityStyle = {
opacity
}
this.showAbs = false
} else {
this.showAbs = true
}
}
},
activated () {
window.addEventListener('scroll', this.handleScroll)
}
}
</script>
<style lang="stylus" scoped>
@import '~styles/varibles.styl';
.header-abs
position:absolute
left:.2rem
top:.2rem
width:.8rem
height:.8rem
border-radius:.4rem
background:rgba(0,0,0,0.8)
text-align:center
line-height:.8rem
.header-abs-back
color:#fff
font-size:.4rem
.header-fixed
height :$headerHeight
line-height:$headerHeight
overflow:hidden
position:fixed
top:0
left:0
right:0
text-align:center
color:#fff
background:$bgColor
font-size:.32rem
.header-icon-back
width:.64rem
text-align:center
font-size:.4rem
position:absolute
top:0
left:0
color:#fff
</style>
//src\pages\detail\Detail.vue
<template>
<div>
<detail-banner></detail-banner>
<detail-header></detail-header>
<div class="container"></div>
</div>
</template>
<script>
import DetailBanner from './components/Banner'
import DetailHeader from './components/Header'
export default {
name: 'Detail',
components: {
DetailBanner,
DetailHeader
}
}
</script>
<style lang="stylus" scoped>
.container
height:50rem
</style>
接下来我们对项目中,全局事件进行解绑
当我们在header.vue组件中使用 window.addEventListener('scroll', this.handleScroll)的时候,
我们会发现,在首页中滚动页面也会调用这个事件
我们使用keep-alive在缓存过程中产生的钩子函数进行解决这个问题
当在这些组件之间切换的时候都会请求一些请求过的数据,每次请求都会导致重复渲染影响性能。这些数据可以存到缓存。此时使用 activate:是在被包裹组件被激活的状态下使用的生命周期钩子,deactivated:在被包裹组件停止使用时调用
我们的header组件中添加
这样就解决了在首页中,也会进行滚动事件的Bug
//header.vue
<template>
<div>
<router-link
class="header-abs"
tag="div"
to="/"
v-show="showAbs"
>
<div class="iconfont header-abs-back">
</div>
</router-link>
<div
class="header-fixed"
v-show="!showAbs"
:style="opacityStyle"
>
<router-link to="/">
<div class="iconfont header-icon-back"></div>
</router-link>
景点详情
</div>
</div>
</template>
<script>
export default {
name: 'DetailHeader',
data () {
return {
showAbs: true,
opacityStyle: {
opacity: 0
}
}
},
methods: {
handleScroll () {
console.log('滾動艦艇', document.documentElement.scrollTop)
const top = document.documentElement.scrollTop
if (top > 60) {
let opacity = top / 140
opacity = opacity > 1 ? 1 : opacity
this.opacityStyle = {
opacity
}
this.showAbs = false
} else {
this.showAbs = true
}
}
},
activated () {
window.addEventListener('scroll', this.handleScroll)
},
// 移除全局事件的影响
dactivated () {
window.removeEventListener('scroll', this.handleScroll)
}
}
</script>
<style lang="stylus" scoped>
@import '~styles/varibles.styl';
.header-abs
position:absolute
left:.2rem
top:.2rem
width:.8rem
height:.8rem
border-radius:.4rem
background:rgba(0,0,0,0.8)
text-align:center
line-height:.8rem
.header-abs-back
color:#fff
font-size:.4rem
.header-fixed
height :$headerHeight
line-height:$headerHeight
overflow:hidden
position:fixed
top:0
left:0
right:0
text-align:center
color:#fff
background:$bgColor
font-size:.32rem
.header-icon-back
width:.64rem
text-align:center
font-size:.4rem
position:absolute
top:0
left:0
color:#fff
</style>
接下来我们使用递归组件实现详情页的列表
所谓递归组件是什么?就是在组件里面调用自身。
我们先放一下实现的效果图
先在detail页面中定义好数据格式,并将数据传递给子组件
//list.vue
<template>
<div>
<detail-banner></detail-banner>
<detail-header></detail-header>
<div class="container">
<detail-list :list="list"></detail-list>
</div>
</div>
</template>
<script>
import DetailBanner from './components/Banner'
import DetailHeader from './components/Header'
import DetailList from './components/List'
export default {
name: 'Detail',
components: {
DetailBanner,
DetailHeader,
DetailList
},
data () {
return {
list: [
{
title: '成人票',
children: [
{
title: '成人一馆联票',
children: [
{
title: '成人一馆联票-宝安连锁店销售'
},
{
title: '成人一馆联票-龙岗连锁店销售'
},
{
title: '成人一馆联票-坂田连锁店销售'
}
]
},
{
title: '成人二馆联票'
},
{
title: '成人三馆联票'
}
]
},
{
title: '学生票',
children: [
{
title: '学生一馆联票'
},
{
title: '学生二馆联票'
},
{
title: '学生三馆联票'
}
]
},
{
title: '儿童票',
children: [
{
title: '儿童一馆联票',
children: [
{
title: '儿童一馆联票-宝安连锁店销售'
},
{
title: '儿童一馆联票-龙岗连锁店销售'
},
{
title: '儿童一馆联票-坂田连锁店销售'
}
]
},
{
title: '儿童二馆联票'
},
{
title: '儿童三馆联票'
}
]
}
]
}
}
}
</script>
<style lang="stylus" scoped>
// .container
// height:50rem
</style>
//list.vue
//src\pages\detail\components\List.vue
<template>
<div>
<div class="item" v-for="(item,index) of list" :key="index">
<!-- 渲染最外层数据 -->
<div class="item-title border-bottom">
<span class="item-title-icon "></span>
{{item.title}}
</div>
<!-- 如果最外层数据有子数据,就渲染子数据,递归调用本身 -->
<div v-if="item.children" class="item-children">
<detail-list :list="item.children"></detail-list>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'DetailList',
props: {
list: Array
}
}
</script>
<style lang="stylus" scoped>
.item-title-icon
display: inline-block;
width: .36rem;
height: .36rem;
background: url(http://s.qunarzz.com/piao/image/touch/sight/detail.png) 0 -.45rem no-repeat;
margin-right: .1rem;
background-size: .4rem 3rem;
vertical-align: middle;
.item-title
line-height:0.8rem
font-size:.32rem
padding:0 .2rem
.item-children
padding-left:0.6rem
</style>
接下来我们使用ajax来动态渲染数据
我们在mock数据引入detail.json
{
"ret": true,
"data": {
"sightName": "大连圣亚海洋世界(AAAA景区)",
"bannerImg": "http://img1.qunarzz.com/sight/p0/201404/23/04b92c99462687fa1ba45c1b5ba4ad77.jpg_600x330_bf9c4904.jpg",
"commentsNum": 27,
"gallaryImgs": [
"http://img1.qunarzz.com/sight/p0/201404/23/04b92c99462687fa1ba45c1b5ba4ad77.jpg_800x800_70debc93.jpg",
"http://img1.qunarzz.com/sight/p0/1709/76/7691528bc7d7ad3ca3.img.png_800x800_9ef05ee7.png"
],
"categoryList": [
{
"title": "成人票",
"children": [
{
"title": "成人三馆联票",
"children": [
{
"title": "成人三馆联票 - 某一连锁店销售"
}
]
},
{
"title": "成人五馆联票"
}
]
},
{
"title": "学生票"
},
{
"title": "儿童票"
},
{
"title": "特惠票"
}
]
}
}
在detail中引入数据
//src\pages\detail\Detail.vue
<template>
<div>
<detail-banner
:sightName="sightName"
:bannerImg="bannerImg"
:bannerImgs="gallaryImgs"
></detail-banner>
<detail-header ></detail-header>
<div class="container">
<detail-list :list="list"></detail-list>
</div>
</div>
</template>
<script>
import DetailBanner from './components/Banner'
import DetailHeader from './components/Header'
import DetailList from './components/List'
import axios from 'axios'
export default {
name: 'Detail',
components: {
DetailBanner,
DetailHeader,
DetailList
},
data () {
return {
sightName: '',
bannerImg: '',
gallaryImgs: [],
list: [
]
}
},
methods: {
getDetailInfo () {
axios.get('/api/detail.json?id=' + this.$route.params, {
params: {
id: this.$route.params.id
}
}).then(this.handleGetDataSucc)
},
handleGetDataSucc (res) {
console.log('res', res)
res = res.data
if (res.ret && res.data) {
const data = res.data
console.log('data', data)
this.sightName = data.sightName
this.bannerImg = data.bannerImg
this.gallaryImgs = data.gallaryImgs
this.list = data.categoryList
}
}
},
mounted () {
this.getDetailInfo()
}
}
</script>
<style lang="stylus" scoped>
// .container
// height:50rem
</style>
将detail中传入的数据,传递给子组件
//src\pages\detail\components\List.vue
<template>
<div>
<div class="item" v-for="(item,index) of list" :key="index">
<!-- 渲染最外层数据 -->
<div class="item-title border-bottom">
<span class="item-title-icon "></span>
{{item.title}}
</div>
<!-- 如果最外层数据有子数据,就渲染子数据,递归调用本身 -->
<div v-if="item.children" class="item-children">
<detail-list :list="item.children"></detail-list>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'DetailList',
props: {
list: Array
}
}
</script>
<style lang="stylus" scoped>
.item-title-icon
display: inline-block;
width: .36rem;
height: .36rem;
background: url(http://s.qunarzz.com/piao/image/touch/sight/detail.png) 0 -.45rem no-repeat;
margin-right: .1rem;
background-size: .4rem 3rem;
vertical-align: middle;
.item-title
line-height:0.8rem
font-size:.32rem
padding:0 .2rem
.item-children
padding-left:0.6rem
</style>
//src\pages\detail\components\Banner.vue
<template>
<div>
<div class="banner" @click="handleBannerClick">
<img :src="bannerImg" alt="" class="banner-img">
<div class="banner-info">
<div class="banner-title">
{{this.sightName}}
</div>
<div class="banner-number">
<span class="iconfont"></span>
{{this.bannerImgs.length}}
</div>
</div>
</div>
<common-gallary
:imgs="bannerImgs"
v-show="showGallery"
@close="handlegalleryClose"
></common-gallary>
</div>
</template>
<script>
import CommonGallary from 'common/gallary/Gallary'
export default {
name: 'DetailBanner',
props: {
sightName: String,
bannerImg: String,
bannerImgs: Array
},
data () {
return {
showGallery: false,
imgs: [
// 'http://img1.qunarzz.com/sight/p55/201211/04/fbcab3e5d6479ce893835fbb.jpg_r_800x800_6360f514.jpg',
// 'http://img1.qunarzz.com/wugc/p180/201306/16/7f08e81624346b1693835fbb.jpg_r_800x800_5f03ad73.jpg'
]
}
},
components: {
CommonGallary
},
methods: {
handleBannerClick () {
this.showGallery = true
},
handlegalleryClose () {
this.showGallery = false
}
}
}
</script>
<style lang="stylus" scoped>
.banner
overflow:hidden
height:0
padding-bottom:55%
position:relative
.banner-img{
width:100%
}
.banner-info
display:flex
position:absolute
left:0
right:0
bottom:0
line-height:0.6rem
background-image:linear-gradient(top,rgba(0,0,0,0),rgba(0,0,0,0.8))
color:#fff
.banner-title
flex:1
font-size:.32rem
padding:0 .2rem
.banner-number
padding:0 .4rem
height:.32rem
line-height:.4rem
margin-top:.24rem
border-radius:.2rem
background:rgba(0,0,0,.8)
font-size:0.24rem
.iconfont
font-size:.24rem
</style>
接下来我们给项目添加一些动画效果,点击我们的banner图片,进入gallery图片,给他一个动画的效果
封装动画组件,transition里面的slot插槽,可以插入各种我们要进行动画处理的组件
//src\common\fade\FadeAnimation.vue
<template>
<div>
<transition>
<slot></slot>
</transition>
</div>
</template>
<script>
export default {
name: 'FadeAnimation'
}
</script>
<style lang="stylus" scoped>
.v-enter,.v-leave-to
opacity:0
.v-enter-active,.v-leave-active
transition: opacity 0.5s
</style>
我们在gallery中使用
效果如下
我已经将我跟着视频做的项目传到了github上面:https://github.com/JserJser/dailyPush/tree/master/travel
恬不知耻向你们求一个star~~~~~
后记:今天接到了一个电话,大抵是以前实习的时候的,问我同学,说是打我同学电话没有打到,然后问我有没有同他联系。有些唏嘘。
想想毕业已经三年了。
不知道自己对自己的未来有什么期许呢~你想成为什么样的人呢?是不是三年前自己想成为的人呢?
好好看视频,好好学习,好好掌握项目吧~我呀, 还差的很远呢~
第十部分主要讲解的是项目接口联调部分,将mock中的数据放入XAMPP中,还有如何手机真机测试,以及如何打包数据,这部分我就是看了而已,没有实际操作。真实数据是与后端联调。视频的老师给了有些学习vue的建议,可以多多研究vue的一些常见组件的源码,还有研究vue的源码,以及,学习vue的ssr服务端的渲染问题等。
还有很多东西不会,要精通,要很厉害啊~~~
跟我一起做一个vue的小项目(APPvue2.5完结篇)的更多相关文章
- 跟我一起做一个vue的小项目(二)
这个vue项目是紧跟着之前的项目跟我一起做一个vue的小项目(一)来的. 我继续后面的开发(写的比较粗糙,边学边记录) 下图是header头部的样式 header组件内容如下 //header.vue ...
- 跟我一起做一个vue的小项目(八)
接下来我们进行的是城市选择页面的路由配置 添加city.vue,使其点击城市,然后跳转到city页面 //router.js import Vue from 'vue' import Router f ...
- 跟我一起做一个vue的小项目(七)
先看下我们所做项目的效果 这些数据都是我们在data中定义的,不是从后端数据中请求的.那么 接下来我们使用axios渲染数据 npm install axios --save 每个组件里面的数据都不相 ...
- 跟我一起做一个vue的小项目(五)
接下来我们要做的是热门推荐页面,我们写一个推荐组件 使用的方法也是前端data中的数据渲染到页面上面,这里对文字过长取省略号的方法不成功使用了一个小技巧 使用了min-width:0 我们来看完整的代 ...
- 跟我一起做一个vue的小项目(四)
接下来我们进行的是轮播页面下面的导航页的开发 我们需要的是实现轮播页下面的图标,并且实现轮播效果 这个话,其实基本思路先是渲染出小图标,然后,我们要对页数进行判断,如果图标的个数展示的就是8个,那个这 ...
- 跟我一起做一个vue的小项目(十一)
接下来我们进行的是详情页动态路由及banner布局 先看页面的效果 下面是代码部分 <template> <div> <div class="banner&qu ...
- 跟我一起做一个vue的小项目(十)
接下来我们对城市列表页面进行优化,除了对数据优化,也会进行节流处理 //src\pages\city\components\Alphabet.vue <template> <ul c ...
- 跟我一起做一个vue的小项目(三)
接下来我们进行轮播的开发 安装插件,选用2.6.7的稳定版本 npm install vue-awesome-swiper@2.6.7 --save 根据其github上面的用法,我们在全局引用,在m ...
- 跟我一起做一个vue的小项目(九)
接下来我们进行的就是城市列表页面数据额动态渲染. 也是在mock数据,进行动态渲染 //city.json { "ret": true, "data":{ &q ...
随机推荐
- ie中onclick问题
代码:<button > <span onclick="xxx();">确定</span></button> 在chrome和fir ...
- ST(RMQ)算法(在线)求LCA
在此之前,我写过另一篇博客,是倍增(在线)求LCA.有兴趣的同学可以去看一看.概念以及各种暴力就不在这里说了,那篇博客已经有介绍了. 不会ST算法的同学点这里 ST(RMQ)算法在线求LCA 这个算法 ...
- 廖雪峰Java13网络编程-2Email编程-1发送email
1.邮件发送 1.1传统邮件发送: 传统的邮件是通过邮局投递,从一个邮局到另一个邮局,最终到达用户的邮箱. 1.2电子邮件发送: 与传统邮件类似,它是从用户电脑的邮件软件(如outlook)发送到邮件 ...
- SpringCloud搭建分布式配置中心(基于git)
1.简介 Spring Cloud Config.它用来为分布式系统中的基础设施和微服务提供集中化的外部配置支持,分为服务端和客户端两个部分. 其中服务端也称为分布式配置中心,他是独立的微服务应用,用 ...
- React中的Ajax
React中的Ajax 组件的数据来源,通常是通过Ajax请求从服务器获取,可以使用componentDidMount方法设置Ajax请求,等到请求成功,再用this.setState方法重新渲染UI ...
- Http协议之content
用android 通过http协议提交数据至服务器 content的内容 代码如下: private static JSONObject connUpload(String baseUrl, Map& ...
- UltraISO刻录CentOS 7安装指南
CentOS 7.2 安装指南(U盘版) 一.准备阶段 1.下载CentOS7镜像文件(ISO文件)到自己电脑,官网下载路径: http://isoredirect.centos.org/centos ...
- 一个四五年的Java开发程序员,该准备哪些去面试?
上周面试了一周,感触颇深,总结一下. 面试了公司大概有阿里,携程,爱奇艺,唯品会,途牛,bilibili,大众点评,阿里和爱奇艺是电话面试,其他现场面试. 首先,五年左右,应该算高级开发工程师,大部分 ...
- 我学习python没有记住的东西
格式化 # 格式化 a=123 b='ww' print("%d,%s,%%"%(a,b)) # %d,%s,%f,%c,%f 格式化代码:print('{}{}'.format( ...
- scrapy中的ImagePipeline下载图片到本地、并提取本地的保存地址
通过scrapy内置到ImagePipeline下载图片到本地 在settings中打开 ITEM_PIPELINES的注释,并在这里面加入 'scrapy.pipelines.images.Imag ...