迎接Skeleton——应对反应式用户界面的Svelte + Tailwind

696 阅读10分钟

如果你曾经发现自己的任务是创建和实施定制的用户界面,那么你就知道要满足现代网络的需求是多么困难。你的界面必须具有响应性、反应性和可访问性,同时保持对广大用户的视觉吸引力。让我们面对现实吧;即使是最老练的前端开发者,这也是一个挑战。

在过去的十年中,我们已经看到了有助于减轻这一负担的UI框架的引入。大多数框架都依赖于JavaScript,并依靠组件和反应式模式来处理实时的用户交互。像AngularReactVue这样的框架已经被确立为我们目前所知的现代前端开发的标准

除了这些工具,我们还看到了像Angular MaterialMantine(用于React)和Vuetify这样的特定框架库的兴起,它们为实现UI提供了一种 "包含电池 "的方法,包括对每个框架的独特功能集的深度整合。随着Svelte等新框架的出现,我们可能会看到类似的库出现以履行这一角色。为了深入了解这些工具可能如何工作,让我们回顾一下Svelte给前端开发带来了什么。

Svelte和SvelteKit

2016年,Rich Harris介绍了Svelte,这是一个用于网络的全新组件。要了解Svelte的好处,请看他在2019年会议上发表的题为 "重新思考反应性 "的演讲,Rich解释了Svelte的起源,并展示了其独特的编译器驱动方法。

Skeleton是由Brain & Bones的开发团队创立的。该团队,包括我自己,一直对Svelte和它为前端开发者带来的工具印象深刻。团队和我正在考虑将几个内部项目从Angular迁移到SvelteKit,当时我们意识到有机会将Svelte的直观组件系统与Tailwind的实用驱动设计系统结合起来,因此Skeleton诞生了。

团队意识到Skeleton有可能使Svelte社区的许多人受益,因此,我们决定将其开源化。我们希望看到Skeleton成长为一个强大的UI工具包,可以帮助许多开发者,无论你的技能是否在前端领域。

为了了解我们的意思,让我们花点时间来创建一个基本的SvelteKit应用程序并整合Skeleton。

开始使用骨架

打开你的终端,运行以下每个命令。请确保将 "my-skeleton-app "设置为你喜欢的任何名称。当出现提示时,我们建议使用Typescript并创建一个裸体(又称 "骨架")项目。

npm create svelte@latest my-skeleton-app
cd my-skeleton-app
npm install
npm run dev -- --open

这将生成SvelteKit应用程序,将你的终端移动到项目目录中,安装所有需要的依赖项,然后启动本地开发服务器。在这里使用-- --open 标志将在你的浏览器中自动打开以下地址。

http://localhost:5173/

在你的终端中,使用Ctrl+C来关闭和停止服务器。别担心,我们一会儿就会恢复它。

接下来,我们需要安装Tailwind。Svelte-add有助于使这一过程变得微不足道。只需运行以下命令,它就会处理剩下的事情。

npx svelte-add@latest tailwindcss
npm install

这将把最新的Tailwind版本安装到你的项目中,创建/src/app.css 来存放你的全局CSS,并生成必要的tailwind.config.cjs 。然后,我们安装我们的新Tailwind依赖。

最后,让我们通过NPM安装Skeleton包。

npm i @brainandbones/skeleton --save-dev

我们几乎已经准备好添加我们的第一个组件了,我们只需要对项目配置做几个快速的更新。

配置Tailwind

为了确保Skeleton与Tailwind的良好配合,在你的项目根部打开tailwind.config.cjs ,并添加以下内容。

module.exports = {
    content: [
        // ...
        './node_modules/@brainandbones/skeleton/*/.{html,js,svelte,ts}'
    ],
    plugins: [
        require('@brainandbones/skeleton/tailwind.cjs')
    ]
}

content 部分确保编译器知道我们的Skeleton组件中的所有Tailwind类,而plugins 使用一个Skeleton文件,为我们将在下一节中设置的主题做准备。

实现一个Skeleton主题

