Communication of Vue components

Keywords: Front-end Vue REST

Preface

In this chapter, we will learn all the contents of Vue component communication. Before that, you'd better master the basic syntax, instructions and other contents of Vue. At the same time, we suggest you check my other articles for supplement.

Component communication

Parent child relationship

Through the figure above, I will show you the implementation principle of parent-child components and the implementation idea of transferring values between components to DOM. Let's take a look at Vue's code to feel it

Pass value from father to son

Template part (variables in components can also be used for value passing here)

<div id="app">
    	<!-- Pass a string constant haha -->
         <son v-bind:text="'haha'" />
</div>

Part js

        // Sub components
        var Son = {
            // Field name to receive
            props:['text'], 
            template:`
                <div>
                    {{ text }}
                </div>`
        };
        Vue.component('son',Son);
        // Parent component
        new Vue({
            el:'#app'
        });

It is obvious that the result is the haha of the subcomponent

Child to parent communication

Imagine a situation in which the parent component controls the display of the child component, and click X from the child component to hide the child component. Then the actual control is really in the parent component

To deal with this problem, the first reaction should be to get the variables in the parent component to control display and hide and change them through the click event of the child component

The code is as follows

// Hide button click function
methods:{
	clickChild(){
        this.$parent.isShow = false;
    }
}

Implementation is right, but

In the framework, we'd better put aside the previous DOM ideas, otherwise we will not be able to realize the ideas brought by the framework, and will remain in the process oriented forever...

Event communication mechanism

In Vue, we use @ xxx to bind events to native DOM elements, such as click, input, etc..

At the same time, we can also bind custom events to subcomponents, no matter what their name is. Give an example:

<!-- Parent component -->
<son v-show="isShow" @callme="callmeFn" />
// Parent component js
methods:{
	callmeFn(params){
		this.isShow = false;
    }
}

Next, the subcomponents only need to trigger this event. From the perspective of low coupling, are the parents and children playing each other?

// In the child component click function, trigger the event for which the parent component binds
this.$emit('callme','You can also pass parameters')

Child to parent synchronous extension

For the example just now, we don't need the execution of the parent component and the child component function. We just need to synchronize the isShow value of the parent component when the child component clicks. So we can write as follows

<!-- Parent component -->
<son v-show="isShow" :isShow.sync="isShow" />

You can see from the code in the subcomponent that the principle is based on the event

// Sub components
this.$emit('update:isShow','value')

Multi level component communication through event objects provided by Vue

There are only three steps to do

  • Create a common communication object
let connector = new Vue();
  • Register the event in the function to trigger the event
connector.$on('Event name',function(params){ });
  • Trigger the above events in the target event
connector.$emit('Event name','value');

Event principle implementation

You may have seen a lot of pain about on and emit, don't you? I don't need to say much about that. I believe it will make you feel better if you directly implement it in source code

	var store = {
			once:{},
			fns:{},
			on(key,fn,isOnce){
				this.fns[key]?this.fns[key].push(fn):this.fns[key] = [fn];
			},
			emit(key,value){
				let t = this.fns[key];
				let o = this.once[key];
				if (!t)return;
				t.forEach(fn=&gt;{
					fn(value);
				});
				if (o)	this.off(key);
			},
			off(key) {
					delete this.fns[key];
			},
			once(key,fn){
				this.once[key] = true;
				this.on(key,fn);
			}
		}

The principle is that an object stores event names with key and functions with value!

Passing DOM elements

Look at the following functions. Six of the nine palaces look the same but different. Therefore, we can try to show their differences by giving them different DOM from the parent component. The child components only need to do some writing for their common characteristics

If most of the content of the child element is customized by the parent element, and the child component is as simple and simple as possible, the component is even low coupling and high cohesion.

How to implement the content area left by the parent component in the child component? The answer is: slot

slot implementation steps

  1. Pit in sub assembly
<!-- Sub components -->
<div>
    <!--A default pit-->
    <slot></slot>
</div>
  1. Passing in DOM in the parent component
<!-- Parent component -->
<!-- Using subcomponents -->
<son>
	<!--Transitive DOM-->
    <template v-slot:default>
        <button>Button for child</button>
    </template>
</son>
  1. Of course, it can also be delivered by name
<!-- Sub components -->
<div>
    <!-- Custom top half -->
    <slot name="head"></slot>
    <!-- Custom lower half -->
    <slot name="foot"></slot>
</div>
  1. The parent component also needs to make its name clear
<!-- Parent component -->
<!-- Using subcomponents -->
<son>
	<!--Transitive DOM-->
    <template v-slot:head>
        <button>Button for the head</button>
    </template>
     <template v-slot:foot>
        <button>For the bottom button</button>
    </template>
</son>

In the end, I'd like to talk about what the general people don't know

Thought sorting: we think of this group of ul+li as a component. It receives an array and renders it for us through v-for. The data is as follows

// Parent component data
todos: [
    	{
            id: 0,
            text: 'ziwei0',
            isComplete: true
        },
        {
            text: 'ziwei1',
            id: 1,
            isComplete: true
        },
        {
            text: 'ziwei2',
            id: 2,
            isComplete: false
        },
        {
            text: 'ziwei3',
            id: 3,
            isComplete: false
        }
];

The parent passes the object to the child

<son :todos="todos"></son>

Leave the rest to the subcomponent, let it handle the specific business! Am I right?

Well, let's make the subcomponent function as single as possible, high cohesion and low coupling. It's all dealing with business. What's more about the public component? The reusability is not high, pass!

So we leave the business judgment function to the parent group, which is what the child component writes

 <!--Sub components-->
  <ul>
    <li v-for="todo in todos" :key="todo.id">
      <slot>
      </slot>
    </li>
  </ul>

So the question is, does the parent component want to pass DOM as the value of slot?

	<!--Parent component-->
	<son :todos="todos">
        <template v-slot:default>
            <span>✓</span>
            <span>content</span>
        </template>
	</son>

Oops, the parent component has passed todos in, but now we need to do business processing through each todo. Look at the figure

Therefore, we use the new function of 2.6, slotProps, to see the value passing of slot

 <!--Sub components-->
  <ul>
    <li v-for="todo in todos" :key="todo.id">
      <slot :todo="todo">
      </slot>
    </li>
  </ul>

See how the parent component receives it. See template where (fixed writing) slotProps is equivalent to the built-in variable

<!--Parent component-->
	<son :todos="todos">
				<template v-slot:default="slotProps">
                    <span v-if="slotProps.todo.isComplete">✓</span>
                	<span>{{slotProps.todo.text}}</span>
           	    </template>
			</son>

Fix it! If you like my article, you can pay attention to me. If you can't help but want to see me every day, you can contact me to join our front-end discussion group

Posted by Druid on Fri, 28 Feb 2020 04:15:38 -0800