Vue2.5 旅游项目实例19 详情页 动态路由及banner布局
创建分支:detail-banner
拉取到本地并切换分支:
git pull
git checkout detail-banner
打开home下的Recommend.vue文件:
<router-link tag="li" class="item border-bottom" :to="'/detail/' + item.id" v-for="item in recommendList" :key="item.id"> <img class="item-img" :src="item.imgUrl" alt="" /> <div class="item-info"> <p class="item-title">{{item.title}}</p> <p class="item-desc">{{item.desc}}</p> <button class="item-button">查看详情</button> </div> </router-link>
然后新建detail文件夹下的Dettail.vue文件,并创建路由:
import Vue from 'vue' import Router from 'vue-router' import Home from '@/pages/home/Home' import City from '@/pages/city/City' import Detail from '@/pages/detail/Detail' Vue.use(Router) export default new Router({ routes: [ { path: '/', name: 'Home', component: Home }, { path: '/city', name: 'City', component: City }, { path: '/detail/:id', name: 'Detail', component: Detail } ] })
在detail目录下创建components文件夹,新建Banner.vue文件:
<template> <div> banner </div> </template> <script> export default { name: 'DetailBanner' } </script> <style lang="stylus" scoped> </style>
然后在Detail.vue中引用banner组件:
<template> <div> <detail-banner></detail-banner> </div> </template> <script> import DetailBanner from './components/Banner' export default { name: 'Detail', components: { DetailBanner } } </script>
继续编辑Banner.vue文件:
<template> <div class="banner"> <img class="banner-img" src="//img1.qunarzz.com/sight/p0/1409/19/adca619faaab0898245dc4ec482b5722.jpg_600x330_f922b488.jpg" /> <div class="banner-info"> <div class="banner-title">故宫(AAAAA景区)</div> <div class="banner-number"><i class="iconfont banner-icon"></i> 12</div> </div> </div> </template> <script> export default { name: 'DetailBanner' } </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:.6rem color: #fff background-image:linear-gradient(top, rgba(0,0,0,0), rgba(0,0,0,0.8)) .banner-title flex: 1 padding:0 .2rem font-size: .32rem .banner-number margin-top:.14rem padding:0 .4rem line-height: .32rem height: .32rem font-size: .24rem border-radius:.2rem background:rgba(0, 0, 0, .8) .banner-icon font-size:.24rem </style>
效果图:
然后我们想要的效果是,点击顶部banner的时候,弹出一个画廊组件,这个组件里可以实现图片的轮播,图片下面还有当前图片的页码。
公用图片画廊组件拆分
在src目录下创建common文件夹,里面存放一些全局公用的组件。
在common目录下创建gallary文件夹,新建Gallary.vue文件:
<template> <div>gallary</div> </template> <script> export default { name: 'CommonGallary' } </script> <style lang="stylus" scoped> </style>
然后打开build目录下的webpack.base.conf.js文件,添加一个别名:
resolve: { extensions: ['.js', '.vue', '.json'], alias: { 'vue$': 'vue/dist/vue.esm.js', '@': resolve('src'), 'styles': resolve('src/assets/styles'), 'common': resolve('src/common'), } },
保存后,记得重启服务。
继续打开Banner.vue文件,引用gallary组件:
<template> <div> <div class="banner"> <img class="banner-img" src="//img1.qunarzz.com/sight/p0/1409/19/adca619faaab0898245dc4ec482b5722.jpg_600x330_f922b488.jpg" /> <div class="banner-info"> <div class="banner-title">故宫(AAAAA景区)</div> <div class="banner-number"><i class="iconfont banner-icon"></i> 12</div> </div> </div> <common-gallary></common-gallary> </div> </template> <script> import CommonGallary from 'common/gallary/Gallary' export default { name: 'DetailBanner', components: { CommonGallary } } </script>
然后就要继续编写Gallary.vue文件:
先写死图片看效果:
<template> <div class="container"> <div class="wrapper"> <swiper :options="swiperOptions"> <swiper-slide > <img width="100%" src="http://img1.qunarzz.com/sight/p0/1409/19/adca619faaab0898245dc4ec482b5722.jpg_r_800x800_6edd8174.jpg" /> </swiper-slide> <swiper-slide > <img width="100%" src="http://img1.qunarzz.com/sight/p0/1907/ca/ca68bd95bc36bdba3.img.jpg_r_800x800_33169c4b.jpg" /> </swiper-slide> <div class="swiper-pagination" slot="pagination"></div> </swiper> </div> </div> </template> <script> export default { name: 'CommonGallary', data () { return { swiperOptions: { pagination: '.swiper-pagination' } } } } </script> <style lang="stylus" scoped> .container display:flex flex-direction:column justify-content:center z-index: 99 position: fixed left:0 right:0 top:0 bottom:0 background: #000 .wrapper width: 100% height: 0 padding-bottom: 66% </style>
这时2张图片可以滚动,下面要添加底部的分页效果:
<script> export default { name: 'CommonGallary', data () { return { swiperOptions: { pagination: '.swiper-pagination', paginationType: 'fraction' } } } } </script> <style lang="stylus" scoped> .container >>> .swiper-container overflow:inherit .swiper-pagination color: #fff bottom: -1rem </style>
现在效果就可以实现了:
然后就可以实现循环逻辑部分了:
<template> <div class="container"> <div class="wrapper"> <swiper :options="swiperOptions"> <swiper-slide v-for="(item, index) in imgs" :key="index"> <img width="100%" :src="item" /> </swiper-slide> <div class="swiper-pagination" slot="pagination"></div> </swiper> </div> </div> </template> <script> export default { name: 'CommonGallary', props: { imgs: { tpye: Array, // 默认函数,返回数组 default () { return [ 'http://img1.qunarzz.com/sight/p0/1409/19/adca619faaab0898245dc4ec482b5722.jpg_r_800x800_6edd8174.jpg', 'http://img1.qunarzz.com/sight/p0/1907/ca/ca68bd95bc36bdba3.img.jpg_r_800x800_33169c4b.jpg'] } } }, data () { return { swiperOptions: { pagination: '.swiper-pagination', paginationType: 'fraction' } } } } </script>
效果和刚才还是一样的,没问题。
然后把默认 default 函数,返回改为空数组。
default () { return [] }
回到Banner.vue文件,把刚才的2个图片地址先写上:
<common-gallary :imgs="imgs"></common-gallary> <script> import CommonGallary from 'common/gallary/Gallary' export default { name: 'DetailBanner', components: { CommonGallary }, data () { return { imgs: ['http://img1.qunarzz.com/sight/p0/1409/19/adca619faaab0898245dc4ec482b5722.jpg_r_800x800_6edd8174.jpg', 'http://img1.qunarzz.com/sight/p0/1907/ca/ca68bd95bc36bdba3.img.jpg_r_800x800_33169c4b.jpg'] } } } </script>
刷新,效果还是一样的。
下面我们把 common-gallary 组件设置为默认隐藏的,当点击banner的时候才会显示:
<div class="banner" @click="handleBanner"> 、、、 </div> <common-gallary :imgs="imgs" v-show="showGallary"></common-gallary> <script> import CommonGallary from 'common/gallary/Gallary' export default { name: 'DetailBanner', components: { CommonGallary }, data () { return { showGallary: false, imgs: ['http://img1.qunarzz.com/sight/p0/1409/19/adca619faaab0898245dc4ec482b5722.jpg_r_800x800_6edd8174.jpg', 'http://img1.qunarzz.com/sight/p0/1907/ca/ca68bd95bc36bdba3.img.jpg_r_800x800_33169c4b.jpg'] } }, methods: { handleBanner () { this.showGallary = true } } } </script>
现在点击banner图片时,可以显示画廊组件了,但是轮播好像滚动有点问题。这个是因为 common-gallary 组件开始是处于隐藏状态,当再次显示时,Swiper计算宽度会有一些问题,导致轮播图无法正常滚动。
打开Gallary.vue文件,添加2个参数:
observeParents:observe应用于Swiper的父元素。当Swiper的父元素变化时,例如window.resize,Swiper更新。
observer:启动动态检查器(OB/观众/观看者),当改变swiper的样式(例如隐藏/显示)或者修改swiper的子元素时,自动初始化swiper。 默认false,不开启,可以使用update()方法更新。
data () { return { swiperOptions: { pagination: '.swiper-pagination', paginationType: 'fraction', observeParents: true, observer: true } } }
OK,回到页面重新刷新,已经可以滚动了。
最后就是点击轮播图,轮播插件给关闭
打开Gallary.vue,给container添加一个点击事件:
<div class="container" @click="handleGallary"> <script> export default { methods: { handleGallary () { this.$emit('close') } } } </script>
在Banner.vue中接收close:
<common-gallary :imgs="imgs" v-show="showGallary" @close="gallaryClose"></common-gallary> <script> import CommonGallary from 'common/gallary/Gallary' export default { methods: { gallaryClose () { this.showGallary = false } } } </script>
OK,功能完成,可以提交代码了:
git add .
git commit -m "banner及公用画廊组件"
git push
git checkout master
git merge detail-banner
git push