feat: nav bar animate

This commit is contained in:
2026-02-04 22:28:00 +08:00
parent e9b38b48e9
commit e0d8cd6cb5
6 changed files with 149 additions and 47 deletions

2
components.d.ts vendored
View File

@@ -12,6 +12,7 @@ export {}
/* prettier-ignore */ /* prettier-ignore */
declare module 'vue' { declare module 'vue' {
export interface GlobalComponents { export interface GlobalComponents {
AnimatePresence: typeof import('motion-v')['AnimatePresence']
Button: typeof import('./src/components/ui/button/Button.vue')['default'] Button: typeof import('./src/components/ui/button/Button.vue')['default']
Calendar: typeof import('./src/components/ui/calendar/Calendar.vue')['default'] Calendar: typeof import('./src/components/ui/calendar/Calendar.vue')['default']
CalendarCell: typeof import('./src/components/ui/calendar/CalendarCell.vue')['default'] CalendarCell: typeof import('./src/components/ui/calendar/CalendarCell.vue')['default']
@@ -47,6 +48,7 @@ declare module 'vue' {
// For TSX support // For TSX support
declare global { declare global {
const AnimatePresence: typeof import('motion-v')['AnimatePresence']
const Button: typeof import('./src/components/ui/button/Button.vue')['default'] const Button: typeof import('./src/components/ui/button/Button.vue')['default']
const Calendar: typeof import('./src/components/ui/calendar/Calendar.vue')['default'] const Calendar: typeof import('./src/components/ui/calendar/Calendar.vue')['default']
const CalendarCell: typeof import('./src/components/ui/calendar/CalendarCell.vue')['default'] const CalendarCell: typeof import('./src/components/ui/calendar/CalendarCell.vue')['default']

View File

@@ -27,6 +27,8 @@ export default defineConfig({
{ text: "组件库", link: "/cli-feature/component-lib" }, { text: "组件库", link: "/cli-feature/component-lib" },
{ text: "国际化", link: "/cli-feature/international" }, { text: "国际化", link: "/cli-feature/international" },
{ text: "图表", link: "/cli-feature/chart" }, { text: "图表", link: "/cli-feature/chart" },
{ text: "辅助工具", link: "/cli-feature/radash" },
{ text: "动画", link: "/cli-feature/motion" },
], ],
}, },
], ],

View File

@@ -0,0 +1,33 @@
# 动画
## 使用
:::warning 警告
motion-v 的自动引入系统经过测试无法使用,您仍需要手动引入
:::
Hucky 安装了 [motion-v](https://motion.net.cn/docs/vue) 库,您可以在组件中使用它来添加动画效果。
简单来看,您只需要引入 motion-v 的 `motion` 组件,并使用它来包裹需要添加动画效果的元素,然后编写 :animate 指令即可。
```html
<motion.div :animate="{ rotate: 360 }" />
```
您也可以通过设置 :initial 指令来设置元素的初始状态。
```html
<motion.div :animate="{ rotate: 360 }" :initial="{ rotate: 0 }" />
```
通过 `AnimatePresence` 组件,您可以在元素进入或退出时添加动画效果。
```html
<AnimatePresence>
<motion.div v-if="show" :exit="{ opacity: 0 }" />
</AnimatePresence>
```
:::tip 提示
exit 会自动为元素的进入也添加动画效果。
:::

View File

@@ -0,0 +1,34 @@
# 辅助工具
## 使用
Hucky 安装了 [Radash](https://radash.uihtm.com/) 库,用于辅助处理数组、对象、字符串等数据。
您可以自行查询文档来了解更多用法。
## 节流
在查阅 Radash 文档时发现其 `throttle` 函数的使用存在错误,在这里补充纠正,在文档中的用法如下:
```ts
import { throttle } from 'radash'
const throttledScroll = throttle(() => {
console.log('Scroll event handled')
}, 100)
window.addEventListener('scroll', throttledScroll)
// 滚动时函数最多每100ms执行一次
```
事实上 `throttle` 函数的第一个参数才是节流时间,第二个参数是函数。正确写法应该如下:
```ts
import { throttle } from 'radash'
const throttledScroll = throttle(100, () => {
console.log('Scroll event handled')
})
window.addEventListener('scroll', throttledScroll)
```

View File

@@ -2,58 +2,88 @@
import ChangeLanguageDropdownButton from "@/components/button/ChangeLanguageDropdownButton.vue"; import ChangeLanguageDropdownButton from "@/components/button/ChangeLanguageDropdownButton.vue";
import ChangeThemeDropdownButton from "@/components/button/ChangeThemeDropdownButton.vue"; import ChangeThemeDropdownButton from "@/components/button/ChangeThemeDropdownButton.vue";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import { throttle } from "radash";
import { AnimatePresence, motion } from "motion-v";
const { t } = useI18n(); const { t } = useI18n();
const showNavBar = ref(true);
const curScrollY = ref(0);
const handleThrottleScroll = throttle(100, () => {
const scrollY = window.scrollY;
if (scrollY > curScrollY.value) {
showNavBar.value = false;
} else {
showNavBar.value = true;
}
curScrollY.value = scrollY;
});
window.addEventListener("scroll", handleThrottleScroll);
</script> </script>
<template> <template>
<div class="navbar bg-base-200 shadow-sm"> <div class="w-full">
<div class="navbar-start"> <AnimatePresence>
<div class="dropdown"> <motion.div
<div tabindex="0" role="button" class="btn btn-ghost lg:hidden"> v-show="showNavBar"
<svg class="navbar bg-base-200 shadow-sm"
xmlns="http://www.w3.org/2000/svg" :exit="{
class="h-5 w-5" y: -100,
fill="none" transition: {
viewBox="0 0 24 24" duration: 0.3,
stroke="currentColor" },
> }"
<path >
stroke-linecap="round" <div class="navbar-start">
stroke-linejoin="round" <div class="dropdown">
stroke-width="2" <div tabindex="0" role="button" class="btn btn-ghost lg:hidden">
d="M4 6h16M4 12h8m-8 6h16" <svg
/> xmlns="http://www.w3.org/2000/svg"
</svg> class="h-5 w-5"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M4 6h16M4 12h8m-8 6h16"
/>
</svg>
</div>
<ul
tabindex="-1"
class="menu dropdown-content bg-base-100 rounded-box z-1 mt-5 w-52 p-2 shadow"
>
<li>
<a>{{ t("nav.home") }}</a>
</li>
<li>
<a>{{ t("nav.about") }}</a>
</li>
</ul>
</div>
<a class="btn btn-ghost text-xl">Hucky</a>
</div> </div>
<ul <div class="navbar-center hidden lg:flex">
tabindex="-1" <ul class="menu menu-horizontal px-1">
class="menu dropdown-content bg-base-100 rounded-box z-1 mt-5 w-52 p-2 shadow" <li>
> <a>{{ t("nav.home") }}</a>
<li> </li>
<a>{{ t("nav.home") }}</a> <li>
</li> <a>{{ t("nav.about") }}</a>
<li> </li>
<a>{{ t("nav.about") }}</a> </ul>
</li> </div>
</ul> <div class="navbar-end">
</div> <ChangeThemeDropdownButton />
<a class="btn btn-ghost text-xl">Hucky</a> <ChangeLanguageDropdownButton />
</div> </div>
<div class="navbar-center hidden lg:flex"> </motion.div>
<ul class="menu menu-horizontal px-1"> </AnimatePresence>
<li>
<a>{{ t("nav.home") }}</a>
</li>
<li>
<a>{{ t("nav.about") }}</a>
</li>
</ul>
</div>
<div class="navbar-end">
<ChangeThemeDropdownButton />
<ChangeLanguageDropdownButton />
</div>
</div> </div>
</template> </template>

View File

@@ -5,6 +5,7 @@ import tailwindcss from "@tailwindcss/vite";
import vueJsx from "@vitejs/plugin-vue-jsx"; import vueJsx from "@vitejs/plugin-vue-jsx";
import AutoImport from "unplugin-auto-import/vite"; import AutoImport from "unplugin-auto-import/vite";
import Components from "unplugin-vue-components/vite"; import Components from "unplugin-vue-components/vite";
import MotionResolver from "motion-v/resolver";
import { ElementPlusResolver } from "unplugin-vue-components/resolvers"; import { ElementPlusResolver } from "unplugin-vue-components/resolvers";
// https://vite.dev/config/ // https://vite.dev/config/
@@ -19,7 +20,7 @@ export default defineConfig({
resolvers: [ElementPlusResolver()], resolvers: [ElementPlusResolver()],
}), }),
Components({ Components({
resolvers: [ElementPlusResolver()], resolvers: [ElementPlusResolver(), MotionResolver()],
dts: true, dts: true,
}), }),
], ],