parent
44e3047a9f
commit
b43f9a8acb
@ -0,0 +1,41 @@ |
||||
# you-touchbox |
||||
|
||||
对nvue做了些兼容处理,但还不成熟,nvue下transition失效的问题无法解决,请大佬指点(现阶段不建议在nvue中使用本插件,问题多多,nvue中遇到问题可以反馈,我尽力实现需求) |
||||
|
||||
***所有像素值参数都不要传单位** |
||||
|
||||
***一切计算以`可使用窗口高度`为基准**,即`uni.getSystemInfoSync().windowHeight` |
||||
|
||||
***上拉框盒子高度默认为`可使用窗口高度`**,可以通过`customStyle`属性设置 |
||||
|
||||
**属性** |
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 | |
||||
| -------------- | :----------------------- | ---------------------------------- | ------------------------------------------------------------ | |
||||
| customStyle | 自定义样式 | String\|Object | -<br />border-radius若要兼容nvue请使用<br />border-top-left-radius,border-top-right-radius分开写 | |
||||
| initTop | 初始top值 | Number\|String\|<br />'min'\|'max' | 默认值为'min',<br />initTop为首次加载时,上拉框显示的高度,<br />所以一般设置为与maxTop或minTop一致,<br />参数可传百分比,像素值,字符串'min''max'<br />max为与maxTop一致,<br />min为与minTop一致<br />0~1为百分比,大于1为像素值,<br />百分比以可使用窗口高度计算,<br />像素值为可使用窗口的顶部位置往下偏移 | |
||||
| maxTop | 最高top值 | Numbe\|String | 默认为可使用窗口的顶部位置,<br />参数可传百分比和像素值,<br />0~1为百分比,大于1为像素值,<br />百分比以可使用窗口高度计算,<br />像素值为可使用窗口的顶部位置往下偏移 | |
||||
| minTop | 最低top值 | Number\|String | 默认为可用区域50%,<br />参数可传百分比和像素值,<br />0~1为百分比,大于1为像素值,<br />百分比以可使用窗口高度计算,<br />像素值为可使用窗口的底部位置往上的偏移 | |
||||
| auto | 是否开启自动复位 | Boolean | true,开启时松手会自动复位到最高最低状态 | |
||||
| limit | 是否开启滑动范围限制 | Boolean | true,开启时滑动范围不可超过maxTop和minTop | |
||||
| customSafeArea | 自定义navbar、tabbar高度 | Object | 如果使用了自定义navbar和tabbar,可以手动设置安全区域 | |
||||
| h5Top | customSafeArea的属性 | Number | -<br />H5的自定义navbar高度 | |
||||
| mpTop | customSafeArea的属性 | Number\|'menuBtn' | -<br />小程序的自定义navbar高度<br />特殊值字符串menuBtn的效果为微信小程序原生navbar的高度<br /> | |
||||
| bottom | customSafeArea的属性 | Number | -<br />自定义tabbar高度<br />因为H5和小程序的navbar高度不一致才需要分开配置,而tabbar一般是一致的,所以不区分 | |
||||
| zIndex | 上拉框z-index | Number\|String | 100 | |
||||
| disable | 禁用滑动 | Boolean | false | |
||||
|
||||
**事件** |
||||
|
||||
| 事件名 | 说明 | 参数 | |
||||
| -------------- | ------------------------------------------------------------ | -------------------------------- | |
||||
| get-end-detail | 获取滑动结束时top信息对象<br />maxTop:最大高度top<br />minTop:最小高度top<br />curTop:当前高度top | Function({maxTop,minTop,curTop}) | |
||||
|
||||
**方法** |
||||
|
||||
此方法要通过ref手动改调用 |
||||
|
||||
| 方法名 | 说明 | 参数 | |
||||
| --------- | ------------------------------------------------------------ | ----------------- | |
||||
| setBottom | 手动设置上拉框高度,参数值传百分比和像素值(不带单位),<br />百分比以可使用窗口高度计算,<br />像素值为可使用窗口的底部位置往上的偏移 | Function(value) | |
||||
|
@ -0,0 +1,244 @@ |
||||
<template> |
||||
<view class="you-touchbox" :class="{touchend:isTouchEnd}" @touchstart="onTouchStart" |
||||
@touchmove.stop.prevent="onTouchmove" @touchend="onTouchend" |
||||
:style="{top: top + distance + 'px',zIndex,height:maxTop*windowHeight+'px'}"> |
||||
<view class="you-touchbox-content" :style="customStyle" @click.stop.prevent> |
||||
<view class="touch-line-box"> |
||||
<view class="touch-line"></view> |
||||
</view> |
||||
<slot></slot> |
||||
|
||||
</view> |
||||
</view> |
||||
</template> |
||||
|
||||
<script> |
||||
|
||||
export default { |
||||
name: "touchbox", |
||||
props: { |
||||
// 禁用滑动 |
||||
disable: { |
||||
type: Boolean, |
||||
default: false |
||||
}, |
||||
zIndex: { |
||||
type: [Number, String], |
||||
default: 100 |
||||
}, |
||||
// 自定义样式 |
||||
customStyle: [String, Object], |
||||
// 自定义安全区域 |
||||
customSafeArea: { |
||||
type: Object, |
||||
default () { |
||||
return { |
||||
h5Top: null, |
||||
wxTop: null, |
||||
bottom: null |
||||
} |
||||
} |
||||
}, |
||||
// 最高top |
||||
maxTop: { |
||||
type: [Number, String], |
||||
default: 1 |
||||
}, |
||||
// 最低top |
||||
minTop: { |
||||
type: [Number, String], |
||||
default: 0.5 |
||||
}, |
||||
// 初始top |
||||
initTop: { |
||||
type: [Number, String], |
||||
default: 'min' |
||||
}, |
||||
// 自动复位 |
||||
auto: { |
||||
type: Boolean, |
||||
default: true |
||||
}, |
||||
// 最高最低限制 |
||||
limit: { |
||||
type: Boolean, |
||||
default: true |
||||
} |
||||
}, |
||||
data() { |
||||
return { |
||||
windowHeight: null, // 可使用区域高度 |
||||
windowTop: null, |
||||
touchStartY: null, // 开始滑动时的Y轴坐标 |
||||
top: null, // 上拉框top |
||||
max: null, // maxTop |
||||
min: null, // minTop |
||||
distance: 0, // 滑动距离 |
||||
isTouchEnd: false, // 是否滑动结束Flag |
||||
boundary: null, // 规定盒子复位为最大或最小状态的分界线,默认为最大最小状态的中间 |
||||
startTime: null, // 开始滑动时间 |
||||
}; |
||||
}, |
||||
mounted() { |
||||
let { |
||||
windowHeight, // 可使用窗口高度 |
||||
windowTop // 可使用窗口的顶部位置 |
||||
} = uni.getSystemInfoSync() |
||||
this.windowHeight = windowHeight |
||||
this.windowTop = windowTop |
||||
let { |
||||
h5Top, |
||||
wxTop, |
||||
bottom |
||||
} = this.customSafeArea |
||||
// H5自定义安全区域 |
||||
// #ifndef MP |
||||
if (h5Top) { |
||||
this.windowHeight -= h5Top |
||||
windowTop += h5Top |
||||
} |
||||
// #endif |
||||
if (bottom) this.windowHeight -= bottom |
||||
// 上拉框最大高度top |
||||
if (this.maxTop <= 1) this.max = this.windowHeight * (1 - +this.maxTop) |
||||
else this.max = +this.maxTop |
||||
// 上拉框最小高度top |
||||
if (this.minTop <= 1) this.min = this.windowHeight * (1 - +this.minTop) |
||||
else this.min = this.windowHeight - (+this.minTop) |
||||
// 初始的上拉框top |
||||
if (['min', 'max'].includes(this.initTop)) this.top = this.initTop === 'min' ? this.min : this.max |
||||
else if (this.initTop <= 1) this.top = this.windowHeight * (1 - +this.initTop) |
||||
else this.top = +this.initTop |
||||
// 微信自定义安全区域 |
||||
// #ifdef MP |
||||
if (wxTop) { |
||||
this.max += wxTop === 'menuBtn' ? uni.getMenuButtonBoundingClientRect().bottom + 10 : wxTop |
||||
this.top += wxTop |
||||
} |
||||
// #endif |
||||
// H5自定义安全区域 |
||||
// #ifndef MP |
||||
this.max += windowTop |
||||
this.min += windowTop |
||||
this.top += windowTop |
||||
// #endif |
||||
this.boundary = (this.max + this.min) / 2 // 规定盒子复位为最大或最小状态的分界线,默认为最大最小状态的中间 |
||||
}, |
||||
methods: { |
||||
setBottom(value) { |
||||
if (this.auto) this.isTouchEnd = true |
||||
if (value <= 1) this.top = this.windowHeight * (1 - +value) |
||||
else this.top = (this.windowHeight - +value) |
||||
// #ifndef MP |
||||
this.top += this.windowTop |
||||
// #endif |
||||
}, |
||||
onTouchStart(e) { |
||||
if (this.disable) return |
||||
this.isTouchEnd = false // 关闭滑动结束Flag,作用为是否开启上拉框的过渡效果 |
||||
// #ifndef APP-NVUE |
||||
this.top = e.currentTarget.offsetTop // 手指触碰到上拉框时,将上拉框top设置为上拉框当前的top |
||||
// #endif |
||||
// #ifdef APP-NVUE |
||||
this.touchStartY = e.touches[0].screenY // 此次滑动开始时的Y轴坐标 |
||||
// #endif |
||||
// #ifndef APP-NVUE |
||||
this.touchStartY = e.touches[0].clientY // 此次滑动开始时的Y轴坐标 |
||||
// #endif |
||||
this.startTime = Date.now() // 设置滑动开始时间 |
||||
}, |
||||
onTouchmove(e) { |
||||
if (this.disable) return |
||||
// #ifdef APP-NVUE |
||||
let distance = e.touches[0].screenY - this.touchStartY // 滑动的距离 |
||||
// #endif |
||||
// #ifndef APP-NVUE |
||||
let distance = e.touches[0].clientY - this.touchStartY // 滑动的距离 |
||||
// #endif |
||||
if (this.limit) { // 是否开启高度限制 |
||||
let nowTop = this.top + distance // 此次滑动的上拉框top值 |
||||
if (nowTop < this.max || nowTop > this.min) { |
||||
// 如果滑动时上拉框top小于最大高度top就让上拉框top等于最大高度top |
||||
// 如果滑动时上拉框top大于最小高度top就让上拉框top等于最小高度top |
||||
this.top = nowTop < this.max ? this.max : this.min |
||||
this.distance = 0 // 滑动距离归零 |
||||
// #ifdef APP-NVUE |
||||
this.touchStartY = e.touches[0].screenY // 此次滑动开始时的Y轴坐标 |
||||
// #endif |
||||
// #ifndef APP-NVUE |
||||
this.touchStartY = e.touches[0].clientY // 此次滑动开始时的Y轴坐标 |
||||
// #endif |
||||
return |
||||
} |
||||
} |
||||
this.distance = distance // 更新滑动距离 |
||||
}, |
||||
onTouchend(e) { |
||||
if (this.disable) return |
||||
this.top = this.top + this.distance // 更新上拉框top |
||||
if (this.auto) { // 是否开启自动复位 |
||||
this.isTouchEnd = true // 开启滑动结束Flag |
||||
let time = (Date.now() - this.startTime) / 1000 // 滑动时间为 滑动结束时间 - 滑动开始时间 |
||||
let speed = Math.abs(this.distance) / time // 滑动速度为 滑动距离/滑动时间 |
||||
if (speed > 800) { // 如果速度大于800px/秒 |
||||
this.top = this.distance > 0 ? this.min : this.max // 根据滑动方向设置top的值 |
||||
// return this.distance = 0 // 滑动距离归零 |
||||
} else { |
||||
|
||||
if (this.top < this.boundary) this.top = this.max // 如果上拉框top小于分界线就让上拉框top等于最大高度top |
||||
else this.top = this.min // 如果上拉框top大于分界线就让上拉框top等于最小高度top |
||||
} |
||||
} |
||||
// 滑动结束时top信息 |
||||
this.$emit('get-end-detail', { |
||||
minTop: this.min, |
||||
maxTop: this.max, |
||||
curTop: this.top |
||||
}) |
||||
this.distance = 0 // 滑动距离归零 |
||||
} |
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
.you-touchbox { |
||||
position: fixed; |
||||
left: 0; |
||||
right: 0; |
||||
bottom: 0; |
||||
} |
||||
|
||||
.touchend { |
||||
transition-property: top; |
||||
transition-duration: .6s; |
||||
} |
||||
|
||||
.you-touchbox-content { |
||||
/* #ifdef APP-NVUE */ |
||||
flex: 1; |
||||
/* #endif */ |
||||
/* #ifndef APP-NVUE */ |
||||
height: 100%; |
||||
/* #endif */ |
||||
background-color: #fff; |
||||
} |
||||
|
||||
|
||||
.touch-line-box { |
||||
padding: 5px 0 10px; |
||||
/* #ifdef APP-NVUE */ |
||||
align-items: center; |
||||
/* #endif */ |
||||
} |
||||
|
||||
.touch-line { |
||||
/* #ifndef APP-NVUE */ |
||||
margin: 0 auto; |
||||
/* #endif */ |
||||
width: 45px; |
||||
height: 5px; |
||||
border-radius: 25px; |
||||
background: rgba(51, 51, 51, 0.2); |
||||
} |
||||
</style> |
Loading…
Reference in new issue