vue2实践:第一个非正规的自定义组件-动态表单对话框

前言

vue一个很重要的概念就是组件,作为一个没有经历过前几代前端开发的我来说,不太能理解它所带来的“进步”,但是,将它与后端c++、java类比,我感觉,组件就像是这些语言中的类和对象的概念,通过封装好的组件(类),可以通过挂载的方式,非常方便的调用其提供的功能,而不必重新写一遍实现逻辑。

我们常用的element UI就是由饿了么所提供的组件库,但是在项目开发中,我们可能还需要额外地定义一些组件来使用,就像java中我们会使用很多很多原生库和三方库以外,也要自己定义许多许多的实体类和工具类来满足项目需要。

需求

之前,使用el-table实现了一个用户可以自己添加删除行并填写内容的动态表格(见文末链接)。缺点是:用户输入了多行数据,在最后保存的时候才会做数据校验和提示。感觉不太符合现在表单设计的通用标准,所以,再次遇到这种需求时,我改成了用el-form来实现,让它能够实时校验用户的输入。与一般的el-form的不同在于,这次需要使用v-for遍历一个数组来使表单的row根据数组的长度来动态变化,其余与前一篇动态表格相似。

<el-form-item label="人员" prop="people">
        <el-row v-for="(row, index) in form.people" :key="index">
          <el-col :span="10">
            <el-form-item
              :prop="`people[${index}].nickName`"
              :rules="[{required: true,message: '人员姓名不能为空',trigger: 'blur'}]">
              <el-input v-model.trim="form.people[index].nickName" placeholder="请输入人员姓名"/>
            </el-form-item>
          </el-col>
        ....
    </el-row>
    ...
</el-form-item>

只是,使用el-form,就可以使用它提供的rules了。具体实现及表单校验方式参见文末

因为是第二次遇到这种需求,为了以后能够不再重复的写这部分代码逻辑,我考虑将它写成一个组件,直接调用。因为这两个需求都是对话框,所以,我写了一个对话框组件,本篇着重记录组件的实现

组件的实现

一、定义输入

就像我们定义一个类时,需要有set/get,定义一个方法,需要有入参和可能的返回值return一样,一个组件,也需要有输入项来支撑它的数据初始化,等它的操作完成,需要通知它的父组件来进行数据处理,比如,刷新列表等。所以,我们先根据实际的业务需求,定义它的输入输出项。

我这里是添加人员,根据所添加人员的角色的不同,对话框的title要发生变化,所以,至少初始化时需要传入角色、或者说title信息,另外,保存时也需要知道公司信息等。因为是对话框,我打算在父组件调用对话框,即显示(show)的时候,接收这些入参。

1、template:将控件放置在一个el-dialog中

  <el-dialog
    :title="dialogTitle"
    class="dialogCls"
    :visible.sync="dlgVisible"
    :close-on-click-modal="false"
    ref="_dialog_"
    v-dialogDrag
    width="700px"
    :before-close="onCancel"
    append-to-body
  >
。。。。

2、为该组件定义一个名字,以供从其它组件中调用。

export default {
      name: 'createAccountDlg',
      props:...
....
}

3、data中定义一个dialogOptions,用来接收入参

dialogOptions:{
    companyId: null,
    ...//其它参数    
},

4、method中提供show方法,供父组件触发该对话框显示 

show: function (options) {
      //备份原始默认选项用于关闭时恢复原状
      this.origDialogOptions = options;
      //扩展复制调用选项到dialogOptions
      let _dialogOptions_ = options || this.defaultDialogOptions;
      this.dialogOptions = $.extend(this.defaultDialogOptions, JSON.parse(JSON.stringify(_dialogOptions_)));

      //显示对话框
      this.dlgVisible = true;
},

5、在computed中定义属性dlgTitle,以在接收到参数后,更新对话框标题

computed: {
  //对话框标题
  dialogTitle(){
  if(this.dlgVisible) {
      return `添加${this.dialogOptions.role.roleName}`;
      }
  },
}

 6、内部添加删除行等的代码实现,跟之前一样,这里不再赘述

二、定义输出

等用户添加完,点击保存时,需要将所有数据保存到数据库中,而且,还要通知它的父组件刷新人员列表,这部分,通过$emit向父组件来发送一个事件,由父组件响应这个事件,并做对应的操作。(这里只是为了展示在保存后使用$emit发射事件的过程,有异步问题带来的bug,下一篇会说)

onSave(){
  this.$refs.form.validate(valid => {
  if (valid) {
     this.addUsrs();  //保存账号
     this.$emit("accountCreated"); //通知父组件保存完成,这里有异步问题
     this.dlgVisible = false;   //关闭对话框
     this.reset();   //重置入参
   }
  });
},

至此,组件的定义完成,主要包括入参处理、内部逻辑,以及结束时的通知事件$emit。如有需要,emit可携带更多参数传递给父组件:

this.$emit("eventName",{param1:param1Value, param2:param2Value})

组件的使用

一、挂载组件

需要先挂载这个组件,就像需要先加载第三方包一样。在整个项目的main.js中,挂载全局组件:

Vue.component('createAccountDlg', createAccountDlg)

二、 父组件中通过点击一个Button来触发

<el-button icon="el-icon-plus" type="primary" plain @click="createAccount">新增账号</el-button>


createAccount(){
   let options = {
      //初始化参数
      companyId: this.from.companyId,              
      role:this.role
    }
   this.$refs.createAccountDlg.show(options);
},

三、组件执行结束,父组件收到accountCreated时的回调函数 

<create-account-dlg ref="createAccountDlg" @accountCreated="onAccountCreated"></create-account-dlg>


onAccountCreated(){
    this.updateUserDataTable();
}

补充

prop

本文之所以叫非正规的自定义组件,是因为我觉得标准的组件定义中,入参应该通过prop来定义,如下:

props: {
        dlgTitle: {
          type: String,
          default: "创建人员"
          //required: true
          //还可以添加其它的类似于el-form rules中的校验逻辑
        },        
},

 这样在调用的时候,就像我们使用标准的element ui控件一样,要给出比如dlgTitle这个属性,替代在show中所给出的参数。(未实现,仅推测)

<create-account-dlg ref="createAccountDlg" dlgTitle="项目经理" @accountCreated="onAccountCreated"></create-account-dlg>

$emit:

看到很多人对emit的解释是:子组件通过$emit的方式,调用父组件中的事件,一直很难理解。在我的概念中,总觉得“调用”该通过名称去调用,而这里

//子组件中emit事件
this.$emit("accountCreated");

//父组件中的响应
<create-account-dlg ref="createAccountDlg" @accountCreated="onAccountCreated"></create-account-dlg>

父组件调用时,用@,表示on event,也就是当父组件收到“accountCreated”这个事件时的响应是由“onAccountCreated”函数来完成的。这里,父组件仅仅是在监听“accountCreated”这个用户自定义的事件,就像监听原生的click事件一样,监听到了,便根据后面的函数,进行逻辑处理,并不关心这个事件是由谁发出的。

这种方式,我觉得更好理解父子间的数据传递逻辑。否则,父组件通过prop传递数据给子组件,子组件又调用父组件的方法,感觉有点混乱。

本文提及的其它文章

vue2实践:el-table实现由用户自己控制行数的动态表格-CSDN博客

vue2表单校验:el-form表单绑定数组并使用rules进行校验_el-form 数组校验-CSDN博客 

vue2表单校验:添加自定义el-form表单校验规则_vue2验证表单-CSDN博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值