(20)详情页开发——② 公用图片画廊组件 | Vue.js 项目实战: 移动端“旅游网站”开发

复制代码
转载请注明出处,未经同意,不可修改文章内容。

🔥🔥🔥"前端一万小时"两大明星专栏------"从零基础到轻松就业"、"前端面试刷题",已于本月大改版,合二为一,干货满满,欢迎点击公众号菜单栏各模块了解。

1 需求

当点击详情页的海报图时,可查看景点介绍的图片:

  • 左右滑动可查看每张图片;
  • 图片下方有分页指示器;
  • 再次点击可见区域时,退出查看图片状态,返回到详情页。

2 公用图片画廊组件

2.1 公用图片画廊组件布局

🔗前置知识:
《深入理解 Vue 组件------② 父子组件间的数据传递》

《首页开发------② 轮播组件》

需求分析:当点击海报时,进入一个查看图片的区域。它的样式非常简单,图片垂直居中;左右滑动查看图片的功能,依然可以借助 vue-awesome-swiper 来实现。并且,在项目中,还有别的地方可能也会用到这样的功能。所以,我们可以将这个功能单独拆分出来,作为一个独立的公用组件(即,公用图片画廊组件),所有需要这个功能的组件直接调用它即可。

1️⃣在 src 下新建一个 common 文件夹,用来放置所有公用组件:

1️⃣-①:在 common 中新建一个 gallery 文件夹(后续若 Gallery 组件变得复杂、庞大时,方便继续在 gallery 文件夹中进行拆分);

1️⃣-②:在 gallery 文件夹中新建公用图片画廊组件 Gallery.vue ;

html 复制代码
<template>
  <div>This is Gallery.</div> <!-- 1️⃣-④:添加一点内容; -->
</template>

<script>
export default {
  name: 'CommonGallery' // 1️⃣-③:公用图片画廊组件命名为 CommonGallery;
}
</script>

<style lang="stylus" scoped>
</style>

1️⃣-⑤:由于我们可能会在任意组件中使用公用组件,所以打开 webpack.base.conf.js 给 common 文件夹路径添加一个别名;

javascript 复制代码
'use strict'
const path = require('path')
const utils = require('./utils')
const config = require('../config')
const vueLoaderConfig = require('./vue-loader.conf')

function resolve (dir) {
  return path.join(__dirname, '..', dir)
}

const createLintingRule = () => ({
  test: /\.(js|vue)$/,
  loader: 'eslint-loader',
  enforce: 'pre',
  include: [resolve('src'), resolve('test')],
  options: {
    formatter: require('eslint-friendly-formatter'),
    emitWarning: !config.dev.showEslintErrorsInOverlay
  }
})

module.exports = {
  context: path.resolve(__dirname, '../'),
  entry: {
    app: './src/main.js'
  },
  output: {
    path: config.build.assetsRoot,
    filename: '[name].js',
    publicPath: process.env.NODE_ENV === 'production'
      ? config.build.assetsPublicPath
      : config.dev.assetsPublicPath
  },
  resolve: {
    extensions: ['.js', '.vue', '.json'],
    alias: {
      'vue$': 'vue/dist/vue.esm.js',
      '@': resolve('src'),
      'styles': resolve('src/assets/styles'),
      
      'common': resolve('src/common') // ❗️给 common 文件夹的路径添加别名。
    }
  },
  module: {
    rules: [
      ...(config.dev.useEslint ? [createLintingRule()] : []),
      {
        test: /\.vue$/,
        loader: 'vue-loader',
        options: vueLoaderConfig
      },
      {
        test: /\.js$/,
        loader: 'babel-loader',
        include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')]
      },
      {
        test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          limit: 10000,
          name: utils.assetsPath('img/[name].[hash:7].[ext]')
        }
      },
      {
        test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          limit: 10000,
          name: utils.assetsPath('media/[name].[hash:7].[ext]')
        }
      },
      {
        test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          limit: 10000,
          name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
        }
      }
    ]
  },
  node: {
    // prevent webpack from injecting useless setImmediate polyfill because Vue
    // source contains it (although only uses it if it's native).
    setImmediate: false,
    // prevent webpack from injecting mocks to Node native modules
    // that does not make sense for the client
    dgram: 'empty',
    fs: 'empty',
    net: 'empty',
    tls: 'empty',
    child_process: 'empty'
  }
}

