一,banner 圖的設計
1. 新建detail的路由
import Detail from '@/pages/detail/Detail' ...... { path: '/detail', name: 'Detail', component: Detail }
Detail.vue
<template> <div> <detail-banner></detail-banner> </div> </template> <script> import DetailBanner from './components/Banner' export default { name: 'Detail', components: { DetailBanner } } </script> <style> </style>
新建 Banner.vue組件
<template> <div class="banner"> <img src="http://img1.qunarzz.com/sight/p0/1409/19/adca619faaab0898245dc4ec482b5722.jpg_600x330_f922b488.jpg" class="banner-img" alt=""> <div class="banner-info"> <div class="banner-title">故宮(AAAAA景區)</div> <div class="banner-number"><span class="iconfont banner-icon"></span>39</div> </div> </div> </template> <script> export default { name: 'DetailBanner' } </script> <style lang="stylus" scoped> .banner position relative overflow hidden height 0 padding-bottom 55% .banner-img width 100% .banner-info position absolute color #ffffff left 0 right 0 bottom 0 line-height .6rem background-image linear-gradient(top,rgba(0,0,0,0),rgba(0,0,0,0.8)) display flex .banner-title font-size .32rem padding 0 .2rem flex 1 .banner-number margin .14rem padding 0 .3rem line-height .4rem height .32rem font-size .24rem border-radius .2rem background rgba(0, 0, 0, 8) .banner-icon font-size .24rem padding .02rem </style>

