uniapp H5预览图片组件
前言
uniapp的预览API, uni.previewImage预览长图在H5环境下长图会模糊
如下图:
手指可以撑开放大, 但会模糊
解决方法:
使用自定义全局预览接口
global-preview-image/index.vue
<template><view v-if="show" class="preview-mask" @click.stop="hide"><!-- 图片预览遮罩层 --><swiperclass="preview-swiper":current="current"duration="300"@change="swiperChange"><!-- 遍历图片地址列表,生成轮播项 --><swiper-item v-for="(item, index) in urls" :key="index"><movable-area class="movable-area"><movable-view class="movable-view" scale scale-min="1"><scroll-view scroll-y class="preview-item"><viewclass="preview-image-box":style="{alignItems:imagesHeight[index] >= windowHeight? 'flex-start': 'center',}"><imageclass="preview-image":class="[`preview-image-${index}`]":src="item":lazy-load="true"mode="widthFix"@click.stop="hide"@load="load(index)"/></view></scroll-view></movable-view></movable-area></swiper-item></swiper><!-- 显示当前图片索引和总数 --><text class="preview-index">{{ current + 1 }}/{{ urls.length }}</text></view>
</template><script>
export default {data() {return {show: false, // 控制预览组件是否显示urls: [], // 图片地址列表loadSuccess: [], // 已加载成功的图片索引列表current: 0, // 当前显示的图片索引windowHeight: 0, // 设备高度imagesHeight: [], // 图片高度列表}},mounted() {/*** 组件挂载时获取系统窗口高度信息*/uni.getSystemInfo({success: (res) => {this.windowHeight = res.windowHeight},})},methods: {/*** 打开图片预览组件* @param {Object} options - 配置参数* @param {Array} options.urls - 图片地址数组* @param {Number} options.current - 当前显示的图片索引*/open({ urls = [], current = 0 }) {uni.showLoading({title: "加载中...",})// 如果urls不为空且current为字符串,则查找current在urls中的索引位置if (urls.length > 0 && typeof current === "string") {current = urls.findIndex((item) => item === current)current = current >= 0 ? current : 0}// 设置组件数据this.urls = urls || []this.loadSuccess = []this.imagesHeight = Array(urls.length).fill(0)this.current = current || 0this.show = true},/*** 关闭图片预览组件*/hide() {this.show = falseuni.hideLoading()setTimeout(() => {this.urls = []}, 300)},/*** 图片加载完成回调* @param {Number} i - 图片索引*/load(i) {if (!this.loadSuccess.includes(i)) this.loadSuccess.push(i)// 如果当前图片已加载完成且为当前显示图片,则隐藏加载提示if (this.loadSuccess.includes(i) && this.current == i) {uni.hideLoading()}// 获取元素const query = uni.createSelectorQuery().in(this)// 获取元素高度query.select(".preview-image-" + i).boundingClientRect((res) => {this.$set(this.imagesHeight, i, res.height)}).exec()},/*** 轮播图切换事件处理* @param {Object} e - 事件对象,包含 detail.current 表示当前切换到的图片索引*/swiperChange(e) {// 根据切换后的图片索引判断是否显示加载提示if (this.loadSuccess.includes(e.detail.current)) {uni.hideLoading()} else {uni.showLoading({title: "加载中...",})}this.current = e.detail.current},},
}
</script><style scoped>
/* 预览遮罩层样式 */
.preview-mask {position: fixed;top: 0;left: 0;right: 0;bottom: 0;background-color: rgba(0, 0, 0, 0.9);z-index: 9999;display: flex;justify-content: center;align-items: center;
}/* 轮播图容器样式 */
.preview-swiper {width: 100%;height: 100%;
}/* 预览项容器样式 */
.preview-item {width: 100vw;height: 100vh;
}
.preview-image-box {display: flex;
}
/* 图片及可移动视图相关样式 */
.preview-image,
.preview-image-box,
.movable-view,
.movable-area {width: 100%;height: 100%;
}/* 可移动视图样式 */
.movable-view {
}/* 预览图片样式 */
.preview-image {display: block;
}/* 图片索引文本样式 */
.preview-index {position: absolute;bottom: 60rpx;color: #fff;font-size: 32rpx;
}
</style>
挂载body上
global-preview-image/index.js
import Vue from 'vue'
import PreviewImage from './index.vue'const PreviewImageConstructor = Vue.extend(PreviewImage)
let instance/*** 初始化预览图片实例* 创建PreviewImage组件实例并将其挂载到DOM中*/
function initInstance() {instance = new PreviewImageConstructor({el: document.createElement('div')})document.body.appendChild(instance.$el)
}/*** 预览图片函数* @param {Object|String} options - 预览配置选项,如果是字符串则作为单张图片URL处理* @param {Array} options.urls - 图片URL数组* @param {Number} options.current - 当前显示图片的索引* @param {Boolean} options.loop - 是否可以循环预览* @param {Function} options.success - 接口调用成功的回调函数* @param {Function} options.fail - 接口调用失败的回调函数* @param {Function} options.complete - 接口调用结束的回调函数*/
function previewImage(options) {// 如果实例不存在,则初始化实例if (!instance) {initInstance()}// 如果传入的是字符串,则转换为包含单个URL的对象格式if (typeof options === 'string') {options = {urls: [options]}}// 调用实例的open方法打开图片预览instance.open(options)
}/*** 插件安装函数* @param {Object} Vue - Vue构造函数*/
function install(Vue) {// 将previewImage方法挂载到Vue原型上,使所有Vue实例都可以访问Vue.prototype.$previewImage = previewImage// 挂载到uni对象if (typeof uni !== 'undefined') {uni.previewImage = previewImage}
}export default {install,previewImage
}
在main.js
引入
...
// #ifdef H5
import PreviewImage from '@/components/global-preview-image'
// #endif
...
// #ifdef H5
Vue.use(PreviewImage)
// #endif
...