修改el-form制作自定义元素登录框

本文介绍了如何在React和Vuetify框架中实现输入框聚焦时文字变小上移的效果,并将此效果应用于Element-UI。通过利用el-input的slot属性,创建自定义前缀元素,结合CSS实现输入框与标签的联动样式。示例代码展示了登录表单的完整实现,包括用户名、密码和验证码输入,以及记住密码、登录按钮和验证码刷新功能。同时,提供了丰富的CSS样式调整建议,帮助读者根据自己的需求定制风格。
最近看到react 和vuetify 的输入框聚焦文字会变小上移,觉得它们框架有的效果,element你也应该有,于是乎,就尝试修改,试了很久发现 el-form-item 中的label和input根本连不上关系,就想到了一个解决办法,那就是el-input中有个自定义的slot属性,借此属性得以实现效果。

下面就是文档的属性。
在这里插入图片描述
这是最终效果图。截图的颜色不好看,有条件的自己修改一下样式即可。
在这里插入图片描述

代码有点套娃,有条件的可以使用slot去进行二次封装。
  <template>
  <div class="login">
    <el-form ref="form" :model="form" :rules="rules" class="login-form" auto-complete="off">

      <el-form-item prop="username">
        <el-input v-model="form.username" type="text" @keyup.enter.native="handleLogin" required clearable>
          <span slot="prefix" class="wrap">
            <i class="el-input__icon el-icon-user-solid" />
            <span>名称</span>
          </span>
        </el-input>
      </el-form-item>

      <el-form-item prop="password">
        <el-input v-model="form.password" type="password" @keyup.enter.native="handleLogin" required clearable>
          <span slot="prefix" class="wrap">
            <i class="el-input__icon el-icon-lock" />
            <span>密码</span>
          </span>
        </el-input>
      </el-form-item>

      <el-form-item prop="captcha">

        <div class="flex justify-around">

          <el-input class="w--55%" v-model="form.captcha" placeholder="验证码" @keyup.enter.native="submit">
            <svg-icon slot="prefix" icon-class="validCode" class="el-input__icon input-icon" />
          </el-input>

          <div class="login-code w--40%">
            <canvas ref="captcha" width="100%" height="38px" @click="captcha('captcha')" />
          </div>

        </div>

      </el-form-item>

      <el-checkbox v-model="form.rememberMe" style="margin: 0px 0px 25px 0px">记住密码</el-checkbox>
      <el-form-item style="width: 100%">
        <el-button :loading="loading" size="medium" type="primary" style="width: 100%" @click.native.prevent="submit">
          {{ loading ? "登 录 中..." : "登 录" }}
        </el-button>

        <div style="float: right" v-if="register">
          <router-link class="link-type" :to="'/register'">立即注册</router-link>
        </div>

      </el-form-item>
    </el-form>
    <!--  底部  -->
    <div class="el-login-footer">
      <span>Copyright © 2018-2022 ruoyi.vip All Rights Reserved.</span>
    </div>

  </div>
</template>