(❗️注意:修改了 Webpack 配置项后,需要在终端重启服务器,让 Webpack 修改生效。)

1️⃣-⑥:打开 detail 下 components 中的 Banner.vue ,在 Banner 组件使用公用画廊组件;

html 复制代码
<template>
  <div> <!-- 1️⃣-⑩:用 div 标签包裹 .banner 和 Gallery 组件。 -->
    <div class="banner">
      <img class="banner-img" src="https://qdywxs.github.io/travel-images/detail-banner-img.jpg">
      <div class="banner-info">
        <div class="banner-title">故宫(AAAAA景区)</div>
        <div class="banner-number">
          <span class="iconfont banner-icon">&#xe64a;</span>
          3
        </div>
      </div>
    </div>
    <common-gallery></common-gallery> <!-- 1️⃣-⑨:在 .banner 下方使用 Gallery 组件; -->
  </div>
</template>

<script>
// 1️⃣-⑦:从 common 目录下的 gallery 引入 Gallery.vue;
import CommonGallery from 'common/gallery/Gallery'

export default {
  name: 'DetailBanner',

  components: { // 1️⃣-⑧:注册公用画廊组件;
    CommonGallery
  }
}
</script>

<style lang="stylus" scoped>
.banner
  position: relative
  overflow: hidden
  height: 0
  padding-bottom: 55%
  .banner-img
    width: 100%
  .banner-info
    position: absolute
    left: 0
    right: 0
    bottom: 0
    display: flex
    line-height: .6rem
    color: #fff
    background-image: linear-gradient(top, rgba(0, 0, 0, 0), rgba(0, 0, 0, .8))
    .banner-title
      flex: 1
      padding: 0 .2rem
      font-size: .32rem
    .banner-number
      height: .32rem
      padding: 0 .4rem
      margin-top: .14rem
      font-size: .24rem
      color: #fff
      line-height: .32rem
      border-radius: .2rem
      background: rgba(0, 0, 0, .8)
      .banner-icon
        font-size: .24rem
</style>

保存后,返回页面查看,页面上正确显示内容,控制台无报错:

2️⃣返回 Gallery.vue 继续编写代码:

html 复制代码
<template>
  <div class="container"> <!-- 2️⃣-①:最外层 div 添加 class 类名为 container,作为内容的
													容器; -->

    <div class="wrapper"> <!-- 2️⃣-②:.container 中有一个 .wrapper,用来撑开图片内容区; -->

      <!-- 2️⃣-⑦:复制 home 下 components 中 Swiper.vue 的轮播区域代码,添加轮播区域
			(去掉不需要的 v-if 部分代码); -->
      <swiper :options="swiperOption">
        
        <swiper-slide> <!-- 2️⃣-⑧:swiper 中添加两个 swiper-slide 标签(去掉 v-for 循环
											 部分的代码),里边各有一个 img 标签类名 gallery-img,内容是景点图片; -->
          <img class="gallery-img" src="https://qdywxs.github.io/travel-images/detail-gallary-img01.jpg">
        </swiper-slide>
        <swiper-slide>
          <img class="gallery-img" src="https://qdywxs.github.io/travel-images/detail-gallary-img02.jpg">
        </swiper-slide>

        <div class="swiper-pagination"  slot="pagination"></div>
      </swiper>

    </div>
  </div>
</template>

<script>
export default {
  name: 'CommonGallery',
  data () {
    return {
      swiperOption: { // 2️⃣-⑨:swiperOption 中传入参数 pagination 给轮播添加分页指示器;
        pagination: '.swiper-pagination'
      }
    }
  }
}
</script>

