• vue中vmodel与.sync语法糖


    sync语法糖

    父组件

    <template>
      <div id="app">
        <Child :name.sync='name' /> -->
        <Child :name='obj.name' @update:name='obj.name=$event' :age='obj.age' @update:age='obj.age=$event' />
        <Child v-bind.sync='obj' />
      </div>
    </template>
    <script>
    import Child from '@/components/Child'
    export default {
      data() {
        return { obj: { name: '小明', age: 28 } }
      },
      components: { Child }
    }
    </script>

    子组件

    <template>
      <div>
        <h1>姓名:{{name}}</h1>
        <h1>年龄:{{age}}</h1>
        <button @click="handleChangeName">改变姓名</button>
        <button @click="handleChangeAge">改变年龄</button>
      </div>
    </template>
    <script>
    export default {
      props: ['name', 'age'],
      methods: {
        handleChangeName() {
          this.$emit('update:name', '小红')
        },
        handleChangeAge() {
          this.$emit('update:age', 100)
        }
      }
    }
    </script>

    为什么age属性经过sync修饰后,修改age时触发的事件名为 update:age ?

    因为 :age.sync='age' 就是 :age='age' @update:age='age=$event' 的语法糖~

    v-model语法糖

    基础用法

    • v-model 本质上不过是语法糖,可以用 v-model 指令在表单 <input><textarea> 及 <select> 元素上创建双向数据绑定。它会根据控件类型自动选取正确的方法来更新元素。它负责监听用户的输入事件以更新数据,并对一些极端场景进行一些特殊处理。v-model 会忽略所有表单元素的 valuecheckedselected 特性的初始值而总是将 Vue 实例的数据作为数据来源。你应该通过 JavaScript 在组件的 data 选项中声明初始值。

    • v-model 在内部为不同的输入元素使用不同的属性并抛出不同的事件:

      • text 和 textarea 元素使用 value 属性和 input 事件;
      • checkbox 和 radio 使用 checked 属性和 change 事件;
      • select 字段将 value 作为 prop 并将 change 作为事件。

    实现原理

    • v-model只不过是一个语法糖而已,真正的实现靠的还是

      • v-bind:绑定响应式数据

      • 触发oninput 事件并传递数据

    • 举例如下:

    • <input v-model="sth" />
      //  等同于
      <input :value="sth" @input="sth = $event.target.value" /> //自html5开始,input每次输入都会触发oninput事件,所以输入时input的内容会绑定到sth中,于是sth的值就被改变;
      //$event 指代当前触发的事件对象;
      //$event.target 指代当前触发的事件对象的dom;
      //$event.target.value 就是当前dom的value值;
      //在@input方法中,value => sth;
      //在:value中,sth => value;
    • v-model是双向绑定,即表单可以拿到vue中的数据,表单中的数据也可以传到vue中
      而v-bind:value 只能是表单拿到vue的数据,vue无法拿到表单的数据
      个人理解,有瑕疵以后补充
      • v-bind

        • 缩写::
        • 预期:any (with argument) | Object (without argument)
        • 参数:attrOrProp (optional)
        • 修饰符:
          • .prop - 被用于绑定 DOM 属性。
          • .camel - (2.1.0+) 将 kebab-case 特性名转换为 camelCase.
          • .sync (2.3.0+) 语法糖,会扩展成一个更新父组件绑定值的 v-on 侦听器。
        • 用法:
          动态地绑定一个或多个特性,或一个组件 prop 到表达式。
          在绑定 class 或 style 特性时,支持其它类型的值,如数组或对象。可以通过下面的教程链接查看详情。
          在绑定 prop 时,prop 必须在子组件中声明。可以用修饰符指定不同的绑定类型。
          没有参数时,可以绑定到一个包含键值对的对象。注意此时 class 和 style 绑定不支持数组和对象。

        v-on

        • 缩写:@
        • 预期:Function | Inline Statement | Object
        • 参数:event
        • 修饰符:
          • .stop - 调用 event.stopPropagation()。
          • .prevent - 调用 event.preventDefault()。
          • .capture - 添加事件侦听器时使用 capture 模式。
          • .self - 只当事件是从侦听器绑定的元素本身触发时才触发回调。
          • .{keyCode | keyAlias} - 只当事件是从特定键触发时才触发回调。
          • .native - 监听组件根元素的原生事件。
          • .once - 只触发一次回调。
          • .left - (2.2.0) 只当点击鼠标左键时触发。
          • .right - (2.2.0) 只当点击鼠标右键时触发。
          • .middle - (2.2.0) 只当点击鼠标中键时触发。
          • .passive - (2.3.0) 以 { passive: true } 模式添加侦听器
        • 用法:
          绑定事件监听器。事件类型由参数指定。表达式可以是一个方法的名字或一个内联语句,如果没有修饰符也可以省略。
          从 2.4.0 开始,v-on 同样支持不带参数绑定一个事件/监听器键值对的对象。注意当使用对象语法时,是不支持任何修饰器的。
          用在普通元素上时,只能监听 原生 DOM 事件。用在自定义元素组件上时,也可以监听子组件触发的自定义事件。
          在监听原生 DOM 事件时,方法以事件为唯一的参数。如果使用内联语句,语句可以访问一个 $event 属性:v-on:click="handle('ok', $event)"
      • 定自组件的v-mdel
      • 首先你要知道 ,在HTML5新特性中,input 元素本身就有个 oninput 事件,类似 onchange ,每当输入框内容发生变化,就会触发 oninput ,把输入框最新的value值传递给 sth(第二句代码)。

        关于$event,懂的朋友请忽略,$event知识点传送门

        我们仔细观察语法糖和后两句完整版本代码,可以得出一个结论:

        在给 <input /> 元素添加 v-model 属性时,默认会把 value 作为v-model的属性,默认把 'input' 事件作为实时传递 value 的触发事件,这就是官方文档这句话的意思:

        • 二、v-model用在组件上

          明白了v-model只是语法糖,它的默认值是value,默认监听事件是oninput,我们来看一个稍复杂的例子,它是将v-model使用在组件上。

          类似于下图的效果,父组件的 price 的初始值是 100,更改子组件的值能实时更新父组件的 price

        • <div id="demo">
            <currency-input v-model="price"></currentcy-input>
            // 实际上是下列代码
            //<currency-input v-bind:value="price" v-on:input=" price = arguments[0] "></currency-input>
           <span>{{price}}</span>
          </div>
          
          <script>
          Vue.component('currency-input', {
            template: `
              <span>
                <input
                  :value="value"
                  <!--这里之所以把 'input' 作为事件名向父级传递,正是因为非语法糖形式中v-on:input监听的是input事件-->
                  @input="$emit('input', $event.target.value)"
                >
              </span>
            `,
            props: ['value'],// 这里的value正是被简写掉的,所以语法糖形式你找不到这个value在哪里绑定的,而在非语法糖形式找得到
          })
          
          var demo = new Vue({
            el: '#demo',
            data: {
              price: 100,
            }
          })
          </script>

          三、v-model的不足与解决方案

          它的不足在官方文档也提出来了:

           

           我们来看看具体是什么意思。

          在创建类似复选框或者单选框的常见组件时,v-model就不好用了

          <input type="checkbox" v-model="sth" />

          v-model 给我们默认提供了 value 属性和 oninput 事件,但是在这里我们需要的不是 value 属性,而是 checked 属性,并且当你点击这个单选框的时候不会触发 oninput 事件,它只会触发 onchange 事件。这就是问题所在。

          这是 v-model 只用在 input 上的情况,解决方案如下:

          <input type="checkbox" :checked="status" @change="status = $event.target.checked" />

          当v-model用在组件上时,解决方案如下:

          <my-checkbox v-model="foo"></my-checkbox>
          
          Vue.component('my-checkbox', {
            tempalte: `<input 
                         type="checkbox"
                         @change="$emit('input', $event.target.checked)"
                         :checked="value"
                       />`
            props: ['value'],
          })

          不明白的同学可以自己将语法糖形式写成完整的非语法糖形式,再结合前面的讲解进行分析

          四、在 Vue 2.2 版本,你可以在定义组件时通过 model 选项的方式来定制 prop/event:

          //在这个组件中使用 v-model
          <base-checkbox v-model="lovingVue"></base-checkbox>
          
          Vue.component('base-checkbox', {
            model: {
              prop: 'checked',
              event: 'change'
            },
            props: {
              checked: Boolean
            },
            template: `
              <input
                type="checkbox"
                v-bind:checked="checked"
                v-on:change="$emit('change', $event.target.checked)"
              >
            `
          })

          lovingVue 的值就会传递给 checked prop。当 <base-checkbox> 内部触发一个 change 事件,并且传递一个新值,lovingVue 属性就会进行更新。

          注意,仍然需要在组件 props 选项中声明 checked prop 属性。

  • 相关阅读:
    2016年3月3日
    性能测试之我解
    Vim命令合集
    vi-vim常用命令
    架构的本质是
    网站三层架构学习之一 分层式结构
    Spring 4 + Quartz 2.2.1 Scheduler Integration Example
    “城市民族工作条例”详解--建议废止
    字符串匹配处理
    LogBack简易教程
  • 原文地址:https://www.cnblogs.com/caihongmin/p/16593855.html
Copyright © 2020-2023  润新知