1
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,919 @@
|
||||
<!-- #ifdef MP-WEIXIN -->
|
||||
<!-- @vue-docgen-ignore-next-line -->
|
||||
<script module="xfs" lang="wxs" src="./xfs.wxs"></script>
|
||||
<!-- #endif -->
|
||||
<script lang="ts" setup>
|
||||
import { getCurrentInstance, ref, computed, watch, onMounted, onBeforeUnmount, nextTick } from "vue"
|
||||
import { checkIsCssUnit, rpx2px, getUid } from "../../core/util/xCoreUtil.uts"
|
||||
import { getDefaultColor, colorAddDeepen } from "../../core/util/xCoreColorUtil.uts"
|
||||
import { xConfig } from "../../config/xConfig.uts"
|
||||
|
||||
type POSITION_TYPE = "bottom" | "top" | "left" | "right"
|
||||
type POSITION_EVENT = {
|
||||
x : number,
|
||||
y : number,
|
||||
classList : Array<string>
|
||||
}
|
||||
|
||||
/**
|
||||
* @name 浮动面板 FloatDrawer
|
||||
* @description 提供流畅的拖拉阻尼效果,回弹丝滑。右滑关闭逻辑已经实现,但在app体验不好,主要是scoll与事件冲突需要官方优化.
|
||||
* @page /pages/index/float-drawer
|
||||
* @category 反馈组件
|
||||
* @constant 平台兼容
|
||||
* | H5 | andriod | IOS | 小程序 | UTS | UNIAPP-X SDK | version |
|
||||
| --- | --- | --- | --- | --- | --- | --- |
|
||||
| ☑ | ☑️ | ☑️ | ☑️ | ☑️ | 4.44+ | 1.1.9 |
|
||||
*/
|
||||
defineOptions({name:"xFloatDrawer"})
|
||||
|
||||
const proxy = getCurrentInstance()?.proxy??null;
|
||||
|
||||
defineSlots<{
|
||||
default(props: { show: boolean, height: number }): any
|
||||
}>()
|
||||
|
||||
const emits = defineEmits([
|
||||
/**
|
||||
* 关闭时执行
|
||||
*/
|
||||
'close',
|
||||
/**
|
||||
* 打开执行的事件
|
||||
*/
|
||||
'open',
|
||||
/**
|
||||
* 打开前执行
|
||||
*/
|
||||
'beforeOpen',
|
||||
/**
|
||||
* 关闭前执行
|
||||
*/
|
||||
'beforeClose',
|
||||
/**
|
||||
* 高度位置变化时触发这个差值.返回参数evt是个百分比,0%是最低下,100%代表是在最顶部.
|
||||
*/
|
||||
'heightChange',
|
||||
/**
|
||||
* 开始拖动
|
||||
*/
|
||||
'movestart',
|
||||
/**
|
||||
* 结束拖动
|
||||
*/
|
||||
'moveend',
|
||||
/**
|
||||
* 等同v-model:show
|
||||
*/
|
||||
'update:show'
|
||||
])
|
||||
|
||||
export type xFloatDrawerPropsType = {
|
||||
/**
|
||||
* 显示可v-model:show双向绑定
|
||||
* 默认是打开还是放置在底部。
|
||||
*/
|
||||
show: boolean,
|
||||
/**
|
||||
* 是否仅允许通过标题栏拖动。
|
||||
*/
|
||||
onlyHeader: boolean,
|
||||
/**
|
||||
* 动画时间
|
||||
*/
|
||||
duration: number,
|
||||
/**
|
||||
* 向上的圆角
|
||||
* 空值时,取全局配置的圆角。
|
||||
*/
|
||||
round: string,
|
||||
/**
|
||||
* 百分比,数字字符或者带单位,
|
||||
* 默认露出的内容高度
|
||||
*/
|
||||
size: string,
|
||||
/**
|
||||
* 弹层最大的高度值,默认为屏幕的可视高
|
||||
* 提供值时不能为百分比,可以是px,rpx单位数字。如果你不带单位,默认转换为rpx单位。
|
||||
*/
|
||||
maxHeight: string,
|
||||
/**
|
||||
* 当拖动时,触发打开和关闭时的临界值,单位是px
|
||||
* 如果没有达到此临界值时,将会回弹至原始位置。
|
||||
*/
|
||||
triggerDy: number,
|
||||
/**
|
||||
* 当拖动时,如果已经达到了关闭和打开时的临界值时
|
||||
* 可以继续拖拉时缓动阻尼值
|
||||
*/
|
||||
threshold: number,
|
||||
/**
|
||||
* 内容层的背景色
|
||||
*/
|
||||
bgColor: string,
|
||||
/**
|
||||
* 暗黑的背景色,空时,取全局的sheetDarkColor
|
||||
*/
|
||||
darkBgColor: string,
|
||||
/**
|
||||
* 拖动标题栏的横线背景色
|
||||
*/
|
||||
actionColor: string,
|
||||
/**
|
||||
* 禁用内部的容器并采用view容器
|
||||
*/
|
||||
disabledScroll: boolean,
|
||||
/**
|
||||
* 没有禁用disabledScroll生效
|
||||
* 容器内部使用的类型
|
||||
* scroll :scroll-view
|
||||
* list : list-view
|
||||
*/
|
||||
containerType: string,
|
||||
/**
|
||||
* 是否禁用用户滚动等来触发关闭或者打开。
|
||||
*/
|
||||
disabled: boolean,
|
||||
/**
|
||||
* 层级
|
||||
*/
|
||||
zIndex: number,
|
||||
/**
|
||||
* 控制内容的边跑,有时需要自定布局时非常有用.
|
||||
* 请直接使用style css规则写margin,
|
||||
*/
|
||||
contentMargin: string
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<xFloatDrawerPropsType>(), {
|
||||
show: false,
|
||||
onlyHeader: false,
|
||||
duration: 350,
|
||||
round: "",
|
||||
size: "15%",
|
||||
maxHeight: "80%",
|
||||
triggerDy: 180,
|
||||
threshold: 0.045,
|
||||
bgColor: "white",
|
||||
darkBgColor: "",
|
||||
actionColor: "#888888",
|
||||
disabledScroll: false,
|
||||
containerType: 'scroll',
|
||||
disabled: false,
|
||||
zIndex: 100,
|
||||
contentMargin: "0 16px 16px 16px"
|
||||
})
|
||||
|
||||
// 响应式数据
|
||||
const _width = ref(0)
|
||||
const _height = ref(0)
|
||||
const elementWrap = ref<UniElement | null>(null)
|
||||
//是否动画中
|
||||
const actioning = ref(false)
|
||||
const status = ref("")
|
||||
const wrapId = ref("xFloatDrawerWrap" + getUid())
|
||||
const _y = ref(0)
|
||||
const _realY = ref(0)
|
||||
const _realYDiff = ref(0)
|
||||
const isHover = ref(false)
|
||||
const disabledMove = ref(true)
|
||||
const netId = ref('xFloatDrawerScrollIds-' + getUid())
|
||||
const tid = ref(0)
|
||||
const startMoveWEB = ref(false)
|
||||
const first = ref(true)
|
||||
const _test_x = ref(0)
|
||||
const _test_y = ref(0)
|
||||
const _scrollDetail_y = ref(0)
|
||||
const moveDy = ref(0)
|
||||
const endtid = ref(12)
|
||||
const isClicking = ref(false)
|
||||
const _heade_x = ref(0)
|
||||
const _heade_y = ref(0)
|
||||
const _scrollDetail_y_start = ref(0)
|
||||
const disabledScolly = ref(false)
|
||||
const isMoving = ref(false)
|
||||
const touchmoevIsOver = ref(false)
|
||||
const tid2 = ref(11)
|
||||
const nowTouchType = ref('body')
|
||||
const moveDir = ref("none")
|
||||
const _reeal_x = ref(0)
|
||||
const _reeal_y = ref(0)
|
||||
const scrollTopDiff = ref(0)
|
||||
|
||||
// 计算属性
|
||||
const _contentMargin = computed((): string => props.contentMargin)
|
||||
const _show = computed((): boolean => props.show)
|
||||
const _disabled = computed((): boolean => props.disabled)
|
||||
const _onlyHeader = computed((): boolean => props.onlyHeader)
|
||||
const _duration = computed((): number => props.duration)
|
||||
|
||||
const _round = computed((): string => {
|
||||
let round = props.round;
|
||||
if (round == "") {
|
||||
round = xConfig.drawerRadius
|
||||
}
|
||||
let radius = checkIsCssUnit(round, 'rpx');
|
||||
let _r = `${radius} ${radius} 0px 0px`
|
||||
return _r
|
||||
})
|
||||
|
||||
const _size = computed((): number => {
|
||||
if (props.size == "") {
|
||||
return _height.value * 0.8
|
||||
}
|
||||
if (props.size.lastIndexOf('rpx') > -1) {
|
||||
let sz = rpx2px(parseFloat(props.size))
|
||||
return _height.value - sz
|
||||
}
|
||||
if (props.size.lastIndexOf('px') > -1) {
|
||||
let sz = parseFloat(props.size)
|
||||
return _height.value - sz
|
||||
}
|
||||
if (props.size.lastIndexOf('%') > -1) {
|
||||
let sz = parseFloat(props.size) / 100 * _height.value
|
||||
return _height.value - sz
|
||||
}
|
||||
let sz = uni.rpx2px(parseFloat(props.size))
|
||||
return _height.value - sz
|
||||
})
|
||||
|
||||
const _maxHeight = computed((): number => {
|
||||
if (props.size == "") {
|
||||
return _height.value * 0.2
|
||||
}
|
||||
if (props.maxHeight.lastIndexOf('rpx') > -1) {
|
||||
let sz = rpx2px(parseFloat(props.maxHeight))
|
||||
return _height.value - sz
|
||||
}
|
||||
if (props.maxHeight.lastIndexOf('px') > -1) {
|
||||
let sz = parseFloat(props.maxHeight)
|
||||
return _height.value - sz
|
||||
}
|
||||
if (props.maxHeight.lastIndexOf('%') > -1) {
|
||||
let sz = parseFloat(props.maxHeight) / 100 * _height.value
|
||||
return _height.value - sz
|
||||
}
|
||||
let sz = rpx2px(parseFloat(props.maxHeight))
|
||||
return _height.value - sz
|
||||
})
|
||||
|
||||
const _bgColor = computed((): string => {
|
||||
if (xConfig.dark == 'dark') {
|
||||
if (props.darkBgColor != '') return getDefaultColor(props.darkBgColor)
|
||||
return getDefaultColor(xConfig.sheetDarkColor)
|
||||
}
|
||||
return getDefaultColor(props.bgColor)
|
||||
})
|
||||
|
||||
const _actionColor = computed((): string => getDefaultColor(props.actionColor))
|
||||
const _animationFun = computed((): string => xConfig.animationFun)
|
||||
|
||||
// 方法
|
||||
function onEnd() {
|
||||
if (status.value == 'close') {
|
||||
/**
|
||||
* 关闭时执行
|
||||
*/
|
||||
emits('close')
|
||||
/**
|
||||
* 等同v-model:show
|
||||
*/
|
||||
emits('update:show', false)
|
||||
emits('heightChange', 0)
|
||||
} else {
|
||||
/**
|
||||
* 打开执行的事件
|
||||
*/
|
||||
emits('open')
|
||||
emits('update:show', true)
|
||||
emits('heightChange', 100)
|
||||
}
|
||||
actioning.value = false;
|
||||
_realYDiff.value = 0
|
||||
}
|
||||
|
||||
function setStyleAni() {
|
||||
try {
|
||||
let duration = _duration.value;
|
||||
if (first.value == true) {
|
||||
duration = 0
|
||||
}
|
||||
if (status.value == 'open') {
|
||||
clearTimeout(tid.value)
|
||||
tid.value = setTimeout(function () {
|
||||
elementWrap.value!.style.setProperty("transition-duration", duration.toString() + 'ms')
|
||||
elementWrap.value!.style.setProperty('transform', `translate(0%,${_maxHeight.value}px)`)
|
||||
}, 50);
|
||||
} else if (status.value == 'close') {
|
||||
clearTimeout(tid.value)
|
||||
tid.value = setTimeout(function () {
|
||||
elementWrap.value!.style.setProperty("transition-duration", duration.toString() + 'ms')
|
||||
elementWrap.value!.style.setProperty('transform', `translate(0%,${_size.value}px)`)
|
||||
}, 50);
|
||||
}
|
||||
} catch (e) {
|
||||
//TODO handle the exception
|
||||
}
|
||||
first.value = false;
|
||||
}
|
||||
|
||||
function closeAlert() {
|
||||
if (actioning.value || status.value == 'close') return
|
||||
|
||||
actioning.value = true;
|
||||
status.value = 'close'
|
||||
/**
|
||||
* 关闭前执行
|
||||
*/
|
||||
emits('beforeClose')
|
||||
emits('heightChange', 0)
|
||||
// #ifndef MP-WEIXIN
|
||||
setStyleAni();
|
||||
// #endif
|
||||
}
|
||||
|
||||
function showAlert() {
|
||||
if (actioning.value) return;
|
||||
if (status.value == 'open') return;
|
||||
actioning.value = true;
|
||||
status.value = 'open'
|
||||
/**
|
||||
* 打开前执行
|
||||
*/
|
||||
emits('beforeOpen')
|
||||
emits('heightChange', 100)
|
||||
// #ifndef MP-WEIXIN
|
||||
setStyleAni();
|
||||
// #endif
|
||||
}
|
||||
|
||||
function openDrawer() {
|
||||
showAlert();
|
||||
}
|
||||
|
||||
function headerClickClose() {
|
||||
if (_disabled.value) return;
|
||||
if (moveDy.value != 0) return;
|
||||
actioning.value = false;
|
||||
if (status.value == 'open') {
|
||||
closeAlert();
|
||||
} else {
|
||||
showAlert();
|
||||
}
|
||||
onEnd()
|
||||
}
|
||||
|
||||
// #ifdef MP-WEIXIN
|
||||
function setOpts(opts: any) {
|
||||
status.value = opts.status;
|
||||
}
|
||||
|
||||
function callEmits(args: any) {
|
||||
if(!args.name) return;
|
||||
if(args.args!=null&&args.args!=undefined){
|
||||
emits(args.name as any, args.args)
|
||||
}else{
|
||||
emits(args.name as any)
|
||||
}
|
||||
}
|
||||
|
||||
function setDisabledScolly(opts: any) {
|
||||
disabledScolly.value = opts.disabledScolly
|
||||
isMoving.value = opts.isMoving
|
||||
}
|
||||
// #endif
|
||||
|
||||
function scrollTopChange() {
|
||||
// 空实现
|
||||
}
|
||||
|
||||
function scollChange(evt: UniScrollEvent) {
|
||||
const stop = Math.max(0,Math.floor(evt.detail.scrollTop));
|
||||
scrollTopDiff.value = stop
|
||||
// #ifdef APP-ANDROID||WEB||APP-HARMONY
|
||||
if(!isMoving.value){
|
||||
_scrollDetail_y.value = stop
|
||||
}
|
||||
disabledScolly.value = _scrollDetail_y.value<=0;
|
||||
// #endif
|
||||
// #ifdef APP-IOS
|
||||
_scrollDetail_y.value = stop
|
||||
//当手指已经离开了屏幕,再置顶不需要再禁用滚动了。如果手指一直在划动则需要禁用。
|
||||
if(!touchmoevIsOver.value){
|
||||
disabledScolly.value = _scrollDetail_y.value<=0;
|
||||
}else{
|
||||
disabledScolly.value = false
|
||||
}
|
||||
// #endif
|
||||
}
|
||||
|
||||
function eventTransform_start(evt: POSITION_EVENT) {
|
||||
try {
|
||||
let ele = elementWrap.value!;
|
||||
if (status.value == 'open') {
|
||||
_y.value = evt.y - (_maxHeight.value)
|
||||
} else if (status.value == 'close') {
|
||||
_y.value = evt.y - (_size.value)
|
||||
}
|
||||
_realY.value = evt.y
|
||||
ele.style.setProperty("transition-duration", '0ms')
|
||||
} catch (e) {
|
||||
//TODO handle the exception
|
||||
}
|
||||
}
|
||||
|
||||
function eventTransform_move(evt: POSITION_EVENT) {
|
||||
try {
|
||||
if (!disabledMove.value) return;
|
||||
|
||||
let ele = elementWrap.value! as UniElement
|
||||
|
||||
if(moveDir.value == 'v'||status.value=='close'){
|
||||
let movey = evt.y - _y.value - (nowTouchType.value == 'header'?0:_scrollDetail_y_start.value )
|
||||
if (movey <= _maxHeight.value) {
|
||||
movey = _maxHeight.value - (_maxHeight.value - movey) * props.threshold
|
||||
} else if (movey >= _size.value) {
|
||||
movey = _size.value + (movey - _size.value) * props.threshold
|
||||
}
|
||||
ele.style.setProperty("transform", `translate(0%, ${movey.toString()}px)`)
|
||||
_realYDiff.value = evt.y - _realY.value
|
||||
let ratioValue = (movey - _size.value) / (_maxHeight.value - _size.value) * 100;
|
||||
emits('heightChange',ratioValue )
|
||||
}else if(moveDir.value == 'h'&&status.value=='open'){
|
||||
disabledScolly.value = true;
|
||||
let traslateX = evt.x - _test_x.value
|
||||
traslateX = Math.max(0,Math.min(traslateX,_width.value))
|
||||
|
||||
ele.style.setProperty("transform", `translate(${traslateX.toString()}px,${_maxHeight.value}px)`)
|
||||
let ratioValue = (1-traslateX / _width.value) * 100
|
||||
emits('heightChange',ratioValue )
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("floatDrawer出现意外错误:",e,"不用担心,这是兼容性错误,不会影响使用!!仅供参考.")
|
||||
}
|
||||
}
|
||||
|
||||
function eventTransform_end(evt: POSITION_EVENT) {
|
||||
const oldStatus = status.value
|
||||
|
||||
try {
|
||||
if (!disabledMove.value) return;
|
||||
isHover.value = false;
|
||||
let ele = elementWrap.value! as UniElement
|
||||
ele.style.setProperty("transition-duration", _duration.value.toString() + 'ms');
|
||||
if(moveDir.value == 'v'||status.value=='close'){
|
||||
if (_realYDiff.value >= props.triggerDy) {
|
||||
ele.style.setProperty("transform", `translate(0%, ${_size.value.toString()}px)`);
|
||||
status.value = 'close';
|
||||
emits('beforeClose');
|
||||
emits('heightChange', 0);
|
||||
} else if (_realYDiff.value < (props.triggerDy * -1)) {
|
||||
ele.style.setProperty("transform", `translate(0%, ${_maxHeight.value.toString()}px)`);
|
||||
status.value = 'open';
|
||||
emits('heightChange', 100);
|
||||
} else {
|
||||
if (status.value === 'open') {
|
||||
ele.style.setProperty("transform", `translate(0%, ${_maxHeight.value.toString()}px)`);
|
||||
emits('heightChange', 100);
|
||||
} else {
|
||||
ele.style.setProperty("transform", `translate(0%, ${_size.value.toString()}px)`);
|
||||
emits('heightChange', 0);
|
||||
}
|
||||
}
|
||||
}else if(moveDir.value == 'h'&&status.value=='open'){
|
||||
let traslateX = evt.x - _test_x.value
|
||||
traslateX = Math.max(0,Math.min(traslateX,_width.value))
|
||||
if(traslateX>=50){
|
||||
status.value = 'close';
|
||||
emits('heightChange',0 )
|
||||
ele.style.setProperty("transform", `translate(0px,${_size.value}px)`)
|
||||
}else{
|
||||
status.value = 'open';
|
||||
emits('heightChange',100 )
|
||||
ele.style.setProperty("transform", `translate(0px,${_maxHeight.value}px)`)
|
||||
disabledScolly.value = true;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
// 处理异常
|
||||
console.error(e)
|
||||
}
|
||||
|
||||
if(oldStatus != status.value){
|
||||
onEnd()
|
||||
}
|
||||
}
|
||||
|
||||
function mStart(evt: UniTouchEvent, type: string) {
|
||||
if (type == 'header'){
|
||||
isHover.value = true;
|
||||
scrollTopDiff.value = -1
|
||||
// 这里的意思,是让这个值引用界面的变化,这样可以避免可能的界面不渲染。
|
||||
nextTick((()=>{
|
||||
scrollTopDiff.value = 0
|
||||
}))
|
||||
}
|
||||
nextTick(()=>{
|
||||
emits('movestart');
|
||||
nowTouchType.value = type
|
||||
touchmoevIsOver.value = true;
|
||||
if (_disabled.value) return;
|
||||
|
||||
if (_onlyHeader.value && type == 'body') return;
|
||||
moveDy.value = 0;
|
||||
_test_x.value = evt.changedTouches[0].clientX;
|
||||
_reeal_x.value = evt.changedTouches[0].clientX
|
||||
_reeal_y.value = evt.changedTouches[0].clientY
|
||||
_scrollDetail_y_start.value = _scrollDetail_y.value; // 记录内部滚动的起始位置
|
||||
disabledScolly.value = false
|
||||
isMoving.value = false
|
||||
// 按头拖时,不要记录起始的位置,否则body与头会出现heady的位移。
|
||||
if (type == 'header'){
|
||||
disabledScolly.value = true
|
||||
}else{
|
||||
_test_y.value = evt.changedTouches[0].clientY;
|
||||
}
|
||||
eventTransform_start({
|
||||
x: evt.changedTouches[0].clientX,
|
||||
y: evt.changedTouches[0].clientY,
|
||||
classList: [] as string[],
|
||||
} as POSITION_EVENT);
|
||||
})
|
||||
}
|
||||
|
||||
function mMove(evt: UniTouchEvent, type: string) {
|
||||
if (_disabled.value) return;
|
||||
if (_onlyHeader.value && nowTouchType.value == 'body') return;
|
||||
|
||||
const currentY = evt.changedTouches[0].clientY;
|
||||
const currentX = evt.changedTouches[0].clientX;
|
||||
const dy = currentY - _test_y.value;
|
||||
const dx_real = currentX - _reeal_x.value
|
||||
const dy_real = currentY - _reeal_y.value
|
||||
|
||||
moveDir.value = 'v'
|
||||
|
||||
if (_scrollDetail_y.value>0&& nowTouchType.value == 'body'&&moveDir.value=='v') return;
|
||||
// #ifdef WEB
|
||||
evt.preventDefault();
|
||||
// #endif
|
||||
|
||||
if(nowTouchType.value == 'body'){
|
||||
if(dy<0){
|
||||
disabledScolly.value = false;
|
||||
isMoving.value = false;
|
||||
}else{
|
||||
_scrollDetail_y.value = 0
|
||||
}
|
||||
}
|
||||
|
||||
let scrollDetail_y_start = nowTouchType.value == 'header'?0:_scrollDetail_y_start.value
|
||||
if (scrollDetail_y_start > 0 && dy < 0) {
|
||||
// 如果内部可以向上滚动,并且拖动是向上的
|
||||
// 计算需要滚动的内部距离
|
||||
const internalScrollDelta = -dy;
|
||||
if (_scrollDetail_y.value - internalScrollDelta >= 0) {
|
||||
// 内部可以滚动,更新内部滚动位置
|
||||
_scrollDetail_y.value -= internalScrollDelta;
|
||||
} else {
|
||||
// 内部已经滚动到顶部,开始拖动整个弹层
|
||||
const excess = internalScrollDelta - scrollDetail_y_start;
|
||||
isMoving.value = true;
|
||||
eventTransform_move({
|
||||
x: evt.changedTouches[0].clientX,
|
||||
y: evt.changedTouches[0].clientY - excess,
|
||||
classList: [] as string[],
|
||||
} as POSITION_EVENT);
|
||||
}
|
||||
} else {
|
||||
isMoving.value = true;
|
||||
// 其他情况,允许拖动整个弹层
|
||||
eventTransform_move({
|
||||
x: evt.changedTouches[0].clientX,
|
||||
y: evt.changedTouches[0].clientY,
|
||||
classList: [] as string[],
|
||||
} as POSITION_EVENT);
|
||||
}
|
||||
}
|
||||
|
||||
function mEnd(evt: UniTouchEvent, type: string) {
|
||||
emits('moveend');
|
||||
isMoving.value = false;
|
||||
touchmoevIsOver.value = false;
|
||||
if (_disabled.value){
|
||||
return;
|
||||
}
|
||||
if (nowTouchType.value == 'header'||_scrollDetail_y.value<0){
|
||||
disabledScolly.value = false
|
||||
}
|
||||
|
||||
let dy = evt.changedTouches[0].clientY - _test_y.value;
|
||||
let dx = evt.changedTouches[0].clientX - _test_x.value;
|
||||
if (dy == dx) return;
|
||||
|
||||
moveDy.value = dy;
|
||||
eventTransform_end({
|
||||
x: evt.changedTouches[0].clientX,
|
||||
y: evt.changedTouches[0].clientY,
|
||||
classList: [] as string[],
|
||||
});
|
||||
|
||||
disabledScolly.value = false;
|
||||
moveDir.value = 'none'
|
||||
}
|
||||
|
||||
// #ifdef WEB
|
||||
function mmStart(evt: UniMouseEvent, type: string) {
|
||||
// @ts-ignore
|
||||
window.FloatDrawerId = wrapId.value
|
||||
emits('movestart')
|
||||
_heade_x.value = evt.clientX
|
||||
_heade_y.value = evt.clientY
|
||||
_test_y.value = evt.clientY;
|
||||
_test_x.value = evt.clientX;
|
||||
if (_disabled.value) return;
|
||||
if (type == 'header'){
|
||||
isHover.value = true;
|
||||
}
|
||||
if (_onlyHeader.value && type == 'body') return
|
||||
startMoveWEB.value = true;
|
||||
eventTransform_start({
|
||||
x: evt.clientX,
|
||||
y: evt.clientY,
|
||||
classList: [] as string[],
|
||||
} as POSITION_EVENT)
|
||||
}
|
||||
|
||||
function mmMove(evt: UniMouseEvent, type: string) {
|
||||
// @ts-ignore
|
||||
if(window.FloatDrawerId!=wrapId.value) return
|
||||
if (_onlyHeader.value && type == 'body') return
|
||||
if (!startMoveWEB.value) return;
|
||||
|
||||
const currentY = evt.clientY;
|
||||
const currentX = evt.clientX;
|
||||
const dy = currentY - _test_y.value;
|
||||
const dx = currentX - _test_x.value
|
||||
if(moveDir.value=='none'&&(Math.abs(dx) - Math.abs(dy))>0){
|
||||
moveDir.value = 'h'
|
||||
}else if(moveDir.value=='none'&&(Math.abs(dx) - Math.abs(dy))<=0){
|
||||
moveDir.value = 'v'
|
||||
}
|
||||
|
||||
eventTransform_move({
|
||||
x: evt.clientX,
|
||||
y: evt.clientY,
|
||||
classList: [] as string[],
|
||||
} as POSITION_EVENT)
|
||||
}
|
||||
|
||||
function mmEnd(evt: UniMouseEvent, type: string) {
|
||||
emits('moveend')
|
||||
let diffx = evt.clientX - _heade_x.value
|
||||
let diffy = evt.clientY - _heade_y.value
|
||||
// @ts-ignore
|
||||
window.FloatDrawerId = ''
|
||||
if (diffx == diffy) return;
|
||||
|
||||
if (_disabled.value) return;
|
||||
|
||||
startMoveWEB.value = false;
|
||||
eventTransform_end({
|
||||
x: evt.clientX,
|
||||
y: evt.clientY,
|
||||
classList: [] as string[],
|
||||
})
|
||||
moveDir.value = 'none'
|
||||
}
|
||||
// #endif
|
||||
|
||||
// 监听器
|
||||
watch((): boolean => props.show, (newval: boolean) => {
|
||||
if (newval && status.value == 'close') {
|
||||
actioning.value = false;
|
||||
showAlert()
|
||||
onEnd()
|
||||
} else if(!newval && status.value == 'open') {
|
||||
actioning.value = false;
|
||||
closeAlert()
|
||||
onEnd()
|
||||
}
|
||||
})
|
||||
|
||||
// 生命周期
|
||||
onMounted(() => {
|
||||
let yachi = 0
|
||||
// #ifdef APP
|
||||
yachi = 250
|
||||
// #endif
|
||||
|
||||
tid.value = setTimeout(function () {
|
||||
let sys = uni.getWindowInfo()
|
||||
// #ifndef APP
|
||||
_width.value = sys.windowWidth
|
||||
_height.value = sys.windowHeight;
|
||||
// #endif
|
||||
// #ifdef APP
|
||||
_width.value = sys.windowWidth
|
||||
_height.value = sys.windowHeight + 44;
|
||||
// #endif
|
||||
if (_show.value) {
|
||||
showAlert();
|
||||
actioning.value = false;
|
||||
status.value = 'open'
|
||||
} else {
|
||||
closeAlert()
|
||||
actioning.value = false;
|
||||
status.value = 'close'
|
||||
}
|
||||
}, yachi);
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
clearTimeout(tid.value)
|
||||
clearTimeout(tid2.value)
|
||||
})
|
||||
|
||||
defineExpose({
|
||||
/** 打开 **/
|
||||
open: () => showAlert(),
|
||||
/** 关闭 **/
|
||||
close: () => closeAlert()
|
||||
})
|
||||
</script>
|
||||
<template>
|
||||
<!-- @transitionend="onEnd" -->
|
||||
<view @click.stop=""
|
||||
ref="elementWrap"
|
||||
class="xFloatDrawerWrapContent" :id="wrapId" :style="{
|
||||
width:'100%',
|
||||
height:_height+'px',
|
||||
borderRadius:_round,
|
||||
backgroundColor:_bgColor,
|
||||
'transition-timing-function':_animationFun,
|
||||
zIndex:props.zIndex
|
||||
}"
|
||||
<!-- #ifdef MP-WEIXIN -->
|
||||
|
||||
@touchstart="xfs.mStart"
|
||||
@touchend="xfs.mEnd"
|
||||
@touchmove="xfs.mMove"
|
||||
:change:prop="xfs.propObserver"
|
||||
:prop="status"
|
||||
:data-opts="{
|
||||
maxHeight:_maxHeight,
|
||||
size:_size,height:_height,
|
||||
status:status,
|
||||
threshold:props.threshold,
|
||||
duration:_duration,
|
||||
triggerDy:props.triggerDy,
|
||||
_scrollDetail_y:_scrollDetail_y
|
||||
}"
|
||||
|
||||
<!-- #endif -->
|
||||
|
||||
>
|
||||
|
||||
|
||||
<view
|
||||
<!-- #ifdef APP||H5 -->
|
||||
@touchstart="mStart($event as TouchEvent,'header')"
|
||||
@touchend="mEnd($event as TouchEvent,'header')"
|
||||
@touchmove="mMove($event as TouchEvent,'header')"
|
||||
<!-- #endif -->
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- #ifdef WEB -->
|
||||
@mousedown="mmStart($event as MouseEvent,'header')"
|
||||
@mousemove="mmMove($event as MouseEvent,'header')"
|
||||
@mouseup="mmEnd($event as MouseEvent,'header')"
|
||||
@mouseleave="mmEnd"
|
||||
<!-- #endif -->
|
||||
class="xFloatDrawerBar"
|
||||
>
|
||||
<view @click="headerClickClose" style="height:100%" class="xFloatDrawerBarSop">
|
||||
<view class="xFloatDrawerBarLine" :style="{'background-color':_actionColor,opacity: isHover?1:0.5}">
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="xFLoatViewWrap"
|
||||
style="flex:1"
|
||||
<!-- #ifdef APP||H5 -->
|
||||
@touchstart.stop="mStart($event as TouchEvent,'body')"
|
||||
@touchend.stop="mEnd($event as TouchEvent,'body')"
|
||||
@touchmove.stop="mMove($event as TouchEvent,'body')"
|
||||
<!-- #endif -->
|
||||
|
||||
|
||||
|
||||
<!-- #ifdef WEB -->
|
||||
@mousedown="mmStart($event as MouseEvent,'body')"
|
||||
@mousemove="mmMove($event as MouseEvent,'body')"
|
||||
@mouseup="mmEnd($event as MouseEvent,'body')"
|
||||
@mouseleave="mmEnd"
|
||||
@mousewheel="disabledScolly = false"
|
||||
<!-- #endif -->
|
||||
>
|
||||
|
||||
<scroll-view
|
||||
:scroll-top="scrollTopDiff"
|
||||
v-if="!props.disabledScroll&&props.containerType=='scroll'"
|
||||
:direction="status=='close'||disabledScolly?'none':'vertical'"
|
||||
:scroll-y="status=='close'||disabledScolly?false:true"
|
||||
@scroll="scollChange"
|
||||
@scrolltoupper="scrollTopChange" :style="{flex:'1',margin:_contentMargin,height:'100px'}"
|
||||
:bounces="false">
|
||||
|
||||
<!--
|
||||
@slot 默认插槽
|
||||
@prop {Boolean} show - 当前是否已显示
|
||||
@prop {Number} height - 容器的高度
|
||||
-->
|
||||
<slot name="default" :show="_show" :height="_maxHeight"></slot>
|
||||
<view :style="{height:_maxHeight+'px'}"></view>
|
||||
</scroll-view>
|
||||
|
||||
<list-view v-else-if="!props.disabledScroll&&props.containerType=='list'"
|
||||
:scroll-top="scrollTopDiff"
|
||||
:scroll-y="status=='close'||disabledScolly?'none':'vertical'"
|
||||
:direction="status=='close'||disabledScolly?'none':'vertical'" @scroll="scollChange"
|
||||
@scrolltoupper="scrollTopChange" :style="{flex:'1',margin:_contentMargin}" :bounces="false">
|
||||
|
||||
<!--
|
||||
@slot 默认插槽
|
||||
@prop {Boolean} show - 当前是否已显示
|
||||
@prop {Number} height - 容器的高度
|
||||
-->
|
||||
<slot name="default" :show="_show" :height="_maxHeight"></slot>
|
||||
<list-item>
|
||||
<view :style="{height:_maxHeight+'px'}"></view>
|
||||
</list-item>
|
||||
</list-view>
|
||||
|
||||
|
||||
<view v-else :style="{flex:'1',margin:_contentMargin}">
|
||||
<!--
|
||||
@slot 默认插槽
|
||||
@prop {Boolean} show - 当前是否已显示
|
||||
@prop {Number} height - 容器的高度
|
||||
-->
|
||||
<slot name="default" :show="_show" :height="_maxHeight"></slot>
|
||||
</view>
|
||||
|
||||
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<style>
|
||||
.xFloatDrawerBarSop {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.xFloatDrawerBar {
|
||||
height: 44px;
|
||||
|
||||
/* #ifdef WEB */
|
||||
cursor: grab;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
/* #ifdef WEB */
|
||||
.xFloatDrawerBar:active {
|
||||
cursor: grabbing;
|
||||
}
|
||||
|
||||
/* #endif */
|
||||
|
||||
|
||||
.xFloatDrawerBarLine {
|
||||
width: 60px;
|
||||
height: 4px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.xFloatDrawerWrapContent {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
/* #ifndef APP-HARMONY */
|
||||
transition-duration: 250ms;
|
||||
/* #endif */
|
||||
/* #ifdef APP-HARMONY */
|
||||
transition-duration: 0ms;
|
||||
/* #endif */
|
||||
/* transition-timing-function: cubic-bezier(.18,.89,.32,1); */
|
||||
transition-property: transform;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
transform: translate(0%, 100%);
|
||||
position: fixed;
|
||||
/* z-index: 100; */
|
||||
left: 0px;
|
||||
bottom: 0px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,837 @@
|
||||
<!-- #ifdef MP-WEIXIN -->
|
||||
<!-- @vue-docgen-ignore-next-line -->
|
||||
<script module="xfs" lang="wxs" src="./xfs.wxs"></script>
|
||||
<!-- #endif -->
|
||||
<script lang="ts">
|
||||
import { checkIsCssUnit, rpx2px, getUid } from "../../core/util/xCoreUtil.uts"
|
||||
import { getDefaultColor, colorAddDeepen } from "../../core/util/xCoreColorUtil.uts"
|
||||
import { xConfig } from "../../config/xConfig.uts"
|
||||
type POSITION_TYPE = "bottom" | "top" | "left" | "right"
|
||||
type POSITION_EVENT = {
|
||||
x : number,
|
||||
y : number,
|
||||
classList : Array<string>
|
||||
}
|
||||
|
||||
/**
|
||||
* @name 浮动面板 FloatDrawer
|
||||
* @description 提供流畅的拖拉阻尼效果,回弹丝滑。右滑关闭逻辑已经实现,但在app体验不好,主要是scoll与事件冲突需要官方优化.
|
||||
* @page /pages/index/float-drawer
|
||||
* @category 反馈组件
|
||||
* @constant 平台兼容
|
||||
* | Harmony | H5 | andriod | IOS | 小程序 | UTS | UNIAPP-X SDK | version |
|
||||
| --- | --- | --- | --- | --- | --- | --- | --- |
|
||||
| ☑ | ☑ | ☑️ | ☑️ | ☑️ | ☑️ | 4.76+ | 1.1.18 |
|
||||
*/
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
_width: 0,
|
||||
_height: 0,
|
||||
status:'close' as 'close'|'open',
|
||||
disabledScrolling:false,
|
||||
actioning:false,
|
||||
diffY:0,
|
||||
first:true,
|
||||
tid:5,
|
||||
_lastTouchY:0,
|
||||
_isTouching:false,
|
||||
_scrollTop:0,
|
||||
_lastScrollTop:0,
|
||||
_topEpsilon:2,
|
||||
_translateY:0,
|
||||
_currentTranslateY:0
|
||||
}
|
||||
},
|
||||
emits: [
|
||||
/**
|
||||
* 关闭时执行
|
||||
*/
|
||||
'close',
|
||||
/**
|
||||
* 打开执行的事件
|
||||
*/
|
||||
'open',
|
||||
/**
|
||||
* 打开前执行
|
||||
*/
|
||||
'beforeOpen',
|
||||
/**
|
||||
* 关闭前执行
|
||||
*/
|
||||
'beforeClose',
|
||||
/**
|
||||
* 高度位置变化时触发这个差值.返回参数evt是个百分比,0%是最低下,100%代表是在最顶部.
|
||||
*/
|
||||
'heightChange',
|
||||
/**
|
||||
* 开始拖动
|
||||
*/
|
||||
'movestart',
|
||||
/**
|
||||
* 结束拖动
|
||||
*/
|
||||
'moveend',
|
||||
/**
|
||||
* 等同v-model:show
|
||||
*/
|
||||
'update:show'],
|
||||
props: {
|
||||
|
||||
/**
|
||||
* 显示可v-model:show双向绑定
|
||||
* 默认是打开还是放置在底部。
|
||||
*/
|
||||
show: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
/**
|
||||
* 是否仅允许通过标题栏拖动。
|
||||
*/
|
||||
onlyHeader: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
|
||||
/**
|
||||
* 动画时间
|
||||
*/
|
||||
duration: {
|
||||
type: Number,
|
||||
default: 350
|
||||
},
|
||||
/**
|
||||
* 向上的圆角
|
||||
* 空值时,取全局配置的圆角。
|
||||
*/
|
||||
round: {
|
||||
type: String,
|
||||
default: ""
|
||||
},
|
||||
/**
|
||||
* 百分比,数字字符或者带单位,
|
||||
* 默认露出的内容高度
|
||||
*/
|
||||
size: {
|
||||
type: String,
|
||||
default: "15%"
|
||||
},
|
||||
/**
|
||||
* 弹层最大的高度值,默认为屏幕的可视高
|
||||
* 提供值时不能为百分比,可以是px,rpx单位数字。如果你不带单位,默认转换为rpx单位。
|
||||
*/
|
||||
maxHeight: {
|
||||
type: String,
|
||||
default: "80%"
|
||||
},
|
||||
/**
|
||||
* 当拖动时,触发打开和关闭时的临界值,单位是px
|
||||
* 如果没有达到此临界值时,将会回弹至原始位置。
|
||||
*/
|
||||
triggerDy: {
|
||||
type: Number,
|
||||
default: 100
|
||||
},
|
||||
/**
|
||||
* 当拖动时,如果已经达到了关闭和打开时的临界值时
|
||||
* 可以继续拖拉时缓动阻尼值
|
||||
*/
|
||||
threshold: {
|
||||
type: Number,
|
||||
default: 0.045
|
||||
},
|
||||
/**
|
||||
* 内容层的背景色
|
||||
*/
|
||||
bgColor: {
|
||||
type: String,
|
||||
default: "white"
|
||||
},
|
||||
/**
|
||||
* 暗黑的背景色,空时,取全局的sheetDarkColor
|
||||
*/
|
||||
darkBgColor: {
|
||||
type: String,
|
||||
default: ""
|
||||
},
|
||||
/**
|
||||
* 拖动标题栏的横线背景色
|
||||
*/
|
||||
actionColor: {
|
||||
type: String,
|
||||
default: "#888888"
|
||||
},
|
||||
/**
|
||||
* 禁用内部的容器并采用view容器
|
||||
*/
|
||||
disabledScroll: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
/**
|
||||
* 没有禁用disabledScroll生效
|
||||
* 容器内部使用的类型
|
||||
* scroll :scroll-view
|
||||
* list : list-view
|
||||
*/
|
||||
containerType: {
|
||||
type: String,
|
||||
default: 'scroll'
|
||||
},
|
||||
/**
|
||||
* 是否禁用用户滚动等来触发关闭或者打开。
|
||||
*/
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
/**
|
||||
* 层级
|
||||
*/
|
||||
zIndex: {
|
||||
type: Number,
|
||||
default: 100
|
||||
},
|
||||
/**
|
||||
* 控制内容的边跑,有时需要自定布局时非常有用.
|
||||
* 请直接使用style css规则写margin,
|
||||
*/
|
||||
contentMargin: {
|
||||
type: String,
|
||||
default: "0 16px 16px 16px"
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
show(_newval : boolean) {
|
||||
if (_newval&&this.status == 'close') {
|
||||
this.actioning = false;
|
||||
this.open()
|
||||
this.onEnd()
|
||||
} else if(!_newval&&this.status == 'open') {
|
||||
this.actioning = false;
|
||||
this.close()
|
||||
this.onEnd()
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
},
|
||||
computed: {
|
||||
_contentMargin() : string {
|
||||
return this.contentMargin
|
||||
},
|
||||
_show() : boolean {
|
||||
return this.show
|
||||
},
|
||||
_disabled() : boolean {
|
||||
return this.disabled
|
||||
},
|
||||
|
||||
_onlyHeader() : boolean {
|
||||
return this.onlyHeader
|
||||
},
|
||||
_duration() : number {
|
||||
return this.duration
|
||||
},
|
||||
|
||||
_round() : string {
|
||||
let round = this.round;
|
||||
if (round == "") {
|
||||
round = xConfig.drawerRadius
|
||||
}
|
||||
let radius = checkIsCssUnit(round, 'rpx');
|
||||
|
||||
let _r = `${radius} ${radius} 0px 0px`
|
||||
return _r
|
||||
},
|
||||
_size() : number {
|
||||
|
||||
if (this.size == "") {
|
||||
return this._height * 0.8
|
||||
}
|
||||
if (this.size.lastIndexOf('rpx') > -1) {
|
||||
let sz = rpx2px(parseFloat(this.size))
|
||||
return this._height - sz
|
||||
}
|
||||
if (this.size.lastIndexOf('px') > -1) {
|
||||
let sz = parseFloat(this.size)
|
||||
|
||||
return this._height - sz
|
||||
}
|
||||
if (this.size.lastIndexOf('%') > -1) {
|
||||
let sz = parseFloat(this.size) / 100 * this._height
|
||||
|
||||
return this._height - sz
|
||||
}
|
||||
|
||||
let sz = uni.rpx2px(parseFloat(this.size))
|
||||
|
||||
return this._height - sz
|
||||
},
|
||||
|
||||
_maxHeight() : number {
|
||||
if (this.size == "") {
|
||||
return this._height * 0.2
|
||||
}
|
||||
if (this.maxHeight.lastIndexOf('rpx') > -1) {
|
||||
let sz = rpx2px(parseFloat(this.maxHeight))
|
||||
return this._height - sz
|
||||
}
|
||||
if (this.maxHeight.lastIndexOf('px') > -1) {
|
||||
let sz = parseFloat(this.maxHeight)
|
||||
return this._height - sz
|
||||
}
|
||||
if (this.maxHeight.lastIndexOf('%') > -1) {
|
||||
let sz = parseFloat(this.maxHeight) / 100 * this._height
|
||||
|
||||
return this._height - sz
|
||||
}
|
||||
|
||||
let sz = rpx2px(parseFloat(this.maxHeight))
|
||||
return this._height - sz
|
||||
},
|
||||
_bgColor() : string {
|
||||
if (xConfig.dark == 'dark') {
|
||||
if (this.darkBgColor != '') return getDefaultColor(this.darkBgColor)
|
||||
return getDefaultColor(xConfig.sheetDarkColor)
|
||||
}
|
||||
return getDefaultColor(this.bgColor)
|
||||
},
|
||||
_actionColor() : string {
|
||||
return getDefaultColor(this.actionColor)
|
||||
},
|
||||
_animationFun() : string {
|
||||
return xConfig.animationFun
|
||||
}
|
||||
|
||||
|
||||
},
|
||||
|
||||
mounted() {
|
||||
let t = this;
|
||||
let yachi = 0
|
||||
// #ifdef APP
|
||||
yachi = 250
|
||||
// #endif
|
||||
|
||||
|
||||
this.tid = setTimeout(function () {
|
||||
let sys = uni.getWindowInfo()
|
||||
t._width = sys.windowWidth
|
||||
t._height = sys.windowHeight;
|
||||
if (t._show) {
|
||||
t.status = 'close'
|
||||
t.open();
|
||||
} else {
|
||||
t.status = 'open'
|
||||
t.close()
|
||||
}
|
||||
}, yachi);
|
||||
},
|
||||
beforeUnmount() {
|
||||
|
||||
},
|
||||
methods: {
|
||||
|
||||
// #ifdef MP-WEIXIN
|
||||
setOpts(opts){
|
||||
this.status = opts.status;
|
||||
},
|
||||
callEmits(args){
|
||||
if(!args.name) return;
|
||||
if(args.name!='open'&&args.name!='close'){
|
||||
if(args.args!=null&&args.args!=undefined){
|
||||
this.$emit(args.name,args.args)
|
||||
}else{
|
||||
this.$emit(args.name)
|
||||
}
|
||||
}else{
|
||||
if(args.name == 'open'){
|
||||
this.status = 'open';
|
||||
}
|
||||
if(args.name == 'close'){
|
||||
this.status = 'close';
|
||||
}
|
||||
this.onEnd()
|
||||
}
|
||||
},
|
||||
setDisabledScolly(opts){
|
||||
this.disabledScrolling = opts.disabledScolly
|
||||
this._isTouching = opts.isMoving
|
||||
},
|
||||
// #endif
|
||||
|
||||
getCurrentHeightPercentByTranslate(translateY:number) : number {
|
||||
const minY = this._maxHeight
|
||||
const maxY = this._size
|
||||
const total = maxY - minY
|
||||
if (total <= 0) return 0
|
||||
let clamped = translateY
|
||||
if (clamped < minY) clamped = minY
|
||||
if (clamped > maxY) clamped = maxY
|
||||
const percent = (maxY - clamped) / total * 100
|
||||
return percent
|
||||
},
|
||||
setStyleAni() {
|
||||
let t = this;
|
||||
|
||||
try {
|
||||
const xFLoatDrawerRef = this.$refs['xFLoatDrawerRef'] as UniElement|null;
|
||||
if(xFLoatDrawerRef == null) return;
|
||||
let duration = t._duration;
|
||||
if (t.first == true) {
|
||||
duration = 0
|
||||
}
|
||||
if (this.status == 'open') {
|
||||
clearTimeout(this.tid)
|
||||
this.tid = setTimeout(function () {
|
||||
xFLoatDrawerRef.style.setProperty("transition-duration", duration.toString() + 'ms')
|
||||
xFLoatDrawerRef.style.setProperty('transform', `translate(0%,${t._maxHeight}px)`)
|
||||
}, 50);
|
||||
} else if (this.status == 'close') {
|
||||
clearTimeout(this.tid)
|
||||
this.tid = setTimeout(function () {
|
||||
xFLoatDrawerRef.style.setProperty("transition-duration", duration.toString() + 'ms')
|
||||
xFLoatDrawerRef.style.setProperty('transform', `translate(0%,${t._size}px)`)
|
||||
|
||||
}, 50);
|
||||
|
||||
}
|
||||
} catch (e) {
|
||||
//TODO handle the exception
|
||||
}
|
||||
t.first = false;
|
||||
},
|
||||
onEnd(){
|
||||
let _this = this;
|
||||
clearTimeout(this._duration)
|
||||
_this.tid = setTimeout(function() {
|
||||
if (_this.status == 'close') {
|
||||
/**
|
||||
* 关闭时执行
|
||||
*/
|
||||
_this.$emit('close')
|
||||
/**
|
||||
* 等同v-model:show
|
||||
*/
|
||||
_this.$emit('update:show', false)
|
||||
_this.$emit('heightChange', 0)
|
||||
|
||||
} else {
|
||||
/**
|
||||
* 打开执行的事件
|
||||
*/
|
||||
_this.$emit('open')
|
||||
_this.$emit('update:show', true)
|
||||
_this.$emit('heightChange', 100)
|
||||
}
|
||||
|
||||
_this.actioning = false;
|
||||
_this.diffY = 0
|
||||
}, _this._duration);
|
||||
},
|
||||
open(){
|
||||
if (this.actioning) return;
|
||||
|
||||
if (this.status == 'open') return;
|
||||
this.actioning = true;
|
||||
this.status = 'open'
|
||||
/**
|
||||
* 打开前执行
|
||||
*/
|
||||
this.$emit('beforeOpen')
|
||||
this.$emit('heightChange', 100)
|
||||
this.setStyleAni();
|
||||
},
|
||||
close(){
|
||||
if (this.actioning || this.status == 'close') return
|
||||
this.actioning = true;
|
||||
this.status = 'close'
|
||||
|
||||
/**
|
||||
* 关闭前执行
|
||||
*/
|
||||
this.$emit('beforeClose')
|
||||
this.$emit('heightChange', 0)
|
||||
this.setStyleAni();
|
||||
},
|
||||
scrollTouchStart(){
|
||||
if (this.status == 'open') {
|
||||
this.disabledScrolling = false
|
||||
}
|
||||
},
|
||||
headerClickClose(){
|
||||
if(this._isTouching) return;
|
||||
if(this.status == 'open'){
|
||||
this.actioning = false;
|
||||
this.close()
|
||||
}else if(this.status == 'close'){
|
||||
this.actioning = false;
|
||||
this.open()
|
||||
}
|
||||
},
|
||||
diffStart(eventx:number,eventy:number){
|
||||
this._isTouching = true
|
||||
this._lastTouchY = eventy
|
||||
this.diffY = 0
|
||||
let ele = this.$refs['xFLoatDrawerRef'] as UniElement
|
||||
if (this.status == 'open') {
|
||||
this._translateY = eventy - (this._maxHeight)
|
||||
this._currentTranslateY = this._maxHeight
|
||||
} else if (this.status == 'close') {
|
||||
this._translateY = eventy - (this._size)
|
||||
this._currentTranslateY = this._size
|
||||
}
|
||||
|
||||
ele.style.setProperty("transition-duration", '0ms')
|
||||
this.$emit('heightChange', this.getCurrentHeightPercentByTranslate(this._currentTranslateY))
|
||||
},
|
||||
diffMove(eventx:number,eventy:number){
|
||||
if(!this._isTouching) return
|
||||
const dy = eventy - this._lastTouchY
|
||||
this.diffY = dy
|
||||
// 手指向上滑动(内容希望上滚)
|
||||
if (dy < 0) {
|
||||
|
||||
// 允许滚动
|
||||
if (this.status == 'open') this.disabledScrolling = false
|
||||
} else if (dy > 0) {
|
||||
// 手指向下滑(内容希望下滚)。若已在顶部(含回弹阈值),禁用滚动交由外层处理
|
||||
const atTop = this._scrollTop <= this._topEpsilon
|
||||
if (atTop) {
|
||||
if (!this.disabledScrolling) {
|
||||
this.disabledScrolling = true
|
||||
// 切换为外层拖拽时,重置拖拽基线,避免位置跳变
|
||||
const base = this.status == 'open' ? this._maxHeight : this._size
|
||||
this._translateY = eventy - base
|
||||
this._lastTouchY = eventy
|
||||
this._currentTranslateY = base
|
||||
const ele = this.$refs['xFLoatDrawerRef'] as UniElement
|
||||
ele.style.setProperty("transition-duration", '0ms')
|
||||
}
|
||||
} else {
|
||||
if (this.disabledScrolling) this.disabledScrolling = false
|
||||
}
|
||||
}
|
||||
// 拖拽位移与阻尼:
|
||||
const ele = this.$refs['xFLoatDrawerRef'] as UniElement
|
||||
const base = this.status == 'open' ? this._maxHeight : this._size
|
||||
const rawTranslate = eventy - this._translateY
|
||||
let newTranslate = base
|
||||
const minY = this._maxHeight
|
||||
const maxY = this._size
|
||||
if (this.status == 'open') {
|
||||
const atTop = this._scrollTop <= this._topEpsilon
|
||||
if (atTop) {
|
||||
if (dy > 0) {
|
||||
// 向下:在 [minY, maxY] 线性;超过 maxY 才强阻尼
|
||||
if (rawTranslate <= maxY) {
|
||||
newTranslate = Math.max(minY, Math.min(rawTranslate, maxY))
|
||||
} else {
|
||||
const over = rawTranslate - maxY
|
||||
const damp = over * this.threshold
|
||||
newTranslate = maxY + Math.min(this.triggerDy, damp)
|
||||
}
|
||||
} else if (dy < 0) {
|
||||
// 向上:仅越过顶部时强阻尼
|
||||
if (rawTranslate >= minY) {
|
||||
newTranslate = minY
|
||||
} else {
|
||||
const overUp = minY - rawTranslate
|
||||
const dampUp = overUp * this.threshold
|
||||
newTranslate = minY - Math.min(this.triggerDy, dampUp)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (dy < 0) {
|
||||
// 向上:在 [minY, maxY] 线性;超过 minY 才强阻尼
|
||||
if (rawTranslate >= minY) {
|
||||
newTranslate = Math.max(minY, Math.min(rawTranslate, maxY))
|
||||
} else {
|
||||
const overUp = minY - rawTranslate
|
||||
const dampUp = overUp * this.threshold
|
||||
newTranslate = minY - Math.min(this.triggerDy, dampUp)
|
||||
}
|
||||
} else if (dy > 0) {
|
||||
// 向下:仅越过底部时强阻尼
|
||||
if (rawTranslate <= maxY) {
|
||||
newTranslate = maxY
|
||||
} else {
|
||||
const overDown = rawTranslate - maxY
|
||||
const dampDown = overDown * this.threshold
|
||||
newTranslate = maxY + Math.min(this.triggerDy, dampDown)
|
||||
}
|
||||
}
|
||||
}
|
||||
this._currentTranslateY = newTranslate
|
||||
|
||||
ele.style.setProperty('transform', `translate(0%,${newTranslate}px)`)
|
||||
this.$emit('heightChange', this.getCurrentHeightPercentByTranslate(newTranslate))
|
||||
},
|
||||
diffEnd(eventx:number,eventy:number){
|
||||
this._isTouching = false
|
||||
const ele = this.$refs['xFLoatDrawerRef'] as UniElement
|
||||
const base = this.status == 'open' ? this._maxHeight : this._size
|
||||
const moved = this._currentTranslateY - base
|
||||
|
||||
const absMoved = Math.abs(moved)
|
||||
|
||||
if (absMoved >= this.triggerDy) {
|
||||
if (this.status == 'open' && moved > 0) {
|
||||
this.status = 'close'
|
||||
this.onEnd()
|
||||
}
|
||||
if (this.status == 'close' && moved < 0) {
|
||||
this.status = 'open'
|
||||
this.onEnd()
|
||||
}
|
||||
}
|
||||
// 复位
|
||||
const fuweiBase = this.status == 'open' ? this._maxHeight : this._size
|
||||
ele.style.setProperty("transition-duration", this._duration.toString() + 'ms')
|
||||
ele.style.setProperty('transform', `translate(0%,${fuweiBase}px)`)
|
||||
if (this.status == 'open') {
|
||||
this.$emit('heightChange', 100)
|
||||
} else if (this.status == 'close') {
|
||||
this.$emit('heightChange', 0)
|
||||
}
|
||||
|
||||
this.diffY = 0
|
||||
},
|
||||
scrolltoTop(){
|
||||
this.disabledScrolling = true;
|
||||
// #ifdef APP
|
||||
let el = this.$refs['xFloatScrollRef']! as UniElement;
|
||||
// el.scrollTop = 0
|
||||
// this._scrollTop = 0
|
||||
// this._lastTouchY = 0
|
||||
// #endif
|
||||
console.log('top....')
|
||||
},
|
||||
onscroll(evt:UniScrollEvent){
|
||||
const scrollTop = evt.detail.scrollTop
|
||||
this._lastScrollTop = this._scrollTop
|
||||
this._scrollTop = scrollTop
|
||||
// 在滚动过程中,如果向上滚动,则始终允许滚动
|
||||
if (this._isTouching) {
|
||||
const delta = this._scrollTop - this._lastScrollTop
|
||||
if (delta > 0) {
|
||||
// 内容向上滚动
|
||||
if (this.disabledScrolling) this.disabledScrolling = false
|
||||
} else if (delta < 0) {
|
||||
// 内容向下滚动
|
||||
const atTop = this._scrollTop <= this._topEpsilon
|
||||
if (atTop) {
|
||||
if (!this.disabledScrolling) this.disabledScrolling = true
|
||||
} else {
|
||||
if (this.disabledScrolling) this.disabledScrolling = false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
mStart(evt:UniTouchEvent){
|
||||
const x = evt.changedTouches[0].clientX
|
||||
const y = evt.changedTouches[0].clientY
|
||||
this.diffStart(x,y)
|
||||
},
|
||||
mMove(evt:UniTouchEvent){
|
||||
const x = evt.changedTouches[0].clientX
|
||||
const y = evt.changedTouches[0].clientY
|
||||
this.diffMove(x,y)
|
||||
},
|
||||
mEnd(evt:UniTouchEvent){
|
||||
const x = evt.changedTouches[0].clientX
|
||||
const y = evt.changedTouches[0].clientY
|
||||
this.diffEnd(x,y)
|
||||
},
|
||||
// #ifdef WEB
|
||||
mmStart(evt:UniMouseEvent){
|
||||
const x = evt.clientX
|
||||
const y = evt.clientY
|
||||
this.diffStart(x,y)
|
||||
},
|
||||
mmMove(evt:UniMouseEvent){
|
||||
const x = evt.clientX
|
||||
const y = evt.clientY
|
||||
this.diffMove(x,y)
|
||||
},
|
||||
mmEnd(evt:UniMouseEvent){
|
||||
const x = evt.clientX
|
||||
const y = evt.clientY
|
||||
this.diffEnd(x,y)
|
||||
},
|
||||
// #endif
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<!-- @transitionend="onEnd" -->
|
||||
<view
|
||||
ref="xFLoatDrawerRef"
|
||||
class="xFloatDrawerWrapContent"
|
||||
:style="{
|
||||
width:'100%',
|
||||
height:_height+'px',
|
||||
borderRadius:_round,
|
||||
backgroundColor:_bgColor,
|
||||
'transition-timing-function':_animationFun,
|
||||
zIndex:zIndex
|
||||
}"
|
||||
<!-- #ifdef MP-WEIXIN -->
|
||||
|
||||
@touchstart="xfs.mStart"
|
||||
@touchend="xfs.mEnd"
|
||||
@touchcancel="xfs.mEnd"
|
||||
@touchmove="xfs.mMove"
|
||||
:change:prop="xfs.propObserver"
|
||||
:prop="status"
|
||||
:data-opts="{
|
||||
maxHeight:_maxHeight,size:_size,height:_height,
|
||||
status:status,
|
||||
threshold:threshold,
|
||||
duration:_duration,
|
||||
triggerDy:triggerDy,
|
||||
_scrollDetail_y:_lastScrollTop
|
||||
}"
|
||||
|
||||
<!-- #endif -->
|
||||
|
||||
<!-- #ifdef APP||H5 -->
|
||||
@touchstart="mStart"
|
||||
@touchmove="mMove"
|
||||
@touchend="mEnd"
|
||||
<!-- #endif -->
|
||||
|
||||
<!-- #ifdef WEB -->
|
||||
@mousedown="mmStart"
|
||||
@mousemove="mmMove"
|
||||
@mouseup="mmEnd"
|
||||
<!-- #endif -->
|
||||
|
||||
>
|
||||
|
||||
<view class="xFloatDrawerBar">
|
||||
<view @click.stop="headerClickClose" style="height:100%" class="xFloatDrawerBarSop">
|
||||
<view class="xFloatDrawerBarLine"
|
||||
:disable="_disabled"
|
||||
:style="{'background-color':_actionColor,opacity: _disabled?0.5:1}">
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="xFLoatViewWrap" :style="{flex:'1',padding:_contentMargin}">
|
||||
<scroll-view
|
||||
ref="xFloatScrollRef"
|
||||
@scrolltoupper="scrolltoTop"
|
||||
@scroll="onscroll"
|
||||
@touchstart="scrollTouchStart"
|
||||
v-if="!disabledScroll&&containerType=='scroll'"
|
||||
<!-- #ifndef MP-WEIXIN -->
|
||||
:scroll-y="!(status=='close'||disabledScrolling)"
|
||||
<!-- #endif -->
|
||||
<!-- #ifdef MP-WEIXIN -->
|
||||
:scroll-y="!(status=='close'||disabledScrolling)"
|
||||
<!-- #endif -->
|
||||
:style="{flex:'1'}"
|
||||
:bounces="false">
|
||||
<!--
|
||||
@slot 默认插槽
|
||||
@prop {Boolean} show - 当前是否已显示
|
||||
-->
|
||||
<slot name="default" :show="show"></slot>
|
||||
<view :style="{height:_maxHeight+'px'}"></view>
|
||||
</scroll-view>
|
||||
|
||||
<list-view
|
||||
ref="xFloatScrollRef"
|
||||
@scroll="onscroll"
|
||||
@touchstart="scrollTouchStart"
|
||||
@scrolltoupper="scrolltoTop"
|
||||
v-else-if="!disabledScroll&&containerType=='list'"
|
||||
<!-- #ifndef MP-WEIXIN -->
|
||||
:direction="status=='close'||disabledScrolling?'none':'vertical'"
|
||||
<!-- #endif -->
|
||||
<!-- #ifdef MP-WEIXIN -->
|
||||
:scroll-y="!(status=='close'||disabledScrolling)"
|
||||
<!-- #endif -->
|
||||
:style="{flex:'1',margin:_contentMargin}" :bounces="false">
|
||||
<!--
|
||||
@slot 默认插槽
|
||||
@prop {Boolean} show - 当前是否已显示
|
||||
-->
|
||||
<slot name="default" :show="show"></slot>
|
||||
<list-item>
|
||||
<view :style="{height:_maxHeight+'px'}"></view>
|
||||
</list-item>
|
||||
</list-view>
|
||||
|
||||
<view v-else :style="{flex:'1',margin:_contentMargin}">
|
||||
<!--
|
||||
@slot 默认插槽
|
||||
@prop {Boolean} show - 当前是否已显示
|
||||
@prop {Number} height - 容器的高度
|
||||
-->
|
||||
<slot name="default" :show="show" :height="_maxHeight"></slot>
|
||||
</view>
|
||||
|
||||
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<style lang="scss">
|
||||
.xFloatDrawerBarSop {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.xFloatDrawerBar {
|
||||
height: 44px;
|
||||
|
||||
/* #ifdef WEB */
|
||||
cursor: grab;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
/* #ifdef WEB */
|
||||
.xFloatDrawerBar:active {
|
||||
cursor: grabbing;
|
||||
}
|
||||
|
||||
/* #endif */
|
||||
|
||||
|
||||
.xFloatDrawerBarLine {
|
||||
width: 60px;
|
||||
height: 4px;
|
||||
border-radius: 8px;
|
||||
/* #ifdef WEB */
|
||||
&:not[disable=true]:hover{
|
||||
opacity: 0.5;
|
||||
}
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.xFloatDrawerWrapContent {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
/* #ifndef APP-HARMONY */
|
||||
transition-duration: 250ms;
|
||||
/* #endif */
|
||||
/* #ifdef APP-HARMONY */
|
||||
transition-duration: 0ms;
|
||||
/* #endif */
|
||||
/* transition-timing-function: cubic-bezier(.18,.89,.32,1); */
|
||||
transition-property: transform;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
transform: translate(0%, 100%);
|
||||
position: fixed;
|
||||
/* z-index: 100; */
|
||||
left: 0px;
|
||||
bottom: 0px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,233 @@
|
||||
var nowTouchType = 'head'
|
||||
var touchmoevIsOver = true;
|
||||
var isHover = true;
|
||||
var isMoving = false;
|
||||
var _test_x = 0
|
||||
var _test_y = 0
|
||||
var _x = 0
|
||||
var _y = 0
|
||||
var _realY = 0
|
||||
var _realYDiff = 0
|
||||
var _scrollDetail_y_start = 0
|
||||
var disabledScolly = false;
|
||||
var defaultTranformYValue = 'matrix(1, 0, 0, 1, 0, 0) '
|
||||
var opts = {
|
||||
maxHeight: 650,
|
||||
size: 480,
|
||||
height: 0,
|
||||
threshold: 0,
|
||||
duration: 300,
|
||||
status: 'close',
|
||||
triggerDy: 180,
|
||||
_scrollDetail_y:0
|
||||
}
|
||||
|
||||
function eventTransform_start(evt, ins) {
|
||||
isHover = true;
|
||||
_scrollDetail_y_start = opts._scrollDetail_y
|
||||
disabledScolly = false
|
||||
isMoving = false
|
||||
|
||||
if (opts.status == 'open') {
|
||||
_y = evt.y - opts.maxHeight
|
||||
|
||||
} else if (opts.status == 'close') {
|
||||
_y = evt.y - opts.size
|
||||
}
|
||||
_realY = evt.y
|
||||
_test_y = evt.y;
|
||||
|
||||
ins.selectComponent('.xFloatDrawerWrapContent').setStyle({
|
||||
'transition-duration': '0ms',
|
||||
'transform': defaultTranformYValue
|
||||
})
|
||||
ins.callMethod('callEmits', {
|
||||
disabledScolly: disabledScolly,
|
||||
isMoving: isMoving
|
||||
})
|
||||
ins.callMethod('setDisabledScolly', {
|
||||
disabledScolly: disabledScolly,
|
||||
isMoving: isMoving
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
function eventTransform_move(evt, ins) {
|
||||
var ele = ins.selectComponent('.xFloatDrawerWrapContent')
|
||||
|
||||
var dy = evt.y - _test_y;
|
||||
|
||||
if(dy<0){
|
||||
disabledScolly = false;
|
||||
isMoving = false;
|
||||
opts._scrollDetail_y = 0
|
||||
}else{
|
||||
opts._scrollDetail_y = 0
|
||||
}
|
||||
|
||||
|
||||
ins.callMethod('callEmits', {
|
||||
disabledScolly: disabledScolly,
|
||||
isMoving: isMoving
|
||||
})
|
||||
ins.callMethod('setDisabledScolly', {
|
||||
disabledScolly: disabledScolly,
|
||||
isMoving: isMoving
|
||||
})
|
||||
|
||||
|
||||
if(disabledScolly) return true;
|
||||
var movey = evt.y - _y
|
||||
if (movey <= opts.maxHeight) {
|
||||
movey = opts.maxHeight - (opts.maxHeight - movey) * opts.threshold
|
||||
} else if (movey >= opts.size) {
|
||||
movey = opts.size + (movey - opts.size) * opts.threshold
|
||||
}
|
||||
|
||||
ele.setStyle({
|
||||
'transition-duration': '0ms',
|
||||
'transform': 'matrix(1, 0, 0, 1, 0, ' + movey + ')'
|
||||
})
|
||||
|
||||
_realYDiff = evt.y - _realY
|
||||
var ratioValue = (movey - opts.size) / (opts.maxHeight - opts.size) * 100;
|
||||
ins.callMethod('callEmits', {
|
||||
name: 'heightChange',
|
||||
args: ratioValue
|
||||
})
|
||||
}
|
||||
|
||||
function eventTransform_end(evt, ins) {
|
||||
isHover = false;
|
||||
var ele = ins.selectComponent('.xFloatDrawerWrapContent')
|
||||
var duration = opts.duration
|
||||
var offset = 0
|
||||
if (_realY - evt.y == 0) return;
|
||||
if (_realYDiff >= opts.triggerDy) {
|
||||
offset = opts.size
|
||||
opts.status = 'close';
|
||||
ins.callMethod('callEmits', 'beforeClose')
|
||||
ins.callMethod('callEmits', {
|
||||
name: 'heightChange',
|
||||
args: 0
|
||||
})
|
||||
ins.callMethod('callEmits', {name:'close'})
|
||||
} else if (_realYDiff < (opts.triggerDy * -1)) {
|
||||
offset = opts.maxHeight
|
||||
opts.status = 'open';
|
||||
ins.callMethod('callEmits', {
|
||||
name: 'heightChange',
|
||||
args: 100
|
||||
})
|
||||
ins.callMethod('callEmits', {name:'open'})
|
||||
} else {
|
||||
if (opts.status === 'open') {
|
||||
offset = opts.maxHeight
|
||||
ins.callMethod('callEmits', {
|
||||
name: 'heightChange',
|
||||
args: 100
|
||||
})
|
||||
|
||||
} else {
|
||||
offset = opts.size
|
||||
ins.callMethod('callEmits', {
|
||||
name: 'heightChange',
|
||||
args: 0
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
ins.callMethod('setOpts', opts)
|
||||
ele.setStyle({
|
||||
'transition-duration': duration + 'ms',
|
||||
'transform': 'matrix(1, 0, 0, 1, 0, ' + offset + ')'
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
|
||||
function setTatus(status,instance){
|
||||
var ele = instance.selectComponent('.xFloatDrawerWrapContent')
|
||||
var offset = 0
|
||||
var duration = opts.duration
|
||||
if (status === 'open') {
|
||||
offset = opts.maxHeight
|
||||
} else {
|
||||
offset = opts.size
|
||||
}
|
||||
|
||||
ele.setStyle({
|
||||
'transition-duration': duration + 'ms',
|
||||
'transform': 'matrix(1, 0, 0, 1, 0, ' + offset + ')'
|
||||
})
|
||||
}
|
||||
function mStartHead(evt, ins) {
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
function mMoveHead(evt, ins) {
|
||||
|
||||
}
|
||||
|
||||
function mEndHead(evt, ins) {
|
||||
|
||||
}
|
||||
|
||||
function mStart(evt, ins) {
|
||||
_test_x = evt.changedTouches[0].clientX;
|
||||
_test_y = evt.changedTouches[0].clientY;
|
||||
// var otps = ins.callMethod('getNowOpts')
|
||||
var ele = ins.selectComponent('.xFloatDrawerWrapContent')
|
||||
opts = ele.getDataset().opts;
|
||||
defaultTranformYValue = ele.getComputedStyle(['transform']).transform
|
||||
isMoving = false
|
||||
ins.callMethod('callEmits', {
|
||||
name: 'movestart',
|
||||
args: null
|
||||
})
|
||||
eventTransform_start({
|
||||
x: _test_x,
|
||||
y: _test_y
|
||||
}, ins);
|
||||
}
|
||||
|
||||
function mMove(evt, ins) {
|
||||
isMoving = true
|
||||
|
||||
eventTransform_move({
|
||||
x: evt.changedTouches[0].clientX,
|
||||
y: evt.changedTouches[0].clientY
|
||||
}, ins);
|
||||
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
function mEnd(evt, ins) {
|
||||
ins.callMethod('callEmits', {
|
||||
name: 'moveend',
|
||||
args: null
|
||||
})
|
||||
eventTransform_end({
|
||||
x: evt.changedTouches[0].clientX,
|
||||
y: evt.changedTouches[0].clientY
|
||||
}, ins)
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
mStart: mStart,
|
||||
mMove: mMove,
|
||||
mEnd: mEnd,
|
||||
mStartHead: mStartHead,
|
||||
mMoveHead: mMoveHead,
|
||||
mEndHead: mEndHead,
|
||||
propObserver: function(newValue, oldValue, ownerInstance, instance) {
|
||||
var ele = ownerInstance.selectComponent('.xFloatDrawerWrapContent')
|
||||
opts = ele.getDataset().opts;
|
||||
if(newValue!=undefined&&oldValue!=undefined&&newValue!=oldValue){
|
||||
setTatus(newValue,ownerInstance)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user