使用 SortableJS 组件的 Blazor 可排序列表

作者:Burke Holland
排版:Alan Wang

在 Web 应用程序中,一个常见功能部分是可排序列表。SortableJS 是我最喜欢的 JavaScript 库之一,在进行 Blazor 开发时我很想念它。为了解决这个问题,我决定包装 SortableJS 库,使其成为 Blazor 组件,名为 Blazor Sortable,我已在 GitHub 上开源了它,我相信您会喜欢它的。在这篇文章中,我将引导您了解如何将其添加到您自己的 Blazor Web 应用程序中。

注意:Blazor Sortable 是一个开源社区组件,而不是 Microsoft 的官方组件。Blazor 的 Fluent UI 团队正在致力于在即将发布的 Blazor 的 Fluent UI 版本中集成可排序组件。您现在可以尝试 Fluent UI Sortable Demo。

请在这里查看演示:https: //blazorsortable.theurlist.com
在这里插入图片描述
每周五,Jon Galloway(虽然你可能从未听说过他,但他值得信赖)和我致力于在 Blazor 中重建一个名为 theurlist.com 的应用程序。该直播在 Twitch 和 .NET YouTube 上被称为“Burke Learns Blazor”(点赞并订阅!)。如果您愿意加入我们,我们将会非常高兴。由于我不知道我们现在需要做些什么,所有我们需要尽可能多的帮助来一起处理这件事。

我们最终需要一个可排序列表组件来进行此重建,虽然有一些“Blazor Sortable”示例,但我还是很想要用 SortableJS。SortableJS 是一个出色的库,用于构建可排序的项目列表,几乎具有您可能需要的所有功能 - 排序、列表之间的排序、克隆项目、过滤、自定义动画缓动、腰部支持。好吧——最后一个不是,但这是它唯一没有的东西。

因此,在 Steve Sanderson 的帮助下,我们在 SortableJS 上构建了一个简单的抽象,您可以将其放入您自己的应用程序中并使用。让我们看一下如何为您自己的 Blazor 应用程序使用和自定义 Blazor Sortable。

使用 Blazor Sortable

Blazor Sortable 的 GitHub 存储库包含可排序列表的源代码以及演示。对于您自己的项目,您只需要 Shared/SortableList.razor、Shared/SortableList.razor.css 和 Shared/SortableList.razor.js 文件。
在这里插入图片描述
SortableList 组件是一个通用组件,它采用项目列表和定义如何呈现可排序列表中每个项目的 SortableItemTemplate。例如,假设您有一个如下所示的书籍列表…

public class Book
{
    public string Title { get; set; } = "";
    public string Author { get; set; }  = "";
    public int Year { get; set; }
}

public List<Book> books = new List<Book>
{
    new Book { Title = "The Very Hungry Caterpillar", Author = "Eric Carle", Year = 1969 },
    new Book { Title = "Where the Wild Things Are", Author = "Maurice Sendak", Year = 1963 },
    new Book { Title = "Goodnight Moon", Author = "Margaret Wise Brown", Year = 1947 },
    new Book { Title = "The Cat in the Hat", Author = "Dr. Seuss", Year = 1957 },
    new Book { Title = "Charlotte's Web", Author = "E.B. White", Year = 1952 },
    new Book { Title = "Harry Potter and the Sorcerer's Stone", Author = "J.K. Rowling", Year = 1997 },
    new Book { Title = "The Lion, the Witch and the Wardrobe", Author = "C.S. Lewis", Year = 1950 },
    new Book { Title = "Matilda", Author = "Roald Dahl", Year = 1988 },
    new Book { Title = "The Giving Tree", Author = "Shel Silverstein", Year = 1964 },
    new Book { Title = "Oh, the Places You'll Go!", Author = "Dr. Seuss", Year = 1990 }
};

您可以在 SortableList 中像下面这样呈现此列表…

<div>
    <SortableList Items="books" Context="book">
        <SortableItemTemplate>
            <div class="book">
                <p>@book.Title</p>
            </div>
        </SortableItemTemplate>
    </SortableList>
</div>

在这里插入图片描述
SortableList 组件将使用 SortableItemTemplate 呈现项目列表,然后使用 SortableJS 使列表变得可以排序。Context 参数用于定义变量的名称,该变量将用于表示列表中的每个项目。在本例中,Context 是 book,因此列表中的每个项目都将由一个名为 book 的变量表示。

但是,如果您此时尝试拖放项目,您会发现无论您怎么拖放一个项目,它都会回到之前的位置。这是因为我们没有告诉 SortableList 在列表排序时该做什么。我们通过处理 OnUpdate 事件并自己进行排序来做到这一点。

