Vue3图片显示组件,支持多张图片,缩略图,全屏动态加载大图

通过imgs参数传入多张图片,图片路径中包含 /small/ 表示是缩略图,将 /small/ 改为 / 即是该图片的大图。组件首先显示缩略图,然后在mounted事件中js动态加载大图,加载完毕后用大图的内容替换缩略图,实现高清图片的丝滑加载显示。

点击图片后进入全屏模式,可浏览整组图片,同样会在后台用Js动态加载大图,实现高清图片的丝滑加载显示。

使用组件:

import BudaImg from 'Img.vue'
<BudaImg :imgs="['a.jpg', 'b.jpg'].map(name=>({ alt: name, src: `/images/houses/small/${name}`}))" :img_class="{detail_image: true}"/>  


以下是Img.vue的内容:

<script setup>
import { ref, reactive, computed, onMounted , onUnmounted, nextTick } from 'vue'

const props = defineProps({
  imgs: Array,
  img_class:{
    type: Object,
    default(rawProps) { return { };  }
  },
}); 
const {imgs, img_class}=props; const imgs_len=imgs.length;
let index=ref(0), fullscreen=ref(false), loading=ref(false); let container_class=computed(() => ({ fullscreen: fullscreen.value }) );
const img = computed(() => imgs[index.value] ); let img_src = ref(img.value.src);

async function GetImgBig(img){
  if(img.big) return; if(!img.src.includes("/small/")) {img.big=img.src; return;} img.big=await GetBlobUrl(img.src.replace("/small/", "/")); console.log('got big image: ', img.src);
}
async function GetNextImgBig(){
  for(let i=0;i<imgs_len;i++){ if(!fullscreen.value) break; let img=imgs[i]; if(img.big) continue; await GetImgBig(img); break; }
}
onMounted(async () => { 
  setTimeout(async () => {
    await GetImgBig(img.value); img_src.value=img.value.big; // console.log('big img', img_src.value);
  }, 1000);
});
onUnmounted(()=>{   
});


async function ClickImg(){
  if(fullscreen.value) return; fullscreen.value=true; document.body.style.overflow = 'hidden'; // 隐藏页面滚动条
  await nextTick(); await GetNextImgBig();
}
function ClickCloseImg(){
  fullscreen.value=false; document.body.style.overflow = ''; // 恢复页面滚动条
}
async function ClickNextImg(type){ 
  let v=index.value; if(type=='left') { v--; if(v<0) v=0; } else { v++; if(v>=imgs_len) v=imgs_len-1; }
  index.value=v; let img=imgs[v]; loading.value=true; await GetImgBig(img); loading.value=false; img_src.value=img.big; 
  await nextTick(); await GetNextImgBig();
}

async function fetchBlob(url) { const response = await fetch(url); const blob = await response.blob(); return blob; }
async function GetBlobUrl(big_src) {  return URL.createObjectURL(await fetchBlob(big_src)); }

</script>


<template>
  <div :class="container_class">
    <img :src="img_src" :alt="img.alt" :title="img.alt" :class="img_class" @click="ClickImg"/>
    <div v-if="fullscreen && loading" class="loading">正在加载图片...</div>
    <div class="img_bottom_bar" v-if="fullscreen">
      <div @click="ClickNextImg('left')" class="left_img_c">
        <div>
          <div v-if="imgs_len>1 && index>0">
            <img src="@/assets/left.svg" alt="上一张" title="上一张" class="left_img"/>
            <div>上一张</div>
          </div>
        </div>
      </div>
      <div class="mid_img_c"><div>第{{index+1}}张 / 共{{imgs_len}}张</div></div>
      <div @click="ClickNextImg('right')" class="right_img_c">
        <div>
          <div v-if="imgs_len>1 && index<imgs_len-1">
            <div>下一张</div>
            <img src="@/assets/right.svg" alt="下一张" title="下一张" class="right_img"/>
          </div>
        </div>
      </div>
    </div>
    <img v-if="fullscreen" src="@/assets/close.svg" class="close_img" alt="关闭全屏" title="关闭全屏" @click="ClickCloseImg"/>    
  </div>
</template>

<style scoped>

.loading{ color: var(--color-site-title); z-index: 999; position:fixed; left: calc(50vw-3rem); top: 50vh; font-size: 2rem; }
.center{text-align: center;}  
.fullscreen { position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; display: flex; justify-content: center;  align-items: center; background-color: #222222ee;  overflow: hidden;  }
.close_img{ width: 3rem; height: 3rem; cursor:pointer; }
.fullscreen .close_img{ position: fixed; right: 0; top:0;}
.img_bottom_bar{position:fixed; bottom: 0; width: 100vw; display: flex; color: var(--color-site-title); align-items: center; font-size: 1.5rem;}
.left_img_c, .mid_img_c, .right_img_c {  display: flex; align-items: center; justify-content: center;   }
.left_img_c > div , .right_img_c > div { width: 7rem; display: flex; align-items: center; justify-content: center; }
.mid_img_c{ flex-grow:1; }
.left_img_c > div > div , .right_img_c > div > div { display: flex; align-items: center; justify-content: center; cursor:pointer; }
.left_img, .right_img { width: 2rem; height: 2rem; }

</style>

以上如有错漏之处,敬请大家指正。我的联系方式:
微信:TobeBuda
Email/Paypal: jinmin.si@outlook.com
邀请您加入「社区资讯服务」创业微信群,共同探讨打造社区资讯服务的美好未来。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
你可以使用 HTML5 的 Canvas 元素来获取大幅图片缩略图显示。具体步骤如下: 1. 创建一个 HTML5 的 Canvas 元素。 2. 使用 JavaScript 的 Image 对象加载大幅图片。 3. 在 Image 对象的 onload 事件中,通过 Canvas 的 drawImage 方法将大幅图片绘制到 Canvas 上,并设置目标尺寸。 4. 使用 Canvas 的 toDataURL 方法将 Canvas 生成的缩略图转换为 Base64 编码的字符串。 5. 将 Base64 编码的字符串设置为 img 元素的 src 属性,即可显示缩略图。 下面是一个简单的实现示例: ```typescript import { ref } from 'vue'; export default { setup() { const thumbnail = ref(''); const createThumbnail = (file: File) => { const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d'); const img = new Image(); img.src = URL.createObjectURL(file); img.onload = () => { const { width, height } = img; const targetWidth = 300; const targetHeight = (height * targetWidth) / width; canvas.width = targetWidth; canvas.height = targetHeight; ctx.drawImage(img, 0, 0, targetWidth, targetHeight); thumbnail.value = canvas.toDataURL(); }; }; const handleChange = (event: Event) => { const target = event.target as HTMLInputElement; const file = target.files && target.files[0]; if (file) { createThumbnail(file); } }; return { thumbnail, handleChange, }; }, }; ``` 在模板中,可以使用 v-if 或 v-show 根据 thumbnail 的值来显示或隐藏 img 元素。 ```html <template> <div> <input type="file" @change="handleChange" /> <img v-if="thumbnail" :src="thumbnail" /> </div> </template> ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qiuzen

您的资助将帮助我创作更好的作品

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值