以详情页获取Ajax数据为例看,解释 mounted缓存问题及页面间滚动互相影响问题
一、mounted缓存问题
1、原因分析:
页面跳转由于之前在APP.vue文件中给全局文件增加了keep-alive标签,使得页面在使用生命周期钩子mounted时存在缓存问题,即从首页点击详情进入详情页面之后,会将本次的信息存下来(ID),再次换一个景点点击进去会发现传值是传的当前景点的ID,但是在NetWork中查看会发现使用的还是上一次的ID,并没有获取新的ID
2、解决方案:
将Detail组件从首页的keep-alive中通过exclude剔除出去,使得Detail这个组件不执行缓存机制
// 根目录的App.vue
// 他这里吧所有的组件都用keep-alive包裹建缓存,使用exclude排除组件,也就是说Detail这个组件不执行缓存机制。
<keep-alive exclude="Detail">
<router-view/>
</keep-alive>
二、页面滚动互相影响问题
1、原因分析:
当第一个页面滚动到已经超出一个屏幕的高度之后,点击进去其他页面会发现,新页面的页面也随之滚动,而没有保持在顶部显示的效果,所以此时需要将各个页面的滚动效果分隔开,互不影响
2、解决方案
在路由中添加scrollBehavior函数,让每个页面独立
export default new Router({
routes: [
{
path: '/',
name: 'Home',
component: Home
}, {
path: '/city',
name: 'City',
component: City
},
{
path: '/detail/:id',
name: 'Detail',
component: Detail
}
],
// 这里添加
scrollBehavior (to, from, savedPosition) {
return { x: 0, y: 0 }
}
})
三、keep-alive和exclude导致的详情头部没办法渐隐渐现问题
1、原因分析:
exclude剔除之后Detail组件相当于没有keep-alive带来的缓存,导致activated和deactivated两个生命周期函数没办法使用,详情见https://cn.vuejs.org/v2/api/#activated
2、解决方案:
在Detail的Header组件上额外添加keep-alive标签,重新赋予Header组件功能即可实现原来渐隐渐现的效果(切不可将keep-alive标签加在组件(Detail.vue)内容组件(Header.vue)上,那样没有效果,只可加在Deatil.vue中)
<keep-alive>
<detail-header></detail-header>
</keep-alive>
详情Ajax获取数据代码共享
Json数据
{
"ret": true,
"data": {
"sightName": "大连圣亚海洋世界(AAAA景区)",
"bannerImg": "http://img1.qunarzz.com/sight/p0/201404/23/04b92c99462687fa1ba45c1b5ba4ad77.jpg_600x330_bf9c4904.jpg",
"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获取
<template>
<div>
<detail-banner
:sightName="sightName"
:bannerImg="bannerImg"
:bannerImgs="gallaryImgs"
></detail-banner>
<keep-alive>
<detail-header></detail-header>
</keep-alive>
<div class="content">
<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', {
params: {
id: this.$route.params.id
}
}).then(this.handleGetDataSucc)
},
handleGetDataSucc (res) {
res = res.data
if (res.ret && res.data) {
const data = res.data
// console.log(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>
.content
height 50rem
</style>
Banner.vue
<template>
<div>
<div class="banner" @click="handleBannerClick">
<img class="banner-img" :src="bannerImg">
<div class="banner-info">
<div class="banner-title">{{this.sightName}}</div>
<div class="banner-number">
<span class="iconfont banner-icon"></span>
{{this.bannerImgs.length}}
</div>
</div>
</div>
<common-gallary :imgs="bannerImgs" v-show="showGallary" @close="handleGallyClose"></common-gallary>
</div>
</template>
<script>
import CommonGallary from 'common/gallary/Gallary'
export default {
name: 'Detail',
props: {
sightName: String,
bannerImg: String,
bannerImgs: Array
},
data () {
return {
showGallary: false
}
},
methods: {
handleBannerClick () {
this.showGallary = true
},
handleGallyClose () {
this.showGallary = false
}
},
components: {
CommonGallary
}
}
</script>
<style lang="stylus" scoped>
.banner
position relative
overflow hidden
height 0
padding-bottom 55%
.banner-img
width 100%
.banner-info
display flex
position absolute
left 0
right 0
bottom 0
line-height .6rem
color #fff
// 渐变色
background-image linear-gradient(top, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.8))
.banner-title
flex 1
font-size .32rem
padding 0 .2rem
.banner-number
margin-top .14rem
padding 0 .4rem
line-height .32rem
height .32rem
border-radius .2rem
background rgba(0, 0, 0, .8)
font-size .24rem
.banner-icon
font-size .24rem
</style>
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 class="item-children" v-if="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>
@import '~styles/varibles.styl'
.border-bottom
&:before
border-color #ccc
.item
.item-title
line-height .8rem
font-size .32rem
padding 0 .2rem
.item-title-icon
position relative
left .06rem
top .06rem
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;
.item-children
padding 0 .2rem
</style>