vue需求:实现签章/签字在页面上自由定位的功能(本质:元素在页面上的拖拽)

news2024/11/27 23:33:20

目录

第一章  效果展示

第二章  了解工具

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->dragoverdrag->drag…的原因也是在拖拽的过程中,节点由原来的节点上方范围内到范围外之后只有drag触发,dragover不触发,最后松开鼠标,拖拽结束了,触发dragend
  •  至于为什么drop没有触发,这里请看文档的实例,如下。(小编理解是,该事件应该在存放的目标模板中使用,而不是自身)

HTML draggable 属性 | 菜鸟教程

  • event的参数(小编就不一一说明了,这里用到clientX和clientY计算偏移量的)

 

第三章 效果实现

3.1 实现思路

  • 三个元素:签名、签章已经模板
  • 页面布局,初步样式控制,小编的样式:(为了方便,小编模板用的图片-->大家用源代码时记得替换)

  •  点击左边的签名,右边模板出现对应的签名,签章同理,利用定位让签章与签名都在模板的左上角
  • 拖拽开始时记录一次最开始的位置
  • 拖拽结束鼠标松开时再记录一次位置
  • 利用两个位置的差计算偏移量
  • 最后再次利用定位top和left将签名和签章固定到模板上

3.2 代码实现

3.2.1 涉及到的点

  • 使用dragstart和dragend记录拖拽元素初始位置和结束位置
  • 利用宽高比例进行页面初始化(正常屏幕宽高1920*1080,根据需求初始化)
  • 了解一下
  1. clientX:当鼠标事件发生时(不管是onclick,还是omousemovenmouseover等),鼠标对于浏览器(这里说的是浏览器的有效区域)x抽的置
  2. clientY:当鼠标事件发生时,鼠标相对于浏览器(这里说的是浏览器的有效区域)y轴的位置;
  3. screenX:当鼠标事件发生时,鼠标相对于显示器屏幕x轴的位置;
  4. screenY:当鼠标事件发生时,鼠标相对于显示器屏幕y轴的位置;
  5. offsetX:当鼠标事件发生时,鼠标相对于事件源x轴的位置(这里的事件源是上一个有定位的父级标签)
  6. 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博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1166705.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Windows Server 2016使用MBR2GPT.EXE教程!

什么是MBR2GPT.exe&#xff1f; MBR2GPT.exe是微软提供的专业工具&#xff0c;可在命令提示符下运行。使用该工具可以将引导磁盘从MBR转换为GPT分区样式&#xff0c;而无需修改或删除所选磁盘上的任何内容。 在Windows Server 2019和Windows 10&#xff08;1703…

Redis的介绍,以及Redis的安装(本机windows版,虚拟机Linux版)和Redis常用命令的介绍

目录 一. Redis简介 二. Redis的安装 2.1 Linux版安装 2.2 windows版安装 三. Redis的常用命令 一. Redis简介 Redis是一个开源&#xff08;BSD许可&#xff09;&#xff0c;内存存储的数据结构服务器&#xff0c;可用作数据库&#xff0c;高速缓存和消息队列代理。 它…

蓝凌EIS智慧协同平台任意文件上传漏洞

蓝凌EIS智慧协同平台任意文件上传漏洞 免责声明漏洞描述漏洞影响漏洞危害网络测绘Fofa: icon_hash"953405444" 漏洞复现1.构造poc2. 发送数据包&#xff0c;获取文件路径3. 访问webshellwebshell地址&#xff1a; 免责声明 仅用于技术交流,目的是向相关安全人员展示…

多用户商城系统对比 多用户商城系统哪个好

大环境越来越好&#xff0c;企业纷纷将消费者引入自己建设的独立商城&#xff0c;如零食行业的良品铺子、三只松鼠&#xff0c;从而打造属于自己的IP形象。此时&#xff0c;挑选一款优秀的商城源码是企业的不二之选。这里将国内三大优秀的多用户商城系统进行对比&#xff0c;以…

OpenAI最新官方GPT最佳实践指南,一文讲清ChatGPT的Prompt玩法

原文&#xff1a;Sina Visitor System OpenAI的官网发表万字GPT最佳实践指南&#xff0c;讲清Prompt提示词的原则和策略&#xff0c;这里是总结和全文翻译 原创图像&#xff0c;AI辅助生成 OpenAI的官网上刚刚发表一篇万字的GPT最佳实践指南&#xff0c;这份指南把写好Promp…

闯关打卡小程序的效果如何

闯关打卡是一种以任务关卡为基础的打卡模式&#xff0c;管理员可配置活动任务关卡&#xff0c;成员加入任务后需依次解锁&#xff0c;打卡完成任务&#xff0c;像闯关游戏一样完成所有任务。 通过打卡活动聚集一群有共同目标、兴趣的人&#xff0c;通过打卡的方式促进共同目标…

青翼科技-国产化ARM系列TES720D-KIT

板卡概述 TES720D-KIT是专门针对我司TES720D&#xff08;基于复旦微FMQL20S400的全国产化ARM核心板&#xff09;的一套开发套件&#xff0c;它包含1个TES720D核心板&#xff0c;加上一个TES720D-EXT扩展底板。 FMQL20S400是复旦微电子研制的全可编程融合芯片&#xff0c;在单…

pandas交换行

