自定义组件使用v-model,太好用了

场景描述

scss 复制代码
我们在一个系统中,会出现这样的情况,
有一个联系人的下拉框,这个下拉框中的数据是从服务端获取的。
在很多页面都需要使用这个联系人(下拉框)。
我们通常是这样做的:
写一个下拉框组件然后调用接口。
这样不仅会造成代码冗余,而且不利于后期的维护。
比如说:如果有一天这个要发生变化,如果整个系统中有几十处。
难道我们要更改几十处?不会吧。这样好难受呀。
有的小伙伴说:这个还不简单:封装成为一个组件呀。

封装成为组件

xml 复制代码
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>

页面使用

xml 复制代码
<template>
  <div>
    <h2>自定义组件也可以使用v-model</h2>
    <concatPersonSelect></concatPersonSelect>
  </div>
</template>
<script>
export default {
  components:{
    concatPersonSelect
  },
  data(){
    return{
      
    }
  }
}
</script>

现在遇见的问题

csharp 复制代码
是的,现在我们是把它封装成为了一个组件。
但是如果获取组件中的值呢?
这........,思考一会。
机智的小伙伴说:子组件提供一个方法,父组件通过ref的方式去调用。
那如果要赋值呢?子组件也提供一个方法,父组件去使用。
这样就可以获取值,赋值了。(耶,简直是一个天才)
这样虽然可以,但是真的优点繁琐,还有其他好的方法吗?
我们可以使用v-model,是的,我们给自己封装的组件使用v-model

组件中使用v-model的想法

kotlin 复制代码
我们给下拉框绑定一个 change 事件,这样值发生变化后。
通过 this.$emit 去更新。
与此同时,v-model中的值是 data中的 userValue 值。
userValue 中的值是从props中来的。
然后使用 model 中的 event 属性与 emit 事件保持一致

改造组件,组件可以使用 v-model

xml 复制代码
<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 了

javascript 复制代码
<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)
    }
  }
}
csharp 复制代码
现在我们可以获取组件中的值了。
并且不需要通过ref这样的方式来获取。
这样一来,更加的方便了。

如果有必填参数怎么搞?

ini 复制代码
我们都知道,如果某一个参数是必填的话。
在elementui中的form表单中。
需要同时满足两个条件,那就是:
rules 属性传入约定的验证规则,
并将 Form-Item 的 prop 属性设置为需校验的字段名即可。
因此,子组件中的 el-form-item中应该有一个 prop属性,
并且这个属性的值与 rules属性中的规则字段相同就行。
我们打算在子组件中使用  
v-bind="$attrs" 和 inheritAttrs: false,
这样页面中的参数可以直接进行传递

更新优化子组件

xml 复制代码
<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>

页面使用

xml 复制代码
<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>

相关推荐
Dream-Y.ocean37 分钟前
鸿蒙PC平台宅匠 3D 室内设计适配实战:基于 Electron 壳方案的 Three.js 双渲染引擎与参数化户型编辑器开发
javascript·3d·harmonyos
Csvn2 小时前
性能监控
前端
Highcharts.js2 小时前
Highcharts Gantt使用符号的自定义数据标签开发甘特图示例
javascript·甘特图·highcharts·图表开发·实战代码·响应式图表
Csvn2 小时前
构建工具
前端
FRing033 小时前
vue2干货总结3(computed计算属性、watch监听器)
开发语言·前端·vue.js·vue2
Java小卷3 小时前
JuanForm vs FormCreate!Vue3 表单引擎联动配置 PK!
vue.js·低代码
kyriewen5 小时前
Skills 榜前 10 我全装了:只有 3 个能直接用
前端·javascript·程序员
IT_陈寒5 小时前
当Java的hashCode遇上Lombok,我的缓存被全清了
前端·人工智能·后端
工控丫丫5 小时前
帆软看板中经常使用的公式函数及经常搭的组合
前端·javascript·数据库
jerrywus6 小时前
我用 GPT-6.1-sol 做了台会讲解的 3D 售货机:60 罐饮料,一口没喝上
前端·agent·claude