web架构师编辑器内容-图层拖动排序功能的开发

这篇具有很好参考价值的文章主要介绍了web架构师编辑器内容-图层拖动排序功能的开发。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

新的学习方法
  • 用手写简单方法实现一个功能
  • 然后用比较成熟的第三方解决方案
  • 即能学习原理又能学习第三方库的使用

从两个DEMO开始

  • Vue Draggable Next: Vue Draggable Next
  • React Sortable HOC: React Sortable HOC
列表排序的三个阶段
  • 拖动开始(dragstart)
    • 被拖动图层的状态变化
    • 会出一个浮层
  • 拖动进行中(dragmove)
    • 浮层会随着鼠标移动
    • 条目发生换位:当浮层下沿超过被拖条目二分之一的时候,触发换位。这是一个比较独特的需求
  • 松开鼠标阶段(drop)
    • 浮层消失
    • 被拖动图层状态复原
    • 数据被更新
      web架构师编辑器内容-图层拖动排序功能的开发,慕课网-Web前端架构师,前端,编辑器
拖动排序功能开发

第一阶段 Dragstart

  • 被拖动图层的状态变化 常规做法
    • 添加mouseDown事件,检查当前的target是那个元素,然后给他添加特定的状态
    • 添加mouseMove事件,创一个和被拖动元素一模一样的的浮层,将它的定位设置
      它的定位为绝对定位,并且随着鼠标的坐标更新。
  • 使用HTML的Drag特性
    • 文档地址:拖拽操作
    • 浏览器的默认拖拽行为:支持图象,链接和选择的文本
    • 其他元素默认情况是不可拖拽的。
    • 如果想可以拖拽可以设置为draggable = true
    • 使用dragstart事件监控拖动开始,并设置对应的属性

LayerList组件中添加draggable属性

// LayerList.vue
<li
  class="ant-list-item"
  v-for="item in list" :key="item.id"
  :class="{ active: item.id === selectedId }"
  @click="handleClick(item.id)"
  draggable="true"
></li>

web架构师编辑器内容-图层拖动排序功能的开发,慕课网-Web前端架构师,前端,编辑器
这样就可以有效果了:当拖动对应条目的时候,它会自动生成半透明的条目,并且跟随鼠标的移动。
接下来就开始使用dragstart事件监控拖动开始,并设置对应的属性

  • 给被拖动元素添加特定的状态:使用一系列的事件来监控拖动的进度,使用dragStart开始拖动操作
// LayerList.vue
// html部分
<li
  class="ant-list-item"
  v-for="item in list" :key="item.id"
  :class="{ active: item.id === selectedId, ghost: dragData.currentDragging === item.id}"
  @click="handleClick(item.id)"
  @dragstart="onDragStart($event, item.id)"
  draggable="true"
></li>
// js部分(setup)
const dragData = reactive({
  currentDragging: ''
})
const onDragStart = (e: DragEvent, id: string ) => {
  dragData.currentDragging = id;
}
// css部分
.ant-list-item.ghost {
  opacity: 0.5;
}

完成出来的效果:
web架构师编辑器内容-图层拖动排序功能的开发,慕课网-Web前端架构师,前端,编辑器
接下来就是在鼠标松开的时候,特定的状态消失:使用drop事件:

<ul :list="list" class="ant-list-items ant-list-border" @drop="onDrop"></ul>
const onDrop = (e: DragEvent ) => {
  dragData.currentDragging = '';
}

但是这样做发现不起作用,后来发现是onDrog事件并没有触发,原因:
dragenter 或 dragover 事件的监听程序用于表示有效的放置目标,也就是被拖拽项目可能放置的地方。网页或应用程序的大多数区域都不是放置数据的有效位置。因此,这些事件的默认处理是不允许放置。
指定放置对象
因为网页大部分区域不是有效的放置位置,这些事件的默认处理都是不允许放置,所以这个行为并不会被触发。
如果你想要允许放置,你必须取消 dragenter 和 dragover 事件来阻止默认的处理。你可以在属性定义的事件监听程序返回 false,或者调用事件的 preventDefault() 方法来实现这一点。在一个独立脚本中的定义的函数里,可能后者更可行。
最终添加阻止默认行为事件:

<ul :list="list" class="ant-list-items ant-list-border" @drop="onDrop" @dragover="onDragOver">