今天遇到了一个问题&#xff0c;就是adata在拼接细胞类型的obs时&#xff0c;两者的index是不对应的&#xff0c;需要把两者的index进行对齐&#xff0c;下面是一些测试的代码 import pandas as pd list_test [[1,2,3],[4,5,6],[7,8,9]] index_colums [A,B,C] index_row [a,…

英国 AI 安全峰会前瞻:为什么是现在,为什么在英国

撰文&#xff1a;Ingrid Lunden 来源&#xff1a;TechCrunch 图片来源&#xff1a;由无界AI生成 人工智能的前景和危害是如今的热门话题。有人说人工智能将拯救我们&#xff0c;可以帮助诊断一些恶性疾病、弥补教育领域的数字鸿沟等。但也有人担心它在战争、安全、错误信息等方…

谷歌推出基于AI的产品图像生成工具;[微软免费课程:12堂课入门生成式AI

&#x1f989; AI新闻 &#x1f680; 谷歌推出基于AI的产品图像生成工具&#xff0c;帮助商家提升广告创意能力 摘要&#xff1a;谷歌推出了一套基于AI的产品图像生成工具&#xff0c;使商家能够利用该工具免费创建新的产品图像。该工具可以帮助商家进行简单任务&#xff08;…

STP、RSTP、MSTP作用及区别?

一、STP 1 基本概念 STP&#xff08;Spanning Tree Protocol&#xff09;即IEEE 802.1D&#xff0c;其作用主要有三个&#xff0c;第一是eliminate logical loops消除逻辑环&#xff0c;第二自动选取最有效的网络路径&#xff0c;第三是当某条链路失效时&#xff0c;自动切换…

苹果M3 Max芯片跑分曝光:GPU性能不及M2 Ultra

驱动中国2023年11月2日消息&#xff0c;近日&#xff0c;据外媒报道&#xff0c;在苹果 M3 芯片现身 GeekBench 跑分库之后&#xff0c;M3 Max 芯片也出现在该跑分平台上。 据悉&#xff0c;搭载 M3 Max 芯片的设备标识符为 Mac15,9&#xff0c;目前共有 4 条信息&#xff0c;其…

phpstudy_2016-2018_rce

phpstudy_2016-2018_rce 代码 import base64 import requests import sysbanner""" PHPStudy_2016-2018( ) ( ) ( ) | |_ _ _ ___ | |/) _| | _ _ _ __ | _\ /_ ) /___)| , < /_ | /_…

淘宝商品评论API接口(评论内容|日期|买家昵称|追评内容|评论图片|评论视频..)

淘宝商品评论API接口是淘宝开放平台提供的一种API接口&#xff0c;可以帮助开发者获取淘宝平台上的商品评论数据。 要使用淘宝商品评论API接口&#xff0c;需要进行以下步骤&#xff1a; 注册淘宝开放平台账号&#xff0c;创建应用并获取App Key和App Secret等信息。确定需要…

操作系统 day05(进程)

一&#xff0c;进程的概念 进程和程序的区别 如下图所示&#xff1a;通过多次点击QQ程序&#xff0c;可以打开多个QQ进程 二&#xff0c;进程的组成&#xff08;更准确的说&#xff0c;应该是进程实体的组成&#xff09; PCB PCB是进程存在的唯一标志&#xff0c;当进…

鉴源论坛 · 观模丨软件单元测试真的有必要吗?(上)

作者 | 包丹珠 上海控安产品总监 版块 | 鉴源论坛 观模 社群 | 添加微信号“TICPShanghai”加入“上海控安51fusa安全社区” “软件单元测试真的有必要吗&#xff1f;”专题将分为上下两期&#xff0c;深度详解软件单元测试的重要意义&#xff0c;分享目前行业内进行的单元测…

Python接口自动化测试实战,一篇足矣

接口自动化测试是指通过编写程序来模拟用户的行为&#xff0c;对接口进行自动化测试。Python是一种流行的编程语言&#xff0c;它在接口自动化测试中得到了广泛应用。下面详细介绍Python接口自动化测试实战。 1、接口自动化测试框架 在Python接口自动化测试中&#xff0c;我们…

vuepress使用及拓展(骚操作)

官网 文章目录 背景问题思考方案思索实现方案实现结果存在问题 背景 当前开放平台文件静态保存在前端项目&#xff0c;每次修改都需要通过修改文件发版的方式&#xff0c;很不便利。 1、需要前端手动维护 2、每次小的修改都要发版 随着对接业务的增多&#xff0c;对接文档的变…

什么是运营商精准大数据?又有什么作用?

大数据&#xff08;big data&#xff09;&#xff0c;指无法在一定时间范围内用常规软件工具进行捕捉、管理和处理的数据集合&#xff0c;是需要新处理模式才能具有更强的决策力、洞察发现力和流程优化能力的海量、高增长率和多样化的信息资产。 精准大数据&#xff0c;是一种…

KaiwuDB 内核解析 - SQL 查询的生命周期

一、概述 KaiwuDB 内核解析系列共分上下两部分&#xff0c;本文是该系列的第一部分&#xff0c;主要涵盖了网络协议到 SQL 执行器&#xff0c;解释 KaiwuDB 如何执行 SQL 查询&#xff0c;包括系统各个组件的执行路径&#xff08;网络协议、SQL 会话管理、解析器、执行计划及优…