|
|
@@ -1,210 +1,50 @@
|
|
|
<template>
|
|
|
- <view
|
|
|
- :class="classes"
|
|
|
- ref="myDrag"
|
|
|
- @touchstart="touchStart($event)"
|
|
|
- @touchmove="touchMove($event)"
|
|
|
- @touchend="touchEnd($event)"
|
|
|
- >
|
|
|
- <slot></slot>
|
|
|
- </view>
|
|
|
+ <movable-area>
|
|
|
+ <movable-view
|
|
|
+ :style="{ width: width + 'px', height: height + 'px' }"
|
|
|
+ :direction="direction"
|
|
|
+ >
|
|
|
+ <slot></slot>
|
|
|
+ </movable-view>
|
|
|
+ </movable-area>
|
|
|
</template>
|
|
|
-
|
|
|
<script lang="ts">
|
|
|
-import {
|
|
|
- onMounted,
|
|
|
- onDeactivated,
|
|
|
- onActivated,
|
|
|
- reactive,
|
|
|
- ref,
|
|
|
- computed
|
|
|
-} from 'vue';
|
|
|
+import { ref, computed, watch, onMounted } from 'vue';
|
|
|
import { createComponent } from '../../utils/create';
|
|
|
import requestAniFrame from '../../utils/raf';
|
|
|
const { componentName, create } = createComponent('drag');
|
|
|
export default create({
|
|
|
props: {
|
|
|
- attract: {
|
|
|
- type: Boolean,
|
|
|
- default: false
|
|
|
- },
|
|
|
direction: {
|
|
|
type: String,
|
|
|
default: 'all'
|
|
|
},
|
|
|
- boundary: {
|
|
|
- type: Object,
|
|
|
- default: () => {
|
|
|
- return {
|
|
|
- top: 0,
|
|
|
- left: 0,
|
|
|
- right: 0,
|
|
|
- bottom: 0
|
|
|
- };
|
|
|
- }
|
|
|
+ width: {
|
|
|
+ type: String,
|
|
|
+ default: ''
|
|
|
+ },
|
|
|
+ height: {
|
|
|
+ type: String,
|
|
|
+ default: ''
|
|
|
}
|
|
|
},
|
|
|
- setup(props, { emit }) {
|
|
|
- const myDrag = ref();
|
|
|
- const state = reactive({
|
|
|
- keepAlive: false,
|
|
|
- elWidth: 0,
|
|
|
- elHeight: 0,
|
|
|
- screenWidth: 0,
|
|
|
- screenHeight: 0,
|
|
|
- startTop: 0,
|
|
|
- startLeft: 0,
|
|
|
- nx: 0,
|
|
|
- ny: 0,
|
|
|
- xPum: 0,
|
|
|
- yPum: 0,
|
|
|
- position: { x: 0, y: 0 },
|
|
|
- boundary: {
|
|
|
- top: 0,
|
|
|
- left: 0,
|
|
|
- right: 0,
|
|
|
- bottom: 0
|
|
|
- } as Record<string, any>
|
|
|
- });
|
|
|
-
|
|
|
- const classes = computed(() => {
|
|
|
- const prefixCls = componentName;
|
|
|
- return {
|
|
|
- [prefixCls]: true
|
|
|
- };
|
|
|
- });
|
|
|
|
|
|
- function getInfo() {
|
|
|
- const domElem = document.documentElement;
|
|
|
- state.elWidth = myDrag.value.offsetWidth;
|
|
|
- state.elHeight = myDrag.value.offsetHeight;
|
|
|
- state.screenWidth = domElem.clientWidth;
|
|
|
- state.screenHeight = domElem.clientHeight;
|
|
|
- }
|
|
|
+ setup(props, { emit }) {
|
|
|
+ const direction = ref('all');
|
|
|
|
|
|
- function goLeft(target: HTMLElement) {
|
|
|
- if (state.boundary.left) {
|
|
|
- if (+target.style.left.split('px')[0] > state.boundary.left) {
|
|
|
- target.style.left = +target.style.left.split('px')[0] - 10 + 'px';
|
|
|
- requestAniFrame(() => {
|
|
|
- goLeft(target);
|
|
|
- });
|
|
|
- } else {
|
|
|
- target.style.left = `${state.boundary.left}px`;
|
|
|
- }
|
|
|
- } else {
|
|
|
- if (+target.style.left.split('px')[0] > 10) {
|
|
|
- target.style.left = +target.style.left.split('px')[0] - 10 + 'px';
|
|
|
- requestAniFrame(() => {
|
|
|
- goLeft(target);
|
|
|
- });
|
|
|
- } else {
|
|
|
- target.style.left = '0px';
|
|
|
- }
|
|
|
+ function checkDirection() {
|
|
|
+ if (props.direction == 'x') {
|
|
|
+ direction.value = 'horizontal';
|
|
|
}
|
|
|
- }
|
|
|
- function goRight(target: HTMLElement, rightLocation: number) {
|
|
|
- if (rightLocation - parseInt(target.style.left.split('px')[0]) > 10) {
|
|
|
- target.style.left =
|
|
|
- parseInt(target.style.left.split('px')[0]) + 10 + 'px';
|
|
|
- requestAniFrame(() => {
|
|
|
- goRight(target, rightLocation);
|
|
|
- });
|
|
|
- } else {
|
|
|
- target.style.left = rightLocation + 'px';
|
|
|
- }
|
|
|
- }
|
|
|
- function touchMove(e: TouchEvent) {
|
|
|
- e.preventDefault();
|
|
|
- const target = e.currentTarget as HTMLElement;
|
|
|
- if (e.targetTouches.length === 1) {
|
|
|
- const touch = e.targetTouches[0];
|
|
|
- state.nx = touch.clientX - state.position.x;
|
|
|
- state.ny = touch.clientY - state.position.y;
|
|
|
- state.xPum = state.startLeft + state.nx;
|
|
|
- state.yPum = state.startTop + state.ny;
|
|
|
- const rightLocation =
|
|
|
- state.screenWidth - state.elWidth - state.boundary.right;
|
|
|
- if (Math.abs(state.xPum) > rightLocation) {
|
|
|
- state.xPum = rightLocation;
|
|
|
- } else if (state.xPum <= state.boundary.left) {
|
|
|
- state.xPum = state.boundary.left;
|
|
|
- }
|
|
|
- if (state.yPum < state.boundary.top) {
|
|
|
- state.yPum = state.boundary.top;
|
|
|
- } else if (
|
|
|
- state.yPum >
|
|
|
- state.screenHeight - state.elHeight - state.boundary.bottom
|
|
|
- ) {
|
|
|
- state.yPum =
|
|
|
- state.screenHeight - state.elHeight - state.boundary.bottom;
|
|
|
- }
|
|
|
- if (props.direction != 'y') {
|
|
|
- target.style.left = state.xPum + 'px';
|
|
|
- }
|
|
|
- if (props.direction != 'x') {
|
|
|
- target.style.top = state.yPum + 'px';
|
|
|
- }
|
|
|
+ if (props.direction == 'y') {
|
|
|
+ direction.value = 'vertical';
|
|
|
}
|
|
|
}
|
|
|
- function touchEnd(e: TouchEvent) {
|
|
|
- const target = e.currentTarget as HTMLElement;
|
|
|
- const touch = e.changedTouches[0];
|
|
|
- let currX = touch.clientX;
|
|
|
- const rightLocation =
|
|
|
- state.screenWidth - state.elWidth - state.boundary.right;
|
|
|
- if (currX > rightLocation) {
|
|
|
- currX = rightLocation;
|
|
|
- } else if (currX < state.boundary.left) {
|
|
|
- currX = state.boundary.left;
|
|
|
- } else {
|
|
|
- currX =
|
|
|
- currX < state.screenWidth / 2 ? state.boundary.left : rightLocation;
|
|
|
- }
|
|
|
- if (props.direction != 'y' && props.attract) {
|
|
|
- if (currX < state.screenWidth / 2) {
|
|
|
- requestAniFrame(() => {
|
|
|
- goLeft(target);
|
|
|
- });
|
|
|
- } else {
|
|
|
- requestAniFrame(() => {
|
|
|
- goRight(target, rightLocation);
|
|
|
- });
|
|
|
- }
|
|
|
- }
|
|
|
- if (props.direction !== 'x') {
|
|
|
- target.style.top = state.yPum + 'px';
|
|
|
- }
|
|
|
- }
|
|
|
- function touchStart(e: TouchEvent) {
|
|
|
- const target = e.currentTarget as HTMLElement;
|
|
|
- const touches = e.touches[0];
|
|
|
- state.startTop = target.offsetTop;
|
|
|
- state.startLeft = target.offsetLeft;
|
|
|
- state.position.x = touches.clientX;
|
|
|
- state.position.y = touches.clientY;
|
|
|
- }
|
|
|
onMounted(() => {
|
|
|
- getInfo();
|
|
|
- state.boundary = props.boundary;
|
|
|
- });
|
|
|
- onActivated(() => {
|
|
|
- if (state.keepAlive) {
|
|
|
- state.keepAlive = false;
|
|
|
- }
|
|
|
- });
|
|
|
- onDeactivated(() => {
|
|
|
- state.keepAlive = true;
|
|
|
- (myDrag as any).removeEventListener('touchstart', touchStart);
|
|
|
- (myDrag as any).removeEventListener('touchmove', touchMove);
|
|
|
- (myDrag as any).removeEventListener('touchend', touchEnd);
|
|
|
+ checkDirection();
|
|
|
});
|
|
|
return {
|
|
|
- classes,
|
|
|
- myDrag,
|
|
|
- touchStart,
|
|
|
- touchMove,
|
|
|
- touchEnd
|
|
|
+ direction
|
|
|
};
|
|
|
}
|
|
|
});
|