element-tiptap和vuedraggable的拖拽冲突

news2024/11/24 2:49:32

今天写项目的时候,遇到一个问题,分享给大家。

场景

我有一个A区域,还有一个B区域。A区域内的Vue组件可以通过Vuedraggable这个框架来拖拽到B区域中。B区域内的Vue组件在标题上使用了element-tiptap组件(用来高级编辑)。然而如果B区与内存在使用了element-tiptap组件的组件。就会出现把 A区域中组件的文本内容拖拽到element-tiptap中。

其实我想要的创建新的组件,而它把我拖拽的组件的文本内容添加到了组件中的element-tiptap中。

问题分析

HTML元素设置了contenteditable="true"之后,或者input输入框之间,默认都是可以把选中的文字拖拽到其他的input的元素或者contenteditable="true"的元素中。

我要做的就是禁止其他页面元素把文本内容拖拽到element-tiptap的组件中,element-tiptap组件的原理就是用的contenteditable="true"来实现高级编辑。

我自己写了一个组件案例,用来验证是否contenteditable="true"的情况下,能通过重写drop事件禁止拖拽:

<script>
//导入自定义的组件
import DragDIV from "@/components/DragDIV";
/* eslint-disable */
export default {
  name: 'App',
  components:{
    DragDIV
  },
  mounted() {
    //根据class类名动态的添加drop事件
    const divs = document.getElementsByClassName('content')
    console.log(divs.length)
    for (var i=0;i<divs.length; i++) {
      let c_item=divs[i]
      console.log(c_item.innerHTML)
      c_item.addEventListener("drop",(e)=>{
        console.log('chesse')
        e.preventDefault()
      })
    }
  }
}
</script>
<template>
    <!--引用自定义的组件-->
  <DragDIV />
</template>

 自定义组件:DragDiv.vue

<template>
  <div  contenteditable="true" class="content"><p>
    姐姐,为什么要告诉这楚枫你的身份?风铃对里雾问道他今日既然帮了忙,之前的恩怨,自然要化解。
    与其日后被他发现,还不如我先告诉他。里雾说道我记得你说过他,但你当时不是说,他是你在祖武天河,遇到的小角色吗?
    那为何这次遇到,你却又突然告知于我,他可以帮我破阵呢?风铃对里雾问道她与楚枫第一次见面,便是在那行宫之内,但其实在她见到楚枫之前
    就已经收到了里雾的通知告关于楚枫要去那行宫,以及楚枫有些特别,风铃可以尝试利用楚枫破解行宫考验等事刚好诅咒之力发作,
    楚枫出手相助,虽然只是化解了表面症状,但能做到这一点已经很不简单。</p>
  </div>
  <div contenteditable="true" @click="handleClick"  class="content">
    <p>人生何处不相逢</p>
  </div>
</template>

<script>
export default {
  name: "DragDIV",
  methods:{
    handleClick(e){
      console.log('handleClick')
      // e.currentTarget.setAttribute("contenteditable",true)
    },
    handleMouse(e){
      // e.currentTarget.setAttribute("contenteditable",false)
    }
  }
}
</script>

<style scoped>
.content{
  width:400px;
  height:800px;
  -webkit-user-drag: none;
  /*margin:0 auto;*/
  float: left;
  border:2px solid lightgrey;
}
</style>

实际是生效的,可以通过这种方式来解决这个问题。所以我应该找的是drop事件相关的配置。这里我想了很多方法:

1. 查找element-tiptap 官方文档和源代码,看看有没有相关的组件配置,用来防止其他页面元素拖拽文件进来。onDrop方法前后打印当前的值,结果是相同的,无法解决当前问题。

2. csdn站内包括其他网站的解决方案:把HTML元素的draggable="false",我加上试了没有生效。并没有修改drop事件的处理函数。element-tiptap中自定义了drop事件的处理函数。

