Vue3的v-model

摘要

vue3.0中对如何在自定义组件上使用v-model进行了重大升级,本文详情列出了变化要点,并给出了示例代码。

内容

1. 历史回顾。v-model的前世今生

2. 具体的变化内容

  • 组件上单个v-model
  • 组件上单个v-model别名
  • 组件上多个v-model
  • 组件上v-model自定义修饰符

    3. 小结

    历史回顾

    Vue 2.0

    v-model 只能绑定在组件的 value 属性上。

    <son-comv-model="msg" />

    也就是说在son-com这个的组件的内部,你只能通过一个名为value的属性来获取父组件中传入的msg的值。

    {
      props:['value']
    }

    这一点其实不太友好:value这个词太没有语义了。所以在后续版本中增加可修改属性名的功能。

    vue 2.2

    在此版本中,组件在定义可以写 model 项,开发者通过这个设置和 v-model 关联的属性和事件。

    具体做法是在组件内部定义一个model项,其中prop用来设置v-model中默认的value的别名, event用来设置v-model中默认的input事件的别名

    Vue.component('SonCom',{
      template: `
        <div>{{checked}} <button @click="$emit('change', false)">设成false</div>
        `
      model: {
        prop: 'checked', // 默认叫value
        event: 'change' // 默认叫input
        }
    }

    Vue 2.x

    一个组件上只能一个v-model。

    当然,你也可以用v-bind.sync来达成多个数据项双向绑定的效果,代码如下:

    <div id="app">
       <h2>父组件</h2>
        {{a}} - {{b}}
       <son-com v-bind:a.sync="a" v-bind:b.sync="b"></son-com>
     </div>
     <script>
     Vue.component('SonCom', {
       props:['a', 'b'],
       template: `
        <div>
          {{a}}<button @click="$emit('update:a',100) ">改父中的a</button>
          {{b}}<button @click="$emit('update:b',200) ">改父中的b</button>
        </div>
        `
     })
      var vm = new Vue({
        el: '#app',
        data: {
          a: 1,
          b: 2
        }
      })
    </script>

    Vue 3

    v-bind的.sync修饰符和组件的model选项被删除了,因为你不再需要它们了,具体说明见后文。

    变化内容

    先把明细列出来:

    • 属性以及事件的默认名称变了
    • v-bind 的 .sync 修饰符和组件的 model 选项被移除了,取而代之的是 v-model 参数
    • 支持同一组件同时设置多个 v-model
    • 支持自定义 v-model 修饰符

      在原生input 上的v-model

      它的使用与2.X的版本是一样的,也可以使用修饰符。

      
      <script src="https://unpkg.com/vue@next"></script>
      <div id="app">
         <h2>父组件</h2>
          {{a}}
         <input v-model.trim="a" />
       </div>
       <script>
         const app = Vue.createApp({
           data() {
              return{
                a: 1
              }
           }
          })
         app.mount("#app")
      </script>

      在组件上的单个v-model

      请注意,属性名是 modelValue, 事件名是:update:modelValue

      
      <script src="https://unpkg.com/vue@next"></script>
      <div id="app">
         <h2>父组件</h2>
          {{a}}
         <son-com v-model="a"></son-com>
      <!--等价于:
      <son-com :modelValue="a" @update:modelValue="a = $event"/>
      -->
      </div>
       <script>
       const app = Vue.createApp({
         data() {
            return{
              a: 1
            }
         },
         components: {
           SonCom: {
            props:['modelValue'],
            template: `
              <div>
                {{modelValue}}<button @click="$emit('update:modelValue',100) ">改父中的a</button>
              </div>
              `
            }
           }
        })
       app.mount("#app")
      </script>

      这种写法就与2.X中的.sync的写法比较一致了。

      在组件上的v-model绑定别名

      下面将传入子组件中的属性从固定的modelValue改个名字。

      <script src="https://unpkg.com/vue@next"></script>
      <div id="app">
         <h2>父组件</h2>
          {{a}}
         <son-com v-model:msg="a"></son-com>
         <!-- 在子组件内部,传入的属性是msg,在父组件中绑定的值是a -->
       </div>
       <script>
       const app = Vue.createApp({
         data() {
            return{
              a: 1
            }
         },
         components: {
           SonCom: {
            props:['msg'],
            template: `
              <div>
                {{msg}}<button @click="$emit('update:msg',100) ">改父中的a</button>
              </div>
              `
            }
         }
      })
      app.mount("#app")

       

      组件上的多个v-model

      终于可以写多个v-model了

      <script src="https://unpkg.com/vue@next"></script>
      <div id="app">
       <h2>父组件</h2>
        {{a}} - {{b}}
       <son-com v-model:a="a" v-model:b="b"></son-com>
      </div>
      <script>
      const app = Vue.createApp({
       data () {
           return { a: 1, b: 2 }
       },
       components: {
         SonCom: {
          props:['a', 'b'],
          template: `
            <div>
              {{a}}<button @click="$emit('update:a',100) ">改父中的a</button>
              {{b}}<button @click="$emit('update:b',200) ">改父中的b</button>
            </div>
            `
          }
         }
      })
       app.mount("#app")
      </script>

      不用羡慕trim啦,你可以自已添加修饰符。定义格式:

        <子组件 v-model.修饰符1.修饰符2="绑定值" />

      原理

      在子组件内部,通过定义一个名为 modelModifiers的属性来收集修饰符,它的结果的格式是:

      {   修饰符1:true
           修饰符2:true
      }

      然后在抛出事件之前,就根据这个修饰符来定义自已的逻辑了。

      示例

      <script src="https://unpkg.com/vue@next"></script>
      <div id="app">
       <h2>父组件</h2>
        {{a}} - {{b}}
       <son-com v-model.big10="a"></son-com>
       <son-com v-model="b"></son-com>
      </div>
      <script>
      const app = Vue.createApp({
       data() {
          return{
            a: 1,
            b: 1
          }
       }
      })
      app.component('SonCom', {
        props:['modelValue', 'modelModifiers'],
        created () {
          console.log(this.modelModifiers) // {big10: true}
        },
        template: `
          <div>
            {{modelValue}}<button @click="hClick">改父中的a</button>
          </div> `
        ,
        methods: {
          hClick () {
            let val = 100
            // 写具体的逻辑
            console.log(this.modelModifiers)
            if (this.modelModifiers && this.modelModifiers.big10) {
              val += 10
            }
            this.$emit('update:modelValue', val)
          }
        }
        })
       app.mount("#app")
      </script>

       

      当然,如果在v-model改了prop的名字,则名字也随之变化。

      如果是: <son-comv-model:foo="a"/>

      则对应的prop及修饰符的名字就会变成: props:['foo','fooModifiers']

      小结

      3.X中的v-model解决了2.X中的两个问题,并有一个新的创新点

      1. 原2.X中只能有一个v-mode,现在可以有多个
      2. 原2.X中要单独学习v-model和sync,理解成本较高,现在统一起来了。

      创新点是:你可以自已添加修饰符了。

      版权声明:
      作者:Joker 链接:https://456787.xyz/archives/201
      文章版权归作者所有,转载请注明出处。
      THE END
      分享
      二维码
      打赏
      < <上一篇
      下一篇>>
      文章目录
      关闭
      目 录