背景
wx.previewImage无法添加文字,所以需要手动封装小程序图片预览插件
$headerIconWidth: 32px;
$swiperImageHeight: 1068rpx; // 534px
page {
background-color: black;
box-sizing: border-box;
height: 100%;
}
.bigImageBox {
background-color: black;
box-sizing: border-box;
color: #ffffff;
height: 100%;
display: flex;
flex-direction: column;
justify-content: space-between;
.header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 9px;
box-sizing: border-box;
width: 100%;
.header-left {
border-radius: 50%;
width: $headerIconWidth;
height: $headerIconWidth;
.header-left-icon {
width: 100%;
height: 100%;
}
}
.header-center {
color: #ffffff;
font-size: 17px;
flex: 1;
display: flex;
justify-content: center;
}
.header-right {
width: $headerIconWidth; // 为了跟.header-left同宽,适应flex
}
}
.bigImage-swiperBox {
// margin-top: 50px;
width: 100%;
.swiperItem {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
justify-content: space-between;
.swiperItem-image {
width: 100%;
height: $swiperImageHeight;
}
}
}
.bigImage-info {
// height: 200rpx;
max-height: 200rpx;
padding: 0 12px 12px 12px;
box-sizing: border-box;
font-size: 12px;
color: #ffffff;
.info-sku {
margin: 6px 0;
color: #999999;
}
}
}
.movableBox {
width: 100%;
height: 100%;
overflow: hidden;
}
movable-view {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
width: 100%;
color: #fff;
}
movable-area {
height: 100%;
width: 100%;
overflow: hidden;
}
头部按钮
<view class="bigImageBox" style="height:100vh;">
<view class="header" style="position: fixed; height: {{menuInfo.height}}px;top:{{menuInfo.top}}px;z-index:999;">
<view class="header-left" catchtap="onPageBack">
<image lazy-load="{{true}}" src="{{commentsTopBackIconUrl}}" class="header-left-icon" />
</view>
<view class="header-center">
<text class="imageIndex">{{swiperCurrent + 1}}</text>
/
<text class="imageLength">{{swiperLength}}</text>
</view>
<view class="header-right"></view>
</view>
<!-- 轮播图+movable -->
<swiper current="{{swiperCurrent}}" class="bigImage-swiperBox" style="width:100%;height:100%;" catchchange="onSwiperChange" catchtransition='onChange'>
<block wx:for="{{imageList}}" wx:key="index">
<swiper-item item-id="">
<movable-area scale-area class='swiperItem movableBox'>
<movable-view direction="all" disabled="{{!item.enableMove && isHSwiper}}" data-index="{{index}}" animation catchscale="onScale" scale damping="999" scale-min="1" scale-max="2" scale-value="{{swiperCurrent===index?scale:1}}" style=" width:100%;height:100%;" catchchange="slideChange" catchvtouchmove="{{!isSwiper?'touchmove':''}}" catchhtouchmove="{{!isSwiper?'touchmove':''}}" out-of-bounds>
<image lazy-load="{{true}}" mode="aspectFit" style="max-width:100%;max-height:100%;" show-menu-by-longpress="{{shareImg}}" src="{{item.bigImagePath || item.imagePath}}" class="swiperItem-image" data-index="{{index}}" catchtap="onClosePage" />
</movable-view>
</movable-area>
</swiper-item>
</block>
</swiper>
<!--文字显示-->
<scroll-view class="bigImage-info" scroll-y="{{true}}" style="position:fixed;bottom:40rpx;">
<wxs module="fn">
module.exports = {
nickNameHandle: function(str = '') {
return str.substring(0, 1) + '***' + str.substring(str.length - 1, str.length)
}
}
</wxs>
<view class="info-name">{{fn.nickNameHandle(detailInfo.nickName)}}</view>
<view class="info-sku">{{detailInfo.skuSpec}}</view>
<view class="info-content">{{detailInfo.content}}</view>
</scroll-view>
</view>
import wepy from 'wepy'
import { productImages } from '@/constant/images'
import { debounce, throttle } from '@/utils/index'
Page({
data: {
commentsTopBackIconUrl: productImages.commentsTopBack,
menuInfo: {},
commentList: [], // 所有评论
commentIndex: 0, // 当前评论的索引
imageIndex: 0, // 当前图片的索引
imageList: [],
swiperCurrent: 0, // 当前所在滑块的index
swiperLength: 0, // 所有滑块的数量
detailInfo: {}, // 显示的名称规格评价等信息
shareImg: true, // 是否可以分享图片
isCloseImg: true, // 是否关闭大图
scale: 1,
lastTapTimeoutFunc: null,
lastTapDiffTime: 0,
isScale: false, // 是否双指放大 ,如果是,用户双击scale变成1
isSwiper: true, // 是否禁止swiper滑动,为解决图片放大滑动和swiper滑动冲突
movableType: 'touch', // movable组件触摸类型,正常touch,触碰到边界out-of-bounds,touch-out-of-bounds
x_axis: 0, // movable的x坐标
allowOneMove: false, // 只允许一次
dxMax: 0,
isHSwiper: false // 上下也会触发边界事件,阻止用户在上下滑动时被当作左右滑动而禁止了movable
},
onLoad(option) {
option = wepy.$instance.commonInitialSceneOptions(option)
let { productId, skuId, commentIndex, imageIndex } = option
this.setData({
commentIndex: Number(commentIndex), // option传递过来是string类型
imageIndex: Number(imageIndex)
})
},
onShow() {
let menuInfo = wx.getMenuButtonBoundingClientRect()
let commentList = wepy.$instance.globalData.commentList || []
console.log('评论页 menuInfo:', commentList)
this.setData({
menuInfo,
commentList
})
this.getImageList()
this.getDetailInfo(this.data.swiperCurrent)
},
// 获取图片list 所有图片,非当前用户发表图片,数量根据已加载的评价数变化
getImageList() {
let allImageList = []
let currentImgIndex = 0
console.log('评论页sadhakdhak:', this.data.commentList)
if (this.data.commentList.length > 0) {
this.data.commentList.forEach((item, index) => {
if (index === this.data.commentIndex) {
currentImgIndex = allImageList.length + this.data.imageIndex
}
if (item.commentImageDtoList && item.commentImageDtoList.length > 0) {
// 评论中有图片时才push
item.commentImageDtoList.forEach((cit, cin) => {
allImageList.push(cit)
})
}
})
}
this.setData({
imageList: allImageList,
swiperCurrent: currentImgIndex,
swiperLength: allImageList.length
})
},
// 获取下方的评论内容detialInfo
getDetailInfo(swiperCurrent) {
let detailInfo = {}
let commentIdCur =
this.data.imageList.length > 0 && this.data.imageList[swiperCurrent]
? this.data.imageList[swiperCurrent].commentId
: ''
if (this.data.commentList.length > 0) {
this.data.commentList.forEach((item) => {
if (String(commentIdCur) === String(item.uuid)) {
// 说明 是某个人的评论
detailInfo = item
}
})
}
this.setData({
detailInfo
})
},
// 左上角返回按钮
onPageBack() {
const eventChannel = this.getOpenerEventChannel()
eventChannel.emit('acceptDataFromOpenedPage', 'commentsBigImage')
wx.navigateBack()
},
// 点击大图后关闭
onClosePage(e) {
if (!this.data.isCloseImg) {
return
}
const { index } = e.currentTarget.dataset
console.log(index, this.data.swiperCurrent, 'onClosePage++++')
let _this = this
let curTime = new Date().getTime()
let lastTime = _this.data.lastTapDiffTime
_this.data.lastTapDiffTime = curTime
// 两次点击间隔小于300ms, 认为是双击
let diff = curTime - lastTime
if (diff < 300) {
_this.setData({
scale:
_this.data.scale == 1 && index === this.data.swiperCurrent ? 2 : 1,
isSwiper: _this.data.scale == 1 // 如果是正常图片可以滑动
})
clearTimeout(_this.data.lastTapTimeoutFunc) // 成功触发双击事件时,取消单击事件的执行
} else {
if (!this.data.isCloseImg) {
return
}
// 单击事件延时300毫秒执行
_this.data.lastTapTimeoutFunc = setTimeout(function () {
console.log(_this.data.isCloseImg, '单击+++')
// 回到pdp
if (_this.data.isCloseImg) {
_this.onPageBack()
}
}, 300)
}
},
// 滑动后将左右两侧的数据重置
resetImageListAdditionProperties(index) {
let _previous = index - 1
let _next = index + 1
if (_previous >= 0) {
this.setData({
[`imageList[${_previous}].isScaling`]: false,
[`imageList[${_previous}].enableMove`]: false
})
}
if (_next < this.data.imageList.length) {
this.setData({
[`imageList[${_next}].isScaling`]: false,
[`imageList[${_next}].enableMove`]: false
})
}
},
// swiper滑动throttle
onSwiperChange(e) {
this.setData({
scale: 1
})
// 微信官方提醒:如果在 bindchange 的事件回调函数中使用 setData 改变 current 值,则有可能导致 setData 被不停地调用,
// 因而通常情况下请在改变 current 值前检测 source 字段来判断是否是由于用户触摸引起
// 1、autoplay 自动播放导致 swiper 变化;
// 2、touch 用户划动引起 swiper 变化;
// 3、其它原因将用空字符串表示。
if (e.detail.source !== 'touch' && e.detail.source !== 'autoplay') {
return false
}
this.resetImageListAdditionProperties(e.detail.current)
this.getDetailInfo(e.detail.current)
this.setData({
swiperCurrent: e.detail.current
})
},
onScale(e) {
const { scale } = e.detail
this.setData(
{
shareImg: false,
isCloseImg: false,
isSwiper: false,
[`imageList[${this.data.swiperCurrent}].isScaling`]: scale > 1,
[`imageList[${this.data.swiperCurrent}].enableMove`]: scale > 1
},
() => {
setTimeout(() => {
this.setData({ shareImg: true, isCloseImg: true })
}, 500)
}
)
},
// 禁止用户滑动
catchTouchMove(e) {
return this.data.isSwiper
},
slideChange: throttle(
function (e) {
console.log(e, 'e+++')
const { source } = e.detail
// 节流,判断是否触碰左右边界
if (source == 'out-of-bounds' || source == 'touch-out-of-bounds') {
this.setData({
isSwiper: true,
[`imageList[${this.data.swiperCurrent}].enableMove`]: false
})
}
this.setData({movableType: source})
},
800,
1
),
onChange: throttle(function (e) {
const {dx} = e.detail
// 当用户触发swiper移动
this.setData({
isHSwiper: true
})
// dx为0 =>滑动又弹回去,可以movalble不可以swiper
// if (this.data.dxMax > parseInt(dx)) {
if (dx > -20 && dx < 20) {
this.setData({
shareImg: false,
isCloseImg: true,
isSwiper: false,
isScale: false,
isHSwiper: false,
[`imageList[${this.data.swiperCurrent}].isScaling`]: false,
[`imageList[${this.data.swiperCurrent}].enableMove`]: true
})
}
if (Math.abs(this.data.dxMax - parseInt(dx)) > 10) {
console.log(dx, 'onChange++++')
this.setData({
dxMax: parseInt(dx)
})
}
}, 100, 2)
})