3. 实在没办法,只能通过浏览器Debug去分析它的加载流程,包括事件的处理顺序,找到了element-tiptap中,设置contenteditable="true"的div,类名是:ProseMirror,它上面加了两个drop事件的处理函数,对应到它框架代码:

editHandlers.drop = (view, _event) => {
    let event = _event;
    let dragging = view.dragging;
    view.dragging = null;
    if (!event.dataTransfer)
        return;
    let eventPos = view.posAtCoords(eventCoords(event));
    if (!eventPos)
        return;
    let $mouse = view.state.doc.resolve(eventPos.pos);
    let slice = dragging && dragging.slice;
    if (slice) {
        view.someProp("transformPasted", f => { slice = f(slice); });
    }
    else {
        slice = parseFromClipboard(view, event.dataTransfer.getData(brokenClipboardAPI ? "Text" : "text/plain"), brokenClipboardAPI ? null : event.dataTransfer.getData("text/html"), false, $mouse);
    }
    let move = !!(dragging && !event[dragCopyModifier]);
    if (view.someProp("handleDrop", f => f(view, event, slice || Slice.empty, move))) {
        event.preventDefault();
        return;
    }
    if (!slice)
        return;
    event.preventDefault();
    let insertPos = slice ? dropPoint(view.state.doc, $mouse.pos, slice) : $mouse.pos;
    if (insertPos == null)
        insertPos = $mouse.pos;
    let tr = view.state.tr;
    if (move)
        tr.deleteSelection();
    let pos = tr.mapping.map(insertPos);
    let isNode = slice.openStart == 0 && slice.openEnd == 0 && slice.content.childCount == 1;
    let beforeInsert = tr.doc;
    if (isNode)
        tr.replaceRangeWith(pos, pos, slice.content.firstChild);
    else
        tr.replaceRange(pos, pos, slice);
    if (tr.doc.eq(beforeInsert))
        return;
    let $pos = tr.doc.resolve(pos);
    if (isNode && NodeSelection.isSelectable(slice.content.firstChild) &&
        $pos.nodeAfter && $pos.nodeAfter.sameMarkup(slice.content.firstChild)) {
        tr.setSelection(new NodeSelection($pos));
    }
    else {
        let end = tr.mapping.map(insertPos);
        tr.mapping.maps[tr.mapping.maps.length - 1].forEach((_from, _to, _newFrom, newTo) => end = newTo);
        tr.setSelection(selectionBetween(view, $pos, tr.doc.resolve(end)));
    }
    view.focus();
    view.dispatch(tr.setMeta("uiEvent", "drop"));
};

这里可以看到它的处理流程还是很复杂,我的需求里面没有拖拽文本到B区域中组件的需求,所以这个事件处理函数可以在它的框架代码中删除。

但是项目下有很多的依赖,暂时只能通过如下方法来解决这个问题:(跳过element-tiptap中的drop事件处理函数)

prosemirror-view/dist/index.js:3403行下加入return; 

总结

1. 前端框架的很多高级特性都基于HTML中不常见的属性来实现,在使用框架过程中,应该多去看看它的实现原理,分析关键代码。

2. 编写简洁的代码。

3. 虽然是前端的框架,但是现在很多框架都是用TypeScript来实现,也是有OOP的实践在里面,要多考虑对象的行为和特性,不能把对象属性都暴露,也不能都不暴露。

4. 复用的可能,如果一个框架中组件的复用度不高,引入这个框架,对于项目的后期维护非常不利,想弃用,有依赖 。想重写,需要兼容。

参考:

GitHub - Leecason/element-tiptap: 🌸A modern WYSIWYG rich-text editor using tiptap and Element UI for Vue2 (🚀 tiptap2 and Vue3 is in alpha)

https://github.com/ueberdosis/tiptap

draggable - HTML(超文本标记语言) | MDN

contenteditable - HTML(超文本标记语言) | MDN

