I recently encountered a problem, that is, how to implement two-way binding prop in Vue.js is better.

Previously I was passing the prop to the child component, and then the child component directly changed the prop directly, this can reflect the result to the parent component, but it is not a good solution.

For example, I often encounter this Warning.

Avoid mutating a prop directly since the value will be overwritten…

In fact, it is better to pass changes from the child component to the parent component using event passing, which requires the child component to $emit an event, and then the parent component listens to this event and then modifies the received value.

The official documentation explains it as follows:

In some cases, we may need to “bi-directionally bind” a prop. Unfortunately, true two-way binding poses maintenance problems, as the child component can change the parent component with no obvious source of change in either the parent or the child.

This is why we recommend the update:myPropName pattern to trigger events instead. As an example, in a hypothetical component containing a title prop, we could express the intent to assign a new value to it in the following way:

1
this.$emit('update:title', newTitle)

So the recommended approach here is to use update:propName to achieve this.

In this case, the parent component is written natively as follows:

1
2
3
4
<text-document
  v-bind:title="doc.title"
  v-on:update:title="doc.title = $event"
></text-document>

Here the name of the prop is called title, the child component needs to receive this value, and then various operations to modify are okay.

For example, the child component can be written as follows:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<template>
  <el-input v-model="titleData"></el-input>
</template>

<script>
export default {
  name: "Child",
  props: {
    title: {
      type: String,
      default: "",
    }
  },
  data() {
    return {
      titleData: this.title
    }
  },
  watch: {
    titleData: {
      handler(val) {
        this.$emit('update:title', val)
      }
    }
  }
}
</script>

So that when the titleData is updated, the title of the parent component is updated.

At this point the parent component can be abbreviated as:

1
<text-document v-bind:title.sync="doc.title"></text-document>

Note that v-bind with .sync modifier cannot be used with expressions (e.g. v-bind:title.sync="doc.title + '!'" is invalid). Instead, you can only provide the property name you want to bind, similar to v-model.

Alternatively, the .sync modifier can be used in conjunction with v-bind when setting multiple prop with a single object:

1
<text-document v-bind.sync="doc"></text-document>

This will pass each property (e.g. title) in the doc object as a separate prop, and then add the v-on listener for each update.

Using v-bind.sync on a literal object such as v-bind.sync="{ title: doc.title }" will not work properly because there are many edge cases to consider when parsing a complex expression like this one.

Above, over.


Reference https://cuiqingcai.com/30006.html