Vue2 implements props bidirectional binding _javascript techniques for components

Source: Internet
Author: User
Tags event listener

Vue Learning notes-3 preface

Vue 2.x compared to Vue 1.x, upgrade changes in addition to the implementation of Virtual-dom, to the user's greatest discomfort is the removal of the components of the props two-way binding function.
In the past, the props twoway and. Sync binding modifiers were used in vue1.x to achieve props bidirectional binding functionality, but this functionality was completely discarded in Vue2, and it was necessary to implement them if bidirectional binding was required.

Vue2 Component Props Communication mode

The props data flow of the component in the Vue2 is changed to only one-way flow, that is, it can only be passed by the component (the calling component side) through the component's DOM attribute props to the component, the component can only passively receive the data that the component is passing over, and within the component, Props data from the outer layer cannot be modified.

The official explanation for this change is:

prop are one-way bound: when the properties of the parent component change, they are passed to the subassembly, but they do not turn. This is to prevent the child component from unintentionally modifying the state of the parent component-which makes the application's data flow difficult to understand.

Although it is beneficial and correct for the overall project to discard the props bidirectional bindings, at some point we do need to modify the props requirements from within the component

Case

Let's say I want to do an iOS-style switch button with only two requirements:

    • Click on the button to achieve on/off status switch
    • Do not click the button, you can also modify the data through the external switch state, such as cascade linkage switch.

The code is roughly like this:

<div id= "App" >
 <!--switch component-->
 <switchbtn:result= "result" ></switchbtn>
 <!-- External control-->
 <input type= "button" value= "change" @click = ' change ' >
</div>
Switch Component code
vue.component ("Switchbtn", {
 Template: "<div @click = ' change ' >{{result? ') Open ': ' Off '}}</div> ',
 props:[' result '],
 methods:{change
 () {
  this.result=!this.result;
 }
 }
});

Invoke Component
new Vue ({
 el: "#app",
 data:{
 result:true//switch state data
 },
 methods:{change
 () {
  this.result=!this.result;
 }}}
);

But the code above in vue2.0 the error when clicking the switch:

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

The props value cannot be modified within the component, and the modified value is not synchronized to the component's outer layer, that is, the calling component party does not know what the current state is inside the component

In Vue2.0, the method of bidirectional binding of component properties is implemented

1. Create a copy of the props property in the data object within the component

Because result is not writable, you need to create a copy myresult variable in data, the initial value is the value of the props property result, At the same time, call this data object Myresultin all parts of the assembly that need to invoke props.

