自主产品,供应链食堂系统。将两个端拆开了。
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

315 lines
7.9 KiB

<template>
<view>
<swiper class="swiper" :animation="animationData"
:style="{ 'opacity': animation ? '0' : '1',
'background-color': perspective ? 'rgba(0,0,0,0.5)' : '#000000'}"
:current="swiper_current" :circular="circular"
v-if="show_assembly" @click="hideAssembly"
@transition="transition"
@touchmove.stop.prevent="touchmove"
@change="e => switchItem(e.detail.current)">
<swiper-item v-for="(item, index) in images" :key="index"
class="swiper-item">
<!-- 可移动缩放操作的容器 -->
<movable-area class="movable-area" :scale-area="true">
<movable-view class="movable-view" direction="all" :scale="true" :inertia="true" @scale="scale" :scale-value="scale_values[swiper_current]">
<image :src="item" class="swiper-image" mode="aspectFit" @mousewheel.stop="mousewheel" @longpress="longpress"></image>
</movable-view>
</movable-area>
<!-- 控制器 -->
<view class="controls" v-if="controls">
<view>
<view @click.stop="switchItem(swiper_current - 1)" v-if="swiper_current != 0">
<uni-icons type="arrowleft" size="36" color="#fff"></uni-icons>
</view>
<view v-else></view>
</view>
<view>
<view @click.stop="switchItem(swiper_current + 1)" v-if="swiper_current != images.length - 1">
<uni-icons type="arrowright" size="36" color="#fff"></uni-icons>
</view>
<view v-else></view>
</view>
</view>
<!-- 指示器 -->
<view class="indicators" v-if="indicators && images.length > 1">
<view class="number" v-if="indicatorType == 'number'">{{ swiper_current + 1 }} / {{ images.length }}</view>
<view class="square" v-else-if="indicatorType == 'square'">
<view v-for="(item, index) in images" :key="index" class="indicators-icon" :style="swiper_current == index ? 'background-color:'+ themeColor : ''"></view>
</view>
<view class="dot" v-else-if="indicatorType == 'dot'">
<view v-for="(item, index) in images" :key="index" class="indicators-icon" :style="swiper_current == index ? 'background-color:'+ themeColor : ''"></view>
</view>
</view>
<!-- 底部菜单弹出层 -->
<view class="menu-popup" v-if="menu && show_menu" @click.stop>
<button @click="download">保存图片</button>
</view>
</swiper-item>
</swiper>
</view>
</template>
<script>
export default {
props: {
controls: {
type: Boolean, // 是否显示左右箭头控制
default: true
},
indicators: {
type: Boolean,
default: true // 是否显示指示器
},
indicatorType: {
type: String, // 指示器类型,dot圆点,square方形,number数字
default: 'number'
},
perspective: {
type: Boolean, // 是否开启背景透视,遮罩透明可以看见底下其他元素
default: true
},
circular: {
type: Boolean, // 是否可以衔接滑动
default: false
},
themeColor: {
type: String, // 主题色
default: '#1833F2'
},
animation: {
type: Boolean, // 是否开启动画
default: false
},
menu: {
type: Boolean, // 长按图片时是否显示菜单按钮,H5不支持,传参无效果
default: true
}
},
data(){
return {
swiper_current: 0, // 当前显示的图片下标
images: [],
show_assembly: false, // 显示预览图片
duration: 500, // 动画持续时间
animationObj: {}, // 动画配置对象
animationData: {}, // 动画导出执行对象
scale_values: [], // 每张图的缩放比例
clientY: 0,
show_menu: false
}
},
created(){
// TODO PC端屏蔽遮罩滚动穿透
// TODO PC端滚轮放大缩小
// TODO 双击时会被关掉
},
methods: {
// 初始化加载动画
initAnimation(){
let animationObj = uni.createAnimation({
duration: this.duration
});
this.animationObj = animationObj;
animationObj.opacity(0).step();
animationObj.opacity(1).step();
this.animationData = animationObj.export();
},
// swiper touchmove事件
touchmove(){
return false;
},
// swiper 位置发生变化
transition(){
if(this.show_menu){
this.show_menu = false;
}
},
// swiper被改变
switchItem(current){
this.swiper_current = current;
// this.clientY = 0; // 切换时需要复位
},
// movable 缩放事件
scale(event){
let scale = parseInt(event.detail.scale * 100) +'%';
uni.showToast({
title: scale,
icon: 'none',
position: 'bottom'
})
},
// 鼠标滚动缩放事件,目前会触发浏览器页面滚动事件,暂时先不要这个功能
mousewheel(event){
return;
let scale = this.scale_values[this.swiper_current];
if(this.clientY > event.clientY){
if(scale < 10){
scale += 0.5;
}
}else{
if(scale > 0.5){
scale -= 0.5;
}
}
this.clientY = event.clientY;
this.scale_values.splice(this.swiper_current, 1, scale);
},
// 显示图片
show(options){
this.images = options.images || [];
this.swiper_current = options.current || 0;
this.scale_values = this.images.map(item => 1);
this.show_assembly = true;
if(this.$props.animation){
this.initAnimation();
}
},
// 关闭隐藏图片
hideAssembly(){
if(this.show_menu){
this.show_menu = false;
return;
}
if(this.$props.animation){
this.animationObj.opacity(0).step();
this.animationData = this.animationObj.export();
setTimeout(() => {
this.show_assembly = false;
}, this.duration);
}else{
this.show_assembly = false;
}
},
// 长按事件
longpress(event){
// #ifndef H5
if(this.$props.menu){
this.show_menu = true;
}
// #endif
},
// 保存图片
download(){
uni.showLoading({
title: '正在保存'
})
this.show_menu = false;
uni.downloadFile({
url: this.images[this.swiper_current],
success: res => {
let tempFilePath = res.tempFilePath;
uni.saveFile({
tempFilePath,
success: result => {
uni.showToast({
title: '保存成功',
icon: 'success'
})
},
fail: err => {
uni.showToast({
title: '保存失败',
icon: 'none'
})
},
complete: () => uni.hideLoading()
})
},
complete: () => uni.hideLoading()
})
}
}
}
</script>
<style lang="scss" scoped="scoped">
.swiper{
width: 100vw;
height: 100vh;
position: fixed;
top: 0;
left: 0;
z-index: 1000;
.swiper-item{
position: relative;
.movable-area, .movable-view, .swiper-image{
width: 100%;
height: 100%;
}
.controls{
position: absolute;
padding: 0 16rpx;
box-sizing: border-box;
display: flex;
justify-content: space-between;
top: 47vh;
left: 0;
font-size: 40rpx;
width: 100%;
z-index: 1002;
}
.indicators{
width: 100%;
position: absolute;
left: 0;
bottom: 10vh;
z-index: 1002;
display: flex;
justify-content: center;
.number, .square, .dot{
width: max-content;
height: max-content;
background-color: #dfe4ea;
}
.number{
padding: 4rpx 26rpx;
border-radius: 40rpx;
color: #555555;
}
.square{
border-radius: 40rpx;
display: flex;
padding: 2rpx 4rpx;
view{
border-radius: 50%;
}
}
.dot{
display: flex;
padding: 4rpx 4rpx;
}
.indicators-icon{
width: 20rpx;
height: 20rpx;
background-color: #bdc5bd;
margin: 2rpx;
}
}
}
}
.menu-popup{
position: fixed;
bottom: 0;
left: 0;
height: max-content;
width: 100%;
background-color: #FFFFFF;
z-index: 1004;
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
button{
height: 100rpx;
line-height: 100rpx;
background-color: transparent;
border-bottom: 1rpx solid #e5e5e5;
&:last-child{
border-bottom: none;
}
}
}
// 轻提示框样式
/deep/.uni-sample-toast{
z-index: 1002;
}
</style>