const onDragOver = (e: DragEvent) => {
  e.preventDefault()
}
处理松开鼠标时进行排序
  1. 修改dragData 添加一个当前索引的属性

        const dragData = reactive({
          currentDragging: '',
          currentIndex: -1,
        });
    
  2. @dragstart=“onDragStart($event, item.id, index)” 方法中多添加一个index参数

        const onDragStart = (e: DragEvent, id: string, index: number) => {
          dragData.currentDragging = id;
          dragData.currentIndex = index;
        };
    

有了开始拖动的index之后,我们要知道drop的时候新的index,我们怎么在onDrop方法中拿到新的index呢?因为在onDrop中我们的参数是event,使用event.target可以拿到dom元素,把最新的index放到dom元素上面就可以了,使用:HTMLElement.dataset
3. 使用 HTMLElement.dataset拿到最新的索引

HTMLElement.dataset属性允许无论是在读取模式和写入模式下访问在HTML 或 DOM中元素上设置的
所有自定义数据属性(data-*)集
它是一个DOMString的映射,每个自定义数据属性的一个条目。
请注意,dataset属性本身可以被读取,但不能直接写入,相反,所有的写入必股友是它的属性,这反过来
表示数据属性。
还要注意,一个HTML data-attribute 及其对应的DOM dataset.property 不共享相同的名称,但它
们总是相似的:

       <li
         class="ant-list-item"
         :class="{
           active: item.id === selectedId,
           ghost: dragData.currentDragging === item.id,
         }"
         v-for="(item, index) in list"
         :key="item.id"
         @click="handleClick(item.id)"
         @dragstart="onDragStart($event, item.id, index)"
         :data-index="index"
         draggable="true"
       >
  1. 修改onDrop事件
const onDrop = (e: DragEvent) => {
  const currentEle = e.target as HTMLElement;
  if (currentEle.dataset.index) {
    const moveIndex = parseInt(currentEle.dataset.index);
    console.log(moveIndex);
  }
  dragData.currentDragging = "";
};

但是这样写moveIndex是不一定存在的,因为e.target是鼠标指向的元素,所以当在目标子元素上面进行释放的话,就会把目标当成子元素,比如如果释放到的元素是锁元素,则currentEle就是锁元素。所以这里需要一个方法来向上进行检索,找到符合条件的父元素。

export const getParentElement = (element: HTMLElement, className: string) => {
  while (element) {
    if (element.classList && element.classList.contains(className)) {
      return element;
    } else {
      element = element.parentNode as HTMLElement;
    }
  }
  return null;
};
    const onDrop = (e: DragEvent) => {
      const currentEle = getParentElement(
        e.target as HTMLElement,
        'ant-list-item'
      );
      if (currentEle && currentEle.dataset.index) {
        const moveIndex = parseInt(currentEle.dataset.index);
        // 使用第三方库arrayMove改变数组
        arrayMove.mutate(props.list, dragData.currentIndex, moveIndex);
      }
      dragData.currentDragging = '';
    };

array-move
最终实现的效果:
web架构师编辑器内容-图层拖动排序功能的开发,慕课网-Web前端架构师,前端,编辑器

在拖动时完成排序:
    const onDragEnter = (e: DragEvent, index: number) => {
      // 这里的判断是为了避免完成转换后,触发新的一次dragEnter事件
      if (index !== dragData.currentIndex) {
        console.log('enter', index, dragData.currentIndex);
        arrayMove.mutate(props.list, dragData.currentIndex, index);
        dragData.currentIndex = index;
        end = index
      }
    };

这样就可以在拖动时完成排序了,onDrop里面就不需要进行同样的操作了,修改一下onDrop事件

let start = -1;
let end = -1;
const onDragStart = (e: DragEvent, id: string, index: number) => {
  dragData.currentDragging = id;
  dragData.currentIndex = index;
  start = index;
};
const onDrop = (e: DragEvent) => {
  context.emit('drop', { start, end})
  dragData.currentDragging = '';
};

现在就完成了可拖动排序的简单编码,主要掌握三个阶段:

  1. 排序开始:监控被拖拽的元素,添加特殊状态和UI
  2. 移动阶段:进入别的列表的时候完成数据的交换
  3. drop阶段:松开按钮的时候,将状态恢复原状,并且发送对应的事件。

使用第三方库进行排序:

使用Vue Draggable进行排序:

vue.draggable.next

npm i -S vuedraggable@next