<style lang="stylus" scoped>
.container /*
  				 2️⃣-③:.container 为固定定位,top、right、left、bottom 为 0,撑满整个区域,
  				 设置背景色为黑色;
  					*/
  position: fixed
  top: 0
  right: 0
  left: 0
  bottom: 0
  background: #000
  
  z-index: 99 /* 2️⃣-④:z-index 设为 99,让 Gallery 显示在最上层; */

  display: flex /* 2️⃣-⑤:.container 设为 flex 布局,容器内元素垂直居中; */
  flex-direction: column
  justify-content: center
  
  .wrapper /* 2️⃣-⑥:.wrapper 宽设为 100%,高为宽的 75%; */
    overflow: hidden
    height: 0
    width: 100%
    padding-bottom: 75%

    .gallery-img /* 2️⃣-⑩:设置图片宽度为 100%; */
      width: 100%
</style>

保存后,返回页面查看,查看图片可左右滑动,也有了分页指示器,但不是"分数"样式的,且指示器位置也不对:

检查元素可以看到,指示器是设置了 bottom 为 10px:

❓如何能够让第三方轮播插件 vue-awesome-swiper 的分页指示器,展示为其他我们所需要的样式呢?

答:vue-awesome-swiper 底层是借助 Swiper 实现的,所以我们在 Swiper 官网的 API 中可以找到 pagination 相关的参数。

我们使用的 vue-awesome-swiper 是基于 Swiper3 的 v2.6.7 版本,所以需要查看 Swiper3 的 API。在 Pagination 下的 paginationType 可以看到分页器样式的类型。我们需要的是"分式 fraction":

2️⃣-⑪:返回 common 下 gallery 中的 Gallery.vue ;

html 复制代码
<template>
  <div class="container">
    <div class="wrapper">
      <swiper :options="swiperOption">
        <swiper-slide>
          <img class="gallery-img" src="https://qdywxs.github.io/travel-images/detail-gallary-img01.jpg">
        </swiper-slide>
        <swiper-slide>
          <img class="gallery-img" src="https://qdywxs.github.io/travel-images/detail-gallary-img02.jpg">
        </swiper-slide>
        <div class="swiper-pagination"  slot="pagination"></div>
      </swiper>

    </div>
  </div>
</template>

<script>
export default {
  name: 'CommonGallery',
  data () {
    return {
      swiperOption: {
        pagination: '.swiper-pagination',
        paginationType: 'fraction' /*
        													 2️⃣-⑫:添加 paginationType,值为 fraction,指定指示器
                                   为"分式";
                                    */
      }
    }
  }
}
</script>

<style lang="stylus" scoped>
.container
  position: fixed
  top: 0
  right: 0
  left: 0
  bottom: 0
  z-index: 99
  display: flex
  flex-direction: column
  justify-content: center
  background: #000
  .wrapper
  	overflow: hidden
    height: 0
    width: 100%
    padding-bottom: 75%
    .gallery-img
      width: 100%

    .swiper-pagination /* 2️⃣-⑬:设置指示器 bottom 为 -1rem,颜色为白色; */
      bottom: -1rem
      color: #fff
</style>

保存后,返回页面查看,指示器完全"不见了"。打开检查发现,其实它已经在轮播图的下方了:

❓为什么"看不见"指示器了呢?

答:因为它的父元素上设置了 overflow: hidden ,且限制了高度,导致扩展出的内容无法显示。

2️⃣-⑭:返回 Gallery.vue ;

html 复制代码
<template>
  <div class="container">
    <div class="wrapper">
      <swiper :options="swiperOption">
        <swiper-slide>
          <img class="gallery-img" src="https://qdywxs.github.io/travel-images/detail-gallary-img01.jpg">
        </swiper-slide>
        <swiper-slide>
          <img class="gallery-img" src="https://qdywxs.github.io/travel-images/detail-gallary-img02.jpg">
        </swiper-slide>
        <div class="swiper-pagination"  slot="pagination"></div>
      </swiper>

    </div>
  </div>
