先看最终的效果展示:
在他人的小程序上发现了类似效果,但似乎用的是uniapp上的插件,所以我使用小程序原生的方式复刻一个。复刻过程中可以了解到关于拖拽的实现、判断拖拽方向、ios弹簧效果禁用、拖拽优化等。
页面的布局文件(wxml格式):
<!--pages/observation-desk/observation-desk.wxml-->
<view class="blur" style="background-image: url({{pictureList[currentIndex].img}});"></view>
<view class="bg">
<view class="picture-box" catch:touchmove="touchMoveHandler" catch:touchend="touchEndHandler"
style="top:calc(50% + {{y + 'px'}}) ;"
>
<image mode="aspectFill" hidden="{{currentIndex + 2 >= pictureList.length}}" src="{{pictureList[currentIndex + 2].img}}" />
<image mode="aspectFill" hidden="{{currentIndex + 1 >= pictureList.length}}" src="{{pictureList[currentIndex + 1].img}}" />
<view style="position: relative;">
<image class="center-picture" mode="aspectFill" src="{{pictureList[currentIndex].img}}" />
<view class="picture-name">
{{pictureList[currentIndex].name}}
</view>
</view>
<image mode="aspectFill" hidden="{{pictureList[currentIndex - 1] == null}}" src="{{pictureList[currentIndex - 1].img}}" />
<image mode="aspectFill" hidden="{{pictureList[currentIndex - 2] == null}}" src="{{pictureList[currentIndex - 2].img}}" />
</view>
</view>
页面的样式文件(wxss格式):
.bg {
width: 100vw;
height: 100vh;
overflow: hidden;
position: relative;
}
/** 模糊的背景 */
.blur {
position: absolute;
background-size: cover;
background-position: center;
background-repeat: no-repeat;
width: 100vw;
height: 100vh;
top: 0;
left: 0;
filter: blur(3px);
}
/** 放所有图片的大盒子 */
.picture-box {
transform: translate(-50%, -50%);
position: absolute;
left: 50%;
display: flex;
align-items: center;
flex-direction: column;
}
/** 当前选中图片的文字描述 */
.picture-name {
z-index: 1001;
position: absolute;
bottom: 10px;
left: 50%;
transform:translateX(-50%);
background-color: rgba(0,0,0,0.3);
color: white;
text-align: center;
width: calc(100% - 10px);
padding: 15px;
}
.picture-box image {
height: 150px;
border: 5px solid white;
border-radius: 8px;
position: relative;
}
.picture-box image::after {
content: "";
background-color: rgba(255,255,255,0.5);
width: 100%;
height: 100%;
top: 0;
left: 0;
position: absolute;
}
/** 当前选中的图片的样式 */
.picture-box .center-picture {
width: 300px;
z-index: 1000;
}
.picture-box .center-picture::after {
background-color: transparent;
}
.picture-box>image:nth-child(1) {
width: 240px;
margin-bottom: -70px;
}
.picture-box>image:nth-child(2) {
width: 260px;
margin-bottom: -70px;
}
.picture-box>image:nth-child(4) {
width: 260px;
margin-top: -70px;
z-index: 999;
}
.picture-box>image:nth-child(5) {
width: 240px;
margin-top: -70px;
z-index: 998;
}
页面的JS文件:
//记录上一次拖拽时的基准位置
let touchY = null;
//拖拽方向:true表示上翻,false表示下翻
let upward = null;
const app = getApp()
Page({
data: {
//通用图片路径的前缀
imgUrl: app.globalData.imgUrl,
//拖拽时元素的y轴方向的位置
y:0,
//图片列表
pictureList: [
{
//图片的url路径,用你自己的图片路径
img: app.globalData.imgUrl + "/" + "observation-desk1.png",
//图片的名字,当图片选中时会显示出来
name: "1号看海"
},{
img: app.globalData.imgUrl + "/" + "observation-desk2.png",
name: "2号嬉海"
},{
img: app.globalData.imgUrl + "/" + "observation-desk3.png",
name: "3号爱海"
}, {
img: app.globalData.imgUrl + "/" + "observation-desk5.jpg",
name: "5号绘海"
}, {
img: app.globalData.imgUrl + "/" + "observation-desk8.jpg",
name: "8号平台"
}
, {
img: app.globalData.imgUrl + "/" + "observation-desk10.jpg",
name: "10号平台"
}, {
img: app.globalData.imgUrl + "/" + "observation-desk12.png",
name: "12号平台"
}
],
//当前选中图片的下标
currentIndex: 0,
},
//拖拽移动事件处理函数
touchMoveHandler(e) {
const {screenY} = e.changedTouches[0]
const offset = screenY - touchY
if(touchY == null) {
touchY = screenY;
return
}
upward = this.data.y - offset > 0
this.setData({y:offset})
},
//拖拽结束事件处理函数
touchEndHandler() {
let {currentIndex,pictureList} = this.data
//下翻的情况
if(upward===false) {
if(currentIndex < pictureList.length - 1) {
currentIndex = currentIndex + 1
}
}
//上翻的情况
else if(upward === true){
if(currentIndex > 0) {
currentIndex = currentIndex - 1
}
}
this.setData({ currentIndex, y:0 })
touchY = null
upward = null
},
})
禁用ios弹簧效果(在页面对应的JSON文件中将disableScroll设置为true)
{
"usingComponents": {},
"disableScroll": true
}
最后:监听touchmove事件时利用catch方式来代替bind可以阻止事件冒泡提高一些性能。