场景描述
我们在一个系统中,会出现这样的情况, 有一个联系人的下拉框,这个下拉框中的数据是从服务端获取的。 在很多页面都需要使用这个联系人(下拉框)。 我们通常是这样做的: 写一个下拉框组件然后调用接口。 这样不仅会造成代码冗余,而且不利于后期的维护。 比如说:如果有一天这个要发生变化,如果整个系统中有几十处。 难道我们要更改几十处?不会吧。这样好难受呀。 有的小伙伴说:这个还不简单:封装成为一个组件呀。
封装成为组件
concatPersonSelect.vue <template> <el-form ref="form" :model="form" label-width="80px"> <el-form-item label="联系人"> <el-select v-model="form.person" placeholder="请选择活动区域"> <el-option v-for="(item,index) in listAtt" :key="index" :label="item.name" :value="item.id"></el-option> </el-select> </el-form-item> </el-form> </template> <script> export default { data() { return { listAtt:[], form: { person: '', } } }, created() { this.getUserList() }, methods: { // 模拟接口 getUserList(){ setTimeout(()=>{ this.listAtt = [{ name:'张三1',id:1 },{ name:'张三2',id:2 },{ name:'张三3',id:3 },{ name:'张三4',id:4 }] },1600) } }, } </script>
页面使用
<template> <div> <h2>自定义组件也可以使用v-model</h2> <concatPersonSelect></concatPersonSelect> </div> </template> <script> export default { components:{ concatPersonSelect }, data(){ return{ } } } </script>
现在遇见的问题
是的,现在我们是把它封装成为了一个组件。 但是如果获取组件中的值呢? 这........,思考一会。 机智的小伙伴说:子组件提供一个方法,父组件通过ref的方式去调用。 那如果要赋值呢?子组件也提供一个方法,父组件去使用。 这样就可以获取值,赋值了。(耶,简直是一个天才) 这样虽然可以,但是真的优点繁琐,还有其他好的方法吗? 我们可以使用v-model,是的,我们给自己封装的组件使用v-model
组件中使用v-model的想法
我们给下拉框绑定一个 change 事件,这样值发生变化后。 通过 this.$emit 去更新。 与此同时,v-model中的值是 data中的 userValue 值。 userValue 中的值是从props中来的。 然后使用 model 中的 event 属性与 emit 事件保持一致
改造组件,组件可以使用 v-model
<template> <el-form ref="form" label-width="80px"> <el-form-item label="联系人"> <el-select @change="changeGetValue" v-model="userValue" placeholder="请选择活动区域"> <el-option v-for="(item,index) in listAtt" :key="index" :label="item.name" :value="item.id"></el-option> </el-select> </el-form-item> </el-form> </template> <script> export default { model: { event: 'input-change', // 这个事件与下面的emit事件与之对应 prop: 'propsInfoValue' // }, props:{ // 父组件传递的值,用于数据回填 propsInfoValue:{ type:String, default:()=>{ return '' } } }, data() { return { listAtt:[], userValue: this.propsInfoValue } }, created() { this.getUserList() }, methods: { // 模拟接口 getUserList(){ setTimeout(()=>{ this.listAtt = [{ name:'张三1',id:'1' },{ name:'张三2',id:'2' },{ name:'张三3',id:'3' },{ name:'张三4',id:'4' }] },1600) }, // 值发生变化会被触发,就去更新 changeGetValue(){ this.$emit('input-change', this.userValue) } } } </script>
页面就可以使用 v-model 了
<template> <div> <h2>自定义组件也可以使用v-model</h2> <concatPersonSelect v-model="obj.name" ></concatPersonSelect> <el-button @click="getHandler"> 获取值 </el-button> </div> </template> import concatPersonSelect from '../components/concatPersonSelect/concatPersonSelect.vue' export default { components:{ concatPersonSelect }, data(){ return{ obj:{ name:'' } } }, methods: { getHandler(){ console.log('获取的值', this.obj) } } }
如何有必填参数怎么搞?
我们都知道,如果某一个参数是必填的话。 在elementui中的form表单中。 需要同时满足两个条件,那就是: rules 属性传入约定的验证规则, 并将 Form-Item 的 prop 属性设置为需校验的字段名即可。 因此,子组件中的 el-form-item中应该有一个 prop属性, 并且这个属性的值与 rules属性中的规则字段相同就行。 我们打算在子组件中使用 v-bind="$attrs" 和 inheritAttrs: false, 这样页面中的参数可以直接进行传递
更新优化子组件
<template> <div> <el-form-item label="联系人" v-bind="$attrs"> <el-select @change="changeGetValue" v-model="userValue" placeholder="请选择联系人"> <el-option v-for="(item,index) in listAtt" :key="index" :label="item.name" :value="item.id"></el-option> </el-select> </el-form-item> </div> </template> <script> export default { model: { event: 'input-change', // 这个事件与下面的emit事件与之对应 prop: 'propsInfoValue' // }, props:{ // 父组件传递的值,用于数据回填 propsInfoValue:{ type:String, default:()=>{ return '' } } }, inheritAttrs: false, //不让属性直接渲染在根节点上 data() { return { listAtt:[], userValue: this.propsInfoValue } }, created() { this.getUserList() }, methods: { // 模拟接口 getUserList(){ setTimeout(()=>{ this.listAtt = [{ name:'张三1',id:'1' },{ name:'张三2',id:'2' },{ name:'张三3',id:'3' },{ name:'张三4',id:'4' }] },1600) }, // 值发生变化会被触发,就去更新 changeGetValue(){ this.$emit('input-change', this.userValue) } }, } </script>
页面使用
<template> <div> <h2>自定义组件也可以使用v-model</h2> <el-form :rules="rules" :model="ruleForm" ref="form" label-width="80px"> <el-form-item label="活动名称" prop="activeName"> <el-input v-model="ruleForm.activeName"></el-input> </el-form-item> <!-- prop中的值必须与验证规则中的字段保持一致,否者无法验证 --> <concatPersonSelect prop="personName" v-model="ruleForm.personName" > </concatPersonSelect> <el-button @click="getHandler"> 获取值 </el-button> </el-form> </div> </template> <script> export default { components:{ concatPersonSelect }, data(){ return{ // 表单中的字段 ruleForm:{ activeName:'', personName:'' }, // 验证规则以及提示语 rules: { activeName: [ { required: true, message: '请输入活动名称', trigger: 'blur' }, ], personName: [ { required: true, message: '请选联系人', trigger: 'change' } ] } } }, methods: { getHandler(){ console.log('获取的值', this.ruleForm) this.$refs['form'].validate((valid) => { // 验证规则成功 console.log(1,valid) }) } } } </script>