</template>

<script>
export default {
  name: 'CommonGallery',
  data () {
    return {
      swiperOption: {
        pagination: '.swiper-pagination',
        paginationType: 'fraction'
      }
    }
  }
}
</script>

<style lang="stylus" scoped>
.container >>> .swiper-container /*
  															 2️⃣-⑯:由于 Swiper 自身容器上也设置了 overflow 值
  															 为 hidden,所以这里使用深度作用选择器设置 .swiper-container
  															 的 overflow 值为 inherit;
  																*/
  overflow: inherit

.container
  position: fixed
  top: 0
  right: 0
  left: 0
  bottom: 0
  z-index: 99
  display: flex
  flex-direction: column
  justify-content: center
  background: #000
  
  .wrapper /* 2️⃣-⑮:去除 .wrapper 的 overflow 属性; */
    height: 0
    width: 100%
    padding-bottom: 75%
    .gallery-img
      width: 100%
    .swiper-pagination
      bottom: -1rem
      color: #fff
</style>

保存后,返回页面查看:分页指示器显示正确,控制台无报错, Gallery.vue 的布局完成。

2.2 公用图片画廊组件逻辑

需求分析:

  • 首先, Gallery.vue 中显示的图片,不会是组件本身的数据,而是使用它的组件从外部传递进来的;
  • 其次, Gallery.vue 默认为隐藏状态,当点击 Banner 组件的海报时展示,再次点击后则隐藏。

3️⃣返回 common 下 gallery 中的 Gallery.vue :

html 复制代码
<template>
  <div class="container">
    <div class="wrapper">
      <swiper :options="swiperOption">
				
        <!-- 3️⃣-③:保留一个 swiper-slide 标签,循环 imgs,动态绑定 key 值为 index; -->
        <swiper-slide v-for="(item, index) of imgs" :key="index">
          
          <!-- 3️⃣-④:动态绑定 src 的值为循环项 item; -->
          <img class="gallery-img" :src="item"> 
        </swiper-slide>
        
        <div class="swiper-pagination"  slot="pagination"></div>
      </swiper>

    </div>
  </div>
</template>

<script>
export default {
  name: 'CommonGallery',

  props: { /* 3️⃣-①:添加 props,从外部接收一个 imgs 属性; */

    imgs: { /* 3️⃣-②:imgs 的类型必须是数组 Array,default 是一个函数,默认 imgs 是一个数组; */
      type: Array,
      default () {
        return []
      }
    }
  },
  data () {
    return {
      swiperOption: {
        pagination: '.swiper-pagination',
        paginationType: 'fraction'
      }
    }
  }
}
</script>

<style lang="stylus" scoped>
.container >>> .swiper-container
  overflow: inherit
.container
  position: fixed
  top: 0
  right: 0
  left: 0
  bottom: 0
  z-index: 99
  display: flex
  flex-direction: column
  justify-content: center
  background: #000
  .wrapper
    height: 0
    width: 100%
    padding-bottom: 75%
    .gallery-img
      width: 100%
    .swiper-pagination
      bottom: -1rem
      color: #fff
</style>

3️⃣-⑤:打开 detail 下 components 中的 Banner.vue ;

html 复制代码
<template>
  <div>
    <div class="banner">
      <img class="banner-img" src="https://qdywxs.github.io/travel-images/detail-banner-img.jpg">
      <div class="banner-info">
        <div class="banner-title">故宫(AAAAA景区)</div>
        <div class="banner-number">
          <span class="iconfont banner-icon">&#xe64a;</span>
          3
        </div>
      </div>
    </div>
    <common-gallery :imgs="imgs"></common-gallery> <!-- 3️⃣-⑦:通过属性 :imgs 传递数据
																									 imgs 给组件 Gallery.vue; -->
  </div>
</template>

