前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【问题解决】如何在 Vue <component> 切换子组件时优雅地进行 Form 表单校验

【问题解决】如何在 Vue <component> 切换子组件时优雅地进行 Form 表单校验

作者头像
sidiot
发布2024-04-18 09:05:05
3290
发布2024-04-18 09:05:05
举报
文章被收录于专栏:技术大杂烩

前言

在项目中使用 Vue <component> 遇到了一些挑战,特别是在需要对子组件中的表单进行校验时。问题在于,通过点击 <el-aside> 标签切换子组件时,并不能自动触发表单校验,这就需要在父组件中集成对子组件表单的校验逻辑。因此写下本篇博文记录这个问题并分享相关思考以及解决方法。

q0.gif
q0.gif

本篇博文所使用到的所有代码点击此处进行跳转

博文中的所有代码全部收集在博主的 GitHub 仓库中,相关技术栈专栏如下:

环境准备

  • Vue2;
  • element 2.15.14;

这里参照 官方文档 安装 Element,并在项目的 main.js 文件里进行导入:

代码语言:javascript
复制
import Vue from 'vue'
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import App from './App.vue'

Vue.config.productionTip = false
Vue.use(ElementUI);

new Vue({
  render: h => h(App),
}).$mount('#app')

根据 官方文档 构建一个自定义化容器,效果如下所示:

q1.gif
q1.gif

构建容器代码如下所示:

代码语言:javascript
复制
<template>
  <el-container style="height: 700px; border: 1px solid #eee">
    <el-aside width="200px" style="background-color: rgb(238, 241, 246)">
      <el-menu :default-openeds="['1']" @select="handleSelect">
        <el-submenu index="1">
          <template slot="title"
            ><i class="el-icon-message"></i>导航一
          </template>
          <el-menu-item index="1-1">选项1</el-menu-item>
          <el-menu-item index="1-2">选项2</el-menu-item>
        </el-submenu>
        <el-menu-item index="2">
          <template slot="title"><i class="el-icon-menu"></i>导航二</template>
        </el-menu-item>
        <el-menu-item index="3">
          <template slot="title">
            <i class="el-icon-setting"></i>导航三
          </template>
        </el-menu-item>
      </el-menu>
    </el-aside>

    <el-container>
      <el-main>
        <ItemOne v-if="currentIndex === '1'"></ItemOne>
        <GroupOne v-else-if="currentIndex === '1-1'"></GroupOne>
        <GroupTwo v-else-if="currentIndex === '1-2'"></GroupTwo>
        <ItemTwo v-else-if="currentIndex === '2'"></ItemTwo>
        <ItemThree v-else-if="currentIndex === '3'"></ItemThree>
      </el-main>
    </el-container>
  </el-container>
</template>

<script>
import GroupOne from "@/components/GroupOne.vue";
import GroupTwo from "@/components/GroupTwo.vue";
import ItemOne from "@/components/ItemOne.vue";
import ItemTwo from "@/components/ItemTwo.vue";
import ItemThree from "@/components/ItemThree.vue";

export default {
  name: "App",
  components: {
    GroupOne,
    GroupTwo,
    ItemOne,
    ItemTwo,
    ItemThree,
  },
  data() {
    return {
      currentIndex: '1'
    };
  },
  methods: {
    handleSelect(index) {
      this.currentIndex = index
    }
  }
};
</script>

子组件模板代码如下所示:

代码语言:javascript
复制
<template>
  <p>导航一</p>
</template>

<script>
export default {
  name: "ItemOne"
}
</script>

使用 <component> 标签优化代码

当构建容器组件时,我们通常希望根据不同的条件,动态地渲染不同的子组件。

代码语言:javascript
复制
<el-container>
  <el-main>
    <ItemOne v-if="currentIndex === '1'"></ItemOne>
    <GroupOne v-else-if="currentIndex === '1-1'"></GroupOne>
    <GroupTwo v-else-if="currentIndex === '1-2'"></GroupTwo>
    <ItemTwo v-else-if="currentIndex === '2'"></ItemTwo>
    <ItemThree v-else-if="currentIndex === '3'"></ItemThree>
  </el-main>
</el-container>

在上述代码中,使用了 if-else 结构来根据 currentIndex 的值选择不同的子组件进行展示。虽然这种方法可以实现功能,但随着子组件数量的增加,代码会变得冗长且难以维护。

为了优化这段代码,我们可以引入一个用于渲染动态组件或元素的 “元组件”:<component>,这是一个对象映射的方式,使代码更加简洁和易于管理,详细原理见官方文档

下面是详细的优化步骤:

  1. data() 中定义一个包含组件名称与对应索引关系的映射对象 componentMap,代码如下所示:
代码语言:javascript
复制
data() {
  return {
    currentIndex: '1',
    componentMap: {
      '1': 'ItemOne',
      '1-1': 'GroupOne',
      '1-2': 'GroupTwo',
      '2': 'ItemTwo',
      '3': 'ItemThree'
    }
  };
},
  1. 然后,通过计算属性来返回当前需要渲染的子组件,在组件中添加计算属性 currentComponent,代码如下所示:
