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