Vue.component ("Switchbtn", {
 Template: "<div @click = ' change ' >{{myresult? ') Open ': ' Off '}}</div> ',
 props: ["result"],
 data:function () {return
 {
  myresult:this.result// New field in Data
 };}
 ,
 ...
};

2. Create a watch for the props property to synchronize changes outside of the component to props

The props of the component (the parent component) has been modified outside the assembly, synchronized to the corresponding props in the component, but not synchronized to the copy you just created in the data object, so you will need to create a watch (listener) for the props attribute result. The data is synchronized when the props is modified to correspond to the copy in Myresult.

Vue.component ("Switchbtn", {
 Template: "<div @click = ' change ' >{{myresult? ') Open ': ' Off '}}</div> ',
 props: [' result '],
 data:function () {return
 {
  myResult:this.result
 };
 } ,
 Watch: {result
 (val) {
  This.myresult = val;//The watch of new result, listening for changes and synchronizing to Myresult
 }
 },
 ......

3. Create a watch for the props replica, notifying the component outside

At this point, the props replica myresultis modified within the component, and the props state in the component is not known outside the component, so it is necessary to create another Myresultfor the props copy, that is, the corresponding data property.
Sends a notification to the outer layer (parent) of the component, notifies the component of the property change, and then changes his data by the outer (parent component) itself

Final full code:

<div id= "App" >
 <switchbtn:result= "result" @on-result-change= "Onresultchange" ></switchbtn>
 <input type= "button" value= "change" @click = ' change ' >
</div>

Vue.component ("Switchbtn", {
 Template: "<div @click = ' change ' >{{myresult? ') Open ': ' Off '}}</div> ',
 props: ["result"],
 data:function () {return
 {
  myresult:this.result// ① Create a copy of props property result--myresult
 };
 watch: {result
 (val) {
  This.myresult = val;// ② listens for changes to the props attribute result, and synchronizes to the data attribute Myresult in the component,
 Myresult (val) {
  //xxcanghai Small Sea Blog Park
  this.$ Emit ("On-result-change", Val), sending an event notification to the outside of a myresult change in the//③ component
 }
 },
 methods: {changes
 () {
  This.myresult =!this.myresult
 }}
);

New Vue ({
 el: "#app",
 data: {
 result:true
 },
 methods: {Change
 () {
  This.result =! This.result
 },
 Onresultchange (val) {
  This.result=val;//④ the outer call to the component side to register the change method, to synchronize the data changes within the component to the data state outside the component
 }
 }
});

At this point, the data in the component and data outside the component of the two-way binding, components and internal data synchronization. Finally, it boils down to the words: The inside of the component itself has changed to tell the outside, the external decision should not change.

4. What kind of props is suitable for two-way binding?

The first thing to declare is that the props of two-way binding is certainly not conducive to data state management between components, especially in complex business, so as little as possible with two-way binding, too complex data processing recommendations to use VUEX (http://vuex.vuejs.org/zh-cn/intro.html)

However, in our normal use of the process does have a props two-way binding requirements, the individual believes that only when the following conditions meet the use of two-way binding props.

    • Internal components need to modify props.
    • Components need to be dynamically controlled externally at run time, rather than simply initialized.
    • Component external needs to read the State within the component for processing

To meet the above conditions, such as the switch switch component in this example, requires external control of the switch state, such as tab multiple tab page components of the Activeindex property, you need to be able to control the External tab page currently open which page, etc.

Automated props bi-directional binding processing

Vue Mixin Components--propsync

Through the example also can be seen in the Vue2.0 to achieve props two-way binding is very troublesome, if there are two props need to do two-way binding the above code to implement two times, the code is extremely redundant.
So I wrote a mixin to automate the need to handle props's two-way binding--propsync.

Main function

    • It realizes the automatic creation of all prop corresponding data properties within the component, and facilitates the modification prop use within the component. It solves the design that the prop is not allowed to modify directly in the vue2.0.
    • The component prop is implemented, the component is modified automatically synchronously to the Data property.
    • Implementation of the component modified the Data property (created by prop), automatic notification of the event outside the component has internal prop modification. Determine if modifications are to be synchronized outside the component outside of the component

How to use Propsync

Writing components

    • For writing components, if props two-way binding is required, direct mixin is introduced and mixin can be declared in the configuration: mixins: [Propsync]
    • This mixin generates the corresponding data property name based on the prop name, by default, by adding "P_" in front of the Prop property name, and the where prop with the field name active, automatically generating the name p_active The data field (props to the data of the name change method can be modified, see Propsync Source configuration at the beginning)
    • Propsync The default will create bidirectional bindings for all props, and you can declare this props through propsync:false without creating a two-way binding.

Cases:

Import Propsync from './mixins/propsync ';//import mixin file
export default {
 Name: "tab",
 mixins: [Propsync], Declares the use of Propsync mixin
 props: {
 active: {
 type: [String, number],//is automatically implemented in two-way binding by Propsync, creating p_ in data Active variable
 },
 width: {
 type: [Number, String],
 propsync:false//will not be propsync to implement bidirectional binding
 }
 },
 methods: {
 setactive (page, index, e) {
 this.p_active = index;//can directly use This.p_active
 }
 }
}

Calling components

When Propsync is introduced, a Onpropschange event is triggered after the internal two-way bound data change. Then at the call component, add an event listener Onpropschange (modifiable), when the component modified props Propsync will trigger this event, return to participate in order to: Modify the prop name, modify the value, modify the previous value. The current component caller (parent component) can decide whether to synchronize changes within the component to the caller
Cases:

<tab:active= "active" @onPropsChange = "Change" ></tab> ...
 
Slightly
{
 data:{
 active:0
 },
 methods:{
 change:function (propname,newval,oldval) {
 this[ Propname]=newval;
 Console.log (The +propname+ property of the Component tab changes to +newval);}}

SOURCE download

The Vue mixin component Propsync has been hosted to GitHub:
Https://github.com/xxcanghai/cnblogsFiles/blob/master/vue-mixins/propsync.js

Related notes

Vue Learning Notes-1 (http://www.jb51.net/article/98869.htm)

Vue Study Note -2 (http://www.jb51.net/article/98878.htm)

Vue Learning notes-3 How to implement component props bidirectional binding in Vue2 (http://www.jb51.net/article/98881.htm)

The above is the entire content of this article, I hope to help you learn, but also hope that we support the cloud habitat community.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.