Vue3 登录页还能这么丝滑?这个 hover 效果太惊艳了

前言

大家好,我是大华!在现代 Web 开发中,用户体验越来越重要。一个简洁、美观又富有动效的登录页,不仅能提升品牌形象,还能增强用户的第一印象。这篇文章,我们将用 Vue3 + CSS3 动画 ,来实现一个悬浮动画和细腻交互效果的 Vue3 登录页面

项目效果预览:

  • 登录框悬浮微动 + 高光掠过动画
  • 输入框标签滑动 + 聚焦反馈
  • 按钮点击涟漪动效
  • 浮动光点循环上升
  • 忘记密码/注册链接悬停切换背景色

技术栈

  • Vue 3<script setup> 语法)
  • Composition APIref, onMounted
  • CSS3 渐变、动画、过渡、伪元素
  • 响应式布局基础

一、页面结构(Template 部分)

html 复制代码
<template>
  <div class="login-page" @mousemove="handleMouseMove">
    <div class="login-container">
      <!-- 浮动装饰图标 -->
      <div class="floating-icons">
        <span 
          v-for="(icon, index) in icons" 
          :key="index" 
          :style="{
            left: icon.left + 'px',
            top: icon.top + 'px',
            width: icon.size + 'px',
            height: icon.size + 'px',
            animationDuration: (10 + Math.random() * 20) + 's',
            animationDelay: (Math.random() * 5) + 's'
          }"
        ></span>
      </div>

      <!-- 标题 -->
      <h2>欢迎登录</h2>

      <!-- 登录表单 -->
      <form @submit.prevent="handleSubmit">
        <!-- 用户名输入 -->
        <div class="input-group">
          <input type="text" required v-model="username">
          <label>用户名</label>
        </div>

        <!-- 密码输入 -->
        <div class="input-group">
          <input type="password" required v-model="password">
          <label>密码</label>
        </div>

        <!-- 登录按钮 -->
        <button type="submit" class="btn">登 录</button>

        <!-- 辅助链接 -->
        <div class="links">
          <a href="#" @mouseenter="changeBgColor('#a1c4fd')">忘记密码?</a>
          <a href="#" @mouseenter="changeBgColor('#fbc2eb')">注册账号</a>
        </div>
      </form>
    </div>
  </div>
</template>

💡 说明:

  • @mousemove="handleMouseMove"实现背景随鼠标移动而旋转渐变。
  • floating-icons是背景中漂浮的圆形光点,通过v-for渲染多个。
  • 表单提交使用@submit.prevent阻止默认刷新行为。

二、逻辑实现(Script 部分)

js 复制代码
<script setup>
import { ref, onMounted } from 'vue';

// 用户输入数据
const username = ref('');
const password = ref('');

// 浮动图标数据
const icons = ref([]);

// 生成浮动图标
const createIcons = () => {
  const iconsCount = 10;
  const newIcons = [];
  for (let i = 0; i < iconsCount; i++) {
    newIcons.push({
      left: Math.random() * 380,     // 随机水平位置
      top: Math.random() * 400,      // 随机起始高度
      size: 20 + Math.random() * 30  // 随机大小(20~50px)
    });
  }
  icons.value = newIcons;
};

// 表单提交
const handleSubmit = () => {
  alert(`欢迎, ${username.value}!`);
};

// 鼠标悬停链接时改变背景色
const changeBgColor = (color) => {
  document.body.style.background = `linear-gradient(45deg, ${color}, ${color.replace(')', '')}80)`;
};

// 鼠标移动时动态改变背景角度
const handleMouseMove = (e) => {
  const x = e.clientX / window.innerWidth; // 0 ~ 1
  const angle = x * 180; // 0 ~ 180deg
  document.body.style.background = `linear-gradient(${angle}deg, #ff9a9e, #fad0c4)`;
};

// 组件挂载后初始化图标
onMounted(() => {
  createIcons();
});
</script>

