main
scout 2 months ago
parent 641364d8e9
commit 1553e32b41

@ -0,0 +1,372 @@
<template>
<view class="previewImage" :style="{ 'background-color': 'rgba(0,0,0,' + opacity + ')' }" v-if="show" @tap="close" @touchmove.stop.prevent>
<swiper class="swiper" :current="index" @change="swiperChange" :disable-touch="swiper" :circular="circular">
<swiper-item v-for="(img, i) in imgs" :key="'swiper-item-'+i" :id="'swiper-item-'+i">
<movable-area class="marea" scale-area>
<movable-view
:id="'movable-view-'+i"
:key="'movable-view-'+i"
class="mview"
direction="all"
:out-of-bounds="false"
:inertia="true"
damping="90"
friction="2"
scale="true"
scale-min="1"
scale-max="4"
:scale-value="scale"
@scale="onScale"
@change="movableChange"
>
<image
:id="'image-'+i"
:key="'movable-view'+i"
class="image"
:src="img"
:style="{ transform: 'rotateZ(' + deg + 'deg)' }"
:data-index="i"
:data-src="img"
mode="widthFix"
@touchmove="handletouchmove"
@touchstart="handletouchstart"
@touchend="handletouchend"
/>
</movable-view>
</movable-area>
</swiper-item>
</swiper>
<view class="page" v-if="imgs.length > 0">
<text class="text">{{ index + 1 }} / {{ imgs.length }}</text>
</view>
<view class="save" v-if="saveBtn" @click.stop.prevent="save"><text class="text"></text></view>
<view class="rotate" v-if="rotateBtn" @click.stop.prevent="rotate"><text class="text"></text></view>
<view class="desc" v-if="descs.length > 0 && descs.length == imgs.length && descs[index].length > 0">{{ descs[index] }}</view>
</view>
</template>
<script>
export default {
name: 'ksj-previewImage', //
props: {
imgs: {
//
type: Array,
required: true,
default: () => {
return [];
}
},
descs: {
//
type: Array,
required: false,
default: () => {
return [];
}
},
//,01
opacity: {
type: Number,
default: 0.8
},
//
saveBtn: {
type: Boolean,
default: true
},
//
rotateBtn: {
type: Boolean,
default: true
},
//
circular:{
type: Boolean,
default: false
}
},
data() {
return {
swiper:false,//
show: false, //
index: 0, //
deg: 0, //
time: 0, //
interval: 1000, //
scale: 1 //
};
},
methods: {
//
onScale(e) {
},
//----------------------------
//
handletouchstart(e) {
var tchs = e.touches.length;
if (tchs != 1) {
return false;
}
this.time = setTimeout(() => {
this.onLongPress(e);
}, this.interval);
return false;
},
//
handletouchend() {
clearTimeout(this.time);
if (this.time != 0) {
//
}
return false;
},
//
handletouchmove() {
clearTimeout(this.time);
this.time = 0;
},
//
onLongPress(e) {
var src = e.currentTarget.dataset.src;
var index = e.currentTarget.dataset.index;
var data = { src: src, index: index };
this.$emit('longPress', data);
},
//----------------------------
//
swiperChange(e) {
this.index = e.target.current; //index
this.$nextTick(function() {
this.scale = 1;
})
//this.deg = 0; //
//this.swiper=true;
},
//
movableChange(e) {
//console.log(e);
/* if(this.old.scale <= 1){
this.swiper=false;
}else if(e.detail.x===0){
this.swiper=false;
} */
},
//
save(e) {
var _this = this;
var src = this.imgs[this.index];
//#ifdef MP-WEIXIN
//
uni.authorize({
scope: 'scope.writePhotosAlbum',
success() {
console.log('kxj-previewImage:允许储存');
_this.downloadImg(src);
}
});
//#endif
//#ifdef APP-PLUS
this.downloadImg(src);
//#endif
//#ifdef H5
//
var abtn = document.createElement('a');
abtn.href = src;
abtn.download = '';
abtn.target = '_blank';
abtn.click();
//#endif
},
//
downloadImg(src) {
//
uni.showLoading({
title: '大图提取中'
});
uni.downloadFile({
url: src,
success: function(res) {
console.log('kxj-previewImage:下载成功');
uni.hideLoading();
uni.saveImageToPhotosAlbum({
filePath: res.tempFilePath,
success: () => {
uni.showToast({
title: '已保存至相册',
duration: 1000
});
}
});
},
fail: function() {
uni.hideLoading();
uni.showToast({
title: '图片下载失败',
icon: 'none',
duration: 1000
});
}
});
},
//
rotate(e) {
this.deg = this.deg == 270 ? 0 : this.deg + 90;
},
//
open(e) {
if (e === null || e === '') {
console.log('kxj-previewImage:打开参数无效');
return;
}
if (!isNaN(e)) {
if(e>=this.imgs.length){
console.log('kxj-previewImage:打开参数无效');
}else{
this.index = e;
}
} else {
var index = this.imgs.indexOf(e);
if(index===-1){
this.imgs = [e];
this.index = 0;
console.log('kxj-previewImage:未在图片地址数组中找到传入的图片,已为你自动打开单张预览模式')
}else{
this.index = this.imgs.indexOf(e);
}
}
console.log('kxj-previewImage:当前预览图片序号'+this.index);
this.show = true;
},
//
close(e) {
this.show = false;
this.index = 0; //
this.deg = 0; //
this.time = 0; //
this.interval = 1000; //
this.scale = 1; //
}
}
};
</script>
<!--使用scss,只在本组件生效-->
<style lang="scss" scoped>
.previewImage {
z-index: 999;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: #000000;
user-select: none;
.swiper {
width: 100%;
height: 100%;
.marea {
height: 100%;
width: 100%;
position: fixed;
overflow: hidden;
.mview {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: auto;
min-height: 100%;
.image {
width: 100%;
}
}
}
}
.page {
position: absolute;
width: 100%;
bottom: 20rpx;
text-align: center;
.text {
color: #fff;
font-size: 26rpx;
background-color: rgba(0, 0, 0, 0.5);
padding: 3rpx 16rpx;
border-radius: 20rpx;
user-select: none;
}
}
.save {
position: absolute;
left: 10rpx;
width: 120rpx;
height: 56rpx;
bottom: 10rpx;
text-align: center;
padding: 10rpx;
.text {
background-color: rgba(0, 0, 0, 0.5);
color: #fff;
font-size: 30rpx;
border-radius: 20rpx;
border: 1rpx solid #f1f1f1;
padding: 6rpx 22rpx;
user-select: none;
}
.text:active {
background-color: rgba(100, 100, 100, 0.5);
}
}
.rotate {
position: absolute;
right: 10rpx;
width: 120rpx;
height: 56rpx;
bottom: 10rpx;
text-align: center;
padding: 10rpx;
.text {
background-color: rgba(0, 0, 0, 0.5);
color: #fff;
font-size: 30rpx;
border-radius: 20rpx;
border: 1rpx solid #f1f1f1;
padding: 6rpx 22rpx;
user-select: none;
}
.text:active {
background-color: rgba(100, 100, 100, 0.5);
}
}
.desc {
position: absolute;
top: 0;
width: 100%;
padding: 5rpx 10rpx;
text-align: center;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
background-color: rgba(0, 0, 0, 0.5);
color: #fff;
font-size: 28rpx;
letter-spacing: 3rpx;
user-select: none;
}
}
</style>