<script>
import CommonGallery from 'common/gallery/Gallery'
export default {
  name: 'DetailBanner',

  data () { // 3️⃣-⑥:在 data 中定义一个变量 imgs,它的值为一个数组,内容是两个图片地址;
    return {
      imgs: ['https://qdywxs.github.io/travel-images/detail-gallary-img01.jpg', 'https://qdywxs.github.io/travel-images/detail-gallary-img02.jpg']
    }
  },
  components: {
    CommonGallery
  }
}
</script>

<style lang="stylus" scoped>
.banner
  position: relative
  overflow: hidden
  height: 0
  padding-bottom: 55%
  .banner-img
    width: 100%
  .banner-info
    position: absolute
    left: 0
    right: 0
    bottom: 0
    display: flex
    line-height: .6rem
    color: #fff
    background-image: linear-gradient(top, rgba(0, 0, 0, 0), rgba(0, 0, 0, .8))
    .banner-title
      flex: 1
      padding: 0 .2rem
      font-size: .32rem
    .banner-number
      height: .32rem
      padding: 0 .4rem
      margin-top: .14rem
      font-size: .24rem
      color: #fff
      line-height: .32rem
      border-radius: .2rem
      background: rgba(0, 0, 0, .8)
      .banner-icon
        font-size: .24rem
</style>

保存后,返回页面查看,内容正确显示,控制台无报错:

默认 Gallery.vue 隐藏,点击 Banner.vue 中的海报时显示,那么只需要一个变量默认为 false(隐藏状态),然后绑定一个点击事件来切换变量为 true(显示状态)即可。

3️⃣-⑧:返回 detail 下 components 中的 Banner.vue ;

html 复制代码
<template>
  <div>
    <!-- 3️⃣-⑪:在 .banner 上绑定点击事件,触发时执行 handleBannerClick 方法; -->
    <div class="banner" @click="handleBannerClick">
      <img class="banner-img" src="https://qdywxs.github.io/travel-images/detail-banner-img.jpg">
      <div class="banner-info">
        <div class="banner-title">故宫(AAAAA景区)</div>
        <div class="banner-number">
          <span class="iconfont banner-icon">&#xe64a;</span>
          3
        </div>
      </div>
    </div>

    <!-- 3️⃣-⑩:添加 v-show 指令,它等于 showGallery 这个变量; -->
    <common-gallery :imgs="imgs" v-show="showGallery"></common-gallery>
  </div>
</template>

<script>
import CommonGallery from 'common/gallery/Gallery'
export default {
  name: 'DetailBanner',

  data () {
    return {
      showGallery: false, // 3️⃣-⑨:定义一个变量 showGallery,默认为 false;
      
      imgs: ['https://qdywxs.github.io/travel-images/detail-gallary-img01.jpg', 'https://qdywxs.github.io/travel-images/detail-gallary-img02.jpg']
    }
  },
  methods: { // 3️⃣-⑫:在 methods 中定义 handleBannerClick 方法;
    handleBannerClick () {
      this.showGallery = true // 3️⃣-⑬:当 Banner 被点击时,将变量 showGallery 变为 true;
    }
  },
  components: {
    CommonGallery
  }
}
</script>

<style lang="stylus" scoped>
.banner
  position: relative
  overflow: hidden
  height: 0
  padding-bottom: 55%
  .banner-img
    width: 100%
  .banner-info
    position: absolute
    left: 0
    right: 0
    bottom: 0
    display: flex
    line-height: .6rem
    color: #fff
    background-image: linear-gradient(top, rgba(0, 0, 0, 0), rgba(0, 0, 0, .8))
    .banner-title
      flex: 1
      padding: 0 .2rem
      font-size: .32rem
    .banner-number
      height: .32rem
      padding: 0 .4rem
      margin-top: .14rem
      font-size: .24rem
      color: #fff
      line-height: .32rem
      border-radius: .2rem
      background: rgba(0, 0, 0, .8)
      .banner-icon
        font-size: .24rem
</style>