🔍 关键点解析:

  • createIcons() 在页面加载时生成 10 个随机位置和大小的"光点"。
  • handleMouseMove 根据鼠标 X 坐标控制渐变角度,实现"视角跟随"效果。
  • changeBgColor 在鼠标进入链接时切换背景主题色,增强交互反馈。

三、样式设计(Style 部分)

1. 全局重置与字体

css 复制代码
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}

2. 页面容器 .login-page

css 复制代码
.login-page {
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 100vh;
  background: linear-gradient(45deg, #ff9a9e, #fad0c4);
  transition: background 0.5s ease;
}

使用flex居中,背景为粉色系渐变,支持过渡动画。


3. 登录框 .login-container

css 复制代码
.login-container {
  position: relative;
  width: 380px;
  padding: 40px;
  background: rgba(255, 255, 255, 0.15);
  backdrop-filter: blur(10px); /* 毛玻璃效果 */
  border-radius: 20px;
  box-shadow: 0 25px 45px rgba(0, 0, 0, 0.1);
  border: 1px solid rgba(255, 255, 255, 0.2);
  overflow: hidden;
  transition: transform 0.3s ease, box-shadow 0.3s ease;
}

.login-container:hover {
  transform: translateY(-5px);
  box-shadow: 0 30px 50px rgba(0, 0, 0, 0.15);
}

backdrop-filter: blur(10px) 实现毛玻璃质感,极具现代感!


4. 悬停高光掠过动画

css 复制代码
.login-container::before {
  content: '';
  position: absolute;
  top: 0;
  left: -100%;
  width: 100%;
  height: 100%;
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.4), transparent);
  transition: 0.5s;
}

.login-container:hover::before {
  left: 100%;
}

当鼠标悬停时,一束高光从左向右扫过登录框,视觉冲击力强。


5. 输入框动效

css 复制代码
.input-group input {
  width: 100%;
  padding: 15px 20px;
  background: rgba(255, 255, 255, 0.2);
  border: none;
  outline: none;
  border-radius: 35px;
  color: #fff;
  font-size: 16px;
  box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05);
  transition: all 0.3s ease;
}

.input-group input:focus, .input-group input:hover {
  background: rgba(255, 255, 255, 0.3);
  box-shadow: 0 8px 20px rgba(0, 0, 0, 0.1);
}

.input-group label {
  position: absolute;
  top: 15px;
  left: 20px;
  color: rgba(255, 255, 255, 0.8);
  pointer-events: none;
  transition: all 0.3s ease;
}

.input-group input:focus + label,
.input-group input:valid + label {
  top: -10px;
  left: 15px;
  font-size: 12px;
  background: rgba(255, 255, 255, 0.2);
  padding: 0 10px;
  border-radius: 10px;
}

实现 Material Design 风格的标签上滑动效,用户体验极佳。


6. 登录按钮动效

css 复制代码
.btn {
  width: 100%;
  padding: 15px;
  background: linear-gradient(45deg, #ff9a9e, #fad0c4);
  border: none;
  border-radius: 35px;
  color: #fff;
  font-weight: 600;
  cursor: pointer;
  box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
  transition: all 0.3s ease;
}

.btn:hover {
  transform: translateY(-3px);
  box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2);
}

.btn::before {
  content: '';
  position: absolute;
  top: 0;
  left: -100%;
  width: 100%;
  height: 100%;
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.4), transparent);
  transition: 0.5s;
}

.btn:hover::before {
  left: 100%;
}

悬停时按钮上浮 + 高光扫过,交互感满分!


7. 浮动光点动画

css 复制代码
.floating-icons {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  z-index: -1;
}

.floating-icons span {
  position: absolute;
  display: block;
  width: 40px;
  height: 40px;
  background: rgba(255, 255, 255, 0.1);
  border-radius: 50%;
  animation: float 15s linear infinite;
  opacity: 0;
}

