Vue3问题:如何实现组件拖拽实时预览功能?

前端功能问题系列文章,点击上方合集↑

序言

大家好,我是大澈!

本文约3000+字,整篇阅读大约需要5分钟。

本文主要内容分三部分,第一部分是需求分析,第二部分是实现步骤,第三部分是问题详解。

如果您只需要解决问题,请阅读第一、二部分即可。

如果您有更多时间,进一步学习问题相关知识点,请阅读至第三部分。

1. 需求分析

实现一个CMS内容管理系统,在后台进行内容编辑,在官网更新展示内容。

关于后台的编辑功能,大致分为两部分:组件拖拽预览组件内容编辑实时预览

对于组件拖拽预览,用户可以在含有各种功能组件的列表中,选择需要的组件进行拖拽。将组件拖拽到预览画布中后,可以在画布中预览组件的内容。

对于组件内容编辑实时预览,用户可以点击编辑按钮,显示对应组件的内容编辑信息。当修改组件内容时,在画布中可以实时预览组件的变化。

图片

图片

2. 实现步骤

2.1 关于拖拽组件库的选择

关于拖拽组件库,在github上有很多,最热门的当属vuedraggable这个库。

它基于Sortable.js,拥有完整的中文文档,所以很多朋友在做拖拽功能时,都会优先考虑它。

图片

但是,我在使用的过程中,在组件拖拽、取消组件拖拽这里,遇到了一些小问题。不知道是我操作的问题,还是库本身存在BUG,所以最终没有选用它。

于是我发现了,一个更加好用的拖拽库vue-draggable-next

图片

它的出现是参考了vuedraggable这个库,所以说很多用法很相似,但是使用起来较之更加友善。总结为一个词,自由。

下面我们的拖拽功能实现,就是利用了vue-draggable-next这个库。

如果你对拖拽底层原理感兴趣,并且有空余时间,劳请阅至第三部分拖拽原理总结。

2.2 拖拽功能代码实例

模版和逻辑中代码都分为了三部分:组件列表预览画布内容编辑

布局时,样式根据需求自定义,此处只是提供了功能的基本逻辑实现。

使用时,关于拖拽组件的需求,根据文档中提供的属性和事件的描述,灵活配置完善。

vue-draggable-next库文档地址:https://github.com/anish2690/vue-draggable-next

安装依赖:

npm install vue-draggable-next
//or
yarn add vue-draggable-next

模板代码:

<template><div style="display: flex;cursor: pointer;"><!-- 组件列表 左侧 --><div style="width:30vw;padding:30px;height:300px;border: 1px solid #000;text-align: center"><h1>组件列表</h1><VueDraggableNext :list="componentNameList" :group="{ name: 'people', pull: 'clone', put: false }" :sort="false"><div v-for="element in componentNameList" :key="element.name"><div style="padding: 10px;background: #ccc;margin-bottom: 10px"><el-button> {{ element.name }}</el-button></div></div></VueDraggableNext></div><!-- 预览画布 中间 --><div style="width:30vw;padding:30px;height:300px;border: 1px solid #000;text-align: center"><h1>预览画布</h1><VueDraggableNext :list="componentList" group="people" :sort="false"><div v-for="(element, index) in componentList" :key="element.name"><div><el-button @click="changeComponent(element)" size="small">编辑</el-button><el-button @click="deleteComponent(index)" size="small">删除</el-button></div><component :is="element.component" :details="element.details"></component></div></VueDraggableNext></div><!-- 内容编辑 右侧 --><div style="width:30vw;padding:30px;height:300px;border: 1px solid #000;text-align: center"><h1>内容编辑</h1><div v-for="(nowDetails, index) in nowComponentDetail.details" :key="index">{{ nowDetails.key }}: <el-input clearable v-model="nowDetails.value" /></div></div></div></template>

逻辑代码:

