使用movable-view制作可拖拽的微信小程序弹出层效果。

时间:2022-02-19 10:22:46

仿了潮汐睡眠小程序的代码。【如果有侵权联系删除

最近做的项目有个弹出层效果,类似音乐播放器那种。按照普通的做了一般感觉交互不是很优雅,设计妹子把潮汐睡眠的弹层给我看了看,感觉做的挺好,于是乘着有空仿照了一下。

首先善用度娘反编译弄到了源码,但是打不开。然后自己研究源码发现他们用的是movable-view实现的。

于是仿照着搭出了基础框架。

新建了个组件

wxml
<!--components/playpanel/playpanel.wxml-->
<movable-area style="height:{{areaH}}px;" class="wrapper">
<movable-view bindchange="onPresent" bindtouchend="dragPanelEnd" bindtouchstart="dragPanelStart" class="sleep-panel-wrapper" damping="{{40}}" direction="vertical" friction="{{1}}" inertia="{{false}}" outOfBounds="{{false}}" style="padding-top:{{0}}px" x="{{0}}" y="{{sleepPanelPosition}}" class="panel"> <view class="" bindtap="presentPanel" hover-class="none" hover-stop-propagation="false">
背景内容
</view>
</movable-view>
</movable-area>
<scroll-view scroll-y style="height:400rpx" class="scroll-w" wx:if="{{showlist}}">
歌曲列表
<view id="green" class="scroll-view-item bc_green"></view>
<view id="red" class="scroll-view-item bc_red"></view>
<view id="yellow" class="scroll-view-item bc_yellow"></view>
<view id="blue" class="scroll-view-item bc_blue"></view>
</scroll-view>

歌曲列表提取出来是因为滚动组件和可拖拽的手势事件会互相影响,如果不需要弹出层有可滚动的区域可以无视。

js部分精简一下就是这样,abcd这些变量名应该是源码做了加密……appjs里还要定义一下初始数据

// components/playpanel/playpanel.js
let d = getApp();
Component({
/**
* 组件的属性列表
*/
properties: {
areaH:Number
}, /**
* 组件的初始数据
*/
data: {
sleepPanelPosition: d.globalData.screenHeight - (d.globalData.isFullScreen ? 24 : 0) - 80 / (375 / d.globalData.screenWidth),
topPosition: d.globalData.statusBarHeight + d.globalData.navBarHeight,
bottomPosition: d.globalData.screenHeight - (d.globalData.isFullScreen ? 24 : 0) - 80 / (375 / d.globalData.screenWidth),
presentProgress: 0,
disableAnimated: !1,
showlist:false,
}, /**
* 组件的方法列表
*/
methods: {
dragPanelEnd(e) { let changedTouches = e.changedTouches;
let pageY = changedTouches[0].pageY;
let topPosition = this.data.topPosition;
let bottomPosition = this.data.bottomPosition;
let distance = pageY - this.dragOrigin;
let speed = (bottomPosition - topPosition)/10; let h = 0;
h = this.data.sleepPanelPosition === topPosition ? distance > speed ? bottomPosition : topPosition : distance < -speed ?topPosition : bottomPosition,this.setData({
sleepPanelPosition: h,
showlist: h === topPosition
}); },
presentPanel() {
const {sleepPanelPosition: a, topPosition: b, bottomPosition: c} = this.data;
this.setData({
sleepPanelPosition: a === b ? c : b,
});
let showList = this.data.sleepPanelPosition === b
this.setData({
showlist: showList
})
},
dragPanelStart(a) {
const {changedTouches: b} = a;
if (b[0]) {
const {pageY: a} = b[0];
this.dragOrigin = a;
}
},
onPresent({detail: a}) {
const {y: b} = a, {topPosition: c, bottomPosition: d} = this.data, e = 1 - parseInt(1e3 * ((b - c) / (d - c))) / 1e3;
e !== this.data.presentProgress && this.setData({
presentProgress: e
}), this.data.disableAnimated || this.setData({
disableAnimated: !0
}), clearTimeout(this.recoverAnimation), this.recoverAnimation = setTimeout(() => {
this.setData({
disableAnimated: !1
}), this.recoverAnimation = null;
}, 100);
},
}
})
//app.js
```
onShow() {
wx.getSystemInfo({
success: a => {
const {
screenHeight: b,
screenWidth: c,
statusBarHeight: d
} = a;
this.globalData.isFullScreen = parseInt(100 * (c / b)) < parseInt(100 * (9 / 17)),
this.globalData.isBiggerScreen = 667 < b, this.globalData.statusBarHeight = d, this.globalData.navBarHeight = 44,
this.globalData.navBarFontSize = 18.5, this.globalData.btnScopeSize = 40, this.globalData.btnSize = 32,
this.globalData.screenHeight = b, this.globalData.screenWidth = c;
}
});
},
```

wxss部分,主要是.panel不要设置top值,其他好像没啥。

/* components/playpanel/playpanel.wxss */
.wrapper {
position: fixed;
top:;
left:;
bottom:;
right:;
width: 100vw;
height: 200vh;
pointer-events:none;
}
.panel {
width: 100%;
background: rgba(233, 233, 255, 0.8);
height: 100vh;
pointer-events: auto;
}
.scroll-view-item {
height: 300rpx;
}
.bc_green {
background: green;
}
.bc_red {
background: red;
}
.bc_yellow {
background: yellow;
}
.bc_blue {
background: blue;
}
.scroll-w {
position: fixed;
bottom:;
}