vue2 表单自定义验证,规则服务端维护

功能描述:

  1、基于element ui 自定义表单验证

  2、vuex 缓存后端返回数据

  3、基于服务端接口返回验证规则适用于,第三方规则

 

 

1、路由守卫前,触发登陆成功获取,动态验证规则集合,存放到vuex

// 全局前置守卫
router.beforeEach((to, from, next) => {
  console.log("路由守卫触发:从", from.path, "", to.path);

  //请求接口获取后台规则 逻辑判断...直接处理响应结构如下 规则字段【pattern,message】后边需要字段不可少

  const backendRules = {
    phone: [
      {
        pattern: /\S/,
        message: "手机号不能为空",
      },
      {
        // 自定义验证规则
        pattern: /^1[3-9]\d{9}$/,
        message: "请输入正确的手机号格式",
      },
    ],
    password: [
      {
        pattern: /\S/,
        message: "密码不能为空",
        trigger: "blur",
      },
      {
        pattern: /^.{8,20}$/,
        message: "密码长度需在8-20位之间",
      },
      {
        pattern: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[^\da-zA-Z]).{8,20}$/,
        message: "密码需包含大小写字母、数字和特殊字符",
      },
    ],
    confirmPassword: [
      {
        pattern: /\S/,
        message: "请确认密码",
      },
      {
        pattern: /\S/,
        message: "两次输入的密码不一致",
        deps: ["password"], // 跨字段校验(与密码一致)
        params: {}, // 预留函数参数
      },
    ],
  };

  store.dispatch('dyRule/ADD_RULES',backendRules)

  // 必须调用 next() 来 resolve 这个钩子
  next();
});

 

 

vuex.---- src/store/ModuleRule/index.js

const Rules = {
  namespaced: true, // 开启命名空间,避免模块间命名冲突
  state: {
    rulesList: {}, // 存放后台返回动态验证规则,假设有 2,3百个,类似码值
  },
  getters: {
    getRules(state) {
      return state.rulesList;
    },
  },
  mutations: {
    SET_RULES(state, rule) {
      state.rulesList = rule;
    },
  },
  actions: {
    ADD_RULES({ commit }, rule) {
      commit("SET_RULES", rule);
    },
  },
};

export default Rules;

 

 

store/index.js. 引用

/*
  
 * @Description:
 */
// store/index.js
import Vue from "vue";
import Vuex from "vuex";
import ModuleA from "./ModuleA";
import ModuleB from "./ModuleB";
import getters from "./getters";
import Rules from "./ModuleRule";

Vue.use(Vuex);

const store = new Vuex.Store({
  state: {
    count: 0, // 示例:计数器状态
    permission: ['sys:user:add'],
  },
  getters,
  mutations: {
    add(state, num) {
      state.count += num;
    },
    addPermission(state, vals) {
      state.permission = vals;
    },
  },
  actions: {
    addUser({ commit }, num) {
      // this.add(state)
      commit("add", num);
    },
  },
  modules: {
    cart: ModuleA, // 注册模块,访问时需加模块名:$store.state.cart.items
    user: ModuleB,
    dyRule: Rules
  },
});

export default store;

 

 

store/getters.js

const getters = {
  getCount: (state) => state.count,
  getCartCount: (state) => state.cart.count,
  getPermission: state =>state.permission,
  getDyRule: state => state.dyRule.rulesList
}

export default getters

 

页面使用。如果不使用vuex.  页面可以直接看效果     ---注释打开 ---

fetchBackendRules
<template>
  <el-form
    :model="form"
    :rules="elementRules"
    ref="formRef"
    label-width="100px"
    class="form-container"
  >
    <el-form-item label="手机号" prop="phone">
      <custom-input v-model="form.phone" placeholder="请输入手机号" />
    </el-form-item>

    <el-form-item label="密码" prop="password">
      <custom-input
        v-model="form.password"
        type="password"
        placeholder="请输入密码"
      />
    </el-form-item>

    <el-form-item label="确认密码" prop="confirmPassword">
      <custom-input
        v-model="form.confirmPassword"
        type="password"
        placeholder="请确认密码"
      />
    </el-form-item>

    <el-form-item>
      <el-button type="primary" @click="handleSubmit">提交</el-button>
      <el-button @click="handleReset">重置</el-button>
    </el-form-item>
  </el-form>
</template>

<script>
import { mapState, mapGetters, mapMutations, mapActions } from "vuex";
import transformBackendRules2 from "@/utils/ruleTransformer2";
import CustomInput from "./CustomInput/index.vue";

// import axios from 'axios';