<script>
import Cookies from "js-cookie";
import { encrypt, decrypt } from "@/utils/jsencrypt";
import { mapActions } from 'pinia';
import { user } from '@/pinia';
export default {
  name: "Login",
  data() {
    const validator = (rule, value, callback) => {
      if (value !== this.captchaCode) return callback(new Error(rule.message))
      callback();
    };
    return {
      form: {
        username: "admin",
        password: "123456",
        captcha: "",
        rememberMe: false,
        uuid: "ccf0a46bfcf9409b95e9aea8700c9ed7",
      },
      rules: {
        username: [{ required: true, trigger: "blur", message: "请输入账号" }],
        password: [{ required: true, trigger: "blur", message: "请输入密码" }],
        captcha: [{ required: true, trigger: 'blur', message: "请输入验证码" }, { validator, trigger: 'blur', message: "验证码错误" }],
      },
      captchaCode: '',
      loading: false,
      register: false, // 注册开关
      redirect: undefined,
    };
  },
  mounted() {
    this.getCookie();
    this.captcha('captcha');
  },
  methods: {
    ...mapActions(user, ['login']),
    getCookie() {
      const username = Cookies.get("username");
      const password = Cookies.get("password");
      const rememberMe = Cookies.get("rememberMe");
      this.form = {
        username: !username ? this.form.username : username,
        password: !password ? this.form.password : decrypt(password),
        rememberMe: !rememberMe ? false : Boolean(rememberMe),
      };
    },
    submit() {
      this.$refs.form.validate(async (valid) => {
        if (!valid) return;
        this.loading = true;
        if (this.form.rememberMe) {
          Cookies.set("username", this.form.username, { expires: 30 });
          Cookies.set("password", encrypt(this.form.password), { expires: 30 });
          Cookies.set("rememberMe", this.form.rememberMe, { expires: 30 });
        } else {
          Cookies.remove("username");
          Cookies.remove("password");
          Cookies.remove("rememberMe");
        }
        try {
          await this.login(this.form);
          this.$router.push({ path: this.redirect || "/" }).catch(() => { });
        } catch (error) {
          console.error(error);
          this.loading = false;
          this.captcha('captcha');
        }
      });
      this.loading = false;
    },
    // 获取生成验证码的canvas
    captcha(el) {
      const container = {
        scope: (max, min) => parseInt(Math.random() * (max - min) + min),
        color: (max, min, o = 1) => `rgba(${container.scope(max, min)},${container.scope(max, min)},${container.scope(max, min)},${o})`,
        num: (n) => Math.floor(Math.random() * n),
        isnum: (n) => typeof n === 'number' && !isNaN(n),
        operator: ['+', '-', '*'],
        rect: [0, 0, 100, 38],
        calculate: [0, '+-*/', 0, '=?']
      }
      const { scope, color, num, isnum, operator, rect, calculate: calcu } = container;
      const ctx = this.$refs[el].getContext("2d");
      const [x1, y1, x2, y2] = rect;

      ctx.clearRect(x1, y1, x2, y2);
      ctx.fillStyle = color(180, 230);
      ctx.save()
      ctx.fillRect(x1, y1, x2, y2);

      Array.from({ length: 4 }, (_, index) => {
        ctx.beginPath();
        ctx.strokeStyle = color(80, 180, .33);
        ctx.save();
        ctx.moveTo(scope(0, x2), scope(0, y2));
        ctx.moveTo(scope(0, x2), scope(0, y2));
        ctx.lineTo(scope(0, x2), scope(0, y2));
        ctx.stroke();
        ctx.beginPath();
        ctx.fillStyle = color(0, 255, .33);
        ctx.save();
        ctx.arc(scope(0, x2), scope(0, y2), 1, 0, 2 * Math.PI);
        ctx.fill();
        ctx.font = `${scope(18, 30)}px Simhei`;
        ctx.fillStyle = color(80, 150);
        ctx.save();
        let item = calcu[index];
        isnum(item) && (item = num(10));
        item === '+-*/' && (item = operator[num(3)]);
        index === 2 && calcu[1] === '-' && calcu[0] <= item && (item = calcu[0] ? calcu[0] : 0);
        calcu[index] = item;
        ctx.translate(22 * index + -12, 10);
        ctx.rotate((scope(-12, 12) * Math.PI) / 180);
        ctx.fillText(item, y2 / 2, y2 / 2);
        ctx.restore();
      });
      const result = eval(calcu.slice(0, calcu.length - 1).join(""));
      this.captchaCode = result.toString();
      return result.toString();
    },
  },
  watch: {
    $route: {
      handler(route) {
        this.redirect = route.query && route.query.redirect;
      },
      immediate: true,
    },
  },
};
</script>

