前端环境在过去几年发生了很大变化(希望变得更好)。现在有一些工具和技术可以帮助我们快速有效地取得出色的成果。在这些工具中,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 提供了提取可重用组件和添加交互性的额外灵活性。

希望您喜欢所提供的示例和步骤,并随时对您可能认为本文遗漏的任何建议或内容发表评论。干杯!

如果您想打造一款很酷的产品或只是想聊天,请随时给我们留言

Logo

前往低代码交流专区

更多推荐