(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!

相关推荐
在无清风1 分钟前
Java实现Redis
前端·windows·bootstrap
_一条咸鱼_1 小时前
Vue 配置模块深度剖析(十一)
前端·javascript·面试
yechaoa2 小时前
Widget开发实践指南
android·前端
赤橙红的黄3 小时前
Spring Boot中接入DeepSeek的流式输出
java·服务器·javascript
前端切图仔0013 小时前
WebSocket 技术详解
前端·网络·websocket·网络协议
upp3 小时前
[bug]langchain agent报错Invalid Format: Missing ‘Action Input:‘ after ‘Action:‘
javascript·python·langchain·bug
JarvanMo3 小时前
关于Flutter架构的小小探讨
前端·flutter
前端开发张小七3 小时前
每日一练:4.有效的括号
前端·python
顾林海4 小时前
Flutter 图标和按钮组件
android·开发语言·前端·flutter·面试
雯0609~4 小时前
js:循环查询数组对象中的某一项的值是否为空
开发语言·前端·javascript