Why use bidirectional binding to encapsulate components?

Two-way binding hides the operation of data changes within components, without direct awareness from callers, and the business layer does not care about the internal implementation logic, simplifying a lot of code that is not relevant to business.

Component bidirectional binding should have the following two characteristics:

  1. The parent component only transmits prop and does not define event reception.
  2. Updated values passed down by child components.

This article explains how to implement three bidirectional binding using v-Model

What is a V-Model?

  1. V-models can be applied to both normal form elements and components.
  2. Vuejs implicitly adds a prop of value, and child components receive values through props. Value.
  3. The child component changes the value of the parent component’s V-model binding via this.$emit(‘input’).
  4. V-models can be bidirectional binding without defining receive events.

Why is v-Model bi-directional binding possible?

The V-Model is actually a syntactic sugar. Here is the template after vUE transformation:

<input v-model="message" />JavaScript // After conversion:<input
  v-bind:value="message"
  v-on:input="message=$event.target.value">
Copy the code
  1. Add v – bind: value.
  2. Add a custom event for V-ON :input.

The value bound to the input dynamically points to the messgae variable and dynamically sets message to the target value when the input event is triggered, effectively completing data binding in both directions. Bidirectional binding is a combination of normal one-way binding and events.

Basic model: Parent component – current component (forward parameters, higher order components) – Child component Parent component without too much explanation, using V-model parameters

<template>
  <div>
    <! -- $attrs & observer -->
    <BaseInputAttrs v-model="pModel"/> <br>

    <! -- watch & data & emit('input') -->
    <BaseInputWatch v-model="pModel"/> <br>

    <! -- computed & emit('input') -->
    <BaseInputComputed v-model="pModel"/> 
   </div>
</template>

<script>
export default {
  data () {
    return {
      pModel: 'V-Model bidirectional binding',}}}</script>
Copy the code

Here are three v-Model implementations of < current component >

Plan 1:

<template>
  <input type="text" v-bind="$attrs" v-on="$listeners">
</template>
Copy the code

$attr: A prop passed by the parent to a child component that the current component does not receive.

$Listeners: Custom events thrown by child components that are passed to the parent component but not received by the current component.

The input will become an event object (object InputEvent).

Because V-ON =”input” is a built-in event, Vue determines that the current component’s tag is a form element of the ‘input’ class and associates value with it.

This.$emit(‘input’, el), which is the [object InputEvent] form object. This.$emit(‘input’, el) ¶

Solution: Intercept the built-in input event, change the reference, and pass the final value to the parent component, as follows.

<template>
    <input type="text" v-bind="$attrs" @input="observerInput">
</template>

<script>
  export default {
    methods: {      
      // Intercepts built-in events
      observerInput (el) {
        this.$emit('input', el.target.value)
      },
    },  
  }
</script>
Copy the code

Scenario 2: Watch listens and transitions properties

Listen for parent and child components, respectively, and store values through the transition property Model

<template>
  <input type="text" v-model="model">
</template>

<script>
  export default {
    props: {
      value: {
        type: String.default: ' ',
      },
    },

    data () {
      return {
        model: ' ',}},watch: {
      value: {
        immediate: true,
        handler (newVal) {
          this.model = newVal
        },
      },

      model (newVal) {
        this.$emit('input', newVal)
      },
    },
  }
</script>
Copy the code

Scheme 3: Calculate the setter getter for the property

Specify the scheme setter for Rain Creek to intercept the modification

<template>
    <input type="text" v-model="model">
</template>

<script>
  export default {
    props: {
      value: {
        type: String,
        default: ' ',
      },
    },

    computed: {
      model: {
        get () {
          return this.value
        },
        set (newVal) {
          this.$emit('input', newVal)
        },
      },
    },
  }
</script>
Copy the code

Summary: All three scenarios modify the final value via this.$emit(‘input’), which is the key to encapsulating components: the unified data source.