将用draggable替换掉ul

<template>
  <draggable
    :list="list"
    class="ant-list-items ant-list-bordered"
    ghost-class="ghost"
    handle=".handle"
    item-key="id"
  >
    <template #item="{ element }">
      <li
        class="ant-list-item"
        :class="{ active: element.id === selectedId }"
        @click="handleClick(element.id)"
      >
        <a-tooltip :title="element.isHidden ? '显示' : '隐藏'">
          <a-button
            shape="circle"
            @click.stop="
              handleChange(element.id, 'isHidden', !element.isHidden)
            "
          >
            <template v-slot:icon v-if="element.isHidden"
              ><EyeInvisibleOutlined />
            </template>
            <template v-slot:icon v-else><EyeOutlined /> </template>
          </a-button>
        </a-tooltip>
        <a-tooltip :title="element.isLocked ? '解锁' : '锁定'">
          <a-button
            shape="circle"
            @click.stop="
              handleChange(element.id, 'isLocked', !element.isLocked)
            "
          >
            <template v-slot:icon v-if="element.isLocked"
              ><LockOutlined/>
            </template>
            <template v-slot:icon v-else><UnlockOutlined  /> </template>
          </a-button>
        </a-tooltip>
        <inline-edit
          class="edit-area"
          :value="element.layerName"
          @change="
            (value) => {
              handleChange(element.id, 'layerName', value);
            }
          "
        ></inline-edit>
        <a-tooltip title="拖动排序">
          <a-button shape="circle" class="handle">
            <template v-slot:icon><DragOutlined /> </template
          ></a-button>
        </a-tooltip>
      </li>
    </template>
  </draggable>
</template>
<script lang="ts">
import { defineComponent, PropType } from 'vue';
import draggable from 'vuedraggable';
import {
  EyeOutlined,
  EyeInvisibleOutlined,
  LockOutlined,
  UnlockOutlined,
  DragOutlined,
} from '@ant-design/icons-vue';
import { ComponentData } from '../store/editor';
import InlineEdit from '../components/InlineEdit.vue';
export default defineComponent({
  props: {
    list: {
      type: Array as PropType<ComponentData[]>,
      required: true,
    },
    selectedId: {
      type: String,
      required: true,
    },
  },
  emits: ['select', 'change', 'drop'],
  components: {
    EyeOutlined,
    EyeInvisibleOutlined,
    LockOutlined,
    UnlockOutlined,
    InlineEdit,
    draggable,
    DragOutlined,
  },
  setup(props, context) {
    const handleClick = (id: string) => {
      context.emit('select', id);
    };
    const handleChange = (id: string, key: string, value: boolean) => {
      const data = {
        id,
        key,
        value,
        isRoot: true,
      };
      context.emit('change', data);
    };
    return {
      handleChange,
      handleClick,
    };
  },
});
</script>

<style scoped>
.ant-list-item {
  padding: 10px 15px;
  transition: all 0.5s ease-out;
  cursor: pointer;
  justify-content: normal;
  border: 1px solid #fff;
  border-bottom-color: #f0f0f0;
}
.ant-list-item.active {
  border: 1px solid #1890ff;
}
.ant-list-item.ghost {
  opacity: 0.5;
}

.ant-list-item:hover {
  background: #e6f7ff;
}
.ant-list-item > * {
  margin-right: 10px;
}
.ant-list-item button {
  font-size: 12px;
}

.ant-list-item .handle {
  cursor: move;
  margin-left: auto;
}
.ant-list-item .edit-area {
  width: 100%;
}
</style>

web架构师编辑器内容-图层拖动排序功能的开发,慕课网-Web前端架构师,前端,编辑器文章来源地址https://www.toymoban.com/news/detail-824560.html

