先介绍一下,我们的应用场景,就是一种图片,能编辑的那种,
主要是:拖动可以该变位置,还可以实现图片的缩小放大。
实现思路是: 通过绝对定位+触摸事件( @touchend @touchstart @touchmove)
注意: 以上三个事件是移动端才有,PC端上不会生效!!!!!!
好了:整理好思路就开始码代码吧
这是我的demo,这样我先把代码贴出来吧,以下是实现的所有代码, 各处代码有详细的注释,如有不解,欢迎评论,或者私信,看到即回 以下带直接新建.vue文件复制即可
<template>
<div>
<h4>移动端拖拽事件,案例</h4>
<!-- 父盒子 用于限制其拖拽范围 -->
<div class="max-box">
<!-- 被拖拽元素 拖拽之后可改变其大小和位置-->
<div class="min-box"
ref="context"
@touchend="touchEnd"
@touchstart="touchStart"
@touchmove="touchMove">
<!-- 图片元素宽高均设置100%这样我们只需要关注,父盒子的宽高就好,至于会变形,哈,那是用户操作的,和我有什么关系,哈哈哈 -->
<img width="100%"
height="100%"
src="@/assets/logo.png"
alt="" />
<!-- 该元素是拖拽点用于实现元素的放大和缩小
要添加.stop修饰符,是因为,父元素也有这个事件,所以阻止事件冒泡,真好用,哈哈哈
-->
<div class="drag-box"
@touchend.stop="touchEndDrag"
@touchstart.stop="touchStartDrag"
@touchmove.stop="touchMoveDrag">
<!-- 这是一个elemant UI的 图标,可以随时替换哈
-->
<i class="el-icon-refresh-left"></i>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data () {
return {
touchX: 0, //触摸点X坐标
touchY: 0, //触摸点Y坐标
contextTop: 0, //拖拽区域距离顶部的距离
contextLeft: 0, //拖拽区域距离左边的距离
contextWidth: 0, //拖拽区域的宽度
contextHeight: 0, //拖拽区域的高度
newTouchX: 0, //拖拽区域的新的X坐标
newTouchY: 0, // 拖拽区域的新的Y坐标
dragBoxtouchX: 0, //拖拽区域距离左部的距离
dragBoxtouchY: 0, //拖拽区域距离顶部的距离
newContextWidth: 0, //拖拽新的区域的宽度
newContextHeight: 0, //拖拽新的区域的高度
}
},
mounted () {
/*
注意:如果你的dom是此时没有,就获取不到相关信息,就是 0。因此你应该在dom显示出来之后,从$nextTick中获取。 此时获取的就是最新的信息, 此处是一个坑 就会导致拖动出现bug
*/
/*
这是初始的一些信息
*/
this.contextTop = this.$refs.context.offsetTop; //拖拽区域距离顶部的距离
this.contextLeft = this.$refs.context.offsetLeft; //拖拽区域距离左边的距离
this.contextWidth = this.$refs.context.offsetWidth; //拖拽区域的宽度
this.contextHeight = this.$refs.context.offsetHeight; //拖拽区域的高度
},
methods: {
// 以下这三个事件对应 拖动改变位置
touchStart (e) { // 这是 触摸开始的事件
this.touchX = e.changedTouches[0].pageX; //触摸点X坐标 记录开始坐标
this.touchY = e.changedTouches[0].pageY; //触摸点Y坐标
},
touchMove (e) { // 触摸过程中的 事件
var touchX = e.changedTouches[0].pageX; //触摸点X坐标 这是当前触摸位置的坐标
var touchY = e.changedTouches[0].pageY; //触摸点Y坐标
let x = touchX - this.touchX; //X轴移动距离
let y = touchY - this.touchY; //Y轴移动距离
let newY = this.contextTop + y; //拖拽区域的新的Y坐标 初始的坐标加上移动的就是新的坐标
let newX = this.contextLeft + x; //拖拽区域的新的X坐标
if (newY >= (500 - Math.abs(this.contextHeight))) { // 以下四个判断是解决 拖动的边界问题,不能超出父元素的大小, 500就是父元素的宽度 和高度
newY = 500 - Math.abs(this.contextHeight); //
}
if (newY <= 0) { // 当小于0时限制不能超出
newY = 0;
}
if (newX >= (500 - Math.abs(this.contextWidth))) { // 改变 left 时要减去 拖动元素的宽度,又因为这个元素的宽度是不固定因此要用一个变量,也就是为什么开始时要获取的原因。 Math.abs() 表示取绝对值
newX = 500 - Math.abs(this.contextWidth);
}
if (newX <= 0) {
newX = 0;
}
this.$refs.context.style.top = `${newY}px`; // 新的高度赋值给拖动的元素
this.$refs.context.style.left = `${newX}px`;
this.newTouchX = x + this.contextLeft; // 新的位置重新保存一下
this.newTouchY = y + this.contextTop;
},
touchEnd () {
this.contextTop = this.newTouchY; // 新的位置 保存给 初始的变量也更新一下,此处应该可以优化以下
this.contextLeft = this.newTouchX;
},
// 以下三个事件 就是拖动角标的 放大和缩小事件 和上面的区别就在于 他改变的是元素的宽度和高度,而上面改变的是元素的top 和 left 偏移量。
touchMoveDrag 区别主要是这个方法,
touchStartDrag (e) {
this.dragBoxtouchX = e.changedTouches[0].pageX;
this.dragBoxtouchY = e.changedTouches[0].pageY;
console.log(this.touchX, this.touchY, '开始拖拽');
},
touchMoveDrag (e) {
var touchX = e.changedTouches[0].pageX;
var touchY = e.changedTouches[0].pageY;
let x = touchX - this.dragBoxtouchX;
let y = touchY - this.dragBoxtouchY;
this.newContextWidth = this.contextWidth + x;
this.newContextHeight = this.contextHeight + y;
// 以下四个判断是用来解决 边界问题
if (this.newContextWidth >= (500 - Math.abs(this.contextLeft))) { // 新的元素宽度是要减去自己的偏移量,用来限制不能超出 父盒子 500 的宽和高
// console.log('超出范围', this.contextLeft);
if (this.contextLeft < 0) { // 该判断用来限制如果时负值 就有可能超出的问题
this.newContextWidth = 500
}
else {
this.newContextWidth = 500 - Math.abs(this.contextLeft);
}
}
if (this.newContextWidth <= 40) { // 此处用来限制拖动的大小,即,拖动最小值是40*40,下面的判断是高度的限制同理
this.newContextWidth = 40;
}
if (this.newContextHeight >= (500 - Math.abs(this.contextTop))) {
// console.log('超出范围', this.contextTop);
if (this.contextTop < 0) {
this.newContextHeight = 500
} else {
this.newContextHeight = 500 - Math.abs(this.contextTop);
}
}
if (this.newContextHeight <= 40) {
this.newContextHeight = 40;
}
this.$refs.context.style.width = `${this.newContextWidth}px`; // 计算之后的高度和宽度直接设置给元素即可
this.$refs.context.style.height = `${this.newContextHeight}px`;
// console.log(touchX, touchY, '移动位置');
},
touchEndDrag (e) {
console.log(e); // 拖动结束再次保存 新的位置 ,
this.contextWidth = this.newContextWidth;
this.contextHeight = this.newContextHeight;
},
},
}
</script>
<style lang="less" scoped>
.max-box {
width: 500px;
height: 500px;
overflow: hidden; // 限制 内部元素不能超出
background-color: rgb(98, 190, 255);
position: relative; // 开启定位,子元素需要绝对定位
.min-box {
width: 100px;
height: 100px;
background-color: rgb(155, 255, 33);
position: absolute; // 开启绝对定位
top: 100px; // 设值初始位置
left: 100px;
.drag-box {
width: 20px;
height: 20px;
background-color: rgb(255, 255, 255);
text-align: center;
line-height: 20px;
position: absolute; // 缩放图标设置位置
right: -10px;
bottom: -10px;
border-radius: 50%;
}
}
}
</style>