细说一下Vue3的v-model,你get了么?

693 阅读2分钟

生活总是要充满期待啊,为什么上来就说这句呢?因为真的是见了身边人对生活失去的兴趣,没有了感兴趣的点可能就对什么都毫无兴趣了吧。生活还是值得期待的,毕竟自己的能力水平提高了优秀了、或者生活有规划了其实这都是一个目标,再或者找不到那就去减肥啊,给自己一个目标,再再或者去追星啊 、疯狂的追星。人嘛总要经历才会成长、人嘛开心最重要了,一切的一切都以人为本。说说今天要讲的吧,有人总觉得不清晰,所以拿出来单讲,总给开小灶好么?给钱么?这个人就是我自己哈哈哈哈哈,但是该弄清楚还是应该弄清楚的

  1. v-model双向数据绑定 input中的

    <template>
      <div>
          <input type="text" v-model="search">
          <span>{{search}}</span>
      </div>
    </template>
    <script >
    export default {
        name: '',
        data(){
            return{
                search:'',
            }
        }
      };
    </script>
    

    有人可能就说啦,就这?不用讲也会啊!别着急啊好饭不怕晚。 都放嘴的鸭子了 ,它还能飞了咋着

  2. 组件中的v-model 不管什么样的v-model都是语法糖啊

    • 初始为完成一个搜索的组件,不就是父组件传了值,子组件去改变父组件的值

      // 父组件  
      <template>
        <div>
            <search @test="getData"></search>
            <button @click="submit">提交</button>
        </div>
      </template>
      <script>
      import search from './components/search.vue'
      export default {
        name: 'App',
        components: {
          search
        }
        data(){
            return {
                keywords:''
            }
        }
        methods:{
            getData(val){
                this.keywords = val
            }
        }
      }
      </script>
      
      // 子组件
      <template>
          <div>
              <input @input="inputChange" type="text" name="keywords">
          </div>
      </template>
      <script>
      export default {
          props: ['keywords'],
          methods: {
              inputChange(e) {
                  this.$emit('test', e.target.value)
              }
          }
      }
      </script>
      
    • 文档中好像v-model可以用给组件啊 什么脑子啊 这就叫优化

      <custom-comp v-model="msg"></custom-comp>
      <!-- 等价于 -->
      <custom-comp :value="msg" @input="msg = $event"></custom-comp>
      
      // 父组件
      <template>
          <div>
              <search v-model="keywords"></search>
              <button @click="submit">提交</button>
          </div>
      </template>
      <script>
      import search from '@/components/index/search.vue'
      export default {
          data() {
              return {
                  keywords: ''
              }
          },
          components: {
              search
          }
      }
      </script>
      
      // 子组件
      <template>
          <div>
              <input :value="value" @input = "$emit('input',$event.target.value)" type = "text" name= "keywords">
          </div>
      </template>
      <script>
      export default {
          props:['value']
      }
      </script>
      
  3. Vue3的v-model和Vue2 的v-model 有什么不一样呢?

    • 写法上: vue3当在自定义组件中使用v-model时,组件接收一个属性modelValue的值,然后通过触发update:modelValue事件来更新该值

      <custom-comp v-model="msg"></custom-comp>
      <!-- 等价于 -->
      <custom-comp :model-value="msg" @update:model-value="msg = $event"></custom-comp>
      <!-- 建议命名按照kebab-cased规范,如:model-value,而不是modelValue -->
      

      根据上边的 逻辑我们自定义一个input 组件让它正常的工作,要满足这个需求 那么

      第一 : input 的value值需要props中名为modelValue的相绑定

      第二: input事件触发将emit update:modelValue

      // 自定义input 组件
      <script>
      app.component('custom-comp',{
        props:['modelValue'],
        template:`<input :value="modelValue"  @input="$emit('update:modeValue',$event.target.value)"`
      })
      </script>
      // 官方还写了一种方法
      <script>
      app.component('custom-input', {
        props: ['modelValue'],
        computed: {
          value: {
            get() {
              return this.modelValue;
            },
            set(v) {
              this.$emit('update:modelValue', v);
            },
          },
        },
        template: ` <input v-model="value">`,
      });
      </script>
      
    • 不用input怎么搞? 其实一样的就没有input的原生方法了

      <custom-input v-model="searchText"></custom-input>
      
      <script>
      app.component('custom-count',{
        props:{
          modelValue:Number
        },
        methods:{
          increment() {
            this.$emit('update:modelValue', ++this.modelValue);
          },
          decrement() {
            this.$emit('update:modelValue', --this.modelValue);
          }
        },
        template:` <button @click="increment">+1</button> ~ 
                <button @click="decrement">-1</button>
                <p>{{modelValue}}</p>`
      })
      
      </script>
      
    • Vue3 不同于v-model 参数

      在上边的例子中我们发现v-model是接收属性 modelValue的值 ,然后触发事件update:modelValue来更新该值的,那么我们就想了这个modelValue 是固定必须这么写么?还是只要方法和值相同就可以 ?其实是可以进行修改的

      <custom-input v-model:mv="msg"></custom-input>;
      
      app.component('custom-input', {
        props: ['mv'],
        template: `
          <input
            :value="mv"
            @input="$emit('update:mv', $event.target.value)"
          >
        `,
      });
      
    • Vue3支持多个v-model绑定

      Vue2 中我们发现 子组件中修改model ,这样也不支持多个v-model,看下代码

      <script>
      Vue.component('custom-count', {
        model: {
          prop: 'v', // default: value
          event: 'i', // default: input
        },
        props: {
          v: Number,
        },
        data() {
          return {
            count: this.v,
          };
        },
        template: `<button @click="$emit('i', ++count)">+1</button>`,
      });
        </script>
      

      Vue3 由于 新增了v-model的参数传递,所以自定义组件可以同时支持多个v-model 的绑定: 并且在父组件的绑定处一目了然,知道绑定了几个v-model 和绑定了什么

      <user-name v-model:first-name="firstName" v-model:last-name="lastName"></user-name>
      
      <script>
      	app.component('user-name', {
        props: {
          firstName: String,
          lastName: String,
        },
        template: `
          <input 
            type="text"
            :value="firstName"
            @input="$emit('update:firstName', $event.target.value)">
          <input
            type="text"
            :value="lastName"
            @input="$emit('update:lastName', $event.target.value)">
        `,
      });
      </script>
      
  4. vue3 的v-model的修饰符

    我们知道v-model有.trim .lazy .number 等修饰符,这些都是默认也就是内置好的修饰符,那我们肯定需要自定义啊,不可能三个修饰符能满足我们所有吧

    • 那我们就来试试自己创建吧,自定义修饰符capitalize ,它的功能就是将v-model绑定提供的字符串的第一个字母大写添加到组件v-model的修饰符将通过modelModifiers prop 提供给组件

         <my-component v-model.capitalize ="bar"></my-component>
      
      <script>
         app.component('my-component',{
           props:{
             modelValue:String,
             modelModifiers:{
               default:()=>({})
             }
           },
           template:`
                 <input type="text" :value="modelValue" @input="$emit('update:modelValue',$event.target.value)">
         `,
           created(){
             console.log(this.modelModifiers) // {capitalize}
           }
         })
      </script>
      
    • 现在我们已经设置了prop的值的,我们可以检查modelModifiers对象键并编写一个处理器来更改发出的值。之后每当input 元素触发input事件时,我们都将字符串开头大写

         // 父组件
         <div id="app">
           <my-component v-model.capitalize="myText"></my-component>
           {{ myText }}
         </div>
         <script>
         const app = Vue.createApp({
           data() {
             return {
               myText: ''
             }
           }
         })
         </script>
      
       // 子组件
       <div>
               <input type="text" :value="modelValue"  @input="emitValue">
       </div>
       <script>
         export default {
                props: {
               modelValue: String,
               modelModifiers: {
                 default: () => ({})
               }
            },
            methods: {
               emitValue(e) {
                 let value = e.target.value
                 if (this.modelModifiers.capitalize) {
                   value = value.charAt(0).toUpperCase() + value.slice(1)
                 }
                 this.$emit('update:modelValue', value)
               }
            },
       };
       </script>
      
    • 那我们带参数的怎么办呢 ?不能都用modelModifiers 吧?那咱们得多个v-model 岂不是受限制了,人家早想到了对于带参数的 v-model 绑定,生成的 prop 名称将为 arg + "Modifiers": 比如下边

        <my-component v-model.capitalize ="bar"></my-component>
      
        <script>
        app.component('my-component', {
          props: ['foo', 'fooModifiers'],
          template: `
            <input type="text" 
              :value="foo"
              @input="$emit('update:foo', $event.target.value)">
          `,
          created() {
            console.log(this.fooModifiers) // { capitalize: true }
          }
        })
        </script>