vue3之v-model升级

2,003 阅读3分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第19天,点击查看活动详情

在vue2中的双向绑定使用 v-model, 但是存在一些问题, 比如哲学问题吧哈哈。

vue2中的v-model存在哪些问题

哲学问题

vue2想要进行双向绑定可以使用v-model既可以到达双向绑定的目的, 又可以少书写代码。(v-model)本质是一个语法糖至于实现原理我相信大家都懂。

<template >
  <div class="test">
    <input type="text" v-model="value">
  </div>
</template>
<script>
export default {
  data() {
    return {
      value:''
    }
  }
}
</script>

这是vue2中常见的写法, 但是在使用一些UI库时会发现有写地方可能会用到sync修饰符,sync的作用也是做双向绑定, 一般用在子组件可以修改父组件的值,父组件为了图方便就可以使用sync修饰符, 所以sync本质上是一个语法糖, 它的实现原理如下:

// 子组件
<template >
    <div class="test-sync-container">
        <input type="text" :value="value" @input="handleValue">
    </div>
</template>
<script>
export default {
    props: ['value'],
    methods: {
        handleValue(event) {
            this.$emit('update:value', event.target.value)
        }
    },
}
</script>

// 父组件
<template >
  <div class="test">
    <TestSync :value="value" @update:value="value = $event"/>
  </div>
</template>
<script>
import TestSync from "./components/TestSync.vue";
export default {
  data() {
    return {
      value: ''
    }
  },
  components: {
    TestSync
  }
}
</script>

父组件中的写法就可以简写为 :value.sync="value" 就可以省略手动书写一个函数。

这里其实就存在一个哲学问题, 既然v-model、sync都是做双向绑定的,那为什么做出两个语法糖?

尤大大在vue3中就删除了sync只保留了v-model

在vue3中怎么统一使用v-model实现双向绑定?

vue3中v-model的语法更新

vue3v-model做了不兼容的更新(具体如下)

  • 非兼容:用于自定义组件时,v-model prop 和事件默认名称已更改:

    • prop:value -> modelValue
    • 事件:input -> update:modelValue
  • 非兼容v-bind 的 .sync 修饰符和组件的 model 选项已移除,可在 v-model 上加一个参数代替;

  • 新增:现在可以在同一个组件上使用多个 v-model 绑定;

  • 新增:现在可以自定义 v-model 修饰符。

非兼容:用于自定义组件时,v-model prop 和事件默认名称已更改:

解释下:在自定义组件v-model不在是绑定value属性, 而是modelValue属性, 触发的事件由input事件改为update:modelValue(注意这都是默认情况下)

用代码解释更清楚

// 子组件
<template >
    <div class="test-sync-container">
        <input type="text" :value="modelValue" @input="handleValue">
    </div>
</template>
<script>
export default {
    props: ['modelValue'], // 默认是这个属性 modelValue
    setup(props, ctx) {
        const handleValue = (event) => {
            // 默认事件名 update:modelValue
            ctx.emit('update:modelValue', event.target.value)
        }
        return {
            handleValue
        }
    }
}
</script>

// 父组件
<template >
  <div class="test">
    <TestSync v-model="value"/> 
  </div>
</template>
<script>
import TestSync from "./components/TestSync.vue";
export default {
  data() {
    return {
      value: ''
    }
  },
  components: {
    TestSync
  }
}
</script>

这是默认情况, 如果相对某些值使用双向绑定可以这样写 v-model:属性名="属性值" 触发的事件改为 update:属性名

// 子组件
<template >
    <div class="test-sync-container">
        <input type="text" :value="test" @input="handleTest">
    </div>
</template>
<script>
export default {
    props: ['test'],
    setup(props, ctx) {
        const handleTest = (event) => {
            // 事件名
            ctx.emit('update:test', event.target.value)
        }
        return {
            handleTest
        }
    }
}
</script>

// 父组件
<template >
  <div class="test">
    <TestSync v-model:test="value"/>
  </div>
</template>
<script>
import TestSync from "./components/TestSync.vue";
export default {
  data() {
    return {
      value: ''
    }
  },
  components: {
    TestSync
  }
}
</script>

vue3规范了v-model的写法使得更加的简介明了。

自定义 v-model 修饰符

vue3中可以对v-model增加自定的修饰符, 自定义修饰符通过props.modelModifiers(默认属性 modelValue), props.属性名Modifiers (自定义属性)

默认情况 v-model.abc="value"

modelModifiers = {
    abc:true
}

自定义属性 v-model:test.time="value"

testModifiers = {
    trim:true
}

对每一个双向绑定的属性都添加了一个 修饰符对象

总结

在 Vue 3 中,双向数据绑定的 API 已经标准化,以减少开发者在使用 v-model 指令时的混淆,并且更加灵活。