<div>
    <SortableList Items="books" Context="book" OnUpdate="@SortList">
        <SortableItemTemplate>
            <div class="book">
                <p>@book.Title</p>
            </div>
        </SortableItemTemplate>
    </SortableList>
</div>
...
public void SortList((int oldIndex, int newIndex) indices)
{
    // deconstruct the tuple
    var (oldIndex, newIndex) = indices;

    var items = this.books;
    var itemToMove = items[oldIndex];
    items.RemoveAt(oldIndex);

    if (newIndex < items.Count)
    {{
        items.Insert(newIndex, itemToMove);
    }}
    else
    {{
        items.Add(itemToMove);
    }}
}

每当列表排序时,都会调用 OnUpdate 事件处理程序。它将传递一个包含已移动项目的旧索引和新索引的元组。在 SortList 方法中,我们将元组解构为两个变量,然后使用它们来移动列表中的项目。

永远不要改变 Blazor 控制的 DOM,这一点非常重要。Blazor 保留 DOM 的内部副本,如果您使用 JavaScript 等内容更改它,您将得到奇怪的结果,因为页面状态将与 Blazor 的内部状态不同步。因此,我们在幕后所做的就是取消 JavaScript 移动,这样被移动的项目就不会真的在页面上移动。然后我们移动列表中的项目,Blazor 将按照新顺序重新渲染列表。

一个更复杂的例子

SortableJS 是一个非常强大的库,它可以做的不仅仅是排序列表。它还可以在列表之间排序、克隆项目、过滤项目等等。SortableList 组件支持许多这样的功能。让我们看一个更复杂的例子——两个列表之间的排序…

<div>
    <div class="container">
        <div class="columns">
            <div class="column">
                <h3>Books</h3>
                <SortableList Items="books" Context="book" OnRemove="@AddToFavoriteList" Group="favorites">
                    <SortableItemTemplate>
                        <div class="book">
                            <p>@book.Title</p>
                        </div>
                    </SortableItemTemplate>
                </SortableList>
            </div>
            <div class="column">
                <h3>Favorite Books</h3>
                <SortableList Items="favoriteBooks" Context="book" OnRemove="@RemoveFromFavoriteList" Group="favorites">
                    <SortableItemTemplate>
                        <div class="book">
                            <p>@book.Title</p>
                        </div>
                    </SortableItemTemplate>
                </SortableList>
            </div>
        </div>
    </div>
</div>

在此示例中,我们有两个列表 - 所有书籍的列表和最喜欢的书籍的列表。它们通过 Group 属性链接在一起。

我们希望能够将书籍从所有书籍列表拖放到最喜欢的书籍列表中。要做到这一点,我们需要处理两个列表的 OnRemove 事件。

public void AddToFavoriteList((int oldIndex, int newIndex) indices)
{
    var (oldIndex, newIndex) = indices;

    var book = books[oldIndex];
    favoriteBooks.Insert(newIndex, book);
    books.RemoveAt(oldIndex);
}

public void RemoveFromFavoriteList((int oldIndex, int newIndex) indices)
{
    var (oldIndex, newIndex) = indices;

    var book = favoriteBooks[oldIndex];
    books.Insert(newIndex, book);
    favoriteBooks.RemoveAt(oldIndex);
}

在这里插入图片描述

设置 SortableList 的样式

默认情况下,SortableList 包含一些默认样式,这些样式在拖动时会隐藏“ghost”元素。这将在您拖动时在项目之间产生间隙。如果没有这种样式更改,项目本身将显示为可放置拖动项目的目标。这有点奇怪,因为这意味着您拖动的项目也是您放置拖动项目的目的地。但如果这就是您想要选的样式,您可以覆盖 SortableList.razor.css 文件中的样式,或者根本不包含它。

由于 SortableList 内呈现的所有内容都呈现在 SortableItemTemplate 子项内,因此您必须使用“::deep”修饰符才能使任何更改生效。

如果您从父页面/组件(即 Index.razor.css)设置 SortableList 的样式,则必须将 SortableList 包装在容器元素中,并使用“::deep”修饰符。如果您不这样做,您的样式将不会生效,您也会因为我制作这个组件却没有这个功能而感到悲伤、困惑和生气。这是 Blazor 的问题,而不是 SortableJS 的问题。您可以在 ASP.NET Core 文档中阅读有关范围样式的更多信息。

我觉得没有人会读最后一段,很多人可能会哀号。我先说声抱歉,但其实我已经尝试过了。

为什么不使用 HTML5 拖放?