<script setup>
import {markRaw, reactive, ref, watch, nextTick} from "vue";
// 引入需要拖拽的组件
import About from "@/views/AboutView.vue"
// 引入拖拽库
import { VueDraggableNext } from "vue-draggable-next";// 组件列表数据
const componentNameList = [{// 组件IDcomponentId:0,// 组件名name:'关于组件',// 组件描述description: '关于组件',// 组件信息component: markRaw(About),// 组件需要编辑内容details: About.props.details.default},{componentId:1,name:'关于组件1',description: '关于组件1',component:markRaw(About),details: About.props.details.default},
];// 预览画布数据
let componentList = reactive([]);watch(componentList, () => {console.log(componentList, 'componentList')
})// 画布中删除的点击事件
const deleteComponent = (index) => {componentList.splice(index, 1);
};// 内容编辑数据
let nowComponentDetail = ref({});// 画布中编辑的点击事件
const changeComponent = (element) => {nowComponentDetail.value = element;
};
</script>

2.3 功能组件代码实例(参考)

此处提供了组件列表中,任意功能组件的编写实例,组件的具体功能根据需求自定义。

特别注意,组件Propsdetails对象属性的结构写法,要灵活应用。

模版代码:

<template><div style="padding: 10px;background: pink;margin-bottom: 10px">{{ props.details.content }}</div>
</template>

逻辑代码:

<script setup>
import { defineProps } from "vue";const props = defineProps({details: {type: Object,default: {content: {key: '内容',value: "我是About",},}}
})
</script>

3. 问题详解

3.1 拖拽实现的底层原理

拖拽的实现原理可以简单描述为以下几个步骤:

  • 触发拖拽:通过监听鼠标或触摸事件,当用户按下鼠标左键或触摸屏幕时,表示开始拖拽操作。

  • 记录拖拽信息:在拖拽开始时,记录拖拽起始位置(鼠标或触摸点的坐标),以及需要拖拽的元素的初始位置(相对于文档的坐标)。

  • 更新拖拽元素位置:在拖拽过程中,通过监听鼠标移动或触摸滑动事件,计算鼠标或触摸点的当前位置,并根据鼠标或触摸点的位置变化,更新拖拽元素的位置。这可以通过修改元素的 CSS 属性(如 left 和 top)或使用 CSS 变换(如 translateX 和 translateY)来实现。

  • 处理拖拽结束:当用户释放鼠标左键或触摸结束时,表示拖拽结束。此时可以执行一些操作,如更新拖拽元素的最终位置、触发事件或回调函数等。

以下是拖拽实现的基本原理代码实例:

// 获取拖拽元素
const draggableElement = document.getElementById('draggable');// 记录拖拽起始位置和拖拽元素的初始位置
let startX, startY, initialX, initialY;// 监听鼠标按下事件
draggableElement.addEventListener('mousedown', dragStart);
draggableElement.addEventListener('touchstart', dragStart);// 监听鼠标移动事件
document.addEventListener('mousemove', drag);
document.addEventListener('touchmove', drag);// 监听鼠标释放事件
document.addEventListener('mouseup', dragEnd);
document.addEventListener('touchend', dragEnd);// 拖拽开始事件处理程序
function dragStart(event) {event.preventDefault();if (event.type === 'touchstart') {startX = event.touches[0].clientX;startY = event.touches[0].clientY;} else {startX = event.clientX;startY = event.clientY;}initialX = draggableElement.offsetLeft;initialY = draggableElement.offsetTop;
}// 拖拽事件处理程序
function drag(event) {event.preventDefault();if (event.type === 'touchmove') {const currentX = event.touches[0].clientX - startX;const currentY = event.touches[0].clientY - startY;draggableElement.style.left = initialX + currentX + 'px';draggableElement.style.top = initialY + currentY + 'px';} else {const currentX = event.clientX - startX;const currentY = event.clientY - startY;draggableElement.style.left = initialX + currentX + 'px';draggableElement.style.top = initialY + currentY + 'px';}
}// 拖拽结束事件处理程序
function dragEnd() {// 执行拖拽结束后的操作
}

3.2 关于vue-draggable-next 库的功能总结

vue-draggable-next 库特点和功能的补充说明:

  • 基于 Vue 3:vue-draggable-next 是为 Vue.js 3 版本设计的拖拽库,充分利用了 Vue 3 的响应式系统和组合式 API。

  • 轻量级和简单易用:该库的代码量较少,易于理解和使用。它提供了一组简单的指令和组件,可以轻松地将拖拽功能集成到 Vue.js 应用程序中。

  • 支持多种拖拽模式:vue-draggable-next 支持多种拖拽模式,包括自由拖拽、列表拖拽、网格拖拽等。您可以根据需求选择适合的拖拽模式。

  • 自定义拖拽样式和行为:该库允许您自定义拖拽元素的样式和行为。您可以定义拖拽时的样式、占位符元素、限制拖拽的范围等。

  • 事件和回调支持:vue-draggable-next 提供了一组事件和回调函数,可以在拖拽过程中监听和处理各种事件。例如,您可以监听拖拽开始、拖拽结束、拖拽元素排序等事件,并执行相应的操作。

  • 支持触摸设备:该库对触摸设备提供了良好的支持,可以在移动设备上实现流畅的拖拽交互。

结语

建立这个平台的初衷:

  • 打造一个仅包含前端问题的问答平台,让大家高效搜索处理同样问题。

  • 通过不断积累问题,一起练习逻辑思维,并顺便学习相关的知识点。

  • 遇到难题,遇到有共鸣的问题,一起讨论,一起沉淀,一起成长。

感谢关注微信公众号:“程序员大澈”,然后加入问答群,让我们一起解决实现所有BUG!

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

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

相关文章

FreeSWITCH mrcp-v2小记

最近得知有人受mrcp的困扰&#xff0c;于是写了这篇小文&#xff0c;希望能有所帮助 FreeSWITCH版本选择 目前当然选择1.10.10&#xff0c;不建议老版本&#xff0c;差别在于老版本用到的libmrcp比较旧&#xff0c;是1.2版本&#xff0c;bug比较多&#xff0c;有时会crash&am…

运维基础-Docker容器命令部署

Docker基础知识 安装问题-有podmanCentos8使用yum install docker -y时&#xff0c;默认安装的是podman-docker软件安装docker yum list installed | grep dockeryum -y remove xxxxDocker安装配置下载安装docker启动docker&#xff0c;并设置开机启动下载所需镜像 centos镜像进…

【报错】错误 C1004 :发现意外的文件尾

文章目录 情景在现出错原因解决方案问题解决 情景在现 出错原因 这个错误通常是由于您在源文件中漏写了某些括号或者分号&#xff0c;导致编译器在处理到文件末尾时发现没有遇到预期的符号。 解决方案 解决这个错误的方法是&#xff0c;打开您的源文件&#xff0c;仔细检查是否…

EMC Unity存储系统如何查看SSD的使用寿命

为什么要写这个博客&#xff1f; 客户对老的EMC unity的存储系统要扩容&#xff0c;如何确定SSD磁盘是全新的还是拆机二手的&#xff1f;很多时候客户还有一个奇葩的要求&#xff0c;就是要和5年前的磁盘PN一致&#xff0c;甚至要求固件版本一致&#xff0c;最关键的还要求是全…

docker 部署和supervisord管理守护进程的区别

docker 部署和supervisord管理守护进程的区别 Docker 部署和 supervisord 管理守护进程是两个不同的概念&#xff0c;但它们可以结合使用以确保在 Docker 容器内部运行的应用程序的可靠性和稳定性。下面是它们之间的主要区别&#xff1a; Docker 部署&#xff1a; 容器化部署&…

大数据(十):数据可视化(二)

专栏介绍 结合自身经验和内部资料总结的Python教程&#xff0c;每天3-5章&#xff0c;最短1个月就能全方位的完成Python的学习并进行实战开发&#xff0c;学完了定能成为大佬&#xff01;加油吧&#xff01;卷起来&#xff01; 全部文章请访问专栏&#xff1a;《Python全栈教…

Redis Sentinel 哨兵模式

Sentinel 哨兵模式 Redis Sentinel 官网 Redis 的 Sentinel 文档 -- Redis中国用户组&#xff08;CRUG&#xff09; Sentinel Redis 命令参考&#xff08;红色&#xff09; Sentinel 通过监控的方式获取主机的工作状态是否正常&#xff0c;当主机发生故障时&#xff0c; Senti…

校验验证码是否过期(定时刷新验证码)

需求&#xff1a; 我们在登录的时候会遇到通过接口请求验证码的操作&#xff0c;这里的验证码会有过期的时间&#xff0c;当我们验证码过期了&#xff0c;我们要进行重新刷新验证码。 我们这里根据后端返回的当前时间和过期时间判断&#xff0c;过期的时间超过了当前时间的时候…

校验 ChatGPT 4.0 真实性的三个经典问题:快速区分 GPT3.5 与 GPT4,并提供免费测试网站

现在已经有很多 ChatGPT 的套壳网站&#xff0c;以下分享验明 GPT-4 真身的三个经典问题&#xff0c;帮助你快速区分套壳网站背后到底用的是 GPT-3.5 还是 GPT-4。 大家可以在这个网站测试&#xff1a;https://ai.hxkj.vip&#xff0c;免登录可以问三条&#xff0c;登录之后无限…

vuepress使用及拓展(骚操作)

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

ch0_OSI 七层网络协议介绍

目录 概述 1、三网融合的概念 三网&#xff1a;电信网络、有线电视网络、计算机网络 概念&#xff1a;把上述三种网络融合成一种网络 2、计算机网络的定义、分类 定义&#xff1a;计算机网络是将地理位置不同的独立计算机系统&#xff0c;通过传输介质链接起来&#xff0c…

开发一款直播弹幕游戏需要多少钱?

开发一款直播弹幕游戏需要多少钱&#xff1f;有好多朋友在咨询过弹幕游戏的开发价格后&#xff0c;都会比较吃惊&#xff0c;一款体量这么小的游戏为什么动辄就要几万块甚至十几万&#xff1f; 我来给你们说分析一下原因&#xff0c;这种游戏如果脱离开直播间&#xff0c;可以…

45基于matlab的ARIMA:AutoregressiveIntegratedMovingAverage model。

基于matlab的ARIMA&#xff1a;AutoregressiveIntegratedMovingAverage model。自回归差分移动平均模型(p,d,q)&#xff0c;AR自回归模型&#xff0c;MA移动平均模型&#xff0c;时间序列模型步骤包括&#xff1a;1. 数据平稳性检验&#xff1b;2. 确定模型参数&#xff1b;3. …

生成第一个 Blazor 应用

前言&#xff1a;博主文章仅用于学习、研究和交流目的&#xff0c;不足和错误之处在所难免&#xff0c;希望大家能够批评指出&#xff0c;博主核实后马上更改。 概述&#xff1a;Blazor 是一个使用 Blazor 生成交互式客户端 Web UI 的框架使用 C# 创建丰富的交互式 UI。共享使…

Flink日志采集-ELK可视化实现

一、各组件版本 组件版本Flink1.16.1kafka2.0.0Logstash6.5.4Elasticseach6.3.1Kibana6.3.1 针对按照⽇志⽂件⼤⼩滚动⽣成⽂件的⽅式&#xff0c;可能因为某个错误的问题&#xff0c;需要看好多个⽇志⽂件&#xff0c;还有Flink on Yarn模式提交Flink任务&#xff0c;在任务执…

vue3使用ts封装axios

以下是使用 TypeScript 封装 Axios 的示例代码&#xff1a; //axios.tsimport axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse, AxiosError } from axios;// 自定义 API 响应类型 interface ApiResponse<T> {code: number;message: string;data: T; }// 自…

中文大语言模型汇总

推荐一篇非常棒的github&#xff1a;Awesome-Chinese-LLM 另附语言模型排行榜&#xff1a;FastChat 里面总结了几乎所有目前主流的中文大语言模型。在此记录一下&#xff0c;方便以后慢慢学习。

单例模式下双重校验锁 DCL 的灵魂三问

文章目录 前言如何实现一个双重校验锁 DCL定义一个单例变量定义一个获取单例的方法性能优化性能优化带来的一点点问题什么是指令重排&#xff1f; 总结如何理解文章开篇理解的三个问题1、为什么需要使用两个 if 语句&#xff1f;2、为什么使用了 synchronized 关键字还需要使用…

AI 引擎系列 4 - 首次运行 AI 引擎编译器和 x86simulator(2022.1 更新)

AI 引擎系列 4 - 首次运行 AI 引擎编译器和 x86simulator&#xff08;2022.1 更新&#xff09; 简介 在 AI 引擎系列的前 3 篇博文中&#xff0c;我们探讨了 AI 引擎应用所需的不同文件。在本篇中&#xff0c;我们将为 X86 目标运行 AI 引擎编译器&#xff0c;观察它生成的不…

二进制搭建 Kubernetes(K8s)

目录 1、环境 1.1 操作系统初始化配置 1.2 部署 docker引擎 1.3 部署 etcd 集群 1.4 准备签发证书环境 1.5 部署 Master 组件 1.6 部署 Worker Node 组件 1.7 部署 CNI 网络组件 1.7.1 部署 flannel 1.7.2 部署 Calico 1.7.3 node02 节点部署 1.7.4 部署 CoreDNS 1…