<style rel="stylesheet/scss" lang="scss" scoped>
	.login {
	  display: flex;
	  justify-content: center;
	  align-items: center;
	  height: 100%;
	  background-image: linear-gradient(
	    to right,
	    #00c6fb,
	    #005bea,
	    #00c6fb,
	    #005bea
	  );
	  background-size: cover;
	  .title {
	    margin: 0px auto 30px auto;
	    text-align: center;
	    color: #707070;
	  }
	  .el-form {
	    position: absolute;
	    top: 50%;
	    left: 75%;
	    width: 400px;
	    padding: 40px 40px 40px 40px;
	    transform: translate(-50%, -50%);
	    background: rgba(0, 0, 0, 0.2);
	    box-sizing: border-box;
	    box-shadow: 0 15px 25px rgba(0, 0, 0, 0.6);
	    border-radius: 10px;
	    .el-form-item {
	      margin-bottom: 30px;
	      h2 {
	        text-align: center;
	        color: #c0c4cc;
	      }
	      /deep/ {
	        .el-input__inner {
	          border: none;
	          border-radius: 0;
	          border-bottom: 1px solid #fff;
	          background-color: transparent !important;
	          color: #c0c4cc;
	          // 伪元素的修改 line
	          & + .el-input__prefix::before {
	            content: "";
	            position: absolute;
	            display: block;
	            bottom: 0%;
	            left: 50%;
	            width: 0;
	            height: 2px;
	            background-color: #409eff;
	            transition: all 0.8s;
	          }
	          &:focus + .el-input__prefix::before {
	            left: 0;
	            width: 100%;
	          }
	          // label的修改 文本存在时的显示css
	          &:-webkit-autofill ~ .el-input__prefix > .wrap,
	          &:focus ~ .el-input__prefix > .wrap,
	          &:valid ~ .el-input__prefix > .wrap {
	            color: #fff;
	            display: inline-block;
	            font-size: 14px;
	            transform: perspective(1000px) translate3d(-10px, -24px, -100px);
	            transition: all 0.4s;
	          }
	        }
	        .el-input__prefix {
	          width: 100%;
	          text-align: left;
	          color: #c0c4cc;
	          font-size: 18px;
	          left: 0px;
	          pointer-events: none;
	          transform-style: preserve-3d;
	          & .wrap {
	            transform: perspective(1000px) translate3d(0, 0, 0);
	            transition: all 0.4s;
	          }
	        }
	      }
	    }
	  }
	
	  .el-login-footer {
	    height: 40px;
	    line-height: 40px;
	    position: fixed;
	    bottom: 0;
	    width: 100%;
	    text-align: center;
	    color: #fff;
	    font-family: Arial;
	    font-size: 12px;
	    letter-spacing: 1px;
	  }
	}
</style>

<style lang="scss">
	input:-webkit-autofill,
	textarea:-webkit-autofill,
	select:-webkit-autofill {
	  -webkit-text-fill-color: #ededed !important; //字体颜色
	  background-color: transparent;
	  background-image: none;
	  transition: background-color 50000s ease-in-out 0s; //背景色透明  生效时长  过渡效果  启用时延迟的时间
	}
</style>