代码语言:javascript
复制
computed:{
  currentComponents() {
    return this.componentMap[this.currentIndex]
  }
},
  1. 最后,在模板中使用这个计算属性来渲染子组件,代码如下所示:
代码语言:javascript
复制
<el-container>
  <el-main>
    <component :is="currentComponents"></component>
  </el-main>
</el-container>

单个组件表单验证

我们以 导航二 ItemTwo 为例,创建一个表单 Form,效果如下所示:

v1.png
v1.png

如果直接点击 “提交” 按钮,即使还有选项没有填写,表单也会被直接提交,效果如下所示:

v2.png
v2.png

因此我们需要进行表单验证,设置数据校验规则,在防止用户犯错的前提下,尽可能让用户更早地发现并纠正错误。

Form 组件提供了表单验证的功能,只需要通过 rules 属性传入约定的验证规则,并将 Form-Item 的 prop 属性设置为需校验的字段名即可。校验规则参见 async-validator

下面是详细的验证步骤:

  1. data() 中定义一个表单规则 rules,代码如下所示:
代码语言:javascript
复制
data() {
  return {
    ...,
    rules: {
      name: [{ required: true, message: "请输入姓名", trigger: "blur" }],
      sex: [{ required: true, message: "请选择性别", trigger: "change" }],
      food: [
        { required: true, message: "请选择喜欢吃的食物", trigger: "change" },
      ],
    },
  }
}
  1. 接着在 Form 组件中传入验证规则,代码如下所示:
代码语言:javascript
复制
<el-form ref="form" :model="form" :rules="rules">
    <el-form-item label="姓名" prop="name">
        ...
    </el-form-item>
    ...
<el-form>
  1. 最后在提交表单时,进行数据的校验,代码如下所示:
代码语言:javascript
复制
methods: {
  submitForm() {
    this.$refs.form.validate((valid) => {
      if (valid) {
        ...
      }
    });
  },
},

最终效果如下所示:

v3.png
v3.png

【ItemTwo.vue】代码点击此处跳转

父组件调用子组件方法

在介绍父组件验证子组件表单之前,需要了解一个前置知识:父组件如何调用子组件的方法。

接下来我们以 App.vue 作为父组件,ItemThree.vue 作为子组件进行介绍父组件如何调用子组件的方法。

1、构建子组件页面,代码如下所示:

代码语言:javascript
复制
<template>
  <div>
    <h1>导航三</h1>
    <p>
      响应内容: <span style="color: #e86666">{{ msg }}</span>
    </p>
  </div>
</template>

<script>
export default {
  name: "ItemThree",
  data() {
    return {
      msg: "当前没有响应内容!",
    };
  },
};
</script>

效果如下所示:

z1.png
z1.png

2、编写一个子组件方法,可以更改 “响应内容”,代码如下所示:

代码语言:javascript
复制
methods: {
  changeMsg(owner) {
    this.msg = `${owner} 组件改变了响应内容!`
  }
}

效果如下所示:

z2.png
z2.png

3、父组件通过 ref 属性来调用子组件的方法。

  1. 向子组件添加 ref 属性,代码如下所示:
代码语言:javascript
复制
<component :is="currentComponents" ref="child"></component>
  1. 编写父组件调用子组件的方法,代码如下所示:
代码语言:javascript
复制
handleClick() {
  this.$refs.child.changeMsg("Parent");
},

效果如下所示:

z3.png
z3.png

父组件校验子组件表单

1、在子组件中创建一个校验方法 handleValidForm(),代码如下所示:

代码语言:javascript
复制
handleValidForm() {
  let flag = false
  this.$refs.form.validate((valid) => {
    if (valid) {
      flag = true
      this.submitForm()
    }
  });
  return flag
},

上述代码先对表单进行校验,若校验通过则触发表单提交,并返回一个标识位 flag,用于标识表单校验是否通过。

2、在父组件中调用此方法,通过获取到的标识位 flag 来判断表单是否校验通过,代码如下所示:

代码语言:javascript
复制
handleSelect(index) {
  if (this.$refs.child.handleValidForm())
    this.currentIndex = index;
}

上述代码表示如果校验通过,则实现子组件的切换,否则不做任何操作。

需要注意的是,每个被 <componet> 所使用的子组件都需要具有 handleValidForm() 方法,否则会出现报错:

代码语言:javascript
复制
vue.runtime.esm.js:4427 [Vue warn]: Error in v-on handler: "TypeError: this.$refs.child.handleValidForm is not a function"

3、效果如下所示:

q2.gif
q2.gif
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-04-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 环境准备
  • 使用 <component> 标签优化代码
  • 单个组件表单验证
  • 父组件调用子组件方法
  • 父组件校验子组件表单
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档