简单说明

当我们封装一个组件,比如说MySelect组件,我们希望他的用法是这样的。

<my-select v-model="job">
  <my-option value="dev">开发人员</my-option>
  <my-option value="test">测试人员</my-option>
  <my-option value="manager">管理人员</my-option>
</my-select>

这个用法很普遍,因为Vue本身对表单元素的双向绑定就是这么使用的。但封装这样的组件我遇到最大的问题就是:无法对props中的value进行改变
所以我们需要先了解一下v-model的实现,下面就详细说一下v-model的实现。

Vue对v-model的实现

如果我们不用v-model来实现双向绑定,那么我们需要这样写:

<template>
  <input type="text" v-bind:value="name" @input="inputHandler"/>
<template>
<script>
  export default {
    data(){
      return {
        name: ''
      }
    },
    methods: {
      inputHandler(value){
        if(value == null){
          this.name = event.target.value;
        }
        else{
          this.name = value;
        }
      }
    }
  }
</script>
  • 我们通过vue的v-bind指令为input绑定了value,那么在name值发生改变时,input的value也会发生改变。这样就实现了数据驱动DOM。(至于vue提供的bind是如何实现的,可以去了解一下Object.defineProperties
  • 我们为input绑定了input事件,在事件处理函数中将event.target.value赋值给name。这样就实现了DOM驱动数据的改变。

基于这两个实现,就实现了DOM和数据的双向绑定。很庆幸Vue对v-model的实现就是这样的(跟官网的描述有些许不同,仅供参考)。可以看出,v-model实际上是通过:value@input来实现的。并且inputHandler中优先以传入的参数value值给我们绑定的变量赋值,这一点很重要。这使得我们在组件中可以直接通过this.$emit('input', newValue)来给外界的data属性赋值。

综上所述,我们简单的对my-select组件进行封装

my-select组件的封装(未测试 ?,大概就是这么个逻辑)

<template>
  ...
</template>
<script>
  export default {
    props:{
      value: String
    },
    watch:{
      // 反向选择:监听value,当value因外界修改发生改变时选中自动选中option
      'value': function(newValue){
      	...
        this.selectByValue(newValue);
      	...
      }
    },
    methods: {
      // 选中,点击Option时触发该方法,并传入Option value和Option选中后所显示的内容。
      select(value, label){
      	...
        this.$emit('input', value);
      	...
      },
      // 根据值来选中Option
      selectByValue(value){
        // 遍历option,找到value与之对应的option,执行其绑定的click事件处理函数,该函数最终调用了select方法。
      }
    }
  }
</script>

上面的代码粗略的实现了my-select的v-model,简单说明一下:

  • DOM驱动数据: 点击Option选项,将Option的value和label(select选中option后显示的内容)作为参数调用select方法,select方法调用this.$emit('input', value),这样就实现了DOM驱动数据。
  • 数据驱动DOM:通过watch监听props value,发生改变后调用selectByValue进行选中,这样就实现了数据驱动DOM。

(完)

Logo

前往低代码交流专区

更多推荐