.login-container:hover .floating-icons span {
  opacity: 1;
}

@keyframes float {
  0% {
    transform: translateY(0) rotate(0deg);
    opacity: 1;
  }
  100% {
    transform: translateY(-1000px) rotate(720deg);
    opacity: 0;
  }
}

✨ 光点在登录框悬停时浮现,并向上漂浮、旋转、淡出,营造梦幻氛围。


四、完整代码

html 复制代码
<template>
  <div class="login-page" @mousemove="handleMouseMove">
    <div class="login-container">
      <div class="floating-icons">
        <span 
          v-for="(icon, index) in icons" 
          :key="index" 
          :style="{
            left: icon.left + 'px',
            top: icon.top + 'px',
            width: icon.size + 'px',
            height: icon.size + 'px',
            animationDuration: (10 + Math.random() * 20) + 's',
            animationDelay: (Math.random() * 5) + 's'
          }"
        ></span>
      </div>
      <h2>欢迎登录</h2>
      <form @submit.prevent="handleSubmit">
        <div class="input-group">
          <input type="text" required v-model="username">
          <label>用户名</label>
        </div>
        <div class="input-group">
          <input type="password" required v-model="password">
          <label>密码</label>
        </div>
        <button type="submit" class="btn">登 录</button>
        <div class="links">
          <a href="#" @mouseenter="changeBgColor('#a1c4fd')">忘记密码?</a>
          <a href="#" @mouseenter="changeBgColor('#fbc2eb')">注册账号</a>
        </div>
      </form>
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted } from 'vue';

const username = ref('');
const password = ref('');
const icons = ref([]);

const createIcons = () => {
  const iconsCount = 10;
  const newIcons = [];
  for (let i = 0; i < iconsCount; i++) {
    newIcons.push({
      left: Math.random() * 380,
      top: Math.random() * 400,
      size: 20 + Math.random() * 30
    });
  }
  icons.value = newIcons;
};

const handleSubmit = () => {
  alert(`欢迎, ${username.value}!`);
};

const changeBgColor = (color) => {
  document.body.style.background = `linear-gradient(45deg, ${color}, ${color.replace(')', '')}80)`;
};

const handleMouseMove = (e) => {
  const x = e.clientX / window.innerWidth;
  document.body.style.background = `linear-gradient(${x * 180}deg, #ff9a9e, #fad0c4)`;
};

onMounted(() => {
  createIcons();
});
</script>

<style scoped>
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}

.login-page {
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 100vh;
  background: linear-gradient(45deg, #ff9a9e, #fad0c4);
  transition: background 0.5s ease;
}

.login-container {
  position: relative;
  width: 380px;
  padding: 40px;
  background: rgba(255, 255, 255, 0.15);
  backdrop-filter: blur(10px);
  border-radius: 20px;
  box-shadow: 0 25px 45px rgba(0, 0, 0, 0.1);
  border: 1px solid rgba(255, 255, 255, 0.2);
  overflow: hidden;
  transition: transform 0.3s ease, box-shadow 0.3s ease;
}

.login-container:hover {
  transform: translateY(-5px);
  box-shadow: 0 30px 50px rgba(0, 0, 0, 0.15);
}

.login-container::before {
  content: '';
  position: absolute;
  top: 0;
  left: -100%;
  width: 100%;
  height: 100%;
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.4), transparent);
  transition: 0.5s;
}

.login-container:hover::before {
  left: 100%;
}

h2 {
  color: #fff;
  text-align: center;
  margin-bottom: 30px;
  font-size: 2em;
  text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.2);
}

.input-group {
  position: relative;
  margin-bottom: 30px;
}

.input-group input {
  width: 100%;
  padding: 15px 20px;
  background: rgba(255, 255, 255, 0.2);
  border: none;
  outline: none;
  border-radius: 35px;
  color: #fff;
  font-size: 16px;
  box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05);
  transition: all 0.3s ease;
}

