加载中...
  • v-model 双向数据绑定实现原理 loading

    准备工作


    我们来手动实现一个 v-model 的功能。

    首先定义了一个component组件,里面有一个template。

    1
    2
    3
    4
    5
    6
    7
    8
      const CompOne = {
    props: ['value'],
    template: `
    <div>
    <input type="text"></input>
    </div>
    `,
    }

    然后再定义一个vue对象,里面引用了该组件。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    new Vue({
    components: {
    CompOne,
    },
    template: `
    <div>
    <comp-one></comp-one>
    </div>
    `,
    }).$mount(root)

    好了,准备工作完成。

    实现


    1.gif

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    const CompOne = {
    props: ['value'], // 接收父组件传递的数据
    template: `
    <div>
    <input type="text" @input="handleInput" :value="value"></input>
    // 添加一个input事件
    // 接收父组件传递的value
    </div>
    `,
    methods: {
    handleInput (e) {
    this.$emit('input', e.target.value) // 通过$emit,当 value 变化时通知父组件
    }
    }
    }

    2.gif

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    new Vue({
    components: {
    CompOne,
    },
    data () {
    return {
    value: 'vue'
    }
    },
    template: `
    <div>
    // value 为传递给子组件的数据
    // @input 接收子组件通过 $emit 传递的参数
    <comp-one :value="value" @input="value = arguments[0]"></comp-one>
    </div>
    `,
    }).$mount(root)

    效果


    3.gif

    大功告成,我们实现了 v-model 的功能!

    拓展


    默认情况下,一个组件上的 v-model 会把 value 用作 prop 且把 input 用作 event。

    但是像单选框、复选框等类型的输入控件可能会将 value attribute 用于不同的目的。model 选项可以用
    来避免这样的冲突。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    new Vue({
    components: {
    CompOne,
    },
    data () {
    return {
    value: 'vue'
    }
    },
    template: `
    <div>
    <comp-one v-model="value"></comp-one> // 使用v-model 满足语法糖规则:属性必须为value,方法名必须为:input
    </div>
    `,
    }).$mount(root)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    // 修改子组件 
    const CompOne = {
    props: ['value1'],
    model: {
    prop: "value1", // 接收的数据 value => value1
    event: "change" // $emit 需要绑定的事件 input => change
    },
    template: `
    <div>
    <input type="text" @input="handleInput" :value="value1"></input>
    </div>
    `,
    methods: {
    handleInput (e) {
    this.$emit('change', e.target.value)
    }
    }
    }

    这样就可以让 v-model 变得更灵活,属性和方法名可以自定义。

    总结


    v-model 时一个语法糖,它做了:

    1. 绑定数据value

    2. 触发输入事件input

    3. data 更新触发重新渲染

    上一篇:
    深入了解 javascript 中的 new 操作符
    下一篇:
    现代JS学习笔记
    本文目录
    本文目录