欢迎大家私信,留言学习交流。

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

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

相关文章

上海发布:应对产业封锁,出台硬核政策扶持集成电路,最高奖励3000万!

上海张江科学城&#xff0c;聚集了全上海超六成集成电路企业 前 言 11月23日&#xff0c;上海市经济信息化委、市财政局发布了关于印发 《上海市集成电路和软件企业核心团队专项奖励办法》的通知。 该文件提出&#xff0c;上海市将在未来5年&#xff0c;对符合要求的集成电路和…

idea打包springboot项目成 docker 镜像方法 (详细)

idea打包springboot项目 详细方法 么有比这个更详细的了 双击package 生成.jar文件 文件生成位置如下图 将041-springboot-thymeleaf-1.0.0.jar 上传到/root/myspringboot文件夹中 默认已经安装好docker linux 操作 cd /root/myspringboot vim Dockerfile bash From openjd…

【leetcode】2273. 移除字母异位词后的结果数组(js实现)

1. 题目 https://leetcode.cn/problems/find-resultant-array-after-removing-anagrams/description/?languageTagsjavascript 2. 思路 对于每个单词&#xff0c;用哈希表统计每个字符出现的次数&#xff0c;前后两个字母进行比较。如果比较以后发现是字母异位词&#xff…

详解设计模式:策略模式

策略模式&#xff08;Strategy Pattern&#xff09;也被称为政策模式&#xff08;Policy Pattern&#xff09;&#xff0c;是在 GoF 23 种设计模式中定义了的行为型模式。 策略模式 是针对一组算法&#xff0c;将每一个算法封装到具有共同接口的独立的类中&#xff0c;使得它们…

BiLSTM-CRF模型 我必须要你能看懂

文章目录BER任务介绍BiLSTM模型介绍----------------------------------------------------------------------------------------------------模型细节如果没有CRF层会是什么样CRF 层CRF原理&#xff1a;一、CRF基础1、条件概率2、图、无向图3、概率图4、马尔可夫性5、概率无向…

rpm包常用命令指南

目录 rpm包查看一般命令 查看系统已安装软件相关命令 卸载rpm包 按照yum源的repo 卸载软件 查询系统已安装的rpm包 查询系统中一个已知的文件属于哪个rpm包 查询已安装的软件包的相关文件的安装路径 查询一个已安装软件包的信息 查看已安装软件的配置文件 查看已安装软…

一文带你走进网络编程

网络编程 什么是网络编程: 就是用来实现网络互通的不同计算机运行程序之间进行数据的交换的编程 网络模型 OSI(模型):七层协议 应用层: 如: HTTP协议 主要解决如何包装数据&#xff0c;用于通信的应用程序和用于消息传输的底层网络提供接口&#xff0c;提供常见的网络应用…

VM系列振弦采集模块全频段扫频

VM系列振弦采集模块全频段扫频 根据起始频率与终止频率范围&#xff0c;频率由低向高向传感器发送渐进的扫频激励信号&#xff0c;直到传感器产生共振并返回共振电流信号。在输出激励信号的过程中&#xff0c;激励信号的频率变化由频率步进和信号周期数量决定。 此激励方法较为…

Day2--使用ESP32双核、U8G2 OLED任务、任务以绝对频率运行、任务内存优化

使用ESP32双核 ESP32-C系列为单核&#xff0c;ESP32的core0主要运行WI-FI和蓝牙 API: xPortGetCoreID() 获取当前任务运行的核心 xTaskCreate() 有系统选择运行核心&#xff0c;优先选择0 xTaskCreatePinnedToCore() 指派任何给指定核心 Arduino的setup和loop默认运行在core1 …

初识Thread类与创建多线程的方法

目录 1.创建一个线程 2.start()方法与run()方法 3.查看线程 4.创建线程的各种方法 4.1实现Runnable接口 4.2使用匿名内部类 4.3使用匿名内部类,实现Runnable 4.4使用Lambda表达式 1.创建一个线程 Java操作线程最核心的类就是Thread类 创建线程有很多方法,下面我们写一…

