
一、前言
这个是我的示例站点,在这里可以看到我目前的进度,www.csyblog.cn/
在决定开发前,我已经看了无数个博客站点,包括一些开源博客系统主题,没有一款是百分百贴合我心意的,这可能就是技术人的通病。但是依然还是有一些很好的创意值得学习,所以我没法在这里给大家一个完整的UI设计,大家可以在这几个网站找一找有没有自己中意的,或者同我一样自由发挥。
本文涉及的所有文档官方地址:
nuxt官网:nuxt.com/
tailwindcss官网:tailwindcss.com/
Inspira UI官网:inspira-ui.com/
motion-v官网:motion.dev/docs/vue/
二、动画组件库 Inspira UI
这是一个开源组件库:快速、高效地构建现代、美观且用户友好的网页或 Web 应用程序。
官网地址:inspira-ui.com/
不瞒您说,这也是我第一次用这个组件库,在一次摸鱼时发现了它,当时就给我留下了比较好的映像,正好这次有机会,就安排上了,而且与 Nuxt + Tailwindcss 高度契合。
正好,这也是我想要传达给大家的一个重要的点,如果去将一个从未接触过的东西应用于我们自己的项目中。
1. 这个组件库是否值得使用?
-
是否可靠性?
- 首先我们可以看一下他的 github star 数,issue 维护情况,以及最近几次 commit 时间。
- 是否有清晰完整的文档,有中文加分,没有也无所谓。
-
是否与当前项目契合?
- 技术栈是否有冲突
- 整合起来改动大不大

如果决定使用,处于职业道德,记得去
GitHub点个 star 支持一下!
2. 安装
技术更新日新月异,各类博主分享的整合案例和教程固然有参考价值,但项目版本与文章内容未必能始终保持一致。如果完全照搬,即便偶尔能成功整合,也常会遇到意料之外的问题。因此,我建议大家养成以官方文档为准的习惯,主动查看官网的最新安装指南和说明------这才是确保环境配置顺利、减少不必要麻烦的最佳路径。
后续我的文章里将不会再列出一些基础的指令,必要的地方我会指明出处。
文档地址:inspira-ui.com/docs/gettin...

1. 安装 tailwindcss, 这个我们之前已经通过模块安装好了。
这里我其实有些顾虑,因为我们是通过模块安装的,这里推荐的是通过
tailwindcss官网,直接整合进项目。所以与我们目前项目还是存在差异的,暂时留个心眼,如果发现有问题,再回过头来调整。
2. 添加一些库
arduino
pnpm install -D clsx tailwind-merge class-variance-authority tw-animate-css
3. 安装 VueUse 和其他支持库。
bash
pnpm install @vueuse/core motion-v
按照此指南在Vue或Nuxt上设置motion-v。 motion.dev/docs/vue
文档中指出,nuxt 提供了模块方式,所以其实这里可以只安装 VueUse 库就可以