这是一个很好的问题,也是我在使用 JavaScript 解决方案之前研究过的一个问题。总而言之,原生 HTML5 对拖放的支持还不够强大,无法实现合适的排序。例如,无法对大部分拖放行为进行样式化。它看起来……很愚蠢……而且我们对此无能为力。它对跨浏览器的支持也很不稳定。有一些基本属性仅适用于 Chrome。

综上所述,SortableJS 实际上会尝试使用 HTML5 拖放,并在 iOS 等平台上退回到 JavaScript 解决方案。但是,您仍然无法控制样式,并且会出现看起来愚蠢的拖放操作。所以我在 SortableList 上关闭了 HTML5 的方式。如果您希望它重新打开,请进入 SortableList.razor.razor.js 文件并删除 forceFallback: true 属性。我可能会在某个时候将其作为一个设置。

获取 Blazor Sortable

查看 Blazor Sortable 并告诉我们您的想法!您可以用它做很多事情,包括克隆项目、禁用某些项目的排序、指定拖动手柄等等。我们还没有实现 SortableJS 的所有功能。欢迎拉取请求!😉

Blazor Sortable 是一个开源社区项目。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【退役之重学前端】vite, vue3, vue-router, vuex, ES6学习日记

学习使用vitevue3的所遇问题总结&#xff08;2024年2月1日&#xff09; 组件中使用<script>标签忘记加 setup 这会导致Navbar 没有暴露出来&#xff0c;导致使用不了&#xff0c;出现以下报错 这是因为&#xff0c;如果不用setup&#xff0c;就得使用 export default…

网络攻击和渗透中:注入信息无回显?(给盲注戴上眼镜)靶机实战利用Ecshop 2.x/3.x SQL注入/任意代码执行漏洞

