<template> <div> <!-- 解释一 --> <label v-if="label">{{ label }}</label> <div> <!-- 解释二 --> <slot></slot> <!-- 解释三 --> <p v-if="validateState === 'error'">{{ validateMessage }}</p> </div> </div> </template> <script> export default { name: "EFormItem", props: { label: { type: String, default: '' }, prop: { type: String, default: '' } }, data() { return { validateState: '', validateMessage: '' } }, } </script> <style scoped> .error { color: red; } </style>
和上面一样,我们接着对上面的代码进行一些解释:
**解释一:**根据 ElementUI 中的用法,我们知道 label 是父组件传来,且当传入时我们展示,不传入时不展示。
解释二: slot 是一个预留的槽位,我们可以在其中放入 input 或其他组件、元素。
解释三: p 标签是用来展示错误信息的,如果验证状态为 error 时,就显示。
此时,我们的 FormItem 组件也可以使用了。同样,我们在 App.vue 中引入该组件。
<template> <div> <e-form-item label="用户名" prop="name"> <e-input v-model="ruleForm.name"></e-input> </e-form-item> <e-form-item label="密码" prop="pwd"> <e-input v-model="ruleForm.pwd"></e-input> </e-form-item> <div> {{ ruleForm }} </div> </div> </template> <script> import EInput from './components/Input.vue'; import EFormItem from './components/FormItem.vue'; export default { name: "app", components: { EInput, EFormItem }, data() { return { ruleForm: { name: '', pwd: '', }, }; }, }; </script>
3. Form 的设计
到现在,我们已经完成了最内部的 input 以及中间层的 FormItem 的设计,现在我们开始设计最外层的 Form 组件。
当层级过多并且组件间需要进行数据传递时,Vue 为我们提供了 provide 和 inject API,方便我们跨层级传递数据。
我们举个例子来简单实现一下 provide 和 inject 。在 App.vue 中,我们提供数据(provide)。
export default { name: "app", provide() { return { msg: '哥是最外层提供的数据' } } }; </script>
接着,我们在最内层的 Input.vue 中注入数据,观察结果。
<template> <div> <!-- 1、绑定 value 2、响应 input 事件--> <input type="text" :value="valueInInput" @input="handleInput"> <div>{{ msg }}</div> </div> </template> <script> export default { name: "EInput", inject: [ 'msg' ], props: { value: { type: String, default: '', } }, data() { return { valueInInput: this.value }; }, methods: { handleInput(event) { this.valueInInput = event.target.value; this.$emit('input', this.valueInInput); } }, }; </script>
根据上图,我们可以看到无论跨越多少层级, provide 和 inject 可以非常方便的实现数据的传递。
理解了上面的知识点后,我们可以开始设计 Form 组件了。
<el-form :model="ruleForm" :rules="rules" ref="loginForm"> </el-form>
根据 ElementUI 中表单的用法,我们知道 Form 组件需要实现以下功能:
提供数据模型 model;
提供校验规则 rules;
提供槽位,里面放我们的 FormItem 等组件;
根据上面的需求,我们创建一个 Form.vue 组件:
<template> <form> <slot></slot> </form> </template> <script> export default { name: 'EForm', props: { // 解释一 model: { type: Object, required: true }, rules: { type: Object } }, provide() { // 解释二 return { eForm: this // 解释三 } } } </script>
解释一:该组件需要用户传递进来一个数据模型 model 进来,类型为 Object 。 rules 为可传项。
解释二:为了让各个层级都能使用 Form 中的数据,需要依靠 provide 函数提供数据。
解释三:直接将组件的实例传递下去。
完成了 Form 组件的设计,我们在 App.vue 中使用一下:
<template> <div> <e-form :model="ruleForm" :rules="rules"> <e-form-item label="用户名" prop="name"> <e-input v-model="ruleForm.name"></e-input> </e-form-item> <e-form-item label="密码" prop="pwd"> <e-input v-model="ruleForm.pwd"></e-input> </e-form-item> <e-form-item> <button>提交</button> </e-form-item> </e-form> </div> </template> <script> import EInput from './components/Input.vue'; import EFormItem from './components/FormItem.vue'; import EForm from "./components/Form"; export default { name: "app", components: { EInput, EFormItem, EForm }, data() { return { ruleForm: { name: '', pwd: '', }, rules: { name: [{ required: true }], pwd: [{ required: true }] }, }; }, }; </script>