[附源码]计算机毕业设计springboot人体健康管理app

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

SpringBoot结合XXL-JOB实现定时任务

《从零打造项目》系列文章 工具 比MyBatis Generator更强大的代码生成器 ORM框架选型 SpringBoot项目基础设施搭建SpringBoot集成Mybatis项目实操SpringBoot集成MybatisPlus项目实操SpringBoot集成Spring Data JPA项目实操 数据库变更管理 数据库变更管理&#xff1a;Liquibase…

阿里自爆秋招面试笔记,福音来了

前言 最近又掀起了一股面试招聘风潮&#xff0c;我们一边要巩固基础知识、备战试题的同时&#xff0c;另外与面试官的对达沟通也直接影响你的成功与否&#xff01;那我们应该如何做好准备呢&#xff1f; ​先说面试过程&#xff0c;今天阿鑫给大家整理了这三个小经验&#xf…

笔试强训Day2

选择题 1. 思路&#xff1a;e是按指数类型输出&#xff0c;f是按照浮点数类型输出&#xff08;输出只有f不用lf&#xff09; 输出默认是右对齐&#xff0c;-则是左对齐&#xff0c;四位精度就是小数点后保留几位用.4&#xff0c;输出字符数用整数30在小数点前表示即可。 如果…

MySQL数据库复习——索引

目录 一、什么是索引&#xff1f;索引的作用 二、索引的简单使用 三、索引背后的数据结构 1、B 树 2、B 树 一、什么是索引&#xff1f;索引的作用 索引是一种特殊的文件&#xff0c;包含着对数据表里所有记录的引用指针。可以对表中的一列或多列创建索引&#xff0c;并指…

Nacos 配置中心

1. 什么是配置中心 1.1 什么是配置 应用程序在启动和运行的时候往往需要读取一些配置信息&#xff0c;配置基本上伴随着应用程序的整个生命周期&#xff0c;比如&#xff1a;数据库连接参数、启动参数等。 配置主要有以下几个特点&#xff1a; 配置是独立于程序的只读变…

java基础讲义03

java基础讲义一 流程控制1.1流程控制语句介绍1.2顺序结构二 选择控制2.1 选择结构介绍2.2 选择语句if2.2.1 格式12.2.2 if格式22.2.3 if格式32.3 选择语句switch2.3.1 switch语句介绍2.3.2 switch注意事项2.3.3 switch面试题2.3.4 if语句与switch语句区别三 循环语句3.1 循环语…

Yolov5 计算访存量MAC与计算量FLOPS

说明&#xff1a;因为yolov5函数中已经计算了 FLOPS&#xff0c;因此如果想要计算访存量那么只需按照flops的位置,添加访存量的计算即可 一、先记住计算量和访存量的公式&#xff1a; 二、找到计算FLOPS的位置&#xff0c;并添加访存量 yolov5中计算flops的位置在torch_utile…

微服务外交官-Feign

引言 书接上篇 负载均衡组件Ribbon核心-LoadBalanced-下 我们讲完了Ribbon负载均衡原理之后&#xff0c;接下讲一个SpringCloud Alibaba新的组件&#xff1a;Fegin 前面章节我们使用Ribbon方式实现负载均衡版的远程调用&#xff0c; //方案4&#xff1a;使用Ribbon方式--带负…

不知道10年老电脑如何重装系统?其实很简单

肯定很多朋友家里都有一两台吃灰的10年老电脑了&#xff0c;当我们有空可以把它拿出来耍耍的时候&#xff0c;却发现电脑无法开机了&#xff0c;想拿去修又觉得不太值得。其实我们可以先试着给电脑重装系统&#xff0c;这样也能先排查系统是否有问题。如果你不知道这台10年老电…