Vue most complete summary of the components of communication

1, a component relationship diagram recognize nouns

  • Parent-child relationship: A and B, A and C, B and D, C and E
  • Fraternal relations: B and C
  • Inter-generational relations: A and D, A and E
  • Non-immediate family: D and E

Summed up in three categories:

  • Sons communication between components
  • Communication between components brothers
  • Mataga级 communication

 

2,8 kinds of communication and the use of summary

  • props / $emit

  • $children / $parent

  • provideinject

  • ref / refs

  • eventBus

  • Vuex

  • localStorage / sessionStorage

  • $attrsversus $listeners

 

Common usage scenarios can be divided into three categories:

  • Sons communication components:  props$parent /  $childrenprovide /  inject ;  ref ;  $attrs / $listeners

  • Brothers communication components:  eventBus ; vuex

  • Cross-level communication:  eventBus; Vuex; provide /  inject , $attrs / $listeners

 

Detailed 3,8 kinds of communication

  • props / $emit

    • 1. The value passed to the parent component subassembly

      The following example shows by a parent component data transfer assembly as He Xiangzai: subassembly article.vuehow to get the parent component section.vuedataarticles:['红楼梦', '西游记','三国演义']
      // section父组件
      <template>
        <div class="section">
          <com-article :articles="articleList"></com-article>
        </div>
      </template>
      
      <script>
      import comArticle from './test/article.vue'
      export default {
        name: 'HelloWorld',
        components: { comArticle },
        data() {
          return {
            articleList: ['红楼梦', '西游记', '三国演义'] } } } </script>
      // 子组件 article.vue
      <template>
        <div>
          <span v-for="(item, index) in articles" :key="index">{{item}}</span>
        </div>
      </template>
      
      <script>
      export default {
        props: ['articles']
      }
      </script>

      Summary: prop only be transferred from one component to the next component (component Sons), i.e. a so-called one-way data flow. And prop read-only, can not be modified, all changes will fail and a warning.

    • 2. parent component subassembly to pass values

      For $emit  my own understanding is this:  $emit bind a custom event, when this statement is executed, it will arg parameter passed to the parent components, the parent listens and receive parameters via v-on. By an example to show how to pass data to the subassembly parent component. On the basis of the previous example, click on the page rendered in ariticle the item display index in the array of parent components
      // 父组件中
      <template>
        <div class="section">
          <com-article :articles="articleList" @onEmitIndex="onEmitIndex"></com-article>
          <p>{{currentIndex}}</p>
        </div>
      </template>
      
      <script>
      import comArticle from './test/article.vue'
      export default {
        name: 'HelloWorld',
        components: { comArticle },
        data() {
          return {
            currentIndex: -1, articleList: ['红楼梦', '西游记', '三国演义'] } }, methods: { onEmitIndex(idx) { this.currentIndex = idx } } } </script>
      <template>
        <div>
          <div v-for="(item, index) in articles" :key="index" @click="emitIndex(index)">{{item}}</div>
        </div>
      </template>
      
      <script>
      export default {
        props: ['articles'],
        methods: {
          emitIndex(index) {
            this.$emit('onEmitIndex', index)
          }
        }
      }
      </script>
  • $children / $parent

    • Through $parentand $childrenyou can access the instance of the component, get examples represent? All methods representatives can access this component and data. Then there is the example of how to achieve to get the specified component.
      // 父组件中
      <template>
        <div class="hello_world">
          <div>{{msg}}</div>
          <com-a></com-a>
          <button @click="changeA">点击改变子组件值</button>
        </div>
      </template>
      
      <script>
      import ComA from './test/comA.vue'
      export default {
        name: 'HelloWorld',
        components: { ComA },
        data() {
          return {
            msg: 'Welcome' } }, methods: { changeA() { // 获取到子组件A this.$children[0].messageA = 'this is new value' } } } </script>
      // 子组件中
      <template>
        <div class="com_a">
          <span>{{messageA}}</span>
          <p>获取父组件的值为:  {{parentVal}}</p>
        </div>
      </template>
      
      <script>
      export default {
        data() {
          return {
            messageA: 'this is old'
          }
        },
        computed:{
          parentVal(){
            return this.$parent.msg;
          }
        }
      }
      </script>
      Borderline cases to be noted that, as #app the take $parent obtained are new Vue() examples, in this instance a chance to $parent get is undefined , and take in the bottom of the sub-assembly $children is an empty array. Also note that to get $parent and $children values are not the same, $children  the value is an array, and $parent is a target
    • Summary: The above two ways of communicating between components Sons, props used for more general parent-child communication components; Both of these can not be used for communication between the non-parent-child assembly
  • provideinject

    • provideinject Is vue2.2.0added api, parent component is simply by provideproviding a variable, then the sub-assembly by injectinjected variable.
    • Note: This sub-assembly nested no matter how deep, as long as the call inject then it can inject providedata, without being limited to only go back data from the current props property of the parent assembly
    • // A.vue
      
      <template>
        <div>
          <comB></comB>
        </div>
      </template>
      
      <script>
        import comB from '../components/test/comB.vue'
        export default {
          name: "A",
          provide: {
            for: "demo"
          },
          components:{
            comB
          }
        }
      </script>
      // B.vue
      
      <template>
        <div>
          {{demo}}
          <comC></comC>
        </div>
      </template>
      
      <script>
        import comC from '../components/test/comC.vue'
        export default {
          name: "B",
          inject: ['for'], data() { return { demo: this.for } }, components: { comC } } </script>
      // C.vue
      <template>
        <div>
          {{demo}}
        </div>
      </template>
      
      <script>
        export default {
          name: "C",
          inject: ['for'],
          data() {
            return { demo: this.for } } } </script>
  • ref / refs

    • ref: If used in a generic DOM element reference point is the DOM elements; if used in the subassembly, reference points to a component instance, the method of Example directly call or access data may be, we see an ref example of access assembly :
      // 子组件 A.vue
      
      export default {
        data () {
          return {
            name: 'Vue.js'
          }
        },
        methods: {
          sayHello () {
            console.log('hello')
          }
        }
      }
      // 父组件 app.vue
      
      <template>
        <component-a ref="comA"></component-a>
      </template>
      <script>
        export default {
          mounted () {
            const comA = this.$refs.comA;
            console.log(comA.name);  // Vue.js
            comA.sayHello();  // hello
          }
        }
      </script>
  • eventBus

    • eventBus Also known as event bus, you can use it as a bridge concept in vue, just as is the same for all components share events center, you can register to receive or send events to the event center, so components can notify other components.
    • eventBus there are inconveniences, when a large project, it is easy to make it difficult to maintain a disaster
    • How to use the Vue project eventBusto achieve data communication between the components of it? By following specific steps
    • 1. Initialization

      // event-bus.js
       
      import View from 'for' 
      export EventBus const = new View ()
    • 2. Send event

      <template>
        <div>
          <show-num-com></show-num-com>
          <addition-num-com></addition-num-com>
        </div>
      </template>
      
      <script>
      import showNumCom from './showNum.vue'
      import additionNumCom from './additionNum.vue'
      export default {
        components: { showNumCom, additionNumCom }
      }
      </script>
      // addtionNum.vue 中发送事件
      
      <template>
        <div>
          <button @click="additionHandle">+加法器</button>    
        </div>
      </template>
      
      <script>
      import {EventBus} from './event-bus.js'
      console.log(EventBus)
      export default {
        data(){
          return{
            num:1
          }
        },
      
        methods:{
          additionHandle(){
            EventBus.$emit('addition', { num:this.num++ }) } } } </script>
    • 3. Receive event

      // showNum.vue 中接收事件
      
      <template>
        <div>计算和: {{count}}</div>
      </template>
      
      <script>
      import { EventBus } from './event-bus.js'
      export default {
        data() {
          return {
            count: 0
          }
        },
      
        mounted() {
          EventBus.$on('addition', param => { this.count = this.count + param.num; }) } } </script>

      This realization of the component addtionNum.vueclick on the button in the addition, the showNum.vueuse of the transfer to the  num results demonstrate summation.

    • 4. Remove event listeners
      If you want to remove the event listener, you can do this as follows:

      import { eventBus } from 'event-bus.js'
      EventBus.$off('addition', {})
  • Vuex

    • Introduction 1. Vuex

      Vuex is a specially developed for Vue.js application state management. It uses the status of all components of the centralized storage management applications, and to ensure appropriate rules state in a predictable manner changed. Vuex solved 多个视图依赖于同一状态and 来自不同视图的行为需要变更同一状态issues to focus developers focus on data rather than the data update on transfer between the components

      2. Vuex each module

      1. state: For storing data, only the data in the source store
      2. getters: Computing vue properties in the same state data based on the secondary packaging, commonly used in the data screening and a plurality of correlation calculation
      3. mutations: Similar functions, the only way to change the state data, and can not be used to handle asynchronous events
      4. actions: Like mutation, for submission mutationto change the state without directly change the status, can contain any asynchronous operation
      5. modules: Similar namespace for each module in the items defined separately and a state operation, easy to maintain

      3. Vuex example application

      // parent element 
      
      <Template> 
        <div ID = "App"> 
          <ChildA /> 
          <ChildB /> 
        </ div> 
      </ Template> 
      
      <Script> 
        import from ChildA './components/ChildA' // A component introduced 
        import ChildB from './components/ChildB' // B components introduced 
        Export default { 
          name: 'the App' ,  components: {ChildA, ChildB} // Register A, B component  }  </ Script>
      
      
      // subassembly ChildA 
      
      <Template> 
        <div the above mentioned id = "ChildA"> 
          <h1> I'm A component </ h1> 
          <@ the Click the Button = "the Transform"> Let me point B component receives data </ the Button> 
          <the p- > because you point to B, so my information is changed: {{BMessage}} </ P> 
        </ div> 
      </ Template> 
      
      <Script> 
        Export default { 
          Data () { 
            return { 
              aMessage: 'the Hello, B components, component I a '  }  },  computed: {  BMessage () {  // where B component obtained from the stored data in the store  return the this $ store.state.BMsg.  }  },  Methods: {  Transform () {  // trigger receiveAMsg, the store data to the store go component A the this .$store.commit('receiveAMsg', { AMsg: this.AMessage }) } } } </script>
      // subassembly ChildB 
      
      <Template> 
        <div the above mentioned id = "ChildB"> 
          <h1> I am a B component </ h1> 
          <@ the Click the Button = "the Transform"> Let me point A component receives data </ the Button> 
          <the p- > because you point a, the I information is changed: {{aMessage}} </ P> 
        </ div> 
      </ Template> 
      
      <Script> 
        Export default { 
          Data () { 
            return { 
              BMessage: 'the Hello, a component, I component B '  }  },  computed: {  aMessage () {  // where component a is stored in the acquired data from the store  return the this $ store.state.AMsg.  }  },  Methods: {  Transform () {  // trigger receiveBMsg, the B component to store data store go the this .$store.commit('receiveBMsg', { BMsg: this.BMessage }) } } } </script>

      vuex of store.js

      Vue from Import 'VUE' 
      Import from Vuex 'vuex' 
      Vue.use (Vuex) 
      const State = { 
        // initialization data A and B components, waiting to acquire 
        AMSG: '' ,  BMSG: ''  } 
       const mutations = {receiveAMsg ( state, payload) {// the data stored in the component a = state.AMsg State payload.AMsg}, receiveBMsg (state, payload) {// the data stored in the B-component = state.BMsg State payload.BMsg}} new new default Export Vuex.Store ({State, mutations})

       

      vuex is vue state manager, data storage is the type of response. But does not save them, then refresh returned to the initial state,
      Specifically, when vuex should change the data in the data localStorage to save a copy of which, after refreshing, if there localStorage to save the data, and then take out the replacement store in the state.

      let defaultCity = "Shanghai" 
      try {// the user closes the local storage, in this case try to add the catch outer ... 
        IF (! defaultCity) { 
          defaultCity the JSON.parse = (window.localStorage.getItem ( 'defaultCity' ) ) 
        } 
      } the catch (E) {} 
      Export default new new Vuex.Store ({  State: {  City: defaultCity  },  mutations: {  changeCity (State, City) {  state.city = City  the try {window.localStorage.setItem ( 'defaultCity ' , the JSON.stringify (state.city)); // change the data when the data is saved to a copy of the catch localStorage inside} (E) {}}}})

      It should be noted that: due vuex, we saved state, is an array, but localStorage only supports strings, so the need to use JSON conversion:

      JSON.stringify(state.subscribeList);   // array -> string
      JSON.parse(window.localStorage.getItem("subscribeList"));    // string -> array 
  • localStorage / sessionStorage

    • This communication is relatively simple, drawbacks and status data is confusing, is not easy to maintain. By window.localStorage.getItem(key)acquiring data by window.localStorage.setItem(key,value)storing data
    • Note that with JSON.parse() /  JSON.stringify() for data format conversion  /  can be combined to achieve persistent data while using vuex solve the data state and confusion. localStoragesessionStoragevuex
  • $attrsversus $listeners

    • Now let's discuss the case, we started assembly diagrams given in the A component and the D component is inter-generational relationships, and that before they communicate what way?

      1. Using propsbinding to an information transfer level, if the D component state change needs to be passed to the data A, using a system-level events are passed up
      2. Use eventBus, this case is quite suitable for use, but when people come to develop code maintainability is low, too low readability
      3. Use Vuex for data management, but if only to transfer data, without making intermediate processing, processing using Vuex feeling a little overkill.

      In vue2.4order to solve this demand, the introduction $attrs and $listeners , added inheritAttrs options. In the previous version 2.4, by default, the parent scope is not recognized as a prop (and get) the characteristics of the binding (except for class and style), will be "rolled back" and as an ordinary HTML attributes used in sub-assemblies the root element.

    • $attrs : Contains the parent scope prop not recognized (and obtain) the binding properties (except for class and style). When a component does not declare any prop, where the parent scope includes all bindings (other than class style), and can be v-bind = "$ attrs" Incoming internal components. Usually used in conjunction with inheritAttrs option.
      $listeners : It contains the parent scope (excluding .native decorator) v-on event listener. It can be v-on = "$ listeners" Incoming internal components
    • Next, look at an example of a cross-level communication:

       

      // app.vue
      // index.vue
      
      <template>
        <div>
          <child-com1
            :name="name"
            :age="age"
            :gender="gender"
            :height="height"
            title="程序员成长指北"
          ></child-com1>
        </div>
      </template>
      <script> const childCom1 = () => import("./childCom1.vue"); export default { components: { childCom1 }, data() { return { name: "zhang", age: "18", gender: "女", height: "158" }; } }; </script>
      ChildCom1.vue // 
      
      <Template class = "border"> 
        <div> 
          <P> name: {{name}} </ P> 
          <P> childCom1 attrs of $: $ attrs {{}} </ P> 
          <Child V = the bind--com2 "$ attrs"> </ Child-COM2> 
        </ div> 
      </ Template> 
      <Script> 
      const childCom2 = () => Import ( "./ childCom2.vue" ); 
      Export default { 
        Components : { 
          childCom2 
        }, 
        inheritAttrs: to false, // can not turn off automatically mounted props attribute declared on the root element assembly  props: {  name: // String name binding properties as props  },  Created () {  Console. log (the this $ attrs.); // { "Age": "18 is", "gender ":" female "," height ":" 158 "," title ":" Growth Programmer "} }}; </ Script>
      
      
      // childCom2.vue
      
      <template>
        <div class="border">
          <p>age: {{ age}}</p>
          <p>childCom2: {{ $attrs }}</p>
        </div>
      </template>
      <script>
      
      export default {
        inheritAttrs: false,
        props: {
          age: String
        },
        created() {
          console.log(this.$attrs); 
          // { "gender": "女", "height": "158", "title": "程序员成长" }
        }
      };
      </script>



 Extra added:

V-model

Value to the sub-assembly is automatically passed prop attribute value of a parent component transmitted through the v-model,

Subassembly automatically modify the values ​​v-model binding by this. $ Emit ( 'input', val), see example below.

 

Parent component:

<template>
    <div>
        <child v-model="total"></child>
        <button @click="increse">增加5</button>
    </div>
</template>

<script>
import Child from "./child.vue"
export default {
    components: {
        Child
    },
    data: function () {
        return {
            total: 0 }; }, methods: { increse: function () { this.total += 5; } } } </script>

Subassembly:

<template>
    <div>
        <span>{{value}}</span>
        <button @click="reduce">减少5</button>
    </div>
</template>

<script>
export default {
    props: {
        value: Number  // 注意这里是value
    },
    methods: {
        reduce: function(){
            this.$emit("input", this.value - 5) // 事件为input
        }
    }
}
</script>

 

 

Guess you like

Origin www.cnblogs.com/Joe-and-Joan/p/11258832.html