vue Custom Component Realizes Bidirectional Binding

  • 2021-10-24 18:48:22
  • OfStack

Scenario:

We compare the commonly used interaction methods between parent and child components:
The parent component flows data into the child component through props;
The child component sends the updated array to the parent component through $emit;

Today, we interact in another way, referring to v-model in the input box, to implement bidirectional data binding of custom components.
That is, when the value of the parent component changes, the value of the child component changes accordingly; On the contrary, the value of the child component changes, and the value of the parent component changes accordingly

Subcomponent definitions:

Since the attribute value of props cannot be modified directly, we define valueData here, receive value value in real time through monitoring, and modify valueData through click method.
Note here that the model syntax sugar prop is the received props attribute value, keeping 1 to. event is the event name passed on first.

The code is as follows:


<template>
  <div>
    <div>{{ ` Subcomponent value : ${value}` }}</div>
    <div @click="click"> Click here to modify the value </div>
  </div>
</template>

<script>
export default {
  name: "",
  model: {
    prop: "value",
    event: "change"
  },
  props: {
    value: Number
  },
  components: {},
  data() {
    return {
      valueData: ""
    };
  },
  watch: {
    value(newValue, oldValue) {
      this.valueData = newValue;
      console.log(` Subcomponent values: ${newValue}`);
    }
  },
  created() {
  },
  mounted() {
  },
  methods: {
    click() {
      this.valueData++;
      this.$emit("change", this.valueData);
    }
  }
};
</script>
<style lang='less' scoped>
</style>

Parent component definition:

The parent component binds the text value through v-model. The name is value if it is not 1, and it can be any other string that conforms to the naming convention, in this case text.
The v-mode binding value changes after the subcomponent updates the data through the change event.
Or when the parent component modifies the text value, the child component value value changes accordingly.

The code is as follows:


<template>
  <div>
    <div>{{ ` Parent component value: ${text}` }}</div>
    <div @click="click"> Click here to modify the value </div>


    <span>-----------------------------------------------------------</span>

    <test-children v-model="text"></test-children>

  </div>
</template>

<script>
import TestChildren from "@/views/TestChildren";

export default {
  name: "",
  components: { TestChildren },
  data() {
    return {
      text: 1
    };
  },
  created() {
  },
  mounted() {
  },
  watch: {
    text(newValue, oldValue) {
      console.log(` Parent component value: ${newValue}`);
    }
  },
  methods: {
    click() {
      this.text--;

    }
  }
};
</script>
<style lang='less' scoped>
</style>

Results:

Direct copy code to your own project test. Whether the value is changed through the parent component or the child component. The values of the two components through the v-mode binding always remain 1.

Answer questions:

Some students asked, isn't this the same as flowing data down through props and passing data up through $emit? It can also achieve the effect of my bidirectional binding. In fact, if we don't pass v-model, we will inevitably write this code in the parent component:


<test-children @change="changeText"></test-children>

Then modify the text value by defining the changeText method.

Imagine, when our page is more complex and the amount of referenced components is relatively large, we need to define more than 10 or 210 methods in the page. Readable lines are greatly reduced and maintenance costs are increased.

Extension:

After vue2.3, sync mode is provided, and bidirectional binding can also be realized

Writing in parent component:


<test-children :value.sync="text"></test-children>

The following model definition is not needed in the subcomponent, but can be deleted directly.


model: {
prop:  " value " ,
event:  " change " 
},

Passing data to the parent component uses the following methods:


this.$emit("update:value", this.valueData);

Related articles: