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

目录

第一章  效果展示

第二章  了解工具

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博客

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C#,数值计算——积分方程与逆理论,构造n点等间隔求积的权重的计算方法与源程序

1 文本格式 using System; namespace Legalsoft.Truffer { /// <summary> /// 构造n点等间隔求积的权重 /// Constructs weights for the n-point equal-interval quadrature /// from O to(n-1)h of a function f(x) times an arbitrary /// (pos…

十年JAVA搬砖路——Linux搭建Ldap服务器。

1.安装命令 yum -y install openldap compat-openldap openldap-clients openldap-servers openldap-servers-sql openldap-devel2.启动ldap systemctl start slapd systemctl enable slapd3.修改密码 slappasswd Aa123456获得返回的密码加密密码串&#xff1a; {SSHA}DkSw0…

免费(daoban)gpt,同时去除广告

一. 内容简介 免费(daoban)gpt&#xff0c;同时去除广告&#xff0c;https://chat18.aichatos.xyz/&#xff0c;也可当gpt用&#xff0c;就是有点广告&#xff0c;大家也可以支持一下 二. 软件环境 2.1 Tampermonkey 三.主要流程 3.1 创建javascript脚本 点击添加新脚本 …

2023第二届全国大学生数据分析大赛A题思路

某电商平台用户行为分析与挖掘 背景&#xff1a;电商是当今用户最大的交易市场之一&#xff0c;电商行业也逐渐成熟&#xff0c; 所有市场中可售卖的商品全都在平台中存在&#xff0c;并且在网络和疫情的影 响下&#xff0c;在线上的消费行为满足全年龄段用户。 用户的交易行为…

2023.11.4 Idea 配置国内 Maven 源

目录 配置国内 Maven 源 重新下载 jar 包 配置国内 Maven 源 <mirror><id>alimaven</id><name>aliyun maven</name><url>http://maven.aliyun.com/nexus/content/groups/public/</url><mirrorOf>central</mirrorOf> …

为你整理了一份抖音小店的高分打造指南

抖音小店是一种在抖音平台上运营的电商店铺。通过打造一个高分店铺&#xff0c;可以吸引更多用户关注和购买&#xff0c;提升销售业绩。下面四川不若与众将介绍一些打造高分店铺的方法。 首先&#xff0c;店铺名称和简介要吸引眼球。店铺名称应该简洁明了&#xff0c;容易被记住…

curl(六)DNS解析、认证、代理

一 DNS解析 ① ip协议 使用ipv4 [-4] 还是ipv6 [-6] ② --resolve 场景&#xff1a; 在不修改系统配置文件 /etc/hosts 的情况下将单个请求临时固定到 ip 地址 1、使用 * 作为通配符,这样请求中调用的所有 Host 都 会转到你指定的 ip curl https://www.wzj.com --resolv…

王道p18 6.从有序顺序表中删除所有其值重复的元素,使表中所有元素的值均不同(c语言代码实现)

视频讲解在这里&#xff1a;&#x1f447; 顺序表p18 第6题wd数据结构课后代码题&#xff08;c语言代码实现&#xff09;_哔哩哔哩_bilibili 本题代码如下 void deleterepeat(struct sqlist* L) {if (L->length 0)printf("表空");int i 0;int k 0;for (i 1…

【软著写作】软著写作过程记录

文章目录 整体流程图&#xff1a;写在前面&#xff1a;一、准备材料1 准备材料2 申请盖章 二、软件登记1 注册账号2 填报软著 整体流程图&#xff1a; 写在前面&#xff1a; 这两天填报了一篇软著&#xff0c;正好将以前第一次填报时&#xff0c;踩的一些坑和过程记录了一下&am…

破解密码 LLM(代码LLM如何从 RNN 发展到 Transformer)

舒巴姆阿加瓦尔 一、说明 近年来&#xff0c;随着 Transformer 的引入&#xff0c;语言模型发生了显着的演变&#xff0c;它彻底改变了我们执行日常任务的方式&#xff0c;例如编写电子邮件、创建文档、搜索网络甚至编码方式。随着研究人员在代码智能任务中应用大型语言模型&am…

[每周一更]-(第70期):常用的GIT操作命令

1、增删文件 # 添加当前目录的所有文件到暂存区 $ git add .# 添加指定文件到暂存区 $ git add <file1> <file2> ...# 添加指定目录到暂存区&#xff0c;包括其子目录 $ git add <dir># 删除工作区文件&#xff0c;并且将这次删除放入暂存区 $ git rm [file…

Redis中的List类型

目录 List类型的命令 lpush lpushx rpush lrange lpop rpop lindex linsert llen lrem ltrim lset 阻塞命令 阻塞命令的使用场景 1.针对一个非空的列表进行操作 2.针对一个空的列表进行操作 3.针对多个key进行操作. 内部编码 lisi类型的应用场景 存储(班级…

SpringSecurity全家桶 (一) —— 简介

1. 概述 Spring Security 是一个框架&#xff0c;提供针对常见攻击的身份验证、授权和保护。 它为保护命令式和响应式应用程序提供了一流的支持&#xff0c;是保护基于 Spring 的应用程序的事实标准。 2. 了解 shiro&#xff1a; 在之前SSM框架盛行的时代&#xff0c;项目的…

C++入门讲解第一篇

大家好&#xff0c;我是Dark Fire&#xff0c;终于进入了C的学习&#xff0c;我知道面对我的将是什么&#xff0c;就算变成秃头佬&#xff0c;也要把C学好&#xff0c;今天是C入门第一篇&#xff0c;我会尽全力将知识以清晰易懂的方式表达出&#xff0c;希望我们一起加油&#…

奇元大模型通过备案 360自研两大模型均获批

11月4日&#xff0c;三六零(601360.SH&#xff0c;下称“360”)大模型“奇元大模型”通过备案落地。今年9月&#xff0c;“360智脑大模型”已获批面向公众开放。360公司也成为国内首家两个大模型均通过备案的科技企业。 从大模型定位和应用角度来看&#xff0c;奇元大模型具备…

Vert.x学习笔记-Vert.x的基本处理单元Verticle

Verticle介绍 Verticle是Vert.x的基本处理单元&#xff0c;Vert.x应用程序中存在着处理各种事件的处理单元&#xff0c;比如负责HTTP API响应请求的处理单元、负责数据库存取的处理单元、负责向第三方发送请求的处理单元。Verticle就是对这些功能单元的封装&#xff0c;Vertic…

UI设计感蓝色商务数据后台网站模板源码

蓝色商务数据后台网站模板是一款适合网站模板下载。提示&#xff1a;本模板调用到谷歌字体库&#xff0c;可能会出现页面打开比较缓慢。 演示下载 qnziyw点cn/wysc/qdmb/20852点html

自动驾驶行业观察之2023上海车展-----智驾供应链(3)

智驾解决方案商发展 华为&#xff1a;五项重磅技术更新&#xff0c;重点发布华为ADS 2.0和鸿蒙OS 3.0 1&#xff09;产品方案&#xff1a;五大解决方案都有了全面的升级&#xff0c;分别推出了ADS 2.0、鸿蒙OS 3.0、iDVP智能汽车数字平台、智能车云服务和华为车载光最新 产品…

spring boot导入导出excel,集成EasyExcel

一、安装依赖 <dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>3.3.2</version></dependency>二、新建导出工具类 package com.example.springbootclickhouse.utils;import javax.s…

R语言657中单色colors颜色索引表---全平台可用

R语言657中单色colors颜色索引表—全平台可用