vue3项目表单验证 input 添加高亮样式

在验证失败时,给 input 添加一个错误高亮样式(红色边框 + 抖动动画),比直接 focus 更合适,因为用户可能已经填过内容但格式不对。

实现思路

  1. ref 获取 input 的 DOM 引用
  2. 验证失败时,添加一个错误 class,并调用 inputRef.value.focus() 聚焦
  3. 用 CSS 定义错误样式和抖动动画

完整代码

html 复制代码
<script setup>
import Editor from '@/components/Editor.vue'
import { ref } from 'vue'
import { posAddArticle } from '@/api/add_article'
import { toast } from '@/components/Toast'

const title = ref('')
const editrValue = ref('')
const titleError = ref(false)
const inputRef = ref(null)

const handleChange = (val) => {
  editrValue.value = val
}

const handleSubmit = async () => {
  // 重置错误状态
  titleError.value = false

  // 验证标题
  if (title.value === '') {
    titleError.value = true
    toast({ msg: '标题为空', type: 'error' })
    inputRef.value?.focus()
    return
  }

  // 验证编辑器内容
  if (editrValue.value === '<p><br></p>') {
    toast({ msg: '编辑器内容为空', type: 'error' })
    return
  }

  // 验证通过,提交
  try {
    const data = await posAddArticle({
      title: title.value,
      content: editrValue.value
    })
    toast({ msg: '提交成功', type: 'success' })
  } catch (err) {
    console.error('请求失败', err)
  }
}
</script>

<template>
  <form @submit.prevent="handleSubmit">
    <input
      ref="inputRef"
      v-model="title"
      placeholder="标题"
      :class="{ 'input-error': titleError }"
      @input="titleError = false"
    />
    <br /><br />
    <Editor @change-content="handleChange" />
    <br />
    <button type="submit">提交</button>
  </form>
</template>

<style scoped>
input {
  height: 35px;
  width: 400px;
  padding: 5px 15px;
  border: 1px solid #ccc;
  outline: none;
  transition: border-color 0.3s;
}

input:focus {
  border: 1px solid #1ec4a0;
}

/* 
错误状态样式 不会生效,因为样式权重低
.input-error {
  border: 1px solid #ff4d4f;
  animation: shake 0.4s ease-in-out;
}
*/

/* 错误状态样式 会生效,样式权重变高 */
form input.input-error {
  border: 1px solid #ff4d4f;
  animation: shake 0.4s ease-in-out;
}

/* 抖动动画 */
@keyframes shake {
  0%, 100% { transform: translateX(0); }
  20% { transform: translateX(-6px); }
  40% { transform: translateX(6px); }
  60% { transform: translateX(-4px); }
  80% { transform: translateX(4px); }
}

button {
  height: 40px;
  width: 250px;
  border: 0;
  cursor: pointer;
  background-color: #00bbc2;
  color: #fff;
  transition: background-color 0.5s;
  border-radius: 2px;
}

button:hover {
  background-color: #15e0e7;
}
</style>

关键点说明

  • ref="inputRef" :获取 input 的 DOM 引用
  • titleError:控制是否显示错误样式
  • :class="{ 'input-error': titleError }" :动态绑定错误 class
  • @input="titleError = false" :用户重新输入时自动清除错误状态
  • inputRef.value?.focus() :验证失败时聚焦到 input
  • shake 动画:验证失败时 input 抖动,提示用户注意

这样用户在提交时,如果标题为空,input 会变成红色边框并抖动,同时自动聚焦到该输入框。


提醒:编辑器内容校验用的是 <p><br></p>,这个字符串是固定的,但有些编辑器(比如wangEditor)在内容为空时可能输出 <p><br></p><p></p> 或空字符串,可以写一个更健壮的校验函数。

相关推荐
:-)29 分钟前
idea中的vue文件没有高亮显示
前端·javascript·vue.js·ecmascript·intellij-idea
IPdodo_31 分钟前
2026年AI 数据采集代理 IP 选型:成功率、并发、轮换与成本评估
前端·网络·人工智能·chrome·python·http·网络调试
计算机魔术师39 分钟前
AI问诊5秒出结果,医生反而更忙了
前端
郭邯40 分钟前
从需求到上线:我用 AI 辅助开发了一个在线倒计时器
前端
Damai1 小时前
Next.js 切换动态路由后,为什么页面还保留着上一个分类的数据?
前端·react.js
程序员鱼皮1 小时前
爆火的《牛来》模型正式发布!DeepSeek 的排名又下降了。。
前端·后端·ai编程
MocMoc1 小时前
从零落地全栈 Monorepo:Turbo + npm workspaces 实战(附一个记账小应用)
前端
灯澜忆梦1 小时前
【基于GO的Web开发15】gin路由和路由组
前端·后端·golang·gin
Southern Wind1 小时前
从一段文字到一部动态漫:如何打造全流程分镜创作工作台 StoryCanvas AI
前端·javascript·vue.js·人工智能