目录
第一章 效果展示
第二章 了解工具
2.1 draggable
2.1.1 了解draggable
2.1.2 draggable方法
2.1.3 利用例子理解方法
第三章 效果实现
3.1 实现思路
3.2 代码实现
3.2.1 涉及到的点
3.2.2 源代
第一章 效果展示
- 效果描述:通过点击左边栏的签名和签章,使其在右边初步展示,然后再拖动确定他们的位置
第二章 了解工具
2.1 draggable
2.1.1 了解draggable
- draggable 属性是 HTML5 新增的。
- Internet Explorer 9+, Firefox, Opera, Chrome, 和 Safari 浏览器支持 draggable 属性,IE8以下不支持
- draggable 属性规定元素是否可拖动
- 用法:
<element draggable="true|false|auto">
- 注意: 图片(
<img>
)和链接(<a>
)不加这个属性,就可以拖拉,对于它们,为了防止拖拽,用到这个属性的时候,往往是将其设为false
- 说明:
true | 规定元素是可拖动的。 |
false | 规定元素是不可拖动的。 |
auto | 使用浏览器的默认特性。 |
2.1.2 draggable方法
- drag:拖拽过程中,在被拖拽的节点上持续触发(相隔几百毫秒)。
- dragstart:用户拖拽开始时,在被拖拽的节点上触发,该事件的target属性是被拖拉的节点。通常在这个事件的监听函数中,指定拖拽的数据。(常用)
- dragend:拖拽结束时(释放鼠标键或按下 ESC 键)在被拖拽的节点上触发,该事件的target属性是被拖拉的节点。它与dragstart事件,在同一个节点上触发。不管拖拉是否跨窗口,或者中途被取消,dragend事件总是会触发的。(常用)
- dragenter:拖拽进入当前节点时,在当前节点上触发一次,该事件的target属性是当前节点。通常应该在这个事件的监听函数中,指定是否允许在当前节点放下(drop)拖拉的数据。如果当前节点没有该事件的监听函数,或者监听函数不执行任何操作,就意味着不允许在当前节点放下数据。在视觉上显示拖拉进入当前节点,也是在这个事件的监听函数中设置。
- dragover:拖拉到当前节点上方时,在当前节点上持续触发(相隔几百毫秒),该事件的target属性是当前节点。该事件与dragenter事件的区别是,dragenter事件在进入该节点时触发,然后只要没有离开这个节点,dragover事件会持续触发。
- dragleave:拖拉操作离开当前节点范围时,在当前节点上触发,该事件的target属性是当前节点。如果要在视觉上显示拖拉离开操作当前节点,就在这个事件的监听函数中设置。
- drop:被拖拉的节点或选中的文本,释放到目标节点时,在目标节点上触发。注意,如果当前节点不允许drop,即使在该节点上方松开鼠标键,也不会触发该事件。如果用户按下 ESC 键,取消这个操作,也不会触发该事件。该事件的监听函数负责取出拖拉数据,并进行相关处理。
2.1.3 利用例子理解方法
<div class="back_box" ref="back_box">
<div
v-if="signShow"
class="drag_box"
draggable="true"
@drag="drag($event)"
@dragstart="dragstart($event)"
@dragend="dragend($event)"
@dragenter="dragenter($event)"
@dragover="dragover($event)"
@dragleave="dragleave($event)"
@drop="drop($event)"
:style="`left:${elLeft}px;top:${elTop}px`"
>
</div>
drag(e){
console.log('drag', e)
},
// 拖拽开始事件
dragstart (e) {
console.log('dragstart', e)
},
// 拖拽完成事件
dragend (e) {
console.log('dragend', e)
},
dragenter (e) {
console.log('dragenter', e)
},
dragover (e) {
console.log('dragover', e)
},
dragleave (e) {
console.log('dragleave', e)
},
- 看效果
- 看右边输出,很明显,小编开始拖拽时,dragstart函数调用,然后drag-> dragenter->dragover调用,这一过程是表示拖拽过程中进入了节点同时还在该节点上方的范围内,后面输出从drag->dragover到drag->drag…的原因也是在拖拽的过程中,节点由原来的节点上方范围内到范围外之后只有drag触发,dragover不触发,最后松开鼠标,拖拽结束了,触发dragend
- 至于为什么drop没有触发,这里请看文档的实例,如下。(小编理解是,该事件应该在存放的目标模板中使用,而不是自身)
HTML draggable 属性 | 菜鸟教程
- event的参数(小编就不一一说明了,这里用到clientX和clientY计算偏移量的)
第三章 效果实现
3.1 实现思路
- 三个元素:签名、签章已经模板
- 页面布局,初步样式控制,小编的样式:(为了方便,小编模板用的图片-->大家用源代码时记得替换)
- 点击左边的签名,右边模板出现对应的签名,签章同理,利用定位让签章与签名都在模板的左上角
- 拖拽开始时记录一次最开始的位置
- 拖拽结束鼠标松开时再记录一次位置
- 利用两个位置的差计算偏移量
- 最后再次利用定位top和left将签名和签章固定到模板上
3.2 代码实现
3.2.1 涉及到的点
- 使用dragstart和dragend记录拖拽元素初始位置和结束位置
- 利用宽高比例进行页面初始化(正常屏幕宽高1920*1080,根据需求初始化)
- 了解一下
- clientX:当鼠标事件发生时(不管是onclick,还是omousemovenmouseover等),鼠标对于浏览器(这里说的是浏览器的有效区域)x抽的置
- clientY:当鼠标事件发生时,鼠标相对于浏览器(这里说的是浏览器的有效区域)y轴的位置;
- screenX:当鼠标事件发生时,鼠标相对于显示器屏幕x轴的位置;
- screenY:当鼠标事件发生时,鼠标相对于显示器屏幕y轴的位置;
- offsetX:当鼠标事件发生时,鼠标相对于事件源x轴的位置(这里的事件源是上一个有定位的父级标签)
- offsetY:当鼠标事件发生时,鼠标相对于事件源y轴的位置(这里的事件源是上一个有定位的父级标签)
3.2.2 源代码
<template>
<div class="page">
<div class="left">
<div class="title">签名</div>
<div class="img" @click="signShow = true">
<img src="./img/sign.png" alt="" style="height: 50px; border: 1px solid #eee;">
</div>
<div class="title">签章</div>
<div class="img" @click="sign2Show = true">
<img src="./img/sign3.png" alt="">
</div>
</div>
<div class="right">
<div class="drag">
<div class="back_box" ref="back_box">
<div
v-if="signShow"
class="drag_box"
draggable="true"
@dragstart="dragstart($event)"
@dragend="dragend($event)"
:style="`left:${elLeft}px;top:${elTop}px`"
>
</div>
<div
v-if="sign2Show"
class="drag_box2"
draggable="true"
@dragstart="sign2dragstart($event)"
@dragend="sign2dragend($event)"
:style="`left:${elLeft2}px;top:${elTop2}px`"
>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data () {
return {
initWidth: 0, // 父元素的宽-自适应值
initHeight: 0, // 父元素的高-自适应值
startclientX: 0, // 元素拖拽前距离浏览器的X轴位置
startclientY: 0, // 元素拖拽前距离浏览器的Y轴位置
elLeft: 0, // 元素的左偏移量
elTop: 0, // 元素的右偏移量,
startclientX2: 0, // 元素拖拽前距离浏览器的X轴位置
startclientY2: 0, // 元素拖拽前距离浏览器的Y轴位置
elLeft2: 0, // 元素的左偏移量
elTop2: 0, // 元素的右偏移量,
signShow: false,
sign2Show: false,
}
},
components: {
},
methods: {
// 页面初始化
initBodySize () {
this.initWidth = this.$refs.back_box.clientWidth // 拿到父元素宽
this.initHeight = this.initWidth * (1080 / 1920) // 根据宽计算高实现自适应
},
// 拖拽开始事件
dragstart (e) {
this.startclientX = e.clientX // 记录拖拽元素初始位置
this.startclientY = e.clientY
},
// 拖拽完成事件
dragend (e) {
let x = e.clientX - this.startclientX // 计算偏移量
let y = e.clientY - this.startclientY
this.elLeft += x // 实现拖拽元素随偏移量移动
this.elTop += y
},
// 拖拽开始事件
sign2dragstart (e) {
this.startclientX2 = e.clientX // 记录拖拽元素初始位置
this.startclientY2 = e.clientY
},
// 拖拽完成事件
sign2dragend (e) {
let x = e.clientX - this.startclientX2 // 计算偏移量
let y = e.clientY - this.startclientY2
this.elLeft2 += x // 实现拖拽元素随偏移量移动
this.elTop2 += y
}
},
mounted () {
this.initBodySize()
}
}
</script>
<style lang="less" scoped>
.page{
width: 100vw;
height: 100vh;
background-color: #fff;
display: flex;
justify-content: flex-start;
.left{
width: 20%;
height: 100%;
cursor: pointer;
border-right: 1px solid #eee;
.title{
font-size: 14px;
margin: 16px;
}
.img{
margin: 16px 50px 16px 16px;
img{
height: 100px;
}
}
}
.right{
width: 80%;
position: relative;
height: 100%;
.back_box {
background-image: url('./img/bg.png');
background-size: 100% 100%;
background-repeat: no-repeat;
width: 70%;
height: 60%;
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
margin: auto;
}
.drag_box {
width: 150px;
height: 50px;
background-image: url('./img/sign.png');
background-size: 100% 100%;
background-repeat: no-repeat;
position: absolute;
z-index: 10;
}
.drag_box2 {
width: 150px;
height: 150px;
background-image: url('./img/sign2.png');
background-size: 100% 100%;
background-repeat: no-repeat;
position: absolute;
z-index: 10;
}
}
}
</style>
第四章 扩展
- 如果该需求大家也需要应用时,如果后端做pdf,前后端首先确定一致的模板
- 前端需要做的是将签名、签章的位置向后端提供(注意前端传的位置必须的等比例的,如果前端模板被用户缩小窗口使用的,提供的位置就不准确了),需要将签名签章的拥有者向后端提供
- 如果后端不自己拿签名签章的图片,还需要将其路径向后端提供;如果图片的宽高用户可以手动控制,前端还需要对对图片的宽高进行处理,获取到宽高然后向后端提供——这里小编有两个方法:一个是通过鼠标滚轮对图片缩放从而控制图片大小(onwheel);另个一个是输入控制,小编后续的文章会谈到
- 如果直接让前端生成pdf,看该文章或许会有帮助:
需求:前端生成一个模板并盖章的pdf文件(单个文件自动下载+多文件生成压缩包下载以及window.print()),一个pdf多个分页进行处理(保证图片、表、文字能完整展示,截断问题解决)_❆VE❆的博客-CSDN博客