二,公用圖片畫廊組件
1. 創建一個公用組件 Gallary.vue
使用 vue-awesome-swiper 完成圖片滾動
<template> <div class="container" @click="HandleClick"> <div class="wrapper"> <swiper :options="swiperOption"> <!-- slides --> <swiper-slide v-for="(item,index) in imgs" :key="index"> <img class="gallery-img" :src="item" alt=""> </swiper-slide> <!-- Optional controls --> <div class="swiper-pagination" slot="pagination"></div> </swiper> </div> </div> </template> <script> export default { name: 'CommonGallary', props: { imgs: { type: Array } }, methods: { HandleClick () { // 關閉 this.$emit('close') } }, data () { return { swiperOption: { loop: true, pagination: '.swiper-pagination', paginationType: 'fraction', // observer啟動動態檢查器(OB/觀眾/觀看者),當改變swiper的樣式(例如隱藏/顯示)或者修改swiper的子元素時,自動初始化swiper。 // 默認false observer: true, observeParents: true } } } } </script> <style lang="stylus" scoped> .container >>> .swiper-container overflow inherit .container display flex flex-direction column justify-content: center background-color #000 position fixed top 0 left 0 right 0 bottom 0 z-index 999 .wrapper padding-bottom 100% height 0 width 100% .gallery-img width 100% .swiper-pagination color #fff bottom -1rem </style>
2. Banner.vue
定義變量 showGallary 負責照片牆的顯示與否
<common-gallary @close="HandleClose" :imgs="imgs" v-show="showGallary"></common-gallary>
監聽變化,傳入圖片數據,顯示與否
<template> <div> <div class="banner"> <img v-show="!showGallary" @click="handleImgClick" src="http://img1.qunarzz.com/sight/p0/1409/19/adca619faaab0898245dc4ec482b5722.jpg_600x330_f922b488.jpg" class="banner-img" alt=""> <div class="banner-info"> <div class="banner-title">故宮(AAAAA景區)</div> <div class="banner-number"><span class="iconfont banner-icon"></span>39</div> </div> </div> <common-gallary @close="HandleClose" :imgs="imgs" v-show="showGallary"></common-gallary> </div> </template> <script> import CommonGallary from 'common/gallary/Gallary' export default { name: 'DetailBanner', data () { return { imgs: [ 'http://img1.qunarzz.com/sight/p0/1510/8e/8eea8eb6f41698290.img.jpg_r_800x800_83a5fe3a.jpg', 'http://img1.qunarzz.com/sight/p0/1510/ca/ca60a080020329ef90.img.jpg_350x240_9ff2208e.jpg', 'http://img1.qunarzz.com/sight/p0/1510/cc/ccafbdaac21bdbf790.img.jpg_350x240_c35f8451.jpg' ], showGallary: false } }, methods: { handleImgClick () { this.showGallary = true }, HandleClose () { 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 position absolute color #ffffff left 0 right 0 bottom 0 line-height .6rem background-image linear-gradient(top,rgba(0,0,0,0),rgba(0,0,0,0.8)) display flex .banner-title font-size .32rem padding 0 .2rem flex 1 .banner-number margin .14rem padding 0 .3rem line-height .4rem height .32rem font-size .24rem border-radius .2rem background rgba(0, 0, 0, 8) .banner-icon font-size .24rem padding .02rem </style>

三,header 漸隱漸現效果
后退符號制作:
<router-link tag="div" to="/" class="header-abs"> <div class="iconfont back-icon header-abs-back"></div> </router-link>
顯示詳情:
<div class="header-fixed" v-show="!showAbs"> <router-link to="/"> <div class="iconfont back-icon header-fixed-back"></div> </router-link> 景點詳情 </div>
當下滑一定距離,header-fixed 顯示出來
添加綁定滾動事件
methods: { handleScroll () { console.log(document.documentElement.scrollTop) } }, activated () { window.addEventListener('scroll', this.handleScroll) }

當滾動> 60 時,顯示出來
handleScroll () { const top = document.documentElement.scrollTop if (top > 60) { this.showAbs = false } else { this.showAbs = true } }

漸隱漸現制作:
opacityStyle // 漸隱漸現變量
給header-fixed綁定 :style="opacityStyle"
handleScroll () { 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 } }

<template> <div> <router-link v-show="showAbs" tag="div" to="/" class="header-abs"> <div class="iconfont back-icon header-abs-back"></div> </router-link> <div class="header-fixed" v-show="!showAbs" :style="opacityStyle"> <router-link to="/"> <div class="iconfont back-icon header-fixed-back"></div> </router-link> 景點詳情 </div> </div> </template> <script> export default { name: 'DetailHeader', data () { return { showAbs: true, opacityStyle: { opacity: 0 } } }, methods: { handleScroll () { 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 line-height .8rem border-radius .4rem text-align center background rgba(0,0,0,.8) .header-abs-back color #ffffff font-size .4rem .header-fixed position fixed top 0 left 0 right 0 overflow hidden height $headerHeight line-height $headerHeight color #ffffff background $bgColor text-align center font-size .32rem .header-fixed-back color #ffffff position absolute top 0 left 0 width .64rem </style>
四,對全局事件解綁
因為綁定了 window.addEventListener(......)
對其他組件也產生影響
activated () { window.addEventListener('scroll', this.handleScroll) },
// 解綁 deactivated () { window.removeEventListener('scroll', this.handleScroll) }
生命周期函數:
activated
keep-alive組件激活時調用。
該鈎子在服務器端渲染期間不被調用。
deactivated
keep-alive組件停用時調用。
該鈎子在服務端渲染期間不被調用
五,遞歸組件實現詳情頁列表
例如有以下數據:
list: [ { title: '成人票', children: [ { title: '特惠雙人票' }, { title: '三人票', children: [ { title: '包午餐三人票' } ] } ] }, { title: '學生票', children: [ { title: '學生票七日游' } ] }, { title: '兒童票' }, { title: '特惠票' } ]
新建LIst.vue
<div class="item" v-for="(item,index) in list" :key="index"> <div class="item-title border-bottom"> <span class="item-title-icon"></span> {{item.title}} </div> <div v-if="item.children" class="children">
// 多層遍歷 <detail-list :list="item.children"></detail-list> </div> </div>
<template> <div> <div class="item" v-for="(item,index) in list" :key="index"> <div class="item-title border-bottom"> <span class="item-title-icon"></span> {{item.title}} </div> <div v-if="item.children" class="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 line-height .8rem font-size .32rem padding 0 .2rem .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 position relative left .06rem top: .06rem .children padding 0 .5rem </style>