<style lang="scss">
$num: 0; // padding、margin
@while $num <= 60 {
  .p-#{$num} {
    padding: #{$num}px !important;
  }
  .pt-#{$num} {
    padding-top: #{$num}px !important;
  }
  .pb-#{$num} {
    padding-bottom: #{$num}px !important;
  }
  .pl-#{$num} {
    padding-left: #{$num}px !important;
  }
  .pr-#{$num} {
    padding-right: #{$num}px !important;
  }
  .px-#{$num} {
    padding-left: #{$num}px !important;
    padding-right: #{$num}px !important;
  }
  .py-#{$num} {
    padding-top: #{$num}px !important;
    padding-bottom: #{$num}px !important;
  }
  .m-#{$num} {
    margin: #{$num}px !important;
  }
  .mt-#{$num} {
    margin-top: #{$num}px !important;
  }
  .mb-#{$num} {
    margin-bottom: #{$num}px !important;
  }
  .ml-#{$num} {
    margin-left: #{$num}px !important;
  }
  .mr-#{$num} {
    margin-right: #{$num}px !important;
  }
  .mx-#{$num} {
    margin-left: #{$num}px !important;
    margin-right: #{$num}px !important;
  }
  .my-#{$num} {
    margin-top: #{$num}px !important;
    margin-bottom: #{$num}px !important;
  }
  $num: $num + 5;
}
$pos: -20; // top、left、right、bottom
@while $pos <= 20 {
  .top-#{$pos} {
    top: #{$pos}px !important;
  }
  .bottom-#{$pos} {
    bottom: #{$pos}px !important;
  }
  .left-#{$pos} {
    left: #{$pos}px !important;
  }
  .right-#{$pos} {
    right: #{$pos}px !important;
  }
  $pos: $pos + 5;
}
$spacing: 0; // width-px、height-px
@while $spacing <= 100 {
  .w--#{$spacing} {
    width: #{$spacing}px !important;
  }
  .h--#{$spacing} {
    height: #{$spacing}px !important;
  }
  $spacing: $spacing + 5;
}
$percentage: 0; // width-%、height-%
@while $percentage <= 100 {
  .w--#{$percentage}\% {
    width: #{$percentage + "%"} !important;
  }
  .h--#{$percentage}\% {
    height: #{$percentage + "%"} !important;
  }
  $percentage: $percentage + 5;
}
.w--unset {
  width: unset !important;
}
.font-style {
  font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "微软雅黑", Arial, sans-serif;
}
html,
body {
  height: 100% !important;
}
.fr {
  float: right !important;
  &::after {
    content: "";
    display: block;
    clear: both;
  }
}
.fl {
  float: right !important;
  &::after {
    content: "";
    display: block;
    clear: both;
  }
}
.text-xs {
  font-size: 12px;
}
.text-sm {
  font-size: 14px;
}
.text-base {
  font-size: 16px;
}
.text-lg {
  font-size: 18px;
}
.text-xl {
  font-size: 20px;
}
.truncate {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.line-clamp-1 {
  overflow: hidden;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 1;
}
.line-clamp-2 {
  overflow: hidden;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
}
.line-clamp-3 {
  overflow: hidden;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
}
.line-clamp-4 {
  overflow: hidden;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 4;
}
.select-none {
  user-select: none !important;
}
.w-full {
  width: 100% !important;
}
.h-full {
  height: 100% !important;
}
.relative {
  position: relative !important;
}
.absolute {
  position: absolute !important;
}
.fixed {
  position: fixed !important;
}
.flex {
  display: flex !important;
}
.inline-block {
  display: inline-block !important;
}
.hidden {
  display: none !important;
}
.text-center {
  text-align: center !important;
}
.text-left {
  text-align: left !important;
}
.text-right {
  text-align: right !important;
}
.cursor-pointer {
  cursor: pointer !important;
}
.flex-wrap {
  flex-wrap: wrap !important;
}
.flex-nowrap {
  flex-wrap: nowrap !important;
}
.flex-col {
  flex-direction: column !important;
}
.flex-row {
  flex-direction: row !important;
}
.justify-center {
  justify-content: center !important;
}
.self-center {
  align-self: center !important;
}
.justify-between {
  justify-content: space-between !important;
}
.justify-around {
  justify-content: space-around !important;
}
.justify-evenly {
  justify-content: space-evenly !important;
}
.items-baseline {
  align-items: baseline !important;
}
.items-center {
  align-items: center !important;
}
.items-stretch {
  align-items: stretch !important;
}
.align-top {
  vertical-align: top !important;
}
.align-middle {
  vertical-align: middle !important;
}
.align-bottom {
  vertical-align: bottom !important;
}
.overflow-hidden {
  overflow: hidden !important;
}
.overflow-y {
  overflow-y: scroll !important;
}
.overflow-x {
  overflow-x: scroll !important;
}
.rounded-none {
  border-radius: 0 !important;
}
.rounded-sm {
  border-radius: 2px !important;
}
.rounded {
  border-radius: 4px !important;
}
.rounded-md {
  border-radius: 6px !important;
}
.rounded-lg {
  border-radius: 8px !important;
}
.rounded-xl {
  border-radius: 12px !important;
}
.rounded-2xl {
  border-radius: 16px !important;
}
.rounded-3xl {
  border-radius: 24px !important;
}
.rounded-full {
  border-radius: 99999px !important;
}
.shadow-sm {
  box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
}
.shadow {
  box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px -1px rgba(0, 0, 0, 0.1);
}
.shadow-md {
  box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1);
}
.shadow-lg {
  box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1);
}
.shadow-xl {
  box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1);
}
.shadow-2xl {
  box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
}
.shadow-inner {
  box-shadow: inset 0 2px 4px 0 rgba(0, 0, 0, 0.05);
}
.shadow-none {
  box-shadow: 0 0 #0000;
}
.grid {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  @at-root .gap {
    gap: 4px !important;
  }
  @at-root .gap-2 {
    gap: 8px !important;
  }
  @at-root .gap-3 {
    gap: 12px !important;
  }
  .grid-item-1 {
    grid-area: auto / span 1 !important;
  }
  .grid-item-2 {
    grid-area: auto / span 2 !important;
  }
  .grid-item-3 {
    grid-area: auto / span 3 !important;
  }
  .grid-item-4 {
    grid-area: auto / span 4 !important;
  }
  .grid-item-5 {
    grid-area: auto / span 5 !important;
  }
  .grid-item-6 {
    grid-area: auto / span 6 !important;
  }
  .grid-item-7 {
    grid-area: auto / span 7 !important;
  }
  .grid-item-8 {
    grid-area: auto / span 8 !important;
  }
  .grid-item-9 {
    grid-area: auto / span 9 !important;
  }
  .grid-item-10 {
    grid-area: auto / span 10 !important;
  }
  .grid-item-11 {
    grid-area: auto / span 11 !important;
  }
  .grid-item-12 {
    grid-area: auto / span 12 !important;
  }
}

