vue fixed 定位且可以拖动的组件

621 阅读1分钟

效果

全部代码

<!--    

    minRight 与 minBottom 可传入,用来设置初始位置,组件内部使用了 百分比定位 ( 考虑到rem 与 px 转换 可能比较麻烦 )
    
    暂时实现不是很完美 需要重新计算
    目前只能初始设置在屏幕的右下部分, 其他部分会有问题

    使用方式
    <DragSide>
         <img  src="./assets/icon/consult.png">
     </DragSide>
 -->

<template>
	<!-- @touchmove.prevent阻止浏览器滚动 -->
    <div
        ref="fixed_side"
        class="fixed-side"
        @touchmove.prevent="touchmove"
        @touchend="touchend"
        :style="{
            bottom: offsetBottom + '%',
            right: offsetRight + '%',
            'transition-duration': transitionDuration,
        }"
    >
        <slot></slot>
    </div>
</template>

<script>
export default {
    props: {
        minRight: {
            type: Number,
            default: 5,
            validator(value) {
                return value > 0 && value < 30;
            },
        },
        minBottom: {
            type: Number,
            default: 10,
        },
    },
    data() {
        return {
            offsetRight: this.minRight,
            offsetBottom: this.minBottom,

            transitionDuration: "0s",
        };
    },
    methods: {
        // 获取dom相关属性(宽,高)
        getRect() {
            let fixedSide = this.$refs.fixed_side;
            return fixedSide.getBoundingClientRect();
        },
        touchmove(e) {
            let { width, height } = this.getRect();

            let { pageX, pageY } = e.targetTouches[0];

            this.offsetRight =
                ((window.innerWidth - pageX - width / 2) / window.innerWidth) * 100;

            this.offsetBottom = ((window.innerHeight - pageY - height / 2) / window.innerHeight) * 100;

            let RightB = 100 - this.minRight - (width / window.innerWidth) * 100;

            // 下边设置上下左右四个边界, 不可移出屏幕
            if (this.offsetRight < this.minRight) this.offsetRight = this.minRight;
            if (this.offsetRight > RightB) this.offsetRight = RightB;

            if (this.offsetBottom < 10) this.offsetBottom = 10;
            if (this.offsetBottom > 90) this.offsetBottom = 90;
        },

        touchend(e) {
            let { pageX } = e.changedTouches[0];

            let innerWidth = window.innerWidth;

            let { width } = this.getRect();

            let RightB = 100 - this.minRight - (width / window.innerWidth) * 100;

            // 通过 transitionDuration 设置松手后的动画效果
            this.transitionDuration = "0.2s";

            // 判断松手的时候手指位置处于屏幕哪一侧
            if (pageX >= innerWidth / 2) this.offsetRight = this.minRight;
            else this.offsetRight = RightB;
			
            // 重新设置为0 是为了在拖动过程中不受影响
            setTimeout(() => {
                this.transitionDuration = "0s";
            }, 30);
        },
    },
};
</script>

<style scoped lang="scss">
.fixed-side {
    position: fixed;
    z-index: 10;
}
</style>

总想为代码找个最优解,但是又找不到, 不说了,学习吧 !