vue 2 实现自定义组件一到多个v-model双向数据绑定的方法

5 篇文章 0 订阅

前言

有时候我们需要对一个组件绑定自定义 v-model,以更方便地实现双向数据,例如自定义表单输入控件。

甚至有时候,我们想要实现绑定多个 “v-model”,也就是多个“双向绑定”,例如带表单输入的模块框,想同时控制模态框的显示状态与表单的输入状态。好在 vue 3 已经实现了多 v-model,那么在 vue 2 上我们可以如下实现。

单个“双向绑定”的实现

  1. 使用 model 实现

    其实 v-model 只是 value + change 的语法糖,监听输入并触发改变,因此只要实现 “监听” + “触发” 就可以自定义 v-model 啦。

    <!-- 父组件 -->
    <template>
    	<Child v-model="value" />
    </template>
    <script>
    export default {
      data() {
        return {
          value: ''
        }
      }
    }
    </script>
    
    <!-- 子组件 -->
    <template>
    	<input v-model="input" />
    </template>
    <script>
    export default {
      props: {
        value: String,
      },
      model: {
        prop: 'value',		// 指定 v-model 要绑定的参数叫什么名字,来自于 props 中定义的参数
        event: 'change',	// 指定要触发的事件名字,将被用于 $emit
      },
      computed: {
        input: {
          // 这里的计算属性使用了 getter、setter,可以简化代码
          // 可参见链接 https://cn.vuejs.org/v2/guide/computed.html#%E8%AE%A1%E7%AE%97%E5%B1%9E%E6%80%A7%E7%9A%84-setter
          get() {
            return this.value;
          },
          set(val) {
            this.$emit('change', val);	// 触发
          }
        }
      }
    }
    </script>
    

    这样一来,就实现了自定义组件的 v-model 实现,重点在于子组件中 model 的声明和 emit 事件。

  2. 使用 .sync 实现

    除了上面 model 的方法,其实还可以通过 sync 来实现。同样也是处理“监听”和“触发”就行。

    在官方文档中有写,https://cn.vuejs.org/v2/guide/components-custom-events.html#sync-修饰符

    用上面相似的例子,可以这样来实现:

    <!-- 父组件 -->
    <template>
    	<Child :value.sync="value" />
    </template>
    <script>
    export default {
      data() {
        return {
          value: ''
        }
      }
    }
    </script>
    
    <!-- 子组件 Child -->
    <template>
    	<input v-model="input" />
    </template>
    <script>
    export default {
      props: {
        value: String,
      },
      computed: {
        input: {
          get() {
            return this.value;
          },
          set(val) {
            this.$emit('update:value', val);	// 这里的事件名字一定是 'update:' + prop的名字
          }
        }
      }
    }
    </script>
    

    很显然,使用这种方法的代码量比第1种要少,因为不用写 model 属性。只是比起 v-model,v-bind:value.sync 的写法还是不那么“引人注目”

多个“双向绑定”的实现

在 vue 3 出来之前,我们知道在一个标签里面最多只能有一个 v-model。但这并不意味着一个组件只能一次双向数据绑定。

根据上面 .sync 的方法,我们可以举一反三,多几个 update:xxxx 就可以了。

  1. 分开绑定

    下面以一个带输入框的模态框为例子,需求是父组件能够打开模态框,子组件在输入确认后能够关闭模态框;子组件能够输入,确认后能够将值传给父组件。

    <!-- 父组件 -->
    <template>
      <!-- 定义了两个v-bind:xxx.sync来实现两个双向绑定 -->
      <ModalInput :value.sync="value" :show.sync="show" />
    </template>
    <script>
    export default {
      data() {
        return {
          value: '',
          show: false
        }
      }
    }
    </script>
    
    <!-- 子组件 ModalInput -->
    <template>
      <!-- 这里假设Modal是一个带“确认”按钮,点击触发confirm事件,并利用v-model来控制展示的模态框 -->
      <Modal v-model="showModal" @confirm="onConfirm">
        <input v-model="input">
      </Modal>
    </template>
    <script>
    export default {
      props: {
        value: String,
        show: Boolean,
      },
      data() {
        return {
          input: ''		// 在这个例子中,使用 data 来声明 input,
                      // 因为只有在点击了“确认”按钮后,才要把值传给父组件(而不是实时传)
        }
      },
      computed: {
        showModal: {
          get() {
            return this.show;
          },
          set(val) {
            this.$emit('update:show', val);
          }
        }
      },
      methods: {
        onConfirm() {
          this.$emit('update:value', this.input);
          this.showModal = false
        }
      }
    }
    </script>
    
  2. 合并绑定

    上面是绑定了两个独立变量的双向绑定,按照官方的文档,我们甚至还可以用 v-bind.sync 来绑定整个对象(的所有成员!)。下面假设一个表单组件,同时收集个人多个信息

    <!-- 父组件 -->
    <template>
      <UserInfoForm v-bind.sync="inputs" />
    </template>
    <script>
    export default {
      data() {
        return {
          inputs: {
            name: '',
            age: 0,
            addr: '',
            phone: ''
          }
        }
      }
    }
    </script>
    
    <!-- 子组件 UserInfoForm -->
    <template>
      <form>
        <input v-model="name">
        <input v-model.number="age">
        <input v-model="addr">
        <input v-model="phone">
      </form>
    </template>
    <script>
    // 与上面例子实现方式相似,这里省略代码若干行。。。
    // 其实就是声明入参 props 有哪些
    // 用 computed 来声明各个变量的 getter 和 setter
    // getter 返回传进来的 prop,setter 中触发 update:xxxx 事件
    </script>
    

参考链接

  • 15
    点赞
  • 45
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Vue中,v-model可以绑定到多种表单元素上,包括input、select和textarea等。\[1\]对于input元素,可以通过v-model数据绑定到其value属性上,例如<input v-model="data" />。\[3\]对于checkbox元素,可以使用v-model数据绑定到其选中状态上,选中时v-model绑定的值会被修改为true,否则为false。\[2\]对于radio元素,可以使用v-model数据绑定到其value属性上,通过选中不同的radio按钮来修改v-model绑定的值。\[3\]对于select元素,可以通过v-model数据绑定到其选中的option的value属性上,通过选择不同的option来修改v-model绑定的值。\[3\]此外,v-model还可以结合.lazy、.number、.trim等修饰符来限定其行为。在自定义组件上使用v-model时,其行为会有所不同,类似于sync修饰符,最终展开的结果是一个modelValue属性和一个update:modelValue事件。在Vue3中,还可以使用参数形式指定多个不同的绑定,例如v-model:foo和v-model:bar。\[3\]总之,v-modelVue中可以绑定到多种表单元素上,提供了方便的双向数据绑定功能。 #### 引用[.reference_title] - *1* [vue中v-model双向绑定原理](https://blog.csdn.net/weixin_57322537/article/details/120428298)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [Vue中v-model表单绑定几种实现方式](https://blog.csdn.net/qq_42707967/article/details/115806262)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [vue中v-model双向绑定使用和原理](https://blog.csdn.net/m0_67749488/article/details/125289608)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值