使用 Vue.js 和 Tailwind 构建动画可拖动界面
前端环境在过去几年发生了很大变化(希望变得更好)。现在有一些工具和技术可以帮助我们快速有效地取得出色的成果。在这些工具中,Vue.js 和 Tailwind 的组合脱颖而出,因为它让您可以超级快速地构建原型(而不仅仅是原型)并在此过程中非常轻松地对其进行修改。如今,快速行动和适应变化似乎是人们非常重视的事情。在本文中,我们将探索如何使用 Vue.js 和 Tailwind 构建动画可拖动界面。下面
前端环境在过去几年发生了很大变化(希望变得更好)。现在有一些工具和技术可以帮助我们快速有效地取得出色的成果。在这些工具中,Vue.js 和 Tailwind 的组合脱颖而出,因为它让您可以超级快速地构建原型(而不仅仅是原型)并在此过程中非常轻松地对其进行修改。如今,快速行动和适应变化似乎是人们非常重视的事情。在本文中,我们将探索如何使用 Vue.js 和 Tailwind 构建动画可拖动界面。下面是要构建的示例之一。如果你只是想看代码,可以在这里找到。让我们开始吧。
[](https://res.cloudinary.com/practicaldev/image/fetch/s--lEz4-2I1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.buttercms .com/hPbVGLABTGqNDx1MOxXw)
设置
1\。我们将使用Vue CLI来搭建一个新项目。它将是具有 Babel 和预处理器支持的基本版本
[](https://res.cloudinary.com/practicaldev/image/fetch/s--UcRj0jjb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.buttercms.com /IbFlhAx7QKSzekvPjfe3)[](https://res.cloudinary.com/practicaldev/image/fetch/s--Tn544JAw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn. Buttercms.com/8LxMS2nVTa2GTTGLjPtx)
2\。我们将安装tailwindcss 并对其进行配置,以便我们可以在 css 中使用 @apply、@screen 实用程序。
您可以在此处按照安装步骤进行操作,但我们也会在下面列出它们。
-
npm install tailwindcss
-
在
src/assets/css/tailwind.css
内新建一个文件,内容如下
@tailwind base;
@tailwind components;
@tailwind utilities;
- 在您的 App.vue 或 main.js 文件中导入此文件
导入'./assets/css/tailwind.css'
-
运行
<span>npx tailwind init</span>
以创建顺风配置文件 -
在 postcss.config.js 或 package.json 中的 postcss 对象内添加这两行代码(以防万一)。请注意,您不必安装任何东西。 Autoprefixer 应该在 Vue CLI 中默认存在
module.exports = {
plugins: [
// ...
require('tailwindcss'),
require('autoprefixer'),
// ...
]
}
而已!我们完成了设置。
创建用户列表
我们将从一个不错的用户列表开始。使用 Tailwind 和 Vue 非常简单。
[](https://res.cloudinary.com/practicaldev/image/fetch/s--_0tMATYw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.buttercms.com /yL9v6zaiQlmASGvkeMg5)
为简单起见,我们现在将所有代码都放在 App.vue 文件中。
1\。布局和背景。我们将首先为页面添加背景并将页面中的所有内容居中。
<div id="app" class="min-h-screen w-screen bg-gray-200 flex items-center justify-center">
</div>
我们将使用的所有 css 类都来自 tailwind 的默认类集。您可以在文档中找到它们,但其中大多数都是不言自明的。
2\。创建列表和卡片。我们将添加一个小数组对象来定义我们的列表。我们的用户将在 App.vue 文件的 data 部分中声明
data() {
return {
users: [
{
id: 1,
name: "Adrian Schubert",
avatar: "https://pickaface.net/gallery/avatar/unr_sample_161118_2054_ynlrg.png"
},
{
id: 2,
name: "Violet Gates",
avatar: "https://pickaface.net/gallery/avatar/freud51c8b3f65e7dc.png"
},
{
id: 3,
name: "Steve Jobs",
avatar: "https://pickaface.net/gallery/avatar/Opi51c74d0125fd4.png"
},
{
id: 4,
name: "Yassine Smith",
avatar: "https://pickaface.net/gallery/avatar/unr_yassine_191124_2012_3gngr.png"
},
{
id: 5,
name: "Senior Saez",
avatar: "https://pickaface.net/gallery/avatar/elmedinilla541c03412955c.png"
}
]
}
}
现在我们有了 users 数组,我们可以非常快速地创建列表并遍历用户以显示卡片。
<ul>
<li v-for="user in users" :key="user.id">
{{user.name}}
</li>
</ul>
好的,但该列表根本没有样式。我们可以通过一些顺风工具来解决这个问题。
<ul class="w-full max-w-md">
<li v-for="user in users"
:key="user.id"
class="p-4 mb-3 flex justify-between items-center bg-white shadow rounded-lg cursor-move">
{{user.name}}
</li>
</ul>
我们的用户列表现在应该或多或少像这样
[](https://res.cloudinary.com/practicaldev/image/fetch/s--a0xKJRty--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.buttercms.com /zVDY3ccBRdGldIzkcMHA)
我们将为其添加更多细节,例如头像和一些操作按钮。对于操作按钮,我们将使用Vue Feather Icons。它是一组 SVG 图标,可以作为 svg 组件导入。
确保安装它npm install vue-feather-icons
由于我们的 users 数组中已经有了头像 url,因此设置头像的样式将非常简单。
<div class="flex items-center">
<img class="w-10 h-10 rounded-full" :src="user.avatar" :alt="user.name">
<p class="ml-2 text-gray-700 font-semibold font-sans tracking-wide">{{user.name}}</p>
</div>
我们的列表现在应该是这样的。好多了!
[](https://res.cloudinary.com/practicaldev/image/fetch/s--4b1fAaVf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.buttercms.com /H7RB7STTTme1JcPC5TsL)
添加拖放支持之前的最后一步是添加那些操作按钮(这是可选的),但我们将这样做是为了示例的完整性。
我们将首先添加图标组件和一些占位符方法。
import { EditIcon, Trash2Icon } from "vue-feather-icons";
export default {
name: "App",
components: {
EditIcon,
Trash2Icon
},
// data
methods: {
onEdit(user) {
alert(`Editing ${user.name}`);
},
onDelete(user) {
alert(`Deleting ${user.name}`);
}
}
}
然后是操作按钮的 html 部分
<div class="flex">
<button aria-label="Edit user"
class="p-1 focus:outline-none focus:shadow-outline text-teal-500 hover:text-teal-600"
@click="onEdit(user)">
<EditIcon/>
</button>
<button aria-label="Delete user"
class="p-1 focus:outline-none focus:shadow-outline text-red-500 hover:text-red-600"
@click="onDelete(user)">
<Trash2Icon/>
</button>
</div>
我们的用户列表在视觉上是完整的。唯一缺少的部分是拖放支持。
[](https://res.cloudinary.com/practicaldev/image/fetch/s--DdiBDJRb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.buttercms.com /3IIVrVQDRN2oQb5ejaCl)
添加拖放支持
对于拖放支持,我们将使用Vue Draggable,它是一个很棒的库(SortableJS 的包装器),它公开了一个组件,您可以使用它来制作可拖动的东西。它非常适合您完全控制 HTML 的地方,但是当涉及第三方组件或例如将其与第三方数据表集成时,最好直接使用 SortableJS。
好的,让我们开始安装它npm install vuedraggable
,然后导入可拖动组件
import Draggable from 'vuedraggable'
export default {
components: {
// other components
Draggable
}
}
现在为了使我们的列表可拖动,我们只需将卡片包装在这个可拖动组件中。
<draggable :list="users">
<li v-for="user in users"
:key="user.id">
<!-- Card code here-->
</li>
</draggable>
通过:list="users"
属性引用我们想要添加拖动支持的列表非常重要,因此可拖动组件知道这是它应该使用的列表。
虽然这已经是一个很好的进步,但我们还有一些问题:用户体验不是很好,并且在我们的<ul>
标签内放置了一个额外的 div。这是因为 draggable 创建了一个额外的 html 元素并将其包裹在我们的列表中。幸运的是,这很容易解决。
[](https://res.cloudinary.com/practicaldev/image/fetch/s--M_3tTb80--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.buttercms.com /7OUeR9K3Ryqe5eyLb33M)
我们可以将draggable
组件转换为<ul>
标签,然后删除旧的 ul 标签。
<draggable tag="ul" class="w-full max-w-md" :list="users">
好的,现在让我们添加动画支持和一些样式。对于动画,有一个animation
道具
<draggable tag="ul" class="w-full max-w-md" :list="users" :animation="200">
现在我们支持了非常棒的流畅动画。我们可以更进一步,突出显示当前正在移动的卡片。我们可以通过一个名为ghost-class
的道具来做到这一点。每当我们选择一个元素并想要拖动它时,Vue draggable 都会将这个类添加到移动元素中。让我们将其命名为moving-card
。另外,为了改善移动端的用户体验,特别是我们将确保我们的卡片不能通过使用filter
道具和过滤我们的按钮来拖动。在这种情况下,我们的过滤器看起来像这样filter=".action-button"
我们的按钮应该包含此类,并且 vue draggable 将忽略这些元素,因此用户可以自由点击它们而不会意外拖动卡片。
<draggable tag="ul" ghost-class="moving-card" filter=".action-button" class="w-full max-w-md" :list="users" :animation="200">
现在,如果您打开 devtools 并拖动其中一张卡片,您将看到此类已应用于移动卡片。我们可以使用它来设置拖动卡片的样式。
! 100076 undefined 100077 100075
在这种情况下,样式将降低不透明度并突出显示边框。我们可以在我们的 CSS 中使用 tailwind@apply
指令来实现
<style lang="scss">
.moving-card {
@apply opacity-50 bg-gray-100 border border-blue-500;
}
</style>
现在我们有了一个动画可拖动列表的完整示例。每当我们在其中移动项目时,users
列表将自动更新它在数组中的对象位置。例如,如果我们将第一个用户移动到最后一个位置,它将自动交换我们数组中索引 0 和索引 4 的内容。您可以在此处找到的完整示例以及单独的github 存储库,您可以在其中针对上述每个步骤遵循git 历史记录。
在两个列表之间拖动元素
在某些实际场景中,我们可能必须将元素从一个地方拖到另一个地方,例如将用户从一个组移动到另一个组,或者将看板中的任务从一列移动到另一列。
我们可以通过 vue draggable 中的group
属性简单地实现这一点。如果你已经做到了这一步,那么这意味着你已经掌握了上面的一些概念,我们将从这里开始更快一点。
首先我们要提取我们的用户卡组件
<template>
<li class="p-4 mb-3 flex justify-between items-center bg-white shadow rounded-lg cursor-move">
<div class="flex items-center">
<img class="w-10 h-10 rounded-full" :src="user.avatar" :alt="user.name">
<p class="ml-2 text-gray-700 font-semibold font-sans tracking-wide">{{user.name}}</p>
</div>
<div class="flex">
<button aria-label="Edit user"
class="p-1 focus:outline-none focus:shadow-outline text-teal-500 hover:text-teal-600"
@click="$emit('on-edit', user)">
<EditIcon/>
</button>
<button aria-label="Delete user"
class="p-1 focus:outline-none focus:shadow-outline text-red-500 hover:text-red-600"
@click="$emit('on-delete', user)">
<Trash2Icon/>
</button>
</div>
</li>
</template>
<script>
import { EditIcon, Trash2Icon } from "vue-feather-icons";
export default {
components: {
EditIcon,
Trash2Icon
},
props: {
user: {
type: Object,
default: () => ({})
}
},
}
</script>
现在我们的列表应该如下所示:
<draggable tag="ul"
class="w-full max-w-md"
ghost-class="moving-card"
:list="users"
:animation="200">
<user-card v-for="user in users"
:user="user"
:key="user.id"
@on-edit="onEdit"
@on-delete="onDelete">
</user-card>
</draggable>
我们将在它附近与另一组用户创建另一个这样的列表。我们的模板应该或多或少像这样
<div class="w-full max-w-md text-center">
<p class="mb-2 text-gray-700 font-semibold font-sans tracking-wide">List 1</p>
<draggable tag="ul"
ghost-class="moving-card"
:list="users"
:animation="200">
<user-card v-for="user in users"
:user="user"
:key="user.id"
@on-edit="onEdit"
@on-delete="onDelete">
</user-card>
</draggable>
</div>
<div class="w-full max-w-md ml-12 text-center">
<p class="mb-2 text-gray-700 font-semibold font-sans tracking-wide">List 2</p>
<draggable tag="ul"
ghost-class="moving-card"
:list="newUsers"
:animation="200">
<user-card v-for="user in newUsers"
:user="user"
:key="user.id"
@on-edit="onEdit"
@on-delete="onDelete">
</user-card>
</draggable>
</div>
此时,如果我们想将用户从一个列表移动到另一个列表,我们将无法做到这一点。为了实现这一点,我们必须通过 group 属性指定可拖动组件是同一个**“group”**的一部分。
<draggable tag="ul" group="all-users" :list="users">
<draggable tag="ul" group="all-users" :list="newUsers">
组的名称在这里并不重要。它必须相同,以便 vue draggable 知道它可以接受两个列表之间的项目。
如果您打开 Vue 开发工具并将用户从一个列表移动到另一个列表,您将看到 2 个列表正在相应更新
[](https://res.cloudinary.com/practicaldev/image/fetch/s--v9U0mCSa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.buttercms.com /qEdVn7yxRrSOkc8MhWtD)
你可以在这里找到完整的代码
这里有一个有趣的注意事项是用户实际上被移动了(从第一个列表中删除并添加到第二个列表中)。如果您碰巧需要克隆用户的行为,您可以通过更明确的组配置来实现。
例如,如果您想在从列表中拖动用户时“克隆”用户,并且不允许将用户从列表 2 移动到列表 1,您可以这样做:
:group="{ name: 'all-users', pull: 'clone', put: false }"
还有许多有用的事件和道具,您可以在这里找到可以让您有更多的限制,例如没有重复的项目,在某些情况下通过 move 回调禁用项目的移动等等。
我们的网站上有另一个很酷的看板示例,您可以在这里查看,它几乎使用了上述技术。
结论
使用 Vue.js 和 Tailwind 构建漂亮的动画可拖动界面相对简单。 Tailwind 非常适合快速设计样式,而 Vue.js 提供了提取可重用组件和添加交互性的额外灵活性。
希望您喜欢所提供的示例和步骤,并随时对您可能认为本文遗漏的任何建议或内容发表评论。干杯!
如果您想打造一款很酷的产品或只是想聊天,请随时给我们留言
更多推荐
所有评论(0)