In some cases, we may need to "double bind" a prop. In fact, this is what the. Sync modifier in Vue 1. X provides. When a child component changes the value of a prop, the change will also be synchronized to the value bound in the parent component. This is convenient, but it can also cause problems, because it breaks the assumption of "one-way data flow".

Because there is no difference between the code of the sub component changing the prop and the normal state changing code, when you look at the code of the sub component, you have no idea when it quietly changes the state of the parent component. This will bring high maintenance cost in the application of debug complex structure.

That's why we removed. Sync in 2.0. However, in the practical application after 2.0 release, we found that. Sync still has its applicability, such as in the development of reusable component library. All we need to do is make it easier to distinguish the code that the child component changes the state of the parent component.

The above excerpt is from Vue tutorial document. For example, I want to implement a simple modal, the code is as follows:

    <div id="app">
        <input type="button" value="click" @click="visible = !visible" />
        <p>{{visible}}</p>
        <child v-bind:show="visible"></child>
    </div>
    <script>
        Vue.component('child', {
            props: ['show'],
            template: '<div v-show="show"><input type="button"  value="hide" @click="show=false"/></div>'
        });
        var vm = new Vue({
            el: '#app',
            data: {
                visible: false
            }
        });
    </script>

The above code cannot modify the value of the outer parent component "visible" and issue a warning:

    [Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "show"

For the official modal example, the code is as follows:

    <div id="app">
        <input type="button" value="click" @click="visible = !visible" />
        <p>{{visible}}</p>
        <child v-bind:show="visible" @close="visible = false"></child>
    </div>
    <script>
        Vue.component('child', {
            props: ['show'],
            template: '<div v-show="show"><input type="button" value="hide" @click="$emit(\'close\')"/></div>'
        });
        var vm = new Vue({
            el: '#app',
            data: {
                visible: false
            }
        });
    </script>

Of course, we need to pass values more often. The code is as follows:

    <div id="app">
        <input type="button" value="click" @click="visible = !visible" />
        <p>{{visible}}</p>
        <child v-bind:show="visible" @show-change="val => visible = val"></child>
    </div>
    <script>
        Vue.component('child', {
            props: ['show'],
            template: '<div v-show="show"><input type="button" value="hide" @click="$emit(\'show-change\', !show)"/></div>',
        });
        var vm = new Vue({
            el: '#app',
            data: {
                visible: false
            }
        });
    </script>

However, when we understand the principle of v-model, we can simplify the outer layer call. The code is as follows:

    <div id="app">
        <input type="button" value="click" @click="visible = !visible" />
        <p>{{visible}}</p>
        <child v-model="visible"></child>
    </div>
    <script>
        Vue.component('child', {
            props: ['value'],
            template: '<div v-show="value"><input type="button" value="hide" @click="$emit(\'input\', !value)"/></div>',
        });
        var vm = new Vue({
            el: '#app',
            data: {
                visible: false
            }
        });
    </script>

Sometimes, because of the "input" event conflict, you can use the * model * attribute to save an "input" event for the child component. The code is as follows:

    <div id="app">
        <input type="button" value="click" @click="visible = !visible" />
        <p>{{visible}}</p>
        <child v-model="visible"></child>
    </div>
    <script>
        Vue.component('child', {
            props: ['show'],
            model: {
                prop: 'show',
                event: 'show-change'
            },
            template: '<div v-show="show"><input type="button" value="hide" @click="$emit(\'show-change\', !show)"/></div>',
        });
        var vm = new Vue({
            el: '#app',
            data: {
                visible: false
            }
        });
    </script>

In the above example, most of the problems have been solved, but they can only deal with the two-way binding of a single value. When multiple values need two-way binding, of course, some skills are needed. Vue 2.3.0 + re introduces the. Sync modifier, but this time it just exists as a compile time syntax sugar. It is extended to a v-on listener that automatically updates the properties of the parent component.

For example code

    <child v-bind:show.sync="visible"></child>

Will be extended to:

    <child v-bind:show.sync="visible" @update:show="val => visible = val"></child>

Then the original code example changes to:

    <div id="app">
        <input type="button" value="click" @click="visible = !visible" />
        <p>{{visible}}</p>
        <child v-bind:show.sync="visible"></child>
    </div>
    <script>
        Vue.component('child', {
            props: ['show'],
            template: '<div v-show="show"><input type="button" value="hide" @click="$emit(\'update:show\', !show)"/></div>',
        });
        var vm = new Vue({
            el: '#app',
            data: {
                visible: false
            }
        });
    </script>

When there are multiple values, such as code:

    <div id="app">
        <input type="button" value="click" @click="visible = !visible" />
        <p>{{visible}}</p>
        <child v-bind:show.sync="visible" v-bind:value.sync="text"></child>
    </div>
    <script>
        Vue.component('child', {
            props: ['show','value'],
            template: '<div v-show="show"><input type="button" :value="value" @click="$emit(\'update:show\', !show)"/><input type="button" value="changeText" @click="$emit(\'update:value\', value + \'^_^\')"/></div>',
        });
        var vm = new Vue({
            el: '#app',
            data: {
                text: 'hide',
                visible: false
            }
        });
    </script>

All Comments

Leave a Reply Cancel Reply

Tips: Your email address will not be disclosed!

If you can't see clearly,please click to change...

Popular Posts

Collections