在Blazor中实现拖放(drag and drop)
前言
我在实现一个含有待办列表功能的页面时,发现了一个好看的设计,它将待办分为——“待办”,“正在进行”,和“已完成”三种状态,并且将待办通过拖拽的方式在这三种状态之间进行切换。
这种方式看起来真不错,但是使用Blazor来实现这种拖拽效果看起来似乎并不太容易。
经过一番百度难以找到,最后搜索英文通过Google找到了合适的解决方案。
感谢Chris Sainty的博客,通过学习他的代码,最终实现了自己想要的效果。
解决方案
需要实现的目标:
跟踪用户正在拖拽的项目
控制该项目在哪里可以掉落
反馈给用户哪些列表可以掉落,哪些不能
鼠标松开时更新项目
数据结构:
public class TodoItemDto
{
public int Id { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public TodoStatusEnum Status { get; set; }
/// <summary>
/// 截止日期
/// </summary>
public DateTime ClosingDate { get; set; }
/// <summary>
/// 标签
/// </summary>
public string Tag { get; set; }
public bool IsImportant { get; set; }
public int RepeatTimes { get; set; }
}
public enum TodoStatusEnum
{
Todo, // 待办
InProgress, // 正在进行
Completed // 已完成
}
Components
使用三个组件来实现该效果:
TodoContainer.razor
- 使用TodoContainer包含Todo,InProgress,Completed三个待办列表
- 跟踪容器内被用户拖拽的项目
- 包含一个事件供状态更新时调用
TodoContainer.razor
<div class="todo-view-content-layout">
@* 将自己作为级联参数传递给子组件(TodoList) *@
<CascadingValue Value="this">
@ChildContent
</CascadingValue>
</div>
TodoContainer.razor.cs
[Parameter] public List<TodoItemDto> Todos { get; set; }
[Parameter] public RenderFragment ChildContent { get; set; } public TodoItemDto Payload { get; set; } // 这个属性用来跟踪被用户拖拽的待办项 /// <summary>
/// 当子组件更新状态时,调用父组件的该方法,改变待办集合中被拖拽项的状态
/// </summary>
/// <param name="newStatus"></param>
public async Task UpdateJobAsync(TodoStatusEnum newStatus)
{
var task = Todos.SingleOrDefault(x => x.Id == Payload.Id); if (task != null)
{
task.Status = newStatus;
task.ClosingDate = DateTime.Now;
await InvokeAsync(StateHasChanged);
}
}
TodoList.razor
- 使用TodoList包含 每个状态 的待办列表(一共三个TodoList)
- 当用户拖拽待办经过列表时呈现不同的UI效果
TodoList.razor
<div class="todo-view-content-item-layout @_dropClass">
<div class="todo-view-content-item">
@* 展示第一行,标题和任务数等(代码省略) *@
...
@* 展示第二行,添加栏(代码省略)*@
...
@* 第三行展示任务列表 *@
<div class="todo-view-content-list"
// 调用html5关于拖拽的原生API,默认(default)阻止其它容器拖拽项目,(preventDefault)则允许容器进行拖拽放置
ondragover="event.preventDefault();"
// 启用FireFox浏览器对拖放的支持
ondragstart="event.dataTransfer.setData('', event.target.id);"
// 当用户进行放置操作时调用HandleDrop方法
@ondrop="HandleDrop"
// 当用户进入该list范围时调用HandleDragEnter来判断能不能放置
@ondragenter="HandleDragEnter"
// 当用户离开list范围后将dropClass置为默认状态
@ondragleave="HandleDragLeave"> @foreach (var todo in Todos)
{
<TodoDisplay TodoItem="todo"/>
}
</div>
</div>
</div>
TodoList.razor.cs
[CascadingParameter] TodoContainer Container { get; set; }
[Parameter] public TodoStatusEnum ListStatus { get; set; }
[Parameter] public TodoStatusEnum AllowedStatuses { get; set; } List<TodoItemDto> Todos = new List<TodoItemDto>();
private string _dropClass = ""; // 用来判断当前list能否放置 protected override void OnParametersSet()
{
Todos.Clear();
Todos.AddRange(Container.Todos.Where(x => x.Status == ListStatus));
} private void HandleDragEnter()
{
if (ListStatus == Container.Payload.Status) return; if (AllowedStatuses != Container.Payload.Status)
{
_dropClass = "can-drop";
}
} private void HandleDragLeave()
{
_dropClass = "";
} private async Task HandleDrop()
{
_dropClass = ""; if (AllowedStatuses == Container.Payload.Status) return; await Container.UpdateJobAsync(ListStatus);
}
TodoDisplay.razor
- 这个组件用来展示单个待办
- 当它被拖拽的时候就通知父组件(TodoContainer)跟踪它
该组件代码逻辑很简单,但是html的代码量过多就不展示了
TodoDisplay.razor
<div class="draggable" draggable="true" title="@TodoItem.Title" @ondragstart="@(() => HandleDragStart(TodoItem))">
// 内容(待办展示)...
</div>
TodoDisplay.razor.cs
[CascadingParameter] TodoContainer Container { get; set; }
[Parameter] public TodoItemDto TodoItem { get; set; }
/// <summary>
/// 通过每次drag开始将Container的Payload赋值以跟踪被拖拽的待办项
/// </summary>
/// <param name="selectedJob"></param>
private void HandleDragStart(TodoItemDto selectedJob)
{
Container.Payload = selectedJob;
}
使用
从TodoView.razor中进行调用
@page "/todo"
@attribute [Authorize]
<div class="todo-layout">
<TodoViewTitle></TodoViewTitle>
<TodoContainer Todos="Todos">
<TodoList ListStatus="TodoStatusEnum.Todo" AllowedStatuses="TodoStatusEnum.Todo"/>
<TodoList ListStatus="TodoStatusEnum.InProgress" AllowedStatuses="TodoStatusEnum.InProgress"/>
<TodoList ListStatus="TodoStatusEnum.Completed" AllowedStatuses="TodoStatusEnum.Completed"/>
</TodoContainer>
</div>
@code {
List<TodoItemDto> Todos = new List<TodoItemDto>
{
new TodoItemDto()
{
Id = 1,
Title = "开发大创项目右侧状态栏",
Description = "无",
IsImportant = true,
RepeatTimes = 1,
Tag = "工作",
ClosingDate = DateTime.Now
},
new TodoItemDto()
{
Id = 12,
Title = "每日背单词",
Description = "无",
IsImportant = true,
RepeatTimes = 1,
Tag = "学习",
ClosingDate = DateTime.Now
},
new TodoItemDto()
{
Id = 11,
Title = "AAAAAAAAAA",
Description = "无",
IsImportant = true,
RepeatTimes = 1,
Tag = "工作",
ClosingDate = DateTime.Now
},
new TodoItemDto()
{
Id = 111,
Title = "BBBBBBBBBBBB",
Description = "无",
IsImportant = true,
RepeatTimes = 1,
Tag = "工作",
ClosingDate = DateTime.Now
},
new TodoItemDto()
{
Id = 2,
Title = "CCCCCCCCCCCCCCCC",
Description = "无",
IsImportant = true,
RepeatTimes = 1,
Tag = "工作",
ClosingDate = DateTime.Now
}
};
}
实现效果如下:
进行拖拽...
拖拽成功!
在Blazor中实现拖放(drag and drop)的更多相关文章
- HTML5 之拖放(drag与drop)
拖放(Drag 和 drop)是 HTML5 标准的组成部分. 拖放是一种常见的特性,即抓取对象以后拖到另一个位置. 在 HTML5 中,拖放是标准的一部分,任何元素都能够拖放. HTML5 拖放实例 ...
- Android开发者指南-用户界面-拖放-Drag and Drop[原创译文]
英文原文:http://developer.android.com/guide/topics/ui/drag-drop.html 版本:Android 4.0 r1 译者注:黄色底色为未决译文 快 ...
- HTML 5 拖放(Drag 和drop)
浏览器支持 Internet Explorer 9.Firefox.Opera 12.Chrome 以及 Safari 5. 1.把标签 draggable 属性设置为 true. 2.向标签添加on ...
- HTML5 拖放---drag和drop
拖放四步走:第一步:设置元素可拖放,即把 draggable属性设置为 true: 例:<div id="div" draggable="true"&g ...
- 拖放(Drag和Drop)--html5
拖放,就是抓取一个对象后拖放到另一个位置.很常用的一个功能,在还没有html5的时候,我们实现这个功能,通常会用大量的js代码,再利用mousemove,mouseup等鼠标事件来实现,总的来说比较麻 ...
- HTML5 拖放(Drag 和 Drop)功能开发——基础实战
随着HTML5的普及度越来越高,现在写代码也遇到一些了,经过同事的点播开展了一次Dojo活动用以技术交流,我也乘此机会将HTML5的拖放功能整理了一下. 简介 拖拽(Drag/Drop)是个非常普遍的 ...
- Blazor 使用拖放(drag and drop)上传文件
在很多上传文件的应用实例中, 都可以看到[拖放文件到此上传]这种骚功能 ,今天我们就来试试Blazor能不能完成这个想法. 简述HTML5拖放 拖放是HTML5标准的一部分,任何元素都能够拖放,也能够 ...
- 拖放API中的drag和drop实战
原文地址:→传送门 写在前面 在HTML5之前,实现拖放功能需要借助mousedown/mousemove/mouseover/mouseout/mouseup等鼠标事件来完成,HTML5中拖放API ...
- 炫酷的html5(Drag 和 drop)拖放
在 HTML5 中,拖放是标准的一部分,任何元素都能够拖放.也是一种常见的特性,即抓取对象以后拖到另一个位置. 浏览器支持 Internet Explorer 9.Firefox.Opera 12.C ...
随机推荐
- Spring系列25:Spring AOP 切点详解
本文内容 Spring 10种切点表达式详解 切点的组合使用 公共切点的定义 声明切点@Poincut @Poincut 的使用格式如下: @Poincut("PCD") // 切 ...
- 20192204 2019-2020-2 《Python程序设计》实验四报告
20192204 2019-2020-2 <Python程序设计>实验四报告 课程:<Python程序设计> 班级: 1922 姓名: 李龙威 学号:20192204 实验教师 ...
- 常见的Socket网络异常场景分析
原创:打码日记(微信公众号ID:codelogs),欢迎分享,转载请保留出处. 简介 在目前微服务的背景下,网络异常越来越常见了,而有一些网络异常非常模糊,理解什么情况下会导致什么异常,还是有一定难度 ...
- 原生 JS 实现 VS Code 自动切换输入法状态!这次没有AHK
上一篇文章:使用 AHK 在 VS Code 中根据上下文自动切换输入法状态 给出一个使用 ahk 在 VSCode 自动切换输入法的方法.不过这个方法实际上很蹩脚,一点都不优(zhuang)雅(bi ...
- 《前端运维》一、Linux基础--09常用软件安装
一.软件包管理 RPM是RedHat Package Manager(RedHat软件包管理工具)类似Windows里面的"添加/删除程序".软件包有几种类型,我们一起来看下: 源 ...
- CVE-2015-5531(目录遍历漏洞)
vulhub漏洞环境搭建 https://blog.csdn.net/qq_36374896/article/details/84102101 启动docker环境 cd vulhub-master/ ...
- Flink不止于计算,存算一体才是未来
"伴随着实时化浪潮的发展和深化,Flink 已逐步演进为实时流处理的领军技术和事实标准.Flink 一方面持续优化其流计算核心能力,不断提高整个行业的流计算处理标准,另一方面沿着流批一体 ...
- MindSpore尝鲜之Vmap功能
技术背景 Vmap是一种在python里面经常提到的向量化运算的功能,比如之前大家常用的就是numba和jax中的向量化运算的接口.虽然numpy中也使用到了向量化的运算,比如计算两个numpy数组的 ...
- pycharm2019版本可用破解
1.下载破解文件 点击链接https://pan.baidu.com/s/1FbpXC4-rACrLMfeuVzJGPQ 提取码:hyed 下载补丁文件jetbrains-agent.jar并将它 ...
- html5与css交互 API 《一》classList
用过jquery的朋友都知道,jquery提供的方法中(3个)可以很方便的为指定的节点添加.删除类选择器,即addClass.removeClass.toggleClass.具体的用法我这里就不谈了, ...