- 将以下代码添加到
main.css文件中,其实就是一些变量
到这里发现,我们之前并没有定义 main.css,但是我为了让 vscode 有代码提示,加过一个 tailwindcss,这个文件只是起到了让编辑器能够读到指令提示。并没有真正的引入项目中。
那我们可以重新按照这里去做,删掉之前的 tailwindcss.css。当然别忘了,这次要真正的引入到项目中。
typescript
// https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({
compatibilityDate: '2025-07-15',
devtools: { enabled: true },
+++ css: ['./app/assets/css/main.css'],
modules: ['@nuxtjs/tailwindcss','motion-v/nuxt']
})
main.css
css
@import "tailwindcss";
@import "tw-animate-css";
@custom-variant dark (&:is(.dark *));
:root {
--card: oklch(1 0 0);
--card-foreground: oklch(0.141 0.005 285.823);
--popover: oklch(1 0 0);
--popover-foreground: oklch(0.141 0.005 285.823);
--primary: oklch(0.21 0.006 285.885);
--primary-foreground: oklch(0.985 0 0);
--secondary: oklch(0.967 0.001 286.375);
--secondary-foreground: oklch(0.21 0.006 285.885);
--muted: oklch(0.967 0.001 286.375);
--muted-foreground: oklch(0.552 0.016 285.938);
--accent: oklch(0.967 0.001 286.375);
--accent-foreground: oklch(0.21 0.006 285.885);
--destructive: oklch(0.577 0.245 27.325);
--destructive-foreground: oklch(0.577 0.245 27.325);
--border: oklch(0.92 0.004 286.32);
--input: oklch(0.92 0.004 286.32);
--ring: oklch(0.705 0.015 286.067);
--radius: 0.625rem;
--background: oklch(1 0 0);
--foreground: oklch(0.141 0.005 285.823);
}
.dark {
--background: oklch(0.141 0.005 285.823);
--foreground: oklch(0.985 0 0);
--card: oklch(0.141 0.005 285.823);
--card-foreground: oklch(0.985 0 0);
--popover: oklch(0.141 0.005 285.823);
--popover-foreground: oklch(0.985 0 0);
--primary: oklch(0.985 0 0);
--primary-foreground: oklch(0.21 0.006 285.885);
--secondary: oklch(0.274 0.006 286.033);
--secondary-foreground: oklch(0.985 0 0);
--muted: oklch(0.274 0.006 286.033);
--muted-foreground: oklch(0.705 0.015 286.067);
--accent: oklch(0.274 0.006 286.033);
--accent-foreground: oklch(0.985 0 0);
--destructive: oklch(0.396 0.141 25.723);
--destructive-foreground: oklch(0.637 0.237 25.331);
--border: oklch(0.274 0.006 286.033);
--input: oklch(0.274 0.006 286.033);
--ring: oklch(0.442 0.017 285.786);
}
@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
--color-card: var(--card);
--color-card-foreground: var(--card-foreground);
--color-popover: var(--popover);
--color-popover-foreground: var(--popover-foreground);
--color-primary: var(--primary);
--color-primary-foreground: var(--primary-foreground);
--color-secondary: var(--secondary);
--color-secondary-foreground: var(--secondary-foreground);
--color-muted: var(--muted);
--color-muted-foreground: var(--muted-foreground);
--color-accent: var(--accent);
--color-accent-foreground: var(--accent-foreground);
--color-destructive: var(--destructive);
--color-destructive-foreground: var(--destructive-foreground);
--color-border: var(--border);
--color-input: var(--input);
--color-ring: var(--ring);
--radius-sm: calc(var(--radius) - 4px);
--radius-md: calc(var(--radius) - 2px);
--radius-lg: var(--radius);
--radius-xl: calc(var(--radius) + 4px);
}
@layer base {
* {
@apply border-border outline-ring/50;
}
body {
@apply bg-background text-foreground;
}
}
html {
color-scheme: light dark;
}
html.dark {
color-scheme: dark;
}
html.light {
color-scheme: light;
}
4. 将以下实用程序添加到 utils.ts
typescript
import { type ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge";
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
export type ObjectValues<T> = T[keyof T];

到这里,就完成了所有整合工作。下面还提供了一些可选操作,整合Icon图标,但是目前我们还用不上,暂时不操作。
3. 测试
我们已经完成了,所有整合操作,接下来体验一下。
作为首页,我想要一个超级炫酷,能够吸引读者的背景。

cv大法,直接将代码全部复制,粘贴到 App.vue 中,启动项目。

报错啦!!!

但是好在我们早有心理准备,可能就是因为之前我们是通过模块引入的
tailwindcss,导致这里找不到。那我们直接改成通过官网引入方式再试一下。直达链接:tailwindcss.com/docs/instal...

1. 先卸载之前通过模块引入的 tailwindcss
bash
pnpm uninstall @nuxtjs/tailwindcss
2. 删除配置中的模块引入

3. 重新安装依赖
bash
pnpm install tailwindcss @tailwindcss/vite
4. 修改配置文件 nuxt.config.ts
php
import tailwindcss from "@tailwindcss/vite";
export default defineNuxtConfig({
compatibilityDate: "2025-07-15",
devtools: { enabled: true },
vite: {
plugins: [
tailwindcss(),
],
},
});
5. 后面步骤我们之前设置过,可以省略,没有则按要求操作即可。
重启后发现,正常显示了,但是没有动画,一点都不炫酷啊。

控制台并没有报错,只是提示,大概意思是组件没有。

6. 重新查看文档
发现原来,我们没有看完,原先以为,整合好以后拿来即用,其实不然,我们仍然需要去安装特定的组件。
这里提供了2种方式,使用cli安装和手动安装。

这里我使用 cli 的方式安装

安装完成后,发现多了这些文件。让我们来启动项目看看。
依旧没有生效,观察目录结构后发现,生成的组件目录并没有遵守 Nuxt 的默认约定,所以这里没有识别出来,手动引入试了一下,可以了。


到这里好似一切都正常了,但是当我打开控制台,天塌了

三、控制台异常解决
1. 组件自动导入的问题
我们既然使用了nuxt,遵循自动导入原则,那就不该手动引入
nuxt默认的自动导入是按照目录拼接的,如果我们不做修改,默认自动导入组件应该是,UIBgFallingStarsFallingStarsBg。这不是我们期待的结果,这里可以修改配置直接使用组件名称作为全局组件名,而不叠加路径参数。
直达链接:nuxtjs.org.cn/docs/4.x/gu...

2. onMounted 异常
Vue warn\]: onMounted is called when there is no active component instance to be associated with. Lifecycle injection APIs can only be used during execution of setup(). If you are using async setup(), make sure to register lifecycle hooks before the first await statement. at
useColorMode()可能内部使用了生命周期钩子(如 onMounted),但在 computed的 getter 函数中调用时,没有正确的组件实例上下文。
改成这样
typescript
<script setup lang="ts">
import { computed } from 'vue'
import { useColorMode } from '@vueuse/core'
// 直接在 setup 中调用,而不是在 computed 中
const colorMode = useColorMode()
const isDark = computed(() => colorMode.value === 'dark')
</script>
重启项目,一切正常了。

千里之行,始于足下。你的"个人公司"从这第一个2小时开始。欢迎在评论区分享你的进展或遇到的卡点,我会逐一查看,尽可能的帮住解决。我们下一篇文章见!