Some checks are pending
Check / lint (push) Waiting to run
Check / typecheck (push) Waiting to run
Check / build (build, 18.x, ubuntu-latest) (push) Waiting to run
Check / build (build, 18.x, windows-latest) (push) Waiting to run
Check / build (build:app, 18.x, ubuntu-latest) (push) Waiting to run
Check / build (build:app, 18.x, windows-latest) (push) Waiting to run
Check / build (build:mp-weixin, 18.x, ubuntu-latest) (push) Waiting to run
Check / build (build:mp-weixin, 18.x, windows-latest) (push) Waiting to run
191 lines
4.4 KiB
Vue
191 lines
4.4 KiB
Vue
<template>
|
||
<!-- #ifdef MP -->
|
||
<view @touchstart="touch.startDrag" @touchmove.stop="touch.onDrag" @touchend="touch.endDrag" :data-prop="towxsShareData">
|
||
<!-- #endif -->
|
||
<!-- #ifdef H5||APP-VUE -->
|
||
<view @touchstart="touch.startDrag" @touchmove="touch.onDrag" @touchend="touch.endDrag" :data-prop="towxsShareData">
|
||
<!-- #endif -->
|
||
<!-- #ifdef APP-NVUE -->
|
||
<view >
|
||
<!-- #endif -->
|
||
<view @touchstart="touchstart" :style="{ left: _offset[0] + 'rpx', top: _offset[1] + 'rpx' }" class="div" id="adsorb" ref="adsorb">
|
||
<view
|
||
:eventPenetrationEnabled="true"
|
||
:style="{
|
||
width: props.width + 'rpx',
|
||
height: props.height + 'rpx'
|
||
}"
|
||
>
|
||
<slot></slot>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
</template>
|
||
<!-- #ifndef APP-NVUE -->
|
||
<script module="touch" lang="wxs" src="touch.wxs"></script>
|
||
<!-- #endif -->
|
||
<script lang="ts" setup>
|
||
import { ref, inject, computed, unref, PropType,getCurrentInstance } from 'vue';
|
||
// #ifdef APP-NVUE
|
||
var dom = weex.requireModule("dom");
|
||
const Binding = uni.requireNativePlugin("bindingx");
|
||
const animation = uni.requireNativePlugin("animation");
|
||
const proxy = getCurrentInstance()?.proxy??null;
|
||
// #endif
|
||
const props = defineProps({
|
||
/** 是否吸附边缘,关闭可以任意托动组件,开启拖动只会吸附在两边。 */
|
||
adsorb: {
|
||
type: Boolean,
|
||
default: true
|
||
},
|
||
/** 开启吸附后,吸附到边缘的动画时间,单位ms */
|
||
duration: {
|
||
type: Number,
|
||
default: 600
|
||
},
|
||
width: {
|
||
type: Number,
|
||
default: 100
|
||
},
|
||
height: {
|
||
type: Number,
|
||
default: 100
|
||
},
|
||
/** 默认的位置 */
|
||
offset: {
|
||
type: Array as PropType<Array<number>>,
|
||
default: () => [0, 0]
|
||
},
|
||
/** 吸附的偏移量,比如向左时,是吸附侧边0还是再往左偏移多少 */
|
||
adsorbX: {
|
||
type: Number,
|
||
default: 0
|
||
}
|
||
});
|
||
const sysinfo = inject(
|
||
'tmuiSysInfo',
|
||
computed(() => {
|
||
return {
|
||
bottom: 0,
|
||
height: 750,
|
||
width: uni.upx2px(750),
|
||
top: 0,
|
||
isCustomHeader: false,
|
||
sysinfo: null
|
||
};
|
||
})
|
||
);
|
||
const _offset = computed(() => props.offset);
|
||
let bindxToken:any = null;
|
||
const towxsShareData = ref({
|
||
adsorb: props.adsorb,
|
||
sys: sysinfo.value,
|
||
adsorbX: props.adsorbX,
|
||
duration: props.duration
|
||
});
|
||
let position = {x:0,y:0};
|
||
function getEl(el: any) {
|
||
if (typeof el === "string" || typeof el === "number") return el;
|
||
if (WXEnvironment) {
|
||
return el.ref;
|
||
} else {
|
||
return el instanceof HTMLElement ? el : el.$el;
|
||
}
|
||
}
|
||
function spinNvueAniEnd(start: number,end:number, duration = props.duration) {
|
||
// #ifdef APP-NVUE
|
||
if (!proxy?.$refs?.adsorb) return;
|
||
animation.transition(
|
||
proxy?.$refs.adsorb,
|
||
{
|
||
styles: {
|
||
transform: `translate(${start}px,${end}px)`,
|
||
transformOrigin: "center center",
|
||
},
|
||
duration: duration, //ms
|
||
timingFunction: "cubicBezier(0.18, 0.89, 0.32, 1)",
|
||
delay: 0, //ms
|
||
},
|
||
() => {
|
||
|
||
}
|
||
);
|
||
|
||
// #endif
|
||
}
|
||
|
||
function touchstart(e: TouchEvent) {
|
||
|
||
// #ifdef APP-NVUE
|
||
if (!proxy?.$refs?.adsorb) return;
|
||
|
||
let icon = getEl(proxy?.$refs.adsorb);
|
||
let icon_bind = Binding.bind(
|
||
{
|
||
anchor: icon,
|
||
eventType: "pan",
|
||
props: [
|
||
{
|
||
element: icon,
|
||
property: "transform.translateX",
|
||
expression: `x+${position.x}`,
|
||
},
|
||
{
|
||
element: icon,
|
||
property: "transform.translateY",
|
||
expression: `y+${position.y}`,
|
||
},
|
||
],
|
||
},
|
||
function (res) {
|
||
if (res.state == "end") {
|
||
position.x+=res.deltaX
|
||
position.y+=res.deltaY
|
||
if(towxsShareData.value.adsorb){
|
||
dom.getComponentRect(proxy?.$refs.adsorb, function (res:UniApp.NodeInfo|UniApp.NodeField) {
|
||
if (res?.size) {
|
||
let left=0
|
||
let top=0
|
||
let rect = res.size;
|
||
let x = uni.upx2px(props.offset[0]);
|
||
let y = uni.upx2px(props.offset[1]);
|
||
if(Math.abs((rect.left+rect.width/2))<=towxsShareData.value.sys.width/2){
|
||
left = x - Math.abs(position.x)
|
||
position.x = -left+position.x - towxsShareData.value.adsorbX
|
||
}else{
|
||
left = towxsShareData.value.sys.width - rect.right;
|
||
position.x =position.x + left + towxsShareData.value.adsorbX
|
||
}
|
||
if(rect.bottom>=towxsShareData.value.sys.height){
|
||
position.y =position.y - (rect.bottom-towxsShareData.value.sys.height)
|
||
}
|
||
if(rect.top<=0){
|
||
position.y =position.y + Math.abs(rect.top)
|
||
}
|
||
|
||
|
||
spinNvueAniEnd(position.x,position.y);
|
||
}
|
||
});
|
||
}
|
||
|
||
} else if (res.state == "start") {
|
||
|
||
}
|
||
}
|
||
);
|
||
bindxToken = icon_bind.token;
|
||
// #endif
|
||
}
|
||
|
||
|
||
defineExpose({});
|
||
</script>
|
||
|
||
<style scoped>
|
||
.div {
|
||
position: fixed;
|
||
}
|
||
</style>
|