Skeleton包括一个简单而强大的主题系统,该系统倾向于Tailwind的最佳实践。该主题控制所有组件的视觉外观,并智能地适应黑暗模式,同时还提供了对代表你的主题独特调色板的Tailwind实用类的访问。

骨架团队提供了一套精心策划的主题,以及一个主题生成器,以帮助设计自定义主题,使用Tailwind颜色或十六进制颜色来匹配您的品牌形象。

为了保持简单,我们将从Skeleton的默认主题开始。将以下CSS复制到*/src/theme.css*中的一个新文件中。

:root {
    /* --- Skeleton Theme --- */
    /* primary (emerald) */
    --color-primary-50: 236 253 245;
    --color-primary-100: 209 250 229;
    --color-primary-200: 167 243 208;
    --color-primary-300: 110 231 183;
    --color-primary-400: 52 211 153;
    --color-primary-500: 16 185 129;
    --color-primary-600: 5 150 105;
    --color-primary-700: 4 120 87;
    --color-primary-800: 6 95 70;
    --color-primary-900: 6 78 59;
    /* accent (indigo) */
    --color-accent-50: 238 242 255;
    --color-accent-100: 224 231 255;
    --color-accent-200: 199 210 254;
    --color-accent-300: 165 180 252;
    --color-accent-400: 129 140 248;
    --color-accent-500: 99 102 241;
    --color-accent-600: 79 70 229;
    --color-accent-700: 67 56 202;
    --color-accent-800: 55 48 163;
    --color-accent-900: 49 46 129;
    /* warning (rose) */
    --color-warning-50: 255 241 242;
    --color-warning-100: 255 228 230;
    --color-warning-200: 254 205 211;
    --color-warning-300: 253 164 175;
    --color-warning-400: 251 113 133;
    --color-warning-500: 244 63 94;
    --color-warning-600: 225 29 72;
    --color-warning-700: 190 18 60;
    --color-warning-800: 159 18 57;
    --color-warning-900: 136 19 55;
    /* surface (gray) */
    --color-surface-50: 249 250 251;
    --color-surface-100: 243 244 246;
    --color-surface-200: 229 231 235;
    --color-surface-300: 209 213 219;
    --color-surface-400: 156 163 175;
    --color-surface-500: 107 114 128;
    --color-surface-600: 75 85 99;
    --color-surface-700: 55 65 81;
    --color-surface-800: 31 41 55;
    --color-surface-900: 17 24 39;
}

注意。 颜色从Hex转换为RGB,以正确支持Tailwind的背景不透明度

接下来,让我们来配置SvelteKit以使用我们的新主题。要做到这一点,打开你的根布局文件:/src/routes/__layout.svelte 。在你的全局样式表之前声明你的主题app.css

import '../theme.css'; // <--
import '../app.css';

为了使事情看起来更漂亮,我们将添加一些基本的<body> 元素样式,支持浅色或深色模式系统设置。将以下内容添加到你的/src/app.css

body { @apply bg-surface-100 dark:bg-surface-900 text-black dark:text-white p-4; }

更多的说明,请参考样式文档,其中包括更详细的全局样式。

添加一个组件

最后,让我们来实现我们的第一个Skeleton组件。打开你的应用程序的主页/src/routes/index.svelte ,添加以下内容。请随意替换该文件的全部内容。

<script lang="ts">
    import { Button } from '@brainandbones/skeleton';
</script>

<Button variant="filled-primary">Skeleton</Button>

为了预览这个,我们需要重启我们的本地开发服务器。在你的终端中运行npm run dev ,并将你的浏览器指向http://localhost:5173/ 。你应该看到页面上出现了一个Skeleton Button组件。

定制组件

与任何Svelte组件一样,可以提供自定义 "props"(读作:属性)来配置你的组件。例如,按钮组件的variant 道具允许我们设置任何数量的罐装选项,以适应你的主题。通过将变量值切换到filled-accent ,我们将看到按钮从我们主题的主色(翡翠色)变为重点色(靛蓝色)。

每个组件都提供了一组道具,供你随意配置。参见Button文档,尝试一个交互式沙盒,你可以测试不同的尺寸、颜色等。