网络攻击和渗透中:注入信息无回显?(给盲注戴上眼镜)靶机实战利用Ecshop 2.x/3.x SQL注入/任意代码执行漏洞。 工具简介: 平常的漏洞检测或漏洞利用需要进一步的用户或系统交互。但是一些漏洞类型没有直接表明攻击是成功的。如Payload触发了却不在前端页面显示。(像ssrf,XX…

vscode无法ssh远程连接到服务器:远程主机可能不符合 glibc 和 libstdc++ VS Code 服务器的先决条件

vscode无法ssh远程连接到服务器&#xff1a;远程主机可能不符合 glibc 和 libstdc VS Code 服务器的先决条件 今天vscode自动更新后无法连接到远程服务器了&#xff0c;提示"远程主机可能不符合 glibc 和 libstdc VS Code 服务器的先决条件" 并且命令窗口一直显示&qu…

【EI会议征稿通知】第三届智能控制与应用技术国际学术会议(AICAT 2024)

第三届智能控制与应用技术国际学术会议&#xff08;AICAT 2024&#xff09; 2024 3rd International Symposium on Artificial Intelligence Control and Application Technology 2024年第三届智能控制与应用技术国际学术会议&#xff08;AICAT 2024&#xff09;定于2024年5月…

ubuntu20.04安装最新版nginx

前言 记录下ubuntu服务器安装nginx 步骤 安装最新版本的 Nginx 可以通过添加 Nginx 官方的软件仓库并更新软件包信息。以下是在 Ubuntu 20.04 上安装最新版本 Nginx 的步骤&#xff1a; 添加 Nginx 软件仓库&#xff1a; 打开终端并执行以下命令&#xff1a; sudo sh -c echo…

字符串左旋

题目&#xff1a;字符串左旋 内容&#xff1a;实现一个函数&#xff0c;可以左旋字符串中的K个字符。 例如&#xff1a; ABCDEF左旋一个字符可以得到BCDEFA ABCDEF左旋两个字符可以得到CDEFAB 方法一&#xff1a;移动字符 #include <stdio.h> #include <string.h>c…

BUUCTF-Real-[ThinkPHP]2-Rce1

任意代码执行漏洞 ThinkPHP 2.x版本中&#xff0c;使用preg_replace的/e模式匹配路由&#xff1a; $res preg_replace((\w).$depr.([^.$depr.\/])e, $var[\\\1\]"\\2";, implode($depr,$paths)); 导致用户的输入参数被插入双引号中执行&#xff0c;造成任意代码执行…

Windows Server 2019 DNS服务器搭建

系列文章目录 目录 系列文章目录 文章目录 前言 一、DNS服务器是什么&#xff1f; 二、配置服务器 1.实验环境搭建 1)实验服务器配置和客户端 2)实验环境 2.服务器配置 正向解析配置 反向解析 实验验证 文章目录 Windows Server 2003 Web服务器搭建Windows Server…

【c/python】GtkBox

一、GtkBox及C语言示例 GtkBox是一个容器部件&#xff0c;用于在GTK&#xff08;GIMP Toolkit&#xff09;应用程序中水平或垂直地排列多个子部件。以下是一个简单的例子&#xff0c;展示了如何在一个基本的GTK应用程序中使用GtkBox来垂直排列两个按钮&#xff1a; 首先&#…

OpenAI开放新功能,可通过@一键调用任意GPTs

人工智能技术的快速发展为我们的生活带来了许多便利和创新。作为人工智能领域的重要成果之一&#xff0c;OpenAI的GPT&#xff08;Generative Pre-trained Transformer&#xff09;模型在自然语言处理方面取得了巨大的突破。 近日&#xff0c;OpenAI宣布推出了GPT Mentions功能…

VC++中使用OpenCV绘制直线、矩形、圆和文字

VC中使用OpenCV绘制直线、矩形、圆和文字 在VC中使用OpenCV绘制直线、矩形、圆和文字非常简单&#xff0c;分别使用OpenCV中的line、rectangle、circle、putText这四个函数即可。具体可以参考OpenCV官方文档&#xff1a;https://docs.opencv.org/4.x/index.html 下面的代码展…

Linux进程信号处理:深入理解与应用(2​​)

&#x1f3ac;慕斯主页&#xff1a;修仙—别有洞天 ♈️今日夜电波&#xff1a;its 6pm but I miss u already.—bbbluelee 0:01━━━━━━️&#x1f49f;──────── 3:18 &#x1f504; ◀️…

2. 路由 Vue-Router

目录 2.1 Vue-Router 介绍 2.2 路由配置 2.3 嵌套路由 Vue1&#xff1a;基础跟使用方式 2.1 Vue-Router 介绍 vue 属于单页面应用&#xff0c;所谓路由&#xff0c;就是根据浏览器路径不同&#xff0c;用不同的视图组件替换这个页面内容。 在vue应用中使用路由功能&#x…

JupyterLab 更换内核 使用 conda 虚拟环境

未有conda虚拟环境default先创建环境 conda create -n default python3.8 ipykernel已有conda虚拟环境default激活后安装ipykernel conda activate defaultpip install ipykernel将虚拟环境写入 jupyter notebook 的 kernel 中 python -m ipykernel install --user --name 虚…

SpringBoot security 安全认证(三)——自定义注解实现接口放行配置

背景&#xff1a;通过Security实现了安全管理&#xff0c;可以配置哪些接口可以无token直接访问。但一个麻烦就是每增加一个匿名访问接口时都要去修改SecurityConfig配置&#xff0c;从程序设计上讲是不太让人接受的。 本节内容&#xff1a;即是解决以上问题&#xff0c;增加一…

SpringBoot整合Flowable最新教程(二)启动流程

介绍 文章主要从SpringBoot整合Flowable讲起&#xff0c;关于Flowable是什么&#xff1f;数据库表解读以及操作的Service请查看SpringBoot整合Flowable最新教程&#xff08;一&#xff09;&#xff1b;   其他说明&#xff1a;Springboot版本是2.6.13&#xff0c;java版本是1…

python2.7安装和添加环境变量

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、python的下载地址二、安装步骤1.双击安装包运行安装2.添加环境变量 三、验证是否安装成功总结 前言 最近要用到python,下载安装成功&#xff0c;添加环境变…

Java 数据结构 二叉树(二)红黑树

目录 数据结构图-树 简介 规则 旋转 重新着色 红黑树构建过程 前言-与正文无关 生活远不止眼前的苦劳与奔波&#xff0c;它还充满了无数值得我们去体验和珍惜的美好事物。在这个快节奏的世界中&#xff0c;我们往往容易陷入工作的漩涡&#xff0c;忘记了停下脚步&#xf…

华清远见嵌入式学习——春节作业——2.4日

作业要求&#xff1a; 编写程序实现二叉树的创建&#xff0c;三种遍历自己销毁 作业答案&#xff1a; 作业代码截图 作业代码效果图 作业代码 #include "myhead.h"// 定义二叉树节点结构体 struct Tree {int value; //编号(值)struct Tree* left; //左子树stru…

9隐藏登录用户(无需接触磁盘即可修改文件内容)_Linux_Rootkit.md

Xcellerator 密码学Linux其他逆向工程 文章目录 [Linux Rootkit 第 9 部分&#xff1a;隐藏登录用户&#xff08;无需接触磁盘即可修改文件内容&#xff09;](https://xcellerator.github.io/posts/linux_rootkits_09/)终端设备UTMP用户空间工具如何解析 UTMP&#xff1f;挂钩…