You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Quasar框架中实现可点击图片的全屏展示功能

纯Quasar实现图片画廊的全屏预览功能

Quasar没有单独的overlay组件,但可以通过QDialog实现全屏图片预览的效果,同时用QBtn配合Quasar的布局类添加右下角的查看按钮。以下是修改后的完整代码:

<template>
  <div class="service-block q-pa-lg text-center column no-wrap flex-center block-wrapper" id="RecentWork">
    <h2 class="text-h2 text-weight-bolder text-dark q-mb-xs">RECENT WORK</h2>
    <h6 class="text-h6 text-weight-light text-dark q-my-none" style="max-width: 800px;">We are a one stop shop for all your home remodeling needs. Check out some of our recent jobs below!</h6>
  </div>
  <q-tabs
        v-model="tab"
        outside-arrows
        mobile-arrows
        inline-label
        active-color="primary"
        indicator-color="primary"
        class="text-grey-7"
      >
        <q-tab name="decks" label="DECKS" class="q-pa-md q-ma-md menu-item" active-class="active-menu-item"></q-tab>
        <q-tab name="interior" label="INTERIOR REMODELING" class="q-pa-md q-ma-md menu-item" active-class="active-menu-item"></q-tab>
        <q-tab name="exterior" label="EXTERIOR REMODELING" class="q-pa-md q-ma-md menu-item" active-class="active-menu-item"></q-tab>
        <q-tab name="new" label="NEW CONSTRUCTION" class="q-pa-md q-ma-md menu-item" active-class="active-menu-item"></q-tab>
    </q-tabs>

    <q-tab-panels v-model="tab" animated>
          <q-tab-panel name="decks">
            <div class="row q-pa-md block-wrapper text-center q-col-gutter-md" style="margin-bottom:100px;">
              <div v-for="item in imagesArray[0]['decks']" :key="item.id" class="col-sm-4 col-xs-12">
                <!-- 相对定位容器,用于放置按钮 -->
                <div class="relative">
                  <q-img :src="item.link" :ratio="16/9" class="rounded-borders"/>
                  <!-- 右下角的查看按钮 -->
                  <q-btn
                    icon="zoom_in"
                    size="sm"
                    round
                    color="white"
                    text-color="black"
                    class="absolute bottom-2 right-2 bg-opacity-80"
                    @click="openPreview(item.link)"
                  />
                </div>
              </div>
            </div>
          </q-tab-panel>
          <q-tab-panel name="interior">
            <div class="row q-pa-md block-wrapper text-center q-col-gutter-md" style="margin-bottom:100px;">
              <div v-for="item in imagesArray[0]['interior']" :key="item.id" class="col-sm-4 col-xs-12">
                <div class="relative">
                  <q-img :src="item.link" :ratio="16/9" class="rounded-borders"/>
                  <q-btn
                    icon="zoom_in"
                    size="sm"
                    round
                    color="white"
                    text-color="black"
                    class="absolute bottom-2 right-2 bg-opacity-80"
                    @click="openPreview(item.link)"
                  />
                </div>
              </div>
            </div>
          </q-tab-panel>
          <q-tab-panel name="exterior">
            <div class="row q-pa-md block-wrapper text-center q-col-gutter-md" style="margin-bottom:100px;">
              <div v-for="item in imagesArray[0]['exterior']" :key="item.id" class="col-sm-4 col-xs-12">
                <div class="relative">
                  <q-img :src="item.link" :ratio="16/9" class="rounded-borders"/>
                  <q-btn
                    icon="zoom_in"
                    size="sm"
                    round
                    color="white"
                    text-color="black"
                    class="absolute bottom-2 right-2 bg-opacity-80"
                    @click="openPreview(item.link)"
                  />
                </div>
              </div>
            </div>
          </q-tab-panel>
          <q-tab-panel name="new">
            <div class="row q-pa-md block-wrapper text-center q-col-gutter-md" style="margin-bottom:100px;">
              <div v-for="item in imagesArray[0]['newConstruction']" :key="item.id" class="col-sm-4 col-xs-12">
                <div class="relative">
                  <q-img :src="item.link" :ratio="16/9" class="rounded-borders"/>
                  <q-btn
                    icon="zoom_in"
                    size="sm"
                    round
                    color="white"
                    text-color="black"
                    class="absolute bottom-2 right-2 bg-opacity-80"
                    @click="openPreview(item.link)"
                  />
                </div>
              </div>
            </div>
          </q-tab-panel>
    </q-tab-panels>

    <!-- 全屏预览弹窗 -->
    <q-dialog
      v-model="showPreviewDialog"
      fullscreen
      content-class="bg-black"
    >
      <q-img
        :src="previewImgUrl"
        class="full-width full-height"
        fit="contain"
      />
      <!-- 关闭按钮 -->
      <q-btn
        icon="close"
        size="lg"
        round
        color="white"
        text-color="black"
        class="absolute top-4 right-4"
        @click="showPreviewDialog = false"
      />
    </q-dialog>
</template>

