作為一名剛接觸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解決了。