@ -1,5 +1,13 @@
import http from './interface' import http from './interface'
// 登录权限
export const checkLogin = (data) => {
return http.request({
url: '/user/artwork/login',
method: 'POST',
data
})
}
//
// 签到 // 签到
export const goLogin = (data) => { export const goLogin = (data) => {
return http.request({ return http.request({
@ -30,6 +38,7 @@ export const getDetail = (data) => {
export default { export default {
goLogin, goLogin,
code, code,
getDetail getDetail,
checkLogin
} }

@ -30,7 +30,7 @@
v-show="showCode" v-show="showCode"
v-model="code" v-model="code"
space="11" space="11"
@finish="goLogin" @finish="checkLogin"
:maxlength="6" :maxlength="6"
></u-code-input> ></u-code-input>
<u--input <u--input
@ -67,7 +67,7 @@
<view <view
style="display: flex; justify-content: space-between; margin-top: 20rpx" style="display: flex; justify-content: space-between; margin-top: 20rpx"
> >
<view @tap="getCode" style="color: #486661;"> <view @tap="getCode" style="color: #486661">
{{ showCode ? tips : "" }} {{ showCode ? tips : "" }}
</view> </view>
<view style="text-align: right; color: #486661" @click="changeType">{{ <view style="text-align: right; color: #486661" @click="changeType">{{
@ -78,7 +78,7 @@
v-if="loginType === 'pwd'" v-if="loginType === 'pwd'"
type="primary" type="primary"
class="search" class="search"
@click="goLogin" @click="checkLogin"
>登录</u-button >登录</u-button
> >
<u-button <u-button
@ -112,6 +112,27 @@ export default {
codeChange(text) { codeChange(text) {
this.tips = text; this.tips = text;
}, },
//
async checkLogin() {
let data = {
telNum: this.telNum,
password: this.password,
code: this.code,
};
let res = await this.$api.login.checkLogin(data);
if (res.status == 0) {
this.goLogin();
} else {
this.$refs.uNotify.show({
top: 10,
type: "error",
message: res.msg,
duration: 1000 * 3,
fontSize: 20,
safeAreaInsetTop: true,
});
}
},
// //
async goLogin() { async goLogin() {
let data = { let data = {

@ -23,7 +23,14 @@
<view class="title">画作名称</view> <view class="title">画作名称</view>
<view class="name">{{ detailData.ArtworkName }}</view> <view class="name">{{ detailData.ArtworkName }}</view>
</view> </view>
<image class="artwork-image" :src="detailData.PreviewImg"></image> <view class="artwork-image">
<u-album
:urls="[detailData.PreviewImg]"
singleSize="100"
></u-album>
</view>
</view> </view>
<u-collapse> <u-collapse>
<u-collapse-item title="" name="Docs guide"> <u-collapse-item title="" name="Docs guide">
@ -38,7 +45,9 @@
</view> </view>
<view class="item"> <view class="item">
<view class="sub1">画作类型</view> <view class="sub1">画作类型</view>
<view class="sub2">{{ artworkTyoeDict[detailData.ArtworkType] }}</view> <view class="sub2">{{
artworkTyoeDict[detailData.ArtworkType]
}}</view>
</view> </view>
</view> </view>
<view class="list"> <view class="list">
@ -116,13 +125,41 @@
></u--textarea> ></u--textarea>
</view> </view>
</view> </view>
<view style="display: flex;align-items: center;margin-top: 120rpx;">
<u-button type="primary" style="width: 130rpx;margin: 0; height: 90rpx;" @click="goback"
>返回</u-button
>
<u-button <u-button
v-if="actName === '破损' && !hasSubmit"
type="primary" type="primary"
:loading="loading" :loading="loading"
class="search" class="search"
@click="goSubmit" @click="goSubmit(1)"
>提交</u-button >提交</u-button
> >
<u-button
v-if="actName === '修复' && !hasSubmitrepair"
type="primary"
:loading="loading"
class="search"
@click="goSubmit(2)"
>提交</u-button
>
<u-button
v-if="actName === '破损' && hasSubmit"
type="primary"
style="background: #cecece"
class="search"
>已提交</u-button
>
<u-button
v-if="actName === '修复' && hasSubmitrepair"
type="primary"
style="background: #cecece"
class="search"
>已提交</u-button
>
</view>
</view> </view>
</view> </view>
</view> </view>
@ -132,6 +169,8 @@
export default { export default {
data() { data() {
return { return {
hasSubmit: false,
hasSubmitrepair: false,
detailData: {}, detailData: {},
tabList: [ tabList: [
{ {
@ -160,6 +199,11 @@ export default {
changeTab(e) { changeTab(e) {
this.actName = e.name; this.actName = e.name;
}, },
goback() {
this.$router.push({
path: "/",
});
},
uploadFilePromise(url) { uploadFilePromise(url) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const Authorization = uni.getStorageSync("repari-token"); const Authorization = uni.getStorageSync("repari-token");
@ -248,7 +292,7 @@ export default {
} }
}, },
// //
async goSubmit() { async goSubmit(val) {
// //
if ( if (
this.fileList < 1 && this.fileList < 1 &&
@ -275,6 +319,7 @@ export default {
RepairedRemark: this.RepairedRemark, RepairedRemark: this.RepairedRemark,
ArtworkUuid: this.detailData.ArtworkUuid, ArtworkUuid: this.detailData.ArtworkUuid,
CreateSource: 2, CreateSource: 2,
RepairType: val,
}; };
let res = await this.$api.management.update(data); let res = await this.$api.management.update(data);
if (res.status == 0) { if (res.status == 0) {
@ -287,11 +332,11 @@ export default {
safeAreaInsetTop: true, safeAreaInsetTop: true,
}); });
this.loading = false; this.loading = false;
setTimeout(() => { if (val == 1) {
this.$router.push({ this.hasSubmit = true;
path: "/", } else {
}); this.hasSubmitrepair = true;
}, 1000); }
} else { } else {
this.loading = false; this.loading = false;
this.$refs.uNotify.show({ this.$refs.uNotify.show({
@ -419,8 +464,17 @@ page {
.artwork-image { .artwork-image {
width: 380rpx; width: 380rpx;
text-align: center;
display: flex;
justify-content: center;
align-items: center;
height: 180rpx; height: 180rpx;
border-radius: 8rpx; border-radius: 8rpx;
uni-img {
width: 380rpx;
height: 180rpx;
border-radius: 8rpx;
}
} }
.repair { .repair {
margin-top: 20rpx; margin-top: 20rpx;
@ -442,7 +496,7 @@ page {
} }
} }
.search { .search {
margin-top: 70rpx; margin-left: 20rpx;
width: 60%; width: 60%;
border: 0; border: 0;
font-size: 34rpx; font-size: 34rpx;

@ -15,7 +15,7 @@
</template> </template>
<script> <script>
import { detail } from '../../http/management';
export default { export default {
data() { data() {

@ -0,0 +1,19 @@
# uon-preview 更新日志
## 2.1.02024-07-07
1、iconfont 图标改成在线链接地址
## 2.0.02024-05-22
1、新增预览图加载动画
2、新增预览图加载失败时可以重新点击加载预览图
3、优化预览图加载方式、切换方式使得多张图片预览的情况下更加流畅
4、修复小程序端已知问题和部分bug
## 1.2.12024-01-29
修复 iconfont 报错问题
## 1.2.02024-01-25
修复图片双指缩放时按钮缩放不同步问题
## 1.1.02024-01-19
新增预览的图片列表
新增预览图左右切换按钮
修复初始化预览图居中问题
## 1.0.02024-01-18
先发布第一个版本,后续内容在下个版本

@ -0,0 +1,511 @@
<template>
<view class="uon-preview-box">
<template v-if="$slots.default">
<view @click="handler()">
<slot></slot>
</view>
</template>
<template v-else>
<image class="image_" :mode="mode" :src="src" :style="imgStyle" @click="handler()"></image>
</template>
<view class="preview-bxo" v-if="previewShow">
<view class="icon iconfont close_" @click="handlerClose()">&#xeb76;</view>
<view class="bottom_">
<view class="icon iconfont" @click="handlerScale(1)">&#xea98;</view>
<view class="icon iconfont" @click="recover()">&#xea6b;</view>
<view class="icon iconfont" @click="handlerScale(2)">&#xea99;</view>
<!-- <view class="icon iconfont">&#xe66b;</view>
<view class="icon iconfont">&#xe66a;</view> -->
</view>
<view v-if="list && list.length > 1" class="icon iconfont left_" @click="handlerChange(1)">&#xe63c;</view>
<view v-if="list && list.length > 1" class="icon iconfont right_" @click="handlerChange(2)">&#xe618;</view>
<movable-area class="movable_area">
<template v-for="(item, i) in movableViewList" :key="i">
<movable-view
v-if="item.show"
:x="mx" :y="my"
direction="all"
class="movale_"
:animation="animationMovable"
:style="item.view"
scale out-of-bounds
:scale-value="scaleValue"
:scale-max="4"
@change="onChange"
@scale="scale">
<image class="preview_image"
:src="item.src"
:style="{width: item.view.width, height: item.view.height, opacity: item.imgShow ? 1 : 0}"
@load="load" @error="error"></image>
</movable-view>
</template>
<view v-if="showMovableLoading" class="loading"></view>
<movable-view class="error-mov" v-if="showImageError" direction="none">
<view class="img-error">
<view class="loader"></view>
<view class="btn_" @click="reloadImage()"></view>
</view>
</movable-view>
</movable-area>
</view>
</view>
</template>
<script>
import { nextTick } from 'vue'
export default {
props: {
mode: {
type: String,
default: 'widthFix'
},
src: {
type: String,
default: ''
},
width: {
type: String,
default: 'auto'
},
height: {
type: String,
default: 'auto'
},
preview: {
type: Boolean,
default: true
},
//
list: {
type: [Array, undefined],
default: undefined
},
//
imgIndex: {
type: Number,
default: -1
},
// key
keyName: {
type: String,
default: ''
}
},
watch: {
src: {
handler(newval) {
//
if(newval) this.initImage({ src: newval })
}
},
list: {
handler(newval) {
console.log('list---', newval)
},
deep: true
}
},
computed: {
imgStyle() {
return {
width: this.setImgWidth,
height: this.setImgHeight
}
},
},
data() {
return {
mx: 0,
my: 0,
imageIndex: 0,
setImgWidth: '',
setImgHeight: '',
windowWidth: '',
windowHeight: '',
animationMovable: false,
previewShow: false,
showMovableView: false,
showMovableLoading: true,
showImageError: false,
scaleValue: 1,
previewIndex: 0,
movableViewList: [
// { show: false, view: { width: '', height: '', top: '', left: '' }, imgShow: false, src: '' },
]
}
},
created() {
const _this = this
//
uni.getSystemInfo({
success(res) {
_this.windowHeight = res.windowHeight
_this.windowWidth = res.windowWidth
_this.initImage({ width: res.windowWidth, height: res.windowHeight })
}
})
},
methods: {
//
initImage(options) {
const { src = '', width = '', height = '', type = 1 } = options
const _this = this
let windowWidth = width ? width : _this.windowWidth
let windowHeight = height ? height : _this.windowHeight
//
uni.getImageInfo({
src: src ? src : _this.src,
success: function (image) {
//
if(type == 1) {
if(_this.width == 'auto') _this.setImgWidth = image.width * 2 + 'rpx'
else _this.setImgWidth = _this.width
if(_this.height != 'auto') _this.setImgHeight = _this.height
}
}
});
},
//
getItemMovable(src, i) {
const _this = this
//
uni.getImageInfo({
src: src,
success: function (image) {
//
let setWidth = 0, setHeight = 0, left = '0%', top = '0%'
//
if(image.width < _this.windowWidth) {
setWidth = image.width
setHeight = image.height
}else {
setWidth = _this.windowWidth
setHeight = ((_this.windowWidth * image.height) / image.width).toFixed(0)
}
//
if(setHeight < _this.windowHeight) {
//
const offset = (_this.windowHeight - Number(setHeight)) / 2
top = ((offset / _this.windowHeight) * 100).toFixed(0) + '%'
}else top = '0%'
//
if(setWidth < _this.windowWidth) {
//
const offset = (_this.windowWidth - setWidth) / 2
left = ((offset / _this.windowWidth) * 100).toFixed(0) + '%'
}else left = '0%'
_this.movableViewList[i] = {
show: true, view: { width: setWidth + 'px', height: setHeight + 'px', top: top, left: left },
imgShow: false, src: image.path
}
},
fail(err) {
console.log(222, err)
_this.showMovableLoading = false
_this.showImageError = true
}
});
},
handlerClose() {
this.showImageError = false
this.showMovableLoading = true
this.previewShow = false
},
//
handler() {
if(!this.preview) return
if(this.list) {
this.movableViewList = Array(this.list.length)
.fill({ show: false, view: { width: '', height: '', top: '', left: '' }, showImg: false, src: '' });
this.getItemMovable(this.src, this.imgIndex)
}else {
this.movableViewList = Array(1)
.fill({ show: false, view: { width: '', height: '', top: '', left: '' }, showImg: false, src: '' });
this.getItemMovable(this.src, 0)
}
this.scaleValue = 1
this.mx = 0
this.my = 0
if(this.list && this.list.length > 0 && this.imgIndex != -1) this.previewIndex = this.imgIndex
this.previewShow = true
},
//
handlerScale(type) {
if(this.showImageError || this.showMovableLoading) return
let scaleNum = this.scaleValue
//
if(type === 1) scaleNum += 0.1
//
if(type === 2) scaleNum -= 0.1
if(scaleNum < 0.5 || scaleNum > 4) return
this.scaleValue = Number(scaleNum.toFixed(1))
},
//
onChange(e) {
this.mx = e.detail.x
this.my = e.detail.y
},
//
recover() {
if(this.showImageError || this.showMovableLoading) return
this.scaleValue = 1
setTimeout(() => {
this.mx = 0
this.my = 0
}, 100)
},
//
handlerChange(type) {
this.scaleValue = 1
this.mx = 0
this.my = 0
let index = this.previewIndex
this.showImageError = false
this.movableViewList[index].show = false
this.movableViewList[index].imgShow = false
this.showMovableLoading = true
if(type === 1) {
if(this.previewIndex <= 0) this.previewIndex = this.list.length - 1
else this.previewIndex -= 1
}else {
if(this.previewIndex >= (this.list.length - 1)) this.previewIndex = 0
else this.previewIndex += 1
}
// if(!this.movableViewList[this.previewIndex].src) this.showMovableLoading = true
if(!this.movableViewList[this.previewIndex].src) this.getItemMovable(this.keyName ? this.list[this.previewIndex][this.keyName] : this.list[this.previewIndex], this.previewIndex)
else {
this.movableViewList[this.previewIndex].show = true
}
},
scale(e) {
this.scaleValue = e.detail.scale
},
//
load(e) {
// console.log('--', e)
setTimeout(() => {
this.movableViewList[this.previewIndex].imgShow = true
this.showMovableLoading = false
this.showImageError = false
}, 200)
},
//
error(e) {
// console.log('--', e)
this.movableViewList[this.previewIndex].show = false
this.movableViewList[this.previewIndex].imgShow = false
this.showMovableLoading = false
this.showImageError = true
},
//
reloadImage() {
this.showMovableLoading = true
this.showImageError = false
if(this.list) {
this.getItemMovable(this.keyName ? this.list[this.previewIndex][this.keyName] : this.list[this.previewIndex], this.previewIndex)
}else {
this.getItemMovable(this.src, 0)
}
}
}
}
</script>
<style lang="scss" scoped>
@import url("https://at.alicdn.com/t/c/font_4410479_ssp1tci0ta.css");
.uon-preview-box {
position: relative;
display: inline-block;
.image_ {
display: block;
}
.preview-bxo {
position: fixed;
width: 100vw;
height: 100vh;
left: 0rpx;
top: 0rpx;
z-index: 998;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
justify-content: center;
align-items: center;
.close_ {
position: absolute;
right: 40rpx;
top: 50rpx;
width: 60rpx;
height: 60rpx;
display: flex;
align-items: center;
justify-content: center;
background-color: rgba(96,98,102, 0.5);
border-radius: 50%;
color: #E5E5E5;
z-index: 100;
font-size: 46rpx;
}
.bottom_ {
position: absolute;
bottom: 60rpx;
width: 400rpx;
height: 80rpx;
border-radius: 50rpx;
display: flex;
background-color: rgba(96,98,102, 0.5);
justify-content: space-around;
align-items: center;
z-index: 100;
&>view {
font-size: 56rpx;
color:#E5E5E5
}
}
.left_, .right_ {
position: absolute;
top: 50%;
margin-top: -35rpx;
width: 70rpx;
height: 70rpx;
display: flex;
align-items: center;
justify-content: center;
background-color: rgba(96,98,102, 0.5);
border-radius: 50%;
color: #E5E5E5;
z-index: 100;
font-size: 50rpx;
}
.left_ {
left: 30rpx;
}
.right_ {
right: 30rpx;
}
.movable_area {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
pointer-events: none;
}
.movale_ {
pointer-events: auto;
height: max-content;
position: absolute !important;
.preview_image {
display: block;
transition: .3s;
}
}
}
.loading {
position: relative;
width: 30px;
height: 30px;
border: 2px solid #409EFF;
border-top-color: rgba(255, 255, 255, 0.6);
border-right-color: rgba(255, 255, 255, 0.6);
border-bottom-color: rgba(255, 255, 255, 0.6);
border-radius: 100%;
animation: circle infinite 0.75s linear;
}
@keyframes circle {
0% {
transform: rotate(0);
}
100% {
transform: rotate(360deg);
}
}
.error-mov {
pointer-events: auto;
width: 250rpx;
height: 200rpx;
position: absolute;
top: 50%;
margin-top: -100rpx;
left: 50%;
margin-left: -125rpx;
}
.img-error {
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
color: rgba(255, 255, 255, 0.5);
width: 250rpx;
height: 200rpx;
}
.btn_ {
font-size: 30rpx;
padding: 10rpx 20rpx;
background-color: #999;
border-radius: 30rpx;
color: #e5e5e5;
}
.loader {
width: 64px;
height: 64px;
position: relative;
background: rgba(255, 255, 255, 0.7);
border-radius: 4px;
overflow: hidden;
}
.loader:before {
content: "";
position: absolute;
left: 0;
bottom: 0;
width: 40px;
height: 40px;
transform: rotate(45deg) translate(30%, 40%);
background: #f1f1f1;
box-shadow: 32px -34px 0 5px #999999;
}
.loader:after {
content: "";
position: absolute;
left: 10px;
top: 10px;
width: 16px;
height: 16px;
border-radius: 50%;
background: #999999;
transform: rotate(0deg);
transform-origin: 35px 145px;
}
}
</style>

@ -0,0 +1,87 @@
{
"id": "uon-preview",
"displayName": "uon-preview 图片预览组件",
"version": "2.1.0",
"description": "图片可以放大缩小、拖拽移动,自适应图片展示居中,支持多张图片预览和长图预览,可自定义内容插槽",
"keywords": [
"图片预览",
"预览组件",
"长图预览",
"放大缩小",
"拖动预览"
],
"repository": "",
"engines": {
"HBuilderX": "^3.99"
},
"dcloudext": {
"type": "component-vue",
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": "791529212"
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": ""
},
"uni_modules": {
"dependencies": [],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y",
"alipay": "y"
},
"client": {
"Vue": {
"vue2": "y",
"vue3": "y"
},
"App": {
"app-vue": "y",
"app-nvue": "n",
"app-uvue": "n"
},
"H5-mobile": {
"Safari": "y",
"Android Browser": "y",
"微信浏览器(Android)": "y",
"QQ浏览器(Android)": "y"
},
"H5-pc": {
"Chrome": "y",
"IE": "y",
"Edge": "y",
"Firefox": "y",
"Safari": "y"
},
"小程序": {
"微信": "y",
"阿里": "y",
"百度": "y",
"字节跳动": "y",
"QQ": "y",
"钉钉": "y",
"快手": "y",
"飞书": "y",
"京东": "y"
},
"快应用": {
"华为": "y",
"联盟": "y"
}
}
}
}
}

@ -0,0 +1,63 @@
# 使用方法
```html
<template>
<view class="content">
<uon-preview src="/static/animo.png"></uon-preview>
<!-- 使用插槽 -->
<uon-preview src="/static/long.jpg">
<text>点击预览长图</text>
</uon-preview>
<!-- Array<String> 展示 -->
<view v-for="(item, index) in data" :key="index">
<uon-preview :src="item.img" :list="data" :img-index="index">
<text>{{ 'list--预览图片----' + index }}</text>
</uon-preview>
</view>
<!-- Array<Object> 展示 -->
<view v-for="(item, index) in objecList" :key="index">
<uon-preview :src="item.img" :list="objecList" :img-index="index" key-name="img">
<text>{{ item.label + index }}</text>
</uon-preview>
</view>
</view>
</template>
```
```js
<script>
export default {
data() {
return {
imageUrl: 'https://img.alicdn.com/imgextra/i4/O1CN01aG16y424E11XsURUd_!!6000000007358-2-tps-206-240.png',
data: [
'https://www.001acg.com/wp-content/uploads/2023/09/2e387-006yt1Omgy1h8kvgn9lypj30jn0rswj5.jpg',
'https://www.001acg.com/wp-content/uploads/2023/09/78f78-006yt1Omgy1h8pgxy2kknj31jk26p7rq.jpg',
'https://img.alicdn.com/imgextra/i4/O1CN01aG16y424E11XsURUd_!!6000000007358-2-tps-206-240.png'
],
objecList: [
{ img: 'https://www.001acg.com/wp-content/uploads/2023/09/2e387-006yt1Omgy1h8kvgn9lypj30jn0rswj5.jpg', label: '预览图片----' },
{ img: 'https://www.001acg.com/wp-content/uploads/2023/09/78f78-006yt1Omgy1h8pgxy2kknj31jk26p7rq.jpg', label: '预览图片----' },
{ img: 'https://img.alicdn.com/imgextra/i4/O1CN01aG16y424E11XsURUd_!!6000000007358-2-tps-206-240.png', label: '预览图片----' },
]
};
}
}
</script>
```
# 组件属性
| 属性名 | 类型 | 默认值 | 说明 | 是否必填 |
| :-----: | :--: | :-------: | :--: | :----: |
| src | String | - | 图片资源地址 | 必填 |
| mode | String | widthFix | 图片裁剪、缩放的模式,与 image 组件用法相同,仅对默认展示图片有效 | 否 |
| width | String | auto | 默认展示图片的宽度 | 否 |
| height | String | auto | 默认展示图片的高度 | 否 |
| preview | Boolean | true | 是否开启预览模式 | 否 |
| list | Array | [] | 可以是 string[] 也可以是 object[]object[]时必须设置对应的图片 key 值 | 否 |
| imgIndex | Number | -1 | 当前显示图片的索引值 | 否 |
| keyName | String | undefined | 对象数组中对应的图片 key 值 | 否 |
Loading…
Cancel
Save