你可能注意到,许多道具值与Tailwind的类名相似。事实上,这正是这些东西!这些道具是逐字提供的。这些道具是逐字提供给组件的模板的。这意味着我们可以将一个组件的背景风格设置为任何主题颜色、任何Tailwind颜色,甚至可以使用Tailwind的任意值语法设置一个一次性的颜色。

<!-- Using our theme color -->
<Button background="bg-accent-500">Accent</Button>

<!-- Using Tailwind colors -->
<Button background="bg-orange-500">Orange</Button>

<!-- Using Tailwind's arbitrary value syntax -->
<Button background="bg-[#BADA55]">Arbitrary</Button>

这使你能够控制保持一套有凝聚力的风格,或者选择用任意值 "画出线外"。不过,你并不局限于默认的道具。你可以使用标准的class 属性为一个组件提供任何有效的CSS类。

<Button variant="filled-primary" class="py-10 px-20">Big!</Button>

形式与功能的结合

像Skeleton这样的框架专用库的主要好处之一是有可能深度整合框架的独特功能集。为了看看Skeleton是如何与Svelte整合的,让我们试试Skeleton的对话系统

首先,在你的应用程序的全局范围内添加Dialog组件。最简单的方法是打开/src/routes/__layout.svelte ,在<slot /> 元素上方添加以下内容。

<script lang="ts">
    // ...
    import { Dialog } from '@brainandbones/skeleton';
</script>

<!-- Add the Dialog component here -->
<Dialog />

<slot />

注意。 对话框组件在页面上默认是不可见的。

接下来,让我们更新我们的主页以触发我们的第一个对话框。打开/src/routes/index.svelte ,用下面的内容替换整个内容。

<script lang="ts">
    import { Button, dialogStore } from '@brainandbones/skeleton';
    import type { DialogAlert } from '@brainandbones/skeleton/Notifications/Stores';

    function triggerDialog(): void {
        const d: DialogAlert = {
            title: ‘Welcome to Skeleton.’,
            body: ‘This is a standard alert dialog.’,
        };
        dialogStore.trigger(d);
    }
</script>

<Button variant="filled-primary" on:click={() => { triggerDialog() }}>Trigger Dialog</Button>

这就提供了触发对话框所需的所有脚手架。在你的浏览器中,点击该按钮,你应该看到你的新对话框信息出现了

Skeleton使用Svelte的可写存储实现了这一点,它是帮助管理全局状态的反应式对象。当按钮被点击时,对话框存储被触发,一个对话框的实例被提供给该存储。然后,该存储空间作为一个队列。由于存储是反应式的,这意味着我们的对话框组件可以监听对存储内容的任何更新。当一个新的对话框被添加到队列中时,对话框组件就会更新以显示屏幕上的内容。

Skeleton总是显示队列中最上面的对话框。当被驳回时,它就会显示队列中的下一个对话框。如果没有剩余的对话框,Dialog组件就会隐藏并返回到默认的不可见状态。

这里有一个简单的模拟,以帮助可视化对话存储队列的数据结构。

dialogStore = [
    // dialog #1, <-- top items the queue, shown on screen
    // dialog #2, <-- the next dialog in line
    // dialog #3, <-- bottom of the queue, the last added
];

正是Skeleton与Svelte功能的紧密结合使这成为可能。这就是针对框架的工具的力量--结构、设计和功能都在一个紧密耦合的软件包中!

了解更多关于骨架的信息

目前,Skeleton处于早期访问测试阶段,但如果你想了解更多,请随时访问我们的文档。该网站提供了详细的指南以帮助开始使用,并涵盖了全套可用的组件和工具。你可以在Skeleton的GitHub上报告问题,请求演练,或贡献代码。我们也欢迎你加入我们的Discord社区,与贡献者聊天并展示你用Skeleton创建的项目。

Skeleton是由Brain & Bones创立的。我们满足游戏玩家对竞争的热爱,提供一个平台,利用超休闲游戏的力量来提高在线和现场的参与度。