到了这里,关于web架构师编辑器内容-图层拖动排序功能的开发的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Unity编辑器扩展】(二)PSD转UGUI Prefab, 图层解析和碎图导出

     书接上回:【Unity编辑器扩展】(一)PSD转UGUI Prefab, Aspose.PSD和Harmony库的使用_TopGames的博客-CSDN博客 解放UI程序/美术? psd文件一键转ui prefab 支持所有ui类型 支持textmeshpro psd一键转ugui prefab工具 设计原理和详细使用方法 工具使用预览: 1. 实现将psd解析生成为UI预制体,并导出UI图

    2024年02月07日
    浏览(90)
  • React 框架下自己写一个braft编辑器,然后将编辑器内容展示在网页端

    1.首先自己写一个编辑器 输入文字; 支持选择表情; 可添加小程序链接;可添加网页链接;并且可以编辑删除;效果如下 2.输入完毕后,点击文本输入框保存,将便携式内容回显, 渲染时,因为是html格式,所以采用dangerouslySetInnerHTML属性来渲染 添加样式,渲染后里面的链接

    2024年02月16日
    浏览(43)
  • AJAX + PHP 编辑器内容自动备份草稿保存到本地 (适用ueditor百度编辑器或其它) 内容变化后自动触发备份txt文件

    百度自带的自动备份功能enableAutoSave存在问题, 比如第一个文章他自动备份了.等发表第二个文章时,结果把第一个文章的内容自动填充进去了.关键你还不知情!出现过多次这种情况了. 一, 百度原版的 ,具体使用方法,看这里个文章 Ueditor百度编辑器内容自动保存到本地防数据丢失

    2024年02月10日
    浏览(41)
  • 【HTML】标签读取富文本编辑器的内容

    1.正确读取富文本内容示例: 代码:  显示结果:  在这个例子中, {$row.content}  是直接输出从数据库中获取的富文本内容,包括可能存在的HTML标签和属性,这样可以确保富文本能够按照预期样式呈现。 2. 错误读取富文本内容示例及其原因分析:  代码:  显示结果: 分析

    2024年02月02日
    浏览(37)
  • 工业组态 物联网组态 组态编辑器 web组态 组态插件 编辑器

     体验地址:by组态[web组态插件] BY组态是一款非常优秀的纯前端的【web组态插件工具】,可无缝嵌入到vue项目,react项目等,由于是原生js开发,对于前端的集成没有框架的限制。同时由于BY组态只是一个插件,不能独立运行,必须嵌入到你方软件平台才能使用,所以你方软件

    2024年04月15日
    浏览(34)
  • 利用三维内容编辑器制作VR交互课件,简单好用易上手

    随着虚拟现实技术的不断发展,越来越多的教育机构开始尝试将其应用于教育教学中。然而,要实现这一目标并不容易,需要专业的技术支持和开发团队。 为了解决这一问题, 广州华锐互动 研发了 三维内容编辑器 ,它是一种基于虚拟现实技术的教育内容编辑器,可以帮助

    2024年02月12日
    浏览(32)
  • Unity编辑器扩展-第二集-按钮排序/分组/放入右键菜单

    第一集链接:Unity编辑器扩展-第一集-在菜单栏加入自己的按钮_菌菌巧乐兹的博客-CSDN博客 一、本节目标+效果展示 1.按钮排序 变成 2.按钮分组 仔细看,有个灰色的杠杠 3.放入右键菜单 4.皮一下  二、按钮排序具体流程 第一集讲,如果想放入标签主要的代码是  但是这行代码

    2024年02月14日
    浏览(29)
  • 最火web大屏可视化编辑器

           乐吾乐Le5le大屏可视化设计器,零代码实现物联网、工业智能制造等领域的可视化大屏、触摸屏端UI以及工控可视化的解决方案。同时也是一个Web组态工具,支持2D、3D等多种形式,用于构建具有实时数据展示、监控预警、丰富交互的组态画面。拥有丰富的大屏组件和行

    2024年02月05日
    浏览(37)
  • 老牌开源 SVG 编辑器 SVGEdit 是如何架构的?

    大家好,我是前端西瓜哥。这次简单看看 SVGEdit 的架构。 SVGEdit 的版本为 7.2.0。 SVGEdit 一款非常老牌的 SVG 图形编辑器,用于编辑处理 SVG,start 数目前是 5.8k。 它的优点在于经过多年的开发,完成度高,较为成熟,功能相当丰富 。 有丰富的工具:选择工具、铅笔工具、钢笔

    2024年02月03日
    浏览(32)
  • JAVA在线电子病历编辑器源码 B/S架构

    电子病历在线制作、管理和使用的一体化电子病历解决方案,通过一体化的设计,提供对住院病人的电子病历书写、保存、修改、打印等功能。电子病历系统将临床医护需要的诊疗资料以符合临床思维的方法展示。建立以病人为中心,以临床诊疗信息为主线,集成门急诊、住

    2024年02月07日
    浏览(25)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包