vue+element 表单封成组件(1)
作为一名刚接触vue不到一个月的菜鸟,思想还没有从操作DOM转变为数据驱动,看vue的代码处处别扭。组里为了让我熟悉vue交给了我一个将element 表单封装成组件的练手任务。由于开发过程中遇到的表单需求千奇百怪,我们不能直接将表单封装成一个组件。所以我尝试把输入框,下拉菜单,滑块,时间选择器,单选,多选等功能各封一个组件(感觉很蠢),但这毕竟是练手任务嘛,最后开发时也不会用我的这个。在封装的过程中遇到了很多问题和疑惑,以下记录我的收获与尚未解决的问题。
1 <template> 2 <el-form :model="ruleForm" ref="ruleForm" label-width="100px" class="demo-ruleForm"> 3 <commonformtext 4 prop="biao" 5 placeholder="这个是测试的" 6 label="活动区域" 7 v-model="ruleForm.biao" 8 :rules="[{ required: true, message: '请输入活动名称', trigger: 'blur' }]" 9 > 10 </commonformtext> 11 <commonformselect 12 prop="select" 13 placeholder="这个是测试的下拉框" 14 label="下拉框" 15 v-model="ruleForm.select" 16 :rules="{ required: true, message: '请选择活动区域', trigger: 'change' }" 17 :selectdata='selectdata' 18 > 19 </commonformselect> 20 <el-form-item> 21 <el-button type="primary" @click="submitForm('ruleForm')">立即创建</el-button> 22 <el-button @click="resetForm('ruleForm')">重置</el-button> 23 </el-form-item> 24 </el-form> 25 </template> 26 <script> 27 import commonformtext from "@/components/common/formtext.vue"; 28 import commonformselect from "@/components/common/formselect.vue"; 29 export default { 30 data() { 31 return { 32 ruleForm: { 33 biao:"", 34 select:"" 35 }, 36 selectdata:[ 37 {lable:"区域1",value:"1"}, 38 {lable:"区域2",value:"2"}, 39 {lable:"区域3",value:"3"}, 40 {lable:"区域4",value:"4"}, 41 {lable:"区域5",value:"5"} 42 ] 43 }; 44 }, 45 components:{ 46 commonformtext, 47 commonformselect, 48 }, 49 methods: { 50 submitForm(formName) { 51 this.$refs[formName].validate((valid) => { 52 if (valid) { 53 alert('submit!'); 54 } else { 55 console.log('error submit!!'); 56 return false; 57 } 58 }); 59 }, 60 resetForm(formName) { 61 this.$refs[formName].resetFields(); 62 } 63 } 64 } 65 </script>
以上是父组件,本篇先传输入框,下拉菜单两个子组件
/* * @property { rules : {String Object} 表单验证 一种验证传对象 一种以上把对象组成数组 } * @property { prop : {String} input的name 传回的字段名与html中input标签name值一样。 } * @property { placeholder : {String} 提示语,与html中input标签placeholder值一样。 } * @property { label : {String} 标签文本。 } * @property { v-model : {String} 语法糖,利用value接值父子组件相互传值 当前表单填写的内容 } * @version 1.0.0 * @edit: 2018/7/30 */ <template> <el-form-item :label="label" :prop="prop" :rules="rules"> <el-input v-model="myValue" :placeholder="placeholder" name="biao"></el-input> </el-form-item> </template> <script> export default { props: { prop: { type: String }, placeholder:{ type: String }, label:{ type: String }, value:{ type: String }, rules:[Object,Array] }, data() { return { activeIndex: '', menuIndex: 0, myValue:"" }; }, mounted(){ this.myValue = this.value; }, watch:{ myValue(val){ this.$emit("input",val) } } } </script>
上面的是输入框子组件
/* * @property { rules : {String Object} 表单验证 一种验证传对象 一种以上把对象组成数组 } * @property { prop : {String} input的name 传回的字段名与html中input标签name值一样。 } * @property { placeholder : {String} 提示语,与html中input标签placeholder值一样。 } * @property { label : {String} 标签文本。 } * @property { v-model : {String} 语法糖,利用value接值父子组件相互传值 当前表单填写的内容 } * @property { selectdata: {Array} option中的数据 } * @version 1.0.0 * @edit: 2018/7/30 */ <template> <el-form-item :label="label" :prop="prop" :rules="rules"> <el-select v-model="myValue" :placeholder="placeholder" v-on:change="change"> <el-option v-for="item in selectdata" :key="item.id" :label="item.lable" :value="item.value"></el-option> </el-select> </el-form-item> </template> <script> export default { props: { selectdata: { type: Array }, prop: { type: String }, placeholder:{ type: String }, label:{ type: String }, value:{ type: String }, rules:[Object,Array] }, data() { return { myValue:"" }; }, mounted(){ this.myValue = this.value; }, methods:{ change(){ this.$emit("input",this.myValue) } } } </script>
这个是下拉框子组件
首先是一个语法糖的知识点,父组件属性中加入v-model子组件需要在props中使用value来接值,然后子组件中用 this.$emit("input",val) 来把值返回父组件,这样父组件中就可以获得当前输入框的内容了。
在输入框子组件中我们采用的是监听输入框中的值的变化,每当输入的值变化我们都会 this.$emit("input",val) 将值返回父组件,但是在下拉栏中我们同样用此方法监听的时候会出现bug
我们明明选择了区域2表单检测却给我们报了错,然后当我们再次选择的时候就好使了
此时我们做一个假设,表单检测值事件运行时我们还没有将已改变的值发给父组件,所以在父组件进行检测的时候没有值,那我们不用watch改用methods来传值会不会变快呢,我们给select绑上change事件?
接下来我们来验证它
methods:{ change(){ console.log(this.myValue,"aaa") } }, watch:{ myValue(val){ console.log(this.myValue,"bbb") this.$emit("input",val) } }
我们在子组件中加入这两句话,来比一比监听值的变化快还是change事件快
先打印出aaa再打印出bbb,所以change事件比较快,那我们可以试试用change将值传给父组件,看看表单检测的时候 this.$emit("input",val) 有没有运行过。
结果change事件确实在表单检测之前将值塞了进去,bug解决了。