| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216 |
- <template>
- <view
- :class="classes"
- ref="myDrag"
- @touchstart="touchStart($event)"
- @touchmove="touchMove($event)"
- @touchend="touchEnd($event)"
- >
- <slot></slot>
- </view>
- </template>
- <script lang="ts">
- import {
- onMounted,
- onDeactivated,
- onActivated,
- reactive,
- ref,
- computed
- } 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
- };
- }
- }
- },
- 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;
- }
- 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 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';
- }
- }
- }
- 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);
- });
- return {
- classes,
- myDrag,
- touchStart,
- touchMove,
- touchEnd
- };
- }
- });
- </script>
- <style lang="scss">
- @import 'index.scss';
- </style>
|