<style>
请勿转载
<think> 首先,用户的问题是:“我想查找el-form自定义填写校验失败框样式的方法 请问el-form自定义填写校验失败框样式的方法”。这涉及到Element UI的el-form组件,特别是自定义校验失败时的样式。 从系统级指令,我需要: - 使用$...$格式的行内数学表达式,但这里没有数学内容,所以可能不需要。 - 独立公式用$$...$$,但同样不适用。 - LaTeX语法正确。 - 用中文回答。 - 生成相关问题。 - 回答中引用的段落末尾添引用标识,如[^1]。 用户提供了两个引用: - 引用[1]:关于el-form自定义校验,特别是图片上传验证,使用了errorMsg字符串和样式类来控制错误消息。 - 引用[2]:关于el-form自定义校验规则传参,解决了循环校验问题。 用户的需求是自定义校验失败框的样式,比如当表单验证失败时,如何改变错误提示的样式。 在Element UI中,表单验证失败时,通常会显示一个错误消息。默认情况下,el-form-item会添一个类来控制错误样式。要自定义这个样式,可以通过CSS来覆盖默认样式。 回顾引用[1],它使用了: - 一个<p>元素显示错误消息,使用了errorMsg变量。 - 应用了类如.errorMsg, .f12, .color999, 以及其他基于条件的类(如.warn或.danger)。 - 在错误消息上绑定了:class="canUpload? &#39;warn&#39;:&#39;danger&#39;",这表示根据canUpload状态改变样式类。 所以,用户可能想通过类似的方式自定义错误框的样式。 在Element UI的el-form-item中,错误消息通常是通过el-form-item自动生成的,但用户可以通过自定义模板或覆盖CSS来改变样式。 方法包括: 1. **使用scoped slots**:Element UI提供了作用域插槽来自定义错误消息的渲染。 2. **覆盖CSS类**:通过添自定义CSS来覆盖默认的样式类。 在引用[1]中,用户手动添了一个<p>元素来显示错误消息,而不是依赖el-form-item的自动错误消息。这可能是通过自定义校验函数设置的。 在自定义校验函数中,可以设置一个错误消息变量,然后在模板中显示该消息,并应用自定义样式。 例如: - 在data中定义errorMsg。 - 在校验函数中,根据校验结果设置errorMsg。 - 在模板中,使用v-if显示errorMsg,并应用自定义样式类。 这类似于引用[1]的做法。 对于el-form-item本身的错误样式,Element UI使用类如.el-form-item__error来显示错误消息。用户可以通过CSS覆盖这个类的样式。 具体步骤: - 在全局CSS或scoped CSS中,定义覆盖.el-form-item__error的样式。 - 或者使用scoped slots来自定义错误消息的内容和样式。 Element UI文档中提到,el-form-item有一个error插槽,用于自定义错误消息。 例如: ```html <el-form-item prop="name"> <template #error="{ error }"> <div class="my-error">{{ error }}</div> </template> <el-input v-model="form.name"></el-input> </el-form-item> ``` 然后,在CSS中定义.my-error的样式。 这样,用户可以完全控制错误消息的渲染和样式。 在引用[1]中,他们没有使用error插槽,而是手动添了一个额外的元素来显示错误消息。这是因为他们可能是在处理非标准的校验场景,比如图片上传。 对于用户的需求“自定义填写校验失败框样式”,我应该推荐使用error插槽或CSS覆盖。 现在,构建回答: 1. **结构清晰**:逐步解释方法。 2. **参考引用**:在相关部分添引用标识。 3. **使用中文**。 4. **生成相关问题**。 回答结构: - 介绍方法一:使用error插槽自定义错误消息样式。 - 介绍方法二:覆盖CSS类来自定义样式。 - 结合引用[1]的例子,说明手动控制错误消息的方法。 -引用标识。 最后,生成相关问题。 确保回答真实可靠:基于Element UI文档和常见实践。 Element UI文档链接:https://element.eleme.io/#/en-US/component/form#custom-error-message 在中文上下文中,使用中文文档或解释。 步骤: 1. **使用error插槽**: -el-form-item中使用scoped slot: error。 - 示例代码。 2. **覆盖CSS类**: - 覆盖.el-form-item__error的样式。 - 示例CSS3. **手动控制错误消息**(如引用[1]): - 定义错误变量,在校验函数中设置。 - 在模板中显示自定义元素。 在引用[1]中,他们是手动设置errorMsg,而不是依赖el-form的自动校验。这可能适用于特定场景,但一般推荐使用内置的校验机制。 对于用户问题,最直接的是使用error插槽或CSS覆盖。 添引用: - 在引用相关段落时添[^1]或[^2]。 生成相关问题: - 例如: 1. 如何在Element UI中自定义表单校验规则? 2. el-form-item的error插槽有哪些用法? 3. 如何处理el-form自定义校验错误样式? 最终回答。 </think>### Element UI 中自定义 el-form 校验失败框样式的方法 在 Element UI 中,自定义 el-form 校验失败时的错误提示样式,主要通过以下方法实现,结合 CSS 覆盖和组件插槽机制。以下是逐步说明: #### 方法 1: 使用 CSS 覆盖默认样式 Element UI 的校验失败框默认使用类名 `.el-form-item__error` 控制样式。您可以通过添自定义 CSS 覆盖这些样式: ```css /* 自定义错误提示框样式 */ .el-form-item__error { color: #ff4d4f !important; /* 修改文字颜色为红色 */ background-color: #fff2f0; /* 添背景色 */ padding: 4px 8px; /* 调整内边距 */ border-radius: 4px; /* 圆角边框 */ border: 1px solid #ffccc7; /* 边框样式 */ font-size: 12px; /* 字体大小 */ } ``` - **优点**:简单直接,全局生效。 - **注意**:使用 `!important` 确保覆盖默认样式。 #### 方法 2: 通过 `error` 插槽自定义渲染(推荐) Element UI 的 `<el-form-item>` 提供 `error` 插槽,允许完全自定义错误提示的 HTML 结构和样式: ```html <el-form-item prop="email" label="邮箱"> <el-input v-model="form.email"></el-input> <!-- 使用 error 插槽自定义错误提示 --> <template #error="{ error }"> <div class="custom-error"> <i class="el-icon-warning"></i> <span>{{ error }}</span> </div> </template> </el-form-item> <style> .custom-error { color: #e6a23c; /* 橙色警告色 */ background: #fdf6ec; padding: 5px; margin-top: 4px; border-left: 3px solid #e6a23c; } </style> ``` - **关键点**: - `#error="{ error }"` 接收错误消息文本。 - 完全自由定义 HTML 结构(如添图标、背景等)。 - 样式通过独立类名(如 `.custom-error`)控制,避免冲突。 #### 方法 3: 手动控制错误消息(适用于特殊场景) 参考引用[1],可在自定义校验函数中手动设置错误消息变量,并在模板中绑定样式: ```html <el-form-item label="上传文件"> <el-upload ...> ... </el-upload> <!-- 手动显示错误消息并绑定样式 --> <p v-if="errorMsg" class="custom-error">{{ errorMsg }}</p> </el-form-item> <script> export default { data() { return { errorMsg: "", // 存储错误消息 }; }, methods: { customValidate(rule, value, callback) { if (!value) { this.errorMsg = "文件不能为空"; // 设置错误消息 callback(new Error("校验失败")); } else { this.errorMsg = ""; // 清除错误 callback(); } } } }; </script> <style> .custom-error { color: #f56c6c; font-size: 12px; margin-top: 5px; } </style> ``` - **适用场景**:当校验逻辑复杂(如文件上传)且需要动态样式时[^1]。 - **优势**:可结合条件动态切换样式类(如引用[1]中的 `:class="canUpload? &#39;warn&#39;:&#39;danger&#39;"`)。 #### 方法 4: 全局修改主题色 若只需修改错误提示颜色,可通过覆盖 Element UI 主题变量: ```css /* 在全局 CSS 文件中修改 */ :root { --el-color-danger: #ff4d4f; /* 修改错误提示主色 */ } ``` ### 最佳实践建议 1. **优先使用 `error` 插槽**:灵活性高,符合 Vue 组件化思想。 2. **避免全局样式污染**:使用 scoped CSS 或 BEM 命名规范(如 `.my-form__error`)。 3. **动态样式控制**:通过 `:class` 绑定实现状态相关样式(如校验失败时添动画): ```html <template #error="{ error }"> <div :class="{ &#39;shake-animation&#39;: hasError }">{{ error }}</div> </template> ``` ### 注意事项 - 自定义校验规则需确保 `callback()` 正确调用(参考引用[2]关于校验函数传参的实践)[^2]。 - 测试响应式:确保样式在移动端兼容。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值