.input-group input:focus, .input-group input:hover {
  background: rgba(255, 255, 255, 0.3);
  box-shadow: 0 8px 20px rgba(0, 0, 0, 0.1);
}

.input-group label {
  position: absolute;
  top: 15px;
  left: 20px;
  color: rgba(255, 255, 255, 0.8);
  pointer-events: none;
  transition: all 0.3s ease;
}

.input-group input:focus + label,
.input-group input:valid + label {
  top: -10px;
  left: 15px;
  font-size: 12px;
  background: rgba(255, 255, 255, 0.2);
  padding: 0 10px;
  border-radius: 10px;
}

.btn {
  position: relative;
  width: 100%;
  padding: 15px;
  background: linear-gradient(45deg, #ff9a9e, #fad0c4);
  border: none;
  outline: none;
  border-radius: 35px;
  color: #fff;
  font-size: 16px;
  font-weight: 600;
  cursor: pointer;
  overflow: hidden;
  transition: all 0.3s ease;
  box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
}

.btn:hover {
  transform: translateY(-3px);
  box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2);
}

.btn::before {
  content: '';
  position: absolute;
  top: 0;
  left: -100%;
  width: 100%;
  height: 100%;
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.4), transparent);
  transition: 0.5s;
}

.btn:hover::before {
  left: 100%;
}

.links {
  display: flex;
  justify-content: space-between;
  margin-top: 20px;
}

.links a {
  color: rgba(255, 255, 255, 0.8);
  text-decoration: none;
  font-size: 14px;
  transition: all 0.3s ease;
}

.links a:hover {
  color: #fff;
  text-shadow: 0 0 10px rgba(255, 255, 255, 0.5);
}

.floating-icons {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  z-index: -1;
}

.floating-icons span {
  position: absolute;
  display: block;
  width: 40px;
  height: 40px;
  background: rgba(255, 255, 255, 0.1);
  border-radius: 50%;
  animation: float 15s linear infinite;
  opacity: 0;
  transition: opacity 0.5s ease;
}

.login-container:hover .floating-icons span {
  opacity: 1;
}

@keyframes float {
  0% {
    transform: translateY(0) rotate(0deg);
    opacity: 1;
  }
  100% {
    transform: translateY(-1000px) rotate(720deg);
    opacity: 0;
  }
}
</style>

优化建议

  • 性能优化:浮动图标数量可控制,避免过多影响性能。
  • 响应式 :添加@media查询适配移动端。
  • 表单验证:增加正则校验、非空判断。
  • 主题切换 :封装背景色切换逻辑为themeService
  • 动画库 :可接入Animate.cssGSAP增强动效。

总结

这篇文章一步步实现了一个高颜值、强交互的 Vue3 登录页,涵盖了:

  • Vue3 Composition API 使用
  • 动态样式绑定
  • 鼠标事件监听
  • CSS3 动画与过渡
  • 毛玻璃(backdrop-filter)特效
  • 渐变背景与视觉动效

这个登录页不仅适合个人项目、后台系统、SaaS 平台,还可以作为你作品集中的亮点之一。

本文首发于公众号:程序员刘大华,专注分享前后端开发的实战笔记。关注我,少走弯路,一起进步!

📌往期精彩

《SpringBoot 中的 7 种耗时统计方式,你用过几种?》

《千万级大表如何新增字段?别再直接 ALTER 了》

《Vue3 如何优雅地实现一个全局的 loading 组件》

《我用 Vue3 + Canvas 做了个超实用的水印工具,同事都在抢着用》

相关推荐
passerby60613 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了3 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅3 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅4 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅4 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment4 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅4 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊4 小时前
jwt介绍
前端
爱敲代码的小鱼5 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax
吹牛不交税5 小时前
admin.net-v2 框架使用笔记-netcore8.0/10.0版
vue.js·.netcore