最近写手机端项目的时候,用的是uniapp + uView,然后出现好多bug。
- uni.showToast() 失效,只能用 u-toast 组件来替代。
- uni.previewImage() 失效,于是就导致 u-upload 图片上传组件默认的图片预览功能也失效。
然后急着要用图片预览这个功能,索性自己手写一个最基础的图片预览。
1. 效果图
2. 引用
简单封装的一个组件,直接在 components 文件夹下创建一个相同名字的目录和vue文件,免注册直接引入。
<template> <g-previewImage :show="preview.show" :url="preview.url" @close="preview.show = false"></g-previewImage> </template> <script> export default { data() { return { preview: { show: false, url: "" } } } } </script>
复制
g-previewImage.vue
<template> <view class="g-previewImage" v-if="show"> <view class="image" :style="{width, height}"> <image :src="url" :mode="mode"></image> </view> <u-icon class="icon" name="close" color="#eee" @click="close"></u-icon> </view> </template> <script> export default { name: "PreviewImage", props: { show: { type: Boolean, default: false }, url: { type: String, default: '' } }, data() { return { isshow: false, width: 0, height: 0, mode: 'aspectFit' // 保持纵横比缩放图片,使图片的长边能完全显示出来。也就是说,可以完整地将图片显示出来。 } }, watch: { show: { handler(n) { this.isshow = n }, immediate: true }, url: { handler(n) { if (n) { const img = new Image() img.src = n this.width = img.width > img.height ? '100%' : img.width + 'px' this.height = img.height > img.width ? '100%' : img.height + 'px' } }, immediate: true } }, methods: { open() { this.$emit('change', true) }, close() { this.$emit('close') } } } </script> <style lang="scss" scoped> .g-previewImage { display: flex; align-items: center; justify-content: center; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, .5); z-index: 99999; .image { // background-color: pink; image { width: 100%; height: 100%; } } .icon { position: absolute; top: 40rpx; right: 40rpx; } } </style>
复制
3. 改进
组件注册引入的方式是救急方案,略显繁琐了,那可不可以做成 uni.previewImage() API 那种 js 直接调用的形式呢?
当然可以实现了!我们就来实现个翻版的 uni.previewImage() API ,主要是通过 Vue.extend() 实现。
preview.js
import Vue from 'vue' import preview from "@/components/previewImage" // 创建一个 预览组件类 const previewImg = Vue.extend(preview) class Preview { constructor() { // 组件实例挂载 this.instance = new previewImg().$mount() document.body.appendChild(this.instance.$el) } // 定义一个 open 函数,调用实例中的 open 函数 open(url) { this.instance.open(url) } } export default new Preview()
复制
main.js
import Preview from "@/static/js/preview.js" Vue.prototype.$preview = Preview
复制
previewImage.vue
<template> <view class="g-previewImage" v-if="show"> <view class="image" :style="{width, height}"> <image :src="link" :mode="mode"></image> </view> <u-icon class="icon" name="close" color="#eee" @click="close"></u-icon> </view> </template> <script> export default { name: "PreviewImage", data() { return { link: "", show: false, width: 0, height: 0, mode: 'aspectFit' // 保持纵横比缩放图片,使图片的长边能完全显示出来。也就是说,可以完整地将图片显示出来。 } }, methods: { open(url) { const img = new Image() img.src = url this.width = img.width > img.height ? '100%' : img.width + 'px' this.height = img.height > img.width ? '100%' : img.height + 'px' this.link = url this.show = true }, close() { this.show = false } } } </script> <style lang="scss" scoped> .g-previewImage { display: flex; align-items: center; justify-content: center; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, .5); z-index: 99999; .image { // background-color: pink; image { width: 100%; height: 100%; } } .icon { position: absolute; top: 40rpx; right: 40rpx; } } </style>
复制
应用:this.$preview.open(url)
</template> <view class="content"> <image :src="url" mode="aspectFit" @click="preview(url)"></image> </view> </template> <script> export default { data() { return { url: require('../../static/img/1.jpg'), } }, methods: { preview(url) { this.$preview.open(url) } } } </script>
复制