<script setup>
  import { ref } from 'vue'
  const imagesArray = [{
    decks:[{ id: 1, link: new URL('../assets/imgs/recentwork/decks/615.jpg', import.meta.url).href},
        { id: 2, link: new URL('../assets/imgs/recentwork/decks/619.jpg', import.meta.url).href},
        { id: 3, link: new URL('../assets/imgs/recentwork/decks/627.jpg', import.meta.url).href},
        { id: 4, link: new URL('../assets/imgs/recentwork/decks/655.jpg', import.meta.url).href},
        { id: 5, link: new URL('../assets/imgs/recentwork/decks/659.jpg', import.meta.url).href},
        { id: 6, link: new URL('../assets/imgs/recentwork/decks/666.jpg', import.meta.url).href},
        { id: 7, link: new URL('../assets/imgs/recentwork/decks/668.jpg', import.meta.url).href},
        { id: 8, link: new URL('../assets/imgs/recentwork/decks/677.jpg', import.meta.url).href},
        { id: 9, link: new URL('../assets/imgs/recentwork/decks/678.jpg', import.meta.url).href}],
    interior:[{ id: 1, link: new URL('../assets/imgs/recentwork/interior/2633.jpg', import.meta.url).href},
        { id: 2, link: new URL('../assets/imgs/recentwork/interior/989.jpg', import.meta.url).href},
        { id: 3, link: new URL('../assets/imgs/recentwork/interior/1015.jpg', import.meta.url).href},
        { id: 4, link: new URL('../assets/imgs/recentwork/interior/2671.jpg', import.meta.url).href},
        { id: 5, link: new URL('../assets/imgs/recentwork/interior/1020.jpg', import.meta.url).href},
        { id: 6, link: new URL('../assets/imgs/recentwork/interior/2123.jpg', import.meta.url).href},
        { id: 7, link: new URL('../assets/imgs/recentwork/interior/2634.jpg', import.meta.url).href},
        { id: 8, link: new URL('../assets/imgs/recentwork/interior/1406.jpg', import.meta.url).href},
        { id: 9, link: new URL('../assets/imgs/recentwork/interior/2041.jpeg', import.meta.url).href}],
    exterior: [{ id: 1, link: new URL('../assets/imgs/recentwork/exterior/642.jpg', import.meta.url).href},
        { id: 2, link: new URL('../assets/imgs/recentwork/exterior/651.jpg', import.meta.url).href},
        { id: 3, link: new URL('../assets/imgs/recentwork/exterior/652.jpg', import.meta.url).href},
        { id: 4, link: new URL('../assets/imgs/recentwork/exterior/672.jpg', import.meta.url).href},
        { id: 5, link: new URL('../assets/imgs/recentwork/exterior/711.jpg', import.meta.url).href},
        { id: 6, link: new URL('../assets/imgs/recentwork/exterior/722.jpg', import.meta.url).href},
        { id: 7, link: new URL('../assets/imgs/recentwork/exterior/732.jpg', import.meta.url).href},
        { id: 8, link: new URL('../assets/imgs/recentwork/exterior/748.jpg', import.meta.url).href},
        { id: 9, link: new URL('../assets/imgs/recentwork/exterior/762.jpg', import.meta.url).href}],
    newConstruction: [{ id: 1, link: new URL('../assets/imgs/recentwork/construction/618.jpg', import.meta.url).href},
        { id: 2, link: new URL('../assets/imgs/recentwork/construction/626.jpg', import.meta.url).href},
        { id: 3, link: new URL('../assets/imgs/recentwork/construction/630.jpg', import.meta.url).href},
        { id: 4, link: new URL('../assets/imgs/recentwork/construction/657.jpg', import.meta.url).href},
        { id: 5, link: new URL('../assets/imgs/recentwork/construction/710.jpg', import.meta.url).href},
        { id: 6, link: new URL('../assets/imgs/recentwork/construction/716.jpg', import.meta.url).href},
        { id: 7, link: new URL('../assets/imgs/recentwork/construction/758.jpg', import.meta.url).href},
        { id: 8, link: new URL('../assets/imgs/recentwork/construction/799.jpg', import.meta.url).href},
        { id: 9, link: new URL('../assets/imgs/recentwork/construction/850.jpg', import.meta.url).href}]
  }]

  const slide = ref(1)
  const tab = ref('decks')
  // 新增预览相关变量
  const showPreviewDialog = ref(false)
  const previewImgUrl = ref('')

  // 打开预览弹窗的方法
  const openPreview = (url) => {
    previewImgUrl.value = url
    showPreviewDialog.value = true
  }
</script>
<style lang="scss" scoped>
  .block-wrapper{
    max-width: 1024px;
    margin-left: auto;
    margin-right: auto;
  }
  .active-menu-item{
    background-color: $background-accent;
    color: $primary !important;
  }

  .menu-item{
    letter-spacing: .15rem;
    font-weight:500;
    border-radius: 7px;
    color:$dark
  }
</style>

关键改动说明

  1. 图片容器与按钮布局:给每个q-img外层添加relative类的容器,用Quasar的absolute、bottom-2、right-2类把按钮固定在图片右下角,bg-opacity-80让按钮半透明不遮挡图片内容。
  2. 全屏预览弹窗:使用q-dialog并设置fullscreen属性,内部的q-img用full-width和full-height配合fit="contain"实现图片自适应全屏且保持比例。
  3. 交互逻辑:新增响应式变量控制弹窗显示状态和当前预览的图片链接,点击按钮时更新变量打开弹窗,点击关闭按钮或弹窗外部可关闭预览。

内容的提问来源于stack exchange,提问作者Qiuzman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 14:58:10