保存后,返回页面查看,控制台无报错, Gallery.vue 是隐藏状态。但当点击 Banner 后,轮播图没有正常显示:

❓为什么轮播没有正确显示呢?

答:因为在刚开始时,我们是让 Gallery.vue 处于隐藏的状态,当再把它显示出来时,导致轮播计算宽度出错。所以轮播图无法正常显示、滑动。

解决这个问题,我们可以在 Swiper 官网找到 Observer 这个配置项(或在官网搜索"observer"关键字):

3️⃣-⑭:打开 common 下 gallery 中的 Gallery.vue ;

html 复制代码
<template>
  <div class="container">
    <div class="wrapper">
      <swiper :options="swiperOption">
        <swiper-slide v-for="(item, index) of imgs" :key="index">
          <img class="gallery-img" :src="item">
        </swiper-slide>
        <div class="swiper-pagination"  slot="pagination"></div>
      </swiper>
    </div>
  </div>
</template>

<script>
export default {
  name: 'CommonGallery',
  props: {
    imgs: {
      type: Array,
      default () {
        return []
      }
    }
  },
  data () {
    return {
      swiperOption: {
        pagination: '.swiper-pagination',
        paginationType: 'fraction',

        observer: true, /*
        								3️⃣-⑮:添加 observer 和 observeParents,且它们的值都为 true
                        (❗️这两句指的是:当 Swiper 本身或它的父级元素发生变化时,会自动初始化
                        一次 swiper);
                         */
        observeParents: true
      }
    }
  }
}
</script>

<style lang="stylus" scoped>
.container >>> .swiper-container
  overflow: inherit
.container
  position: fixed
  top: 0
  right: 0
  left: 0
  bottom: 0
  z-index: 99
  display: flex
  flex-direction: column
  justify-content: center
  background: #000
  .wrapper
    height: 0
    width: 100%
    padding-bottom: 75%
    .gallery-img
      width: 100%
    .swiper-pagination
      bottom: -1rem
      color: #fff
</style>

保存后,返回页面查看,轮播恢复了正常:

❓现在只剩一个问题:如何点击 Gallery 时,将它隐藏?

答:其实依然很简单。我们只需要在 Gallery.vue 上绑定一个点击事件,当它被点击时,向外触发一个事件(比如触发一个 close 事件)。

然后,调用 Gallery 的父组件 Banner.vue 就可以来接收这个事件。当 close 事件触发后,去更改 showGallery 为 false。

4️⃣打开 common 下 gallery 中的 Gallery.vue :

html 复制代码
<template>
  <!-- 4️⃣-①:在 .container 上绑定一个点击事件,触发时执行 handleGalleryClick 方法; -->
  <div class="container" @click="handleGalleryClick">
    <div class="wrapper">
      <swiper :options="swiperOption">
        <swiper-slide v-for="(item, index) of imgs" :key="index">
          <img class="gallery-img" :src="item">
        </swiper-slide>
        <div class="swiper-pagination"  slot="pagination"></div>
      </swiper>
    </div>
  </div>
</template>

<script>
export default {
  name: 'CommonGallery',
  props: {
    imgs: {
      type: Array,
      default () {
        return []
      }
    }
  },
  data () {
    return {
      swiperOption: {
        pagination: '.swiper-pagination',
        paginationType: 'fraction',
        observer: true,
        observeParents: true
      }
    }
  },
  methods: {
    handleGalleryClick () {  // 4️⃣-②:handleGalleryClick 方法向外触发一个 close 事件;
      this.$emit('close')
    }
  }
}
</script>

<style lang="stylus" scoped>
.container >>> .swiper-container
  overflow: inherit
.container
  position: fixed
  top: 0
  right: 0
  left: 0
  bottom: 0
  z-index: 99
  display: flex
  flex-direction: column
  justify-content: center
  background: #000
  .wrapper
    height: 0
    width: 100%
    padding-bottom: 75%
    .gallery-img
      width: 100%
    .swiper-pagination
      bottom: -1rem
      color: #fff
