更新记录
1.1.3(2023-06-16)
1.1.2(2023-06-16)
1.1.1(2023-06-16)
查看更多
平台兼容性
App |
快应用 |
微信小程序 |
支付宝小程序 |
百度小程序 |
字节小程序 |
QQ小程序 |
app-vue |
× |
√ |
× |
× |
× |
× |
钉钉小程序 |
快手小程序 |
飞书小程序 |
京东小程序 |
× |
× |
× |
× |
H5-Safari |
Android Browser |
微信浏览器(Android) |
QQ浏览器(Android) |
Chrome |
IE |
Edge |
Firefox |
PC-Safari |
√ |
√ |
√ |
√ |
√ |
√ |
√ |
√ |
√ |
custom-bottom-sheet-dialog
手势滑动关闭的弹窗
提示: 使用该插件前确保你已经导入 uni-popup
插件。
有问题可以加 QQ 群:297080738(已满),新群:460688316
Props
属性名 |
类型 |
默认值 |
说明 |
animation |
Boolean |
ture |
是否开启弹窗动画 |
is-mask-click |
Boolean |
true |
点击遮罩关闭弹窗 |
mask-background-color |
String |
rgba(0,0,0,0.4) |
蒙版颜色,建议使用 rgba 颜色值 |
background-color |
String |
none |
主窗口背景色 |
safe-area |
Boolean |
true |
是否适配底部安全区 |
contentHeight |
String |
auto |
设置弹窗高度,例如 auto 或者 300px |
threshold |
String | Number |
0 |
设置滑动阈值,滑动多少距离之后触发自动关闭,设置超过可视区域或弹窗高度则会取消自动关闭 |
speed |
Number |
0.8 |
设置滑动速度,范围 0 - 1 ,没有滑动指定距离,但是滑动很快,达到速度阈值同样会触发自动关闭。如果设置为 0 ,只要有下滑操作都会自动关闭弹窗 |
beforeClose |
Function |
- |
关闭弹窗前的回调,使用方法见下方示例。 |
Events
事件名称 |
说明 |
返回值 |
touchstart |
按下滑动区域触发 |
e |
touchmove |
滑动时触发 |
e |
touchend |
松开手触发 |
e |
popupStateChange |
弹窗打开和关闭时触发 |
e={show: true | false,type:当前模式} |
maskClick |
点击遮罩 |
- |
clickTouchBar |
点击滑动区域时触发,可以执行内部滚动区域返回顶部操作 |
- |
Slot
最佳实践
此示例模仿实际业务中查看详情信息等情况,实现数据展示、上拉加载、下拉刷新、返回顶部等功能,复制代码即可运行
<template>
<view class="content">
<button @click="handleOpenPopup">打开弹窗</button>
<custom-bottom-sheet-dialog
ref="popup"
:contentHeight="contentHeight"
:threshold="contentHeight"
:speed="0.2"
@clickTouchBar="goTop"
@close="handleClosePullToRefresh"
>
<template>
<scroll-view
class="scroll-view"
scroll-y="true"
:scroll-top="scrollTop"
:refresher-enabled="true"
:refresher-triggered="refresherTriggered"
@touchmove.stop
@scrolltolower="getList('next')"
@refresherrefresh="getList('refresh')"
>
<uni-list :border="false">
<uni-list-item
thumb-size="lg"
v-for="item in list"
:key="item.id"
:title="item.title"
:note="item.note"
:thumb="item.thumb"
:rightText="item.rightText"
></uni-list-item>
</uni-list>
<uni-load-more
v-show="!refresherTriggered"
:status="loadMoreStatus"
@clickLoadMore="clickLoadMore"
></uni-load-more>
</scroll-view>
</template>
</custom-bottom-sheet-dialog>
</view>
</template>
<script>
export default {
data() {
return {
contentHeight: '',
scrollTop: 0,
limit: 10,
offset: 1,
listCount: 0,
refresherTriggered: false,
loadMoreStatus: 'more',
list: []
}
},
created() {
this.contentHeight = `${Math.floor(
uni.getSystemInfoSync().screenHeight * 0.7
)}px`
},
methods: {
handleOpenPopup() {
this.$refs.popup.open()
this.getList()
},
// 列表返回顶部
goTop() {
this.scrollTop = 10
this.$nextTick(() => {
this.scrollTop = 0
uni.showToast({
title: '已返回顶部',
icon: 'none',
duration: 1000,
position: 'bottom'
})
})
},
// 打开底部弹窗时禁用原生下拉刷新, app生效
handleClosePullToRefresh(support = true) {
// #ifdef APP-PLUS
const pages = getCurrentPages()
const page = pages[pages.length - 1]
const currentWebview = page.$getAppWebview()
currentWebview.setStyle({
pullToRefresh: {
support,
style: plus.os.name === 'Android' ? 'circle' : 'default'
}
})
// #endif
},
// 手动点击加载更多
clickLoadMore() {
if (this.loadMoreStatus === 'noMore') return
// 获取下一页数据
this.getList('next')
},
// 获取列表数据
async getList(type) {
if (type === 'next') {
if (this.loadMoreStatus === 'noMore') return
this.offset++
}
if (!type || type === 'refresh') {
this.listCount = 0
this.offset = 1
this.list = []
}
if (type === 'refresh') {
this.refresherTriggered = true
if (Math.random() > 0.8) {
this.loadMoreStatus = 'noMore'
setTimeout(() => {
this.refresherTriggered = false
}, 0)
return
}
}
this.loadMoreStatus = 'loading'
// 发送请求获取列表数据...
const { data } = await this.queryList({
limit: this.limit,
offset: this.offset
})
if (!data.length) {
this.loadMoreStatus = 'noMore'
} else {
this.loadMoreStatus = 'more'
}
this.refresherTriggered = false
this.list.push(...data)
},
queryList({ limit, offset }) {
return new Promise((resolve) => {
setTimeout(() => {
resolve({
code: 200,
data:
offset >= 3
? []
: new Array(limit).fill(0).map(() => ({
id: this.listCount++,
title: `这是第${this.listCount}项`,
note: `描述信息`,
thumb:
'https://qiniu-web-assets.dcloud.net.cn/unidoc/zh/unicloudlogo.png'
}))
})
}, 500)
})
}
}
}
</script>
<style lang="scss" scoped>
.content {
padding: 4px 5px 0;
}
.scroll-view {
touch-action: none;
flex: 1;
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
</style>
基础使用示例
<template>
<view class="content">
<button type="primary" @click="$refs.popupEmpty.open()">
打开空白弹窗
</button>
<button style="margin-top: 8px" type="primary" @click="handleOpenCol">
打开弹窗纵向
</button>
<button style="margin-top: 8px" type="primary" @click="handleOpenRow">
打开弹窗横向
</button>
<custom-bottom-sheet-dialog ref="popupEmpty">
<template>
<view style="padding: 8px; text-align: center">
<text>这里是插槽</text>
</view>
</template>
</custom-bottom-sheet-dialog>
<custom-bottom-sheet-dialog ref="popupCol" threshold="200">
<template>
<scroll-view class="scroll-view-box" scroll-y="true" @touchmove.stop>
<view class="col-list">
<view
class="col-list-item"
v-for="item in 15"
:key="item"
@click="handleLiClick(item)"
>
{{ item }}
</view>
</view>
</scroll-view>
</template>
</custom-bottom-sheet-dialog>
<custom-bottom-sheet-dialog ref="popupRow" threshold="50">
<template>
<scroll-view
class="scroll-view-box row"
scroll-x="true"
@touchmove.stop
>
<view class="row-list">
<view
class="row-list-item"
v-for="item in 15"
:key="item"
@click="handleLiClick(item)"
>
<image
class="logo"
src="/static/logo.png"
mode="aspectFit"
:draggable="false"
></image>
<view class="name">
<text>菜单</text>
<text>{{ item }}</text>
</view>
</view>
</view>
<view class="row-list">
<view
class="row-list-item"
v-for="item in 15"
:key="item"
@click="handleLiClick(item)"
>
<image
class="logo"
src="/static/logo.png"
mode="aspectFit"
:draggable="false"
></image>
<view class="name">
<text>菜单</text>
<text>{{ item }}</text>
</view>
</view>
</view>
</scroll-view>
</template>
</custom-bottom-sheet-dialog>
</view>
</template>
<script>
export default {
data() {
return {}
},
methods: {
handleOpenCol() {
this.$refs.popupCol.open()
},
handleOpenRow() {
this.$refs.popupRow.open()
},
handleLiClick(value) {
uni.showToast({
title: `点击了第${value}个`,
icon: 'none',
duration: 1000
})
console.log(value)
},
beforeClose(done) {
uni.showModal({
title: '提示',
content: '确认关闭底部弹窗?',
cancelText: '再想想',
confirmText: '关闭',
success: function (res) {
if (res.confirm) {
done()
} else if (res.cancel) {
// 用户点击取消
}
}
})
}
}
}
</script>
<style lang="scss" scoped>
.content {
padding: 8px 10px 0;
}
.scroll-view-box {
max-height: 300px;
width: auto;
&.row {
display: flex;
}
}
.col-list-item {
padding: 8px 10px;
text-align: center;
font-size: 16px;
}
.row-list {
display: flex;
.row-list-item {
padding: 8px 10px 8px 0;
&:first-child {
margin-left: 10px;
}
.logo {
width: 40px;
height: 40px;
}
.name {
font-size: 12px;
text-align: center;
}
}
}
</style>