export default {
  name: "DynamicForm",
  components: {
    CustomInput,
  },
  computed: {
    ...mapGetters("dyRule", ["getRules"]),
    getRules1() {
      return this.$store.getters.getDyRule;
    },
  },
  data() {
    return {
      form: {
        phone: "",
        password: "",
        confirmPassword: "",
      },
      elementRules: {}, // 转换后的Element UI规则
    };
  },
  created() {
    // console.log("getRules", this.getRules);
    const backRules = this.$store.getters.getDyRule;
    // console.log("backRules-----", backRules);
    // console.log('getRules1',this.getRules1)

    // 初始化时获取后端规则
    this.fetchBackendRules(backRules);
  },
  methods: {
    // 获取后端规则
    async fetchBackendRules(backendRules) {
      try {
        // const response = await axios.get('/api/form/rules'); // 替换为实际接口地址
        // const backendRules = response.data; // 后端返回的规则对象
        // 转换规则(传入表单对象,用于跨字段校验)

        // const backendRules = {
        //   phone: [
        //     {
        //       pattern: /\S/,
        //       message: "手机号不能为空",
        //     },
        //     {
        //       // 自定义验证规则
        //       pattern: /^1[3-9]\d{9}$/,
        //       message: "请输入正确的手机号格式",
        //     },
        //   ],
        //   password: [
        //     {
        //       pattern: /\S/,
        //       message: "密码不能为空",
        //       trigger: "blur",
        //     },
        //     {
        //       pattern: /^.{8,20}$/,
        //       message: "密码长度需在8-20位之间",
        //     },
        //     {
        //       pattern:
        //         /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[^\da-zA-Z]).{8,20}$/,
        //       message: "密码需包含大小写字母、数字和特殊字符",
        //     },
        //   ],
        //   confirmPassword: [
        //     {
        //       pattern: /\S/,
        //       message: "请确认密码",
        //     },
        //     {
        //       pattern: /\S/,
        //       message: "两次输入的密码不一致",
        //       deps: ["password"], // 跨字段校验(与密码一致)
        //       params: {}, // 预留函数参数
        //     },
        //   ],
        // };
        this.elementRules = transformBackendRules2(backendRules, this.form);
      } catch (error) {
        console.error("获取后端规则失败:", error);
        //  fallback:使用默认规则(可选)
        this.elementRules = this.getDefaultRules();
      }
    },

    // 表单提交
    handleSubmit() {
      this.$refs.formRef.validate((valid) => {
        if (valid) {
          console.log("表单校验通过,提交数据:", this.form);
          // 此处执行提交逻辑(如调用接口)
        } else {
          console.log("表单校验失败");
          return false;
        }
      });
    },

    // 重置表单
    handleReset() {
      this.$refs.formRef.resetFields();
      // this.$refs.formRef.clearValidate(); // 清除校验提示
      // Object.keys(this.form).forEach((key) => {
      //   this.form[key] = ""; // 清空表单数据
      // });
    },

    // 可选:定义默认规则(当后端规则获取失败时使用)
    getDefaultRules() {
      return {
        username: [
          { required: true, message: "用户名不能为空", trigger: "blur" },
        ],
        // 其他字段的默认规则...
      };
    },
  },
};
</script>

<style scoped>
.form-container {
  width: 500px;
  margin: 20px auto;
  padding: 20px;
  border: 1px solid #ebeef5;
  border-radius: 4px;
}
</style>

 

 

ruleTransformer2.js
// src/utils/ruleTransformer.js
/**
 * 将后端规则转换为Element UI的rules格式
 * @param {Object} backendRules - 后端返回的规则对象
 * @param {Object} form - 表单数据对象(用于跨字段校验)
 * @returns {Object} - 转换后的Element UI rules
 */

export default function transformBackendRules2(backendRules, form) {
  const elementRules = {};

  console.log("form", form);
  // 后台返回验证集合包括需要验证
  // form:{
  // name:'',
  //}

  //1、当前form 数据是否在 后台返回集合里边,有就需要验证
  Object.keys(form).forEach((propName) => {
    const backendRule = backendRules[propName] || "";
    if (backendRule) {
      // 属性存在,组装element验证规范
      elementRules[propName] = backendRule.map((rule) => {
        if (rule.pattern) {
          return {
            required: true,
            // trigger: rule.trigger || 'blur',
            trigger:['change','blur'],
            validator: (_rule, value, callback) => {
              const ruleStr = rule.pattern;
              // console.log("valuevalue", value);
              if (!ruleStr.test(value)) {
                return callback(new Error(rule.message));
              } else if (rule.deps) {
                // 验证两个属性有依赖,密码及确认密码
                const [otherField] = rule.deps; // 解构
                if (form[otherField] !== value) {
                  return callback(new Error(rule.message));
                }
              } else {
                callback();
              }
            },
          };
        } else {
          return rule;
        }
      });
    }
  });
  console.log("elementRules", elementRules);
  return elementRules;
}

 

posted on 2025-11-21 13:45  Mc525  阅读(17)  评论(0)    收藏  举报

导航