</style>

4️⃣-③:打开 detail 下 components 中的 Banner.vue ;

html 复制代码
<template>
  <div>
    <div class="banner" @click="handleBannerClick">
      <img class="banner-img" src="https://qdywxs.github.io/travel-images/detail-banner-img.jpg">
      <div class="banner-info">
        <div class="banner-title">故宫(AAAAA景区)</div>
        <div class="banner-number">
          <span class="iconfont banner-icon">&#xe64a;</span>
          3
        </div>
      </div>
    </div>
    
    <!-- 4️⃣-④:在 Banner.vue 中接收 close 事件,事件触发时执行 handleGalleryClose 方法; -->
    <common-gallery :imgs="imgs" v-show="showGallery" @close="handleGalleryClose"></common-gallery>
  </div>
</template>

<script>
import CommonGallery from 'common/gallery/Gallery'
export default {
  name: 'DetailBanner',

  data () {
    return {
      showGallery: false,
      imgs: ['https://qdywxs.github.io/travel-images/detail-gallary-img01.jpg', 'https://qdywxs.github.io/travel-images/detail-gallary-img02.jpg']
    }
  },
  methods: {
    handleBannerClick () {
      this.showGallery = true
    },
    handleGalleryClose () { /*
    												4️⃣-⑤:定义 handleGalleryClose 方法,方法执行时,
                            更改 showGallery 为 false(即,隐藏 Gallery.vue)。
                             */
      this.showGallery = false
    }
  },
  components: {
    CommonGallery
  }
}
</script>

<style lang="stylus" scoped>
.banner
  position: relative
  overflow: hidden
  height: 0
  padding-bottom: 55%
  .banner-img
    width: 100%
  .banner-info
    position: absolute
    left: 0
    right: 0
    bottom: 0
    display: flex
    line-height: .6rem
    color: #fff
    background-image: linear-gradient(top, rgba(0, 0, 0, 0), rgba(0, 0, 0, .8))
    .banner-title
      flex: 1
      padding: 0 .2rem
      font-size: .32rem
    .banner-number
      height: .32rem
      padding: 0 .4rem
      margin-top: .14rem
      font-size: .24rem
      color: #fff
      line-height: .32rem
      border-radius: .2rem
      background: rgba(0, 0, 0, .8)
      .banner-icon
        font-size: .24rem
</style>

保存后,返回页面查看。当点击 Banner 时,显示 Gallery.vue ,且左右滑动流畅(轮播显示正常)。当点击 Gallery.vue 时,则恢复隐藏状态:

以上,我们拆分出了一个公用图片画廊组件 Gallery.vue ,并完善了 Banner 的逻辑。

祝好,qdywxs ♥ you!

相关推荐
陈随易2 小时前
Postman 被曝自动往 Claude Code 和 Codex 装插件
前端·后端·程序员
Dream-Y.ocean4 小时前
鸿蒙PC平台宅匠 3D 室内设计适配实战:基于 Electron 壳方案的 Three.js 双渲染引擎与参数化户型编辑器开发
javascript·3d·harmonyos
Csvn5 小时前
性能监控
前端
Highcharts.js5 小时前
Highcharts Gantt使用符号的自定义数据标签开发甘特图示例
javascript·甘特图·highcharts·图表开发·实战代码·响应式图表
Csvn5 小时前
构建工具
前端
FRing036 小时前
vue2干货总结3(computed计算属性、watch监听器)
开发语言·前端·vue.js·vue2
Java小卷6 小时前
JuanForm vs FormCreate!Vue3 表单引擎联动配置 PK!
vue.js·低代码
kyriewen8 小时前
Skills 榜前 10 我全装了:只有 3 个能直接用
前端·javascript·程序员
IT_陈寒8 小时前
当Java的hashCode遇上Lombok,我的缓存被全清了
前端·人工智能·后端
工控丫丫9 小时前
帆软看板中经常使用的公式函数及经常搭的组合
前端·javascript·数据库