列表的单行icon的动效

Vue任务状态动效切换
//dom                   

<span v-if="row.taskValidateStatus == 1" @click="taskStatusHandle(row,0)">
                      <img
                      :ref="`img${row.taskGuid}`"
                        src="@/assets/icon/caozuo.png"
                      />
                      启用
                    </span>


//js

let img = this.$refs[`img${row.taskGuid}`];
      console.log( img.className , 'className')
      img.className = "img_move moveleft"




//style

/* 启用状态动效 */
.img_move{
  transition: all .5s;
}
.moveleft{
  transform: translateX(10px);
}
.moveright{
  transform: translateX(-10px);
}


<template> <div class="login-container"> <!-- 左侧宣传区 --> <div class="side-banner"> <h1>儿童体能训练馆</h1> <p>管理课程 · 预约教练 · 记录成长</p> <div class="tagline">让每一次训练都有迹可循</div> </div> <!-- 右侧登录区 --> <div class="login-form-wrapper"> <el-form ref="form" :model="loginform" label-width="60px" label-position="left" > <h2 class="title">欢迎登录</h2> <el-form-item label="用户名"> <el-input v-model="loginform.userName" placeholder="请输入用户名" clearable prefix-icon="el-icon-user" /> </el-form-item> <el-form-item label="密码"> <el-input v-model="loginform.pwd" type="password" placeholder="请输入密码" clearable prefix-icon="el-icon-lock" @keyup.enter.native="submit" /> </el-form-item> <el-form-item class="actions"> <el-button type="primary" @click="submit" :loading="loading"> 登 录 </el-button> <el-button @click="dialogFormVisible = true">注 册</el-button> </el-form-item> </el-form> <!-- 注册弹窗(已放大并美化) --> <el-dialog :visible.sync="dialogFormVisible" width="500px" center custom-class="register-dialog" append-to-body @close="resetForm" > <template #title> <h3 style="text-align: center; color: #1e3a8a; font-weight: 600"> 🧒 创建新用户 </h3> </template> <el-form :model="form" :rules="registerRules" ref="registerRef" label-position="left" label-width="70px" style="padding: 0 20px" > <!-- 第一行:用户名 + 昵称 --> <div style="display: flex; gap: 20px"> <el-form-item label="用户名" prop="userName" style="flex: 1"> <el-input v-model="form.userName" placeholder="6-10位字母或数字" /> </el-form-item> <el-form-item label="昵称" prop="nickName" style="flex: 1"> <el-input v-model="form.nickName" placeholder="如:小明爸爸" /> </el-form-item> </div> <!-- 第二行:密码 + 手机号 --> <div style="display: flex; gap: 20px"> <el-form-item label="密码" prop="pwd" style="flex: 1"> <el-input v-model="form.pwd" type="password" placeholder="6-10位密码" /> </el-form-item> <el-form-item label="手机号" prop="phoneCode" style="flex: 1"> <el-input v-model="form.phoneCode" placeholder="用于接收通知" /> </el-form-item> </div> <!-- 头像上传 + 角色选择 水平排列 --> <div style=" display: flex; gap: 40px; align-items: flex-start; margin-bottom: 20px; " > <!-- 头像 --> <el-form-item label="头像"> <el-upload class="avatar-uploader" action="http://localhost:8081/file/upload" :show-file-list="false" :on-success="handleAvatarSuccess" :before-upload="beforeAvatarUpload" > <img v-if="form.pic" :src="form.pic" class="avatar" alt="头像" /> <i v-else class="el-icon-plus avatar-uploader-icon"></i> </el-upload> </el-form-item> <!-- 角色 --> <el-form-item label="角色" prop="roleId" style="flex: 1"> <el-radio-group v-model="form.roleId" style="margin-top: 12px"> <div style="margin-bottom: 8px"> <el-radio-button label="1">管理员</el-radio-button> </div> <div style="margin-bottom: 8px"> <el-radio-button label="2">家长/用户</el-radio-button> </div> <div> <el-radio-button label="3">教练</el-radio-button> </div> </el-radio-group> </el-form-item> </div> <!-- 操作按钮 --> <el-form-item style="text-align: center; margin-top: 20px"> <el-button type="primary" @click="register" size="medium" style="width: 120px" > 注 册 </el-button> <el-button @click="resetForm" size="medium" style="width: 120px; margin-left: 20px" > 重 置 </el-button> </el-form-item> </el-form> </el-dialog> </div> </div> </template> <script> import { login } from "@/api/Login"; import { register } from "@/api/Login"; export default { name: "LoginView", data() { return { loading: false, dialogFormVisible: false, pic: "", loginform: { userName: "", pwd: "", }, form: { roleId: "2", // 默认选中用户 pic: "", }, registerRules: { userName: [ { required: true, message: "请输入用户名", trigger: "blur" }, { min: 6, max: 10, message: "长度在 6 到 10 个字符", trigger: "blur", }, ], nickName: [ { required: true, message: "请输入昵称", trigger: "blur" }, { min: 1, max: 6, message: "长度在 1 到 6 个字符", trigger: "blur" }, ], pwd: [ { required: true, message: "请输入密码", trigger: "blur" }, { min: 6, max: 10, message: "长度在 6 到 10 个字符", trigger: "blur", }, ], phoneCode: [ { required: true, message: "请输入手机号", trigger: "blur" }, { pattern: /^1[3-9]\d{9}$/, message: "请输入正确的手机号", trigger: "blur", }, ], roleId: [{ required: true, message: "请选择角色", trigger: "change" }], }, }; }, methods: { handleAvatarSuccess(res) { if (res.data?.url) { this.form.pic = res.data.url; this.$message.success("头像上传成功!"); } else { this.$message.error("上传失败,请重试"); } }, beforeAvatarUpload(file) { const isImage = ["image/jpeg", "image/jpg", "image/png"].includes( file.type ); const isLt2M = file.size / 1024 / 1024 < 2; if (!isImage) { this.$message.error("头像必须是 JPG 或 PNG 格式!"); return false; } if (!isLt2M) { this.$message.error("头像图片大小不能超过 2MB!"); return false; } return true; }, submit() { this.$refs.form.validateField(["userName", "pwd"], (valid) => { if (!valid) { this.loading = true; login(this.loginform) .then((resp) => { if (resp.data.code === 200) { this.$message.success("登录成功!"); const user = resp.data.data.user; localStorage.setItem("userId", user.id); localStorage.setItem("roleId", user.roleId); if (user.roleId == 1) { this.$router.push("/adminChart"); } else if (user.roleId == 2) { this.$router.push("/user/bulletin"); } else { this.$router.push("/coach/bulletin"); } } else { this.$message.error(resp.data.message || "登录失败"); } }) .catch((err) => { console.error("登录请求失败:", err); this.$message.error("网络错误,请检查连接"); }) .finally(() => { this.loading = false; }); } }); }, register() { this.$refs.registerRef.validate((valid) => { if (valid) { register(this.form) .then((resp) => { if (resp.data.code === 200) { this.$message.success("注册成功,请登录"); this.dialogFormVisible = false; } else { this.$message.error(resp.data.message || "注册失败"); } }) .catch((err) => { console.error("注册失败:", err); this.$message.error("网络异常,请稍后重试"); }); } }); }, resetForm() { if (this.$refs.registerRef) { this.$refs.registerRef.resetFields(); } this.form.pic = ""; this.pic = ""; }, }, }; </script> <style scoped> .login-container { display: flex; height: 100vh; font-family: "Segoe UI", system-ui, -apple-system, sans-serif; background: url("@/assets/login.jpg") no-repeat center center fixed; background-size: cover; } /* 左侧宣传栏 */ .side-banner { flex: 1; background: rgba(0, 0, 0, 0.4); color: #fff; display: flex; flex-direction: column; justify-content: center; align-items: center; text-align: center; padding: 40px; backdrop-filter: blur(8px); border-radius: 0 20px 20px 0; } .side-banner h1 { font-size: 2.5rem; margin-bottom: 12px; font-weight: 700; text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3); } .side-banner p { font-size: 1.2rem; margin-bottom: 8px; } .tagline { font-size: 1rem; color: #e2e8f0; margin-top: 16px; padding: 10px 20px; border-top: 1px solid rgba(255, 255, 255, 0.2); border-bottom: 1px solid rgba(255, 255, 255, 0.2); } /* 右侧登录框 */ .login-form-wrapper { width: 420px; background: rgba(255, 255, 255, 0.95); backdrop-filter: blur(10px); border-radius: 20px 0 0 20px; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.15); padding: 40px 30px; display: flex; flex-direction: column; justify-content: center; animation: slide-in 0.6s ease; } .title { text-align: center; color: #1e3a8a; margin-bottom: 30px; font-size: 1.6rem; font-weight: 600; } .actions { margin-top: 10px; } ::v-deep .el-form-item__label { font-weight: 500; color: #333; } /* 画入场 */ @keyframes slide-in { from { transform: translateX(100%); opacity: 0; } to { transform: translateX(0); opacity: 1; } } /* 头像上传美化 */ .avatar-uploader { display: inline-block; } .avatar-uploader-icon { border: 2px dashed #c0ccda; border-radius: 50%; width: 100px; height: 100px; line-height: 100px; text-align: center; font-size: 24px; color: #999; cursor: pointer; transition: all 0.3s ease; } .avatar-uploader-icon:hover { border-color: #409eff; color: #409eff; } .avatar { width: 100px; height: 100px; object-fit: cover; border-radius: 50%; border: 3px solid #e6f1ff; transition: transform 0.3s ease; } .avatar:hover { transform: scale(1.05); } /* 注册弹窗样式 */ ::v-deep .register-dialog { border-radius: 16px; overflow: hidden; } ::v-deep .register-dialog .el-dialog__body { padding: 30px 20px; } /* 响应式适配 */ @media (max-width: 768px) { .login-container { flex-direction: column; } .side-banner { padding: 20px; border-radius: 20px 20px 0 0; } .login-form-wrapper { width: 100%; border-radius: 0; margin-top: -40px; z-index: 10; } .side-banner h1 { font-size: 1.8rem; } } </style> 更漂亮些
09-23
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值