前言

我在实现一个含有待办列表功能的页面时,发现了一个好看的设计,它将待办分为——“待办”,“正在进行”,和“已完成”三种状态,并且将待办通过拖拽的方式在这三种状态之间进行切换。

这种方式看起来真不错,但是使用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)的更多相关文章

  1. HTML5 之拖放(drag与drop)

    拖放(Drag 和 drop)是 HTML5 标准的组成部分. 拖放是一种常见的特性,即抓取对象以后拖到另一个位置. 在 HTML5 中,拖放是标准的一部分,任何元素都能够拖放. HTML5 拖放实例 ...

  2. Android开发者指南-用户界面-拖放-Drag and Drop[原创译文]

      英文原文:http://developer.android.com/guide/topics/ui/drag-drop.html 版本:Android 4.0 r1 译者注:黄色底色为未决译文 快 ...

  3. HTML 5 拖放(Drag 和drop)

    浏览器支持 Internet Explorer 9.Firefox.Opera 12.Chrome 以及 Safari 5. 1.把标签 draggable 属性设置为 true. 2.向标签添加on ...

  4. HTML5 拖放---drag和drop

    拖放四步走:第一步:设置元素可拖放,即把 draggable属性设置为 true:  例:<div id="div" draggable="true"&g ...

  5. 拖放(Drag和Drop)--html5

    拖放,就是抓取一个对象后拖放到另一个位置.很常用的一个功能,在还没有html5的时候,我们实现这个功能,通常会用大量的js代码,再利用mousemove,mouseup等鼠标事件来实现,总的来说比较麻 ...

  6. HTML5 拖放(Drag 和 Drop)功能开发——基础实战

    随着HTML5的普及度越来越高,现在写代码也遇到一些了,经过同事的点播开展了一次Dojo活动用以技术交流,我也乘此机会将HTML5的拖放功能整理了一下. 简介 拖拽(Drag/Drop)是个非常普遍的 ...

  7. Blazor 使用拖放(drag and drop)上传文件

    在很多上传文件的应用实例中, 都可以看到[拖放文件到此上传]这种骚功能 ,今天我们就来试试Blazor能不能完成这个想法. 简述HTML5拖放 拖放是HTML5标准的一部分,任何元素都能够拖放,也能够 ...

  8. 拖放API中的drag和drop实战

    原文地址:→传送门 写在前面 在HTML5之前,实现拖放功能需要借助mousedown/mousemove/mouseover/mouseout/mouseup等鼠标事件来完成,HTML5中拖放API ...

  9. 炫酷的html5(Drag 和 drop)拖放

    在 HTML5 中,拖放是标准的一部分,任何元素都能够拖放.也是一种常见的特性,即抓取对象以后拖到另一个位置. 浏览器支持 Internet Explorer 9.Firefox.Opera 12.C ...

随机推荐

  1. JavaWeb 03_创建servlet项目(详细)

    一.创建web项目 1. File--New--Project 2. 设置项目相关信息 3. 设置项目名称及工作空间 4. web项目目录结构如下 二.Servlet的实现 1. 新建包---类    ...

  2. 淘宝 NPM 镜像站切换新域名啦

    镜像下载.域名解析.时间同步请点击 阿里云开源镜像站 源起 淘宝 NPM 镜像站(npm.taobao.org)自 2014 年 正式对外服务,一开始只是想简单地做 NPM 的中国镜像站点,回馈国内前 ...

  3. 实践:Linux下安装mysql8.0

    镜像下载.域名解析.时间同步请点击 阿里云开源镜像站 一.下载mysql8.0安装包 1.在local创建mysql文件夹 cd /usr/local mkdir mysql cd mysql 2.使 ...

  4. 配置 PackMan 镜像

    一.参考链接 阿里云镜像站 二.PackMan 镜像介绍 Packman 是 OpenSUSE 最大的第三方软件源,主要为 OpenSUSE 提供额外的软件包,包括音视频解码器.多媒体应用.游戏等. ...

  5. Kettle错误记录之couldn't open file XXX

    业务背景: 简单的TXT文件入库逻辑 组件: 文件文本输入,表输出 具体BUG: 这里报错是无法打开文件,在我尝试了多个思路后,最终发现了问题所在. 因为使用的txt文件的格式是Unix的,而我的文本 ...

  6. [转载]我的WafBypass之道(upload篇)

    现在位置: 首页 > 文章 > Web安全 > 正文 我的WafBypass之道(upload篇) 2016 /11/30 15:20 4,901 沙发 0x00 前言 玩waf当然 ...

  7. FPGA设计流程

    今天学习了FPGA设计流程的视频,我理解要做一个完整的FPGA系统,所要经历的步骤,先将它简单总结如下: 我在对上面的流程图进行解释: 第一:设计定义就是我们这个FPGA系统或者FPGA设计所要实现的 ...

  8. BUAA_DS_北航数据结构:输出全排列

    输入一个数 \(n\),输出 \(1\sim n\) 的所有全排列,每个排列占一行,每个字符保留 \(5\) 个场宽.勤奋的同学一定已经开始打表了是吧. 说是能做肯定不是骗大家,那怎么做呢~ 其实回溯 ...

  9. OSPF的五种报文

    OSPF的五种报文 Hello报文 DD(Database Description)数据库描述报文 LSR(LinkState Request)链路状态请求报文 LSU(LinkState Updat ...

  10. Java中实现多态的机制是什么?

    Java允许父类或接口定义的引用变量指向子类或具体实现类的实例对象,而程序调用的方法在运行时才动态绑定,就是引用变量所指向的具体实例对象的方法,也就是内存里正在运行的那个对象的方法,而不是引用变量的类 ...