[Switch] vuejs communication summarized essence component

Classification of components

  1. Conventional page components, each page generated by the vue-router, which is essentially a component (.vue), the main bearing structures of the current HTML page will contain a data acquisition, data reduction, data visualization and other conventional operations.
  2. Abstract functional component does not contain a base component business, independent, specific functions, such as a date picker, pop warnings. Such components as the basis for control of the project, will be widely used, so the API component abstract high strength can be achieved through different functions in different configurations.
  3. Business component, it is not like second class independent component contains only one function, but business is multiplexed multiple pages, it is the difference between individual components, business components will be used only in the current project, not versatile, and include some services, such as data request; free assembly independent service, can be used in any project, a single function, such as a data input box having a check function.

Relations assembly

Father and son Components

A parent-child relationship that is using a component B component in its template, it is the parent component of the component A, component B is subcomponents.

// 注册一个子组件
Vue.component('child', {
    data: function(){ return { text: '我是father的子组件!' } }, template: '<span>{{ text }}</span>' }) // 注册一个父组件 Vue.component('father', { template: '<div><child></child></div>' // 在模板中使用了child组件 })

Brothers components

Two components and do not reference, for the brothers components.

Vue.component('brother1', {
    template: '<div>我是大哥</div>'
})
Vue.component('brother2', {
    template: '<div>我是小弟</div>' })

When using components:

<div id="app">
    <brother1></brother1> <brother2></brother2> </div>

Cross-level components

Is the parent-child relationship, across the middle of a lot of tiers

Constituent components

A more complex components, are composed of three parts: prop, event, slot, which constitute the API Vue.js assembly.

Properties prop

prop define which attributes this component has configurable core functional components of it are also determined. When writing generic components, props is best to use the wording of the object, so you can, default or custom validation attribute value for each property type is set, this is a very important component in the development, but many people ignore it, directly the use of an array of props, such components are often not rigorous.

Slot slot

Slot slot, it can distribute content components. And HTML elements, we often need to deliver content to a component, like this:

<alert-box>
  Something bad happened.
</alert-box>

You might render such a thing:

Error!Something bad happended.

Fortunately, Vue from <slot> element defined so that it becomes very simple:

Vue.component('alert-box', {
  template: `
    <div class="demo-alert-box"> <strong>Error!</strong> <slot></slot> </div> ` })

As you can see, we simply add slot where needed on the line - it's that simple!

Custom Event event

Two way:

  • Custom Event event in internal components
<template>
  <button @click="handleClick"> <slot></slot> </button> </template> <script> export default { methods: { handleClick (event) { this.$emit('on-click', event); } } } </script>

By $ emit, you can trigger custom events on-click, in the parent to listen via @ on-click:

<i-button @on-click="handleClick"></i-button>
  • Directly in the statement by the parent event modifier .native

So the above example could also write:

<i-button @click.native="handleClick"></i-button>

If you do not write .native modifier that is above @click custom event click, rather than the original event click, but we only triggered on-click event in the assembly, rather than click, so do not write directly @click will listen to.

Communication components

and children and ref

Vue.js built-in means of communication, there are two:

  • ref: reference to an element or component registration information;
  • children: access parent / child instance.

With ref to access components (omitted portions of code):

// component-a
export default {
  data () {
    return {
      title: 'Vue.js' } }, methods: { sayHello () { window.alert('Hello'); } } }
<template>
  <component-a ref="comA"></component-a> </template> <script> export default { mounted () { const comA = this.$refs.comA; console.log(comA.title); // Vue.js comA.sayHello(); // 弹窗 } } </script>

Similar and children, is also based on the current context access to all of the parent component or sub-assembly.
The drawbacks of these two methods is not in cross-level communication between brothers or, as in the following structure:

// parent.vue
<component-a></component-a>
<component-b></component-b> <component-b></component-b>

We would like component-a, a reference to its access to the page (this is parent.vue) of the two component-b component that in this case, is temporarily unable to achieve, will explain the method behind.

provide / inject

A method of communication components without dependence: Vue.js built provide / inject Interface

provide / inject a new post Vue.js version 2.2.0 API, introduced in this document:
This option needs to be used together to allow an ancestor component inject a dependency to all future generations, regardless of how deep the component hierarchy and always take effect on the upstream and downstream relationship established time. If you are familiar React, which React context characteristics very similar.
provide and inject mainly provides use cases for high-end plug-ins / component library. Not recommended for direct application code.
Suppose there are two components: A.vue and B.vue, B is a sub-assembly A:

// A.vue
export default {
  provide: {
    name: 'Aresn' } } // B.vue export default { inject: ['name'], mounted () { console.log(this.name); // Aresn } }

Note that:
the Provide and inject bindings can not respond. This is deliberate. However, if you pass an object that can monitor, then the object or its properties can respond.

As long as a component using the data provided downwardly provide that all of its sub-components may be injected through Inject, no matter how many generations in the interval, and data may be injected from a plurality of different parents provided. Note that, once injected some data that this component you can not declare the data, because it has been occupied parent.

provide / inject API mainly to solve the communication problem between the cross-level components, but its usage scenarios, mainly sub-assembly components to obtain higher status, between the cross-level components to establish a relationship of dependency injection and unsolicited. Then there are two scenarios that it can not solve:

  • The parent component subassembly (support cross-level) data transfer;
  • Sub-assemblies to the parent component (support cross-level) data transfer.

Such Sons (including cross-level) data transfer communication, Vue.js does not provide native support for API, the following describes a method and a broadcast dispatch communication between parent and child components.

And listeners

If the parent component A has the following sub-components B, component B has the following components C, then if A wants to transfer data to the component assembly C how to do it? Vue 2.4 and began offering the listeners to solve this problem, allowing to pass messages between components A component C.

Vue.component('C',{
        template:`
            <div>
                <input type="text" v-model="$attrs.messagec" @input="passCData($attrs.messagec)"> </div> `, methods:{ passCData(val){ //触发父组件A中的事件 this.$emit('getCData',val) } } }) Vue.component('B',{ data(){ return { mymessage:this.message } }, template:` <div> <input type="text" v-model="mymessage" @input="passData(mymessage)"> <!-- C组件中能直接触发getCData的原因在于 B组件调用C组件时 使用 v-on 绑定了$listeners 属性 --> <!-- 通过v-bind 绑定$attrs属性,C组件可以直接获取到A组件中传递下来的props(除了B组件中props声明的) --> <C v-bind="$attrs" v-on="$listeners"></C> </div> `, props:['message'],//得到父组件传递过来的数据 methods:{ passData(val){ //触发父组件中的事件 this.$emit('getChildData',val) } } }) Vue.component('A',{ template:` <div> <p>this is parent compoent!</p> <B :messagec="messagec" :message="message" v-on:getCData="getCData" v-on:getChildData="getChildData(message)"></B> </div> `, data(){ return { message:'hello', messagec:'hello c' //传递给c组件的数据 } }, methods:{ getChildData(val){ console.log('这是来自B组件的数据') }, //执行C子组件触发的事件 getCData(val){ console.log("这是来自C组件的数据:"+val) } } }) var app=new Vue({ el:'#app', template:` <div> <A></A> </div> ` })

Broadcast distribution - implemented method of self-broadcast dispatch and

Dispatch and broadcast methods to be implemented, will have the following features:
the child component calls dispatch method, trigger custom event component instance designated by the parent on the (most recent), and transfers data, and the higher level component has been previously by listening to this events; the contrary, call methods in the parent component, the component instance specified by the lower trigger on the (recent) custom events, and transfers data, and the subordinate components are pre-listening through on this event.

// 部分代码省略
import Emitter from '../mixins/emitter.js'

export default { mixins: [ Emitter ], methods: { handleDispatch () { this.dispatch(); // ① }, handleBroadcast () { this.broadcast(); // ② } } }
 //emitter.js 的代码:
function broadcast(componentName, eventName, params) { this.$children.forEach(child => { const name = child.$options.name; if (name === componentName) { child.$emit.apply(child, [eventName].concat(params)); } else { broadcast.apply(child, [componentName, eventName].concat([params])); } }); } export default { methods: { dispatch(componentName, eventName, params) { let parent = this.$parent || this.$root; let name = parent.$options.name; while (parent && (!name || name !== componentName)) { parent = parent.$parent; if (parent) { name = parent.$options.name; } } if (parent) { parent.$emit.apply(parent, [eventName].concat(params)); } }, broadcast(componentName, eventName, params) { broadcast.call(this, componentName, eventName, params); } } };

Because it is introduced as mixins, the dispatch methods defined in the broadcast and methods will be mixed in the component, the nature and can be used this.dispatch this.broadcast used.
Both methods have received the three parameters, a first component is the value of the name, to find a corresponding component recursive traversal upward or downward, the second and third custom event name is analyzed above and data to be transferred.
It can be seen in the dispatch, the while statement by constantly updating the current traversing component (i.e. a component of the process context of the current call) the parent component instance (i.e., parent parent component instance variables) upwards, until the matching with the defined componentName name options for a higher level when the same components, the end of the cycle, and on the component instance is found, call the $ emit method to trigger a custom event eventName. Similarly broadcast method, just looking down traversal.

Look at the specific use. There A.vue and B.vue two components, wherein component B is a child of A, might span multiple intermediate stages, the communication B in A:

<!-- A.vue -->
<template>
    <button @click="handleClick">触发事件</button> </template> <script> import Emitter from '../mixins/emitter.js'; export default { name: 'componentA', mixins: [ Emitter ], methods: { handleClick () { this.broadcast('componentB', 'on-message', 'Hello Vue.js'); } } } </script>
// B.vue
export default {
  name: 'componentB',
  created () {
    this.$on('on-message', this.showMessage); }, methods: { showMessage (text) { window.alert(text); } } }

Similarly, if it is B, call the dispatch method in B to A communication, you can use the $ on listening to events in A.
These are the dispatch method and broadcast self-fulfilling.

Find any component instance --findComponents series method

It applies to the following scenarios:

  • Consists of a component, locate the nearest specified component upward;
  • Of a component, to find all of the specified component upwardly;
  • It consists of a component, down to find the nearest specified component;
  • Of a component, down to find all of the specified components;
  • Consists of a component, the brothers find components specified component.

Five different scenarios, corresponding to the five different functions, similar principles are implemented.

Up to find the nearest specified component --findComponentUpward

// 由一个组件,向上找到最近的指定组件
function findComponentUpward (context, componentName) { let parent = context.$parent; let name = parent.$options.name; while (parent && (!name || [componentName].indexOf(name) < 0)) { parent = parent.$parent; if (parent) name = parent.$options.name; } return parent; } export { findComponentUpward };

For example the following example, there are components A and B, component A is the parent of B, and call the data acquisition and process A in B:

<!-- component-a.vue -->
<template>
  <div> 组件 A <component-b></component-b> </div> </template> <script> import componentB from './component-b.vue'; export default { name: 'componentA', components: { componentB }, data () { return { name: 'Aresn' } }, methods: { sayHello () { console.log('Hello, Vue.js'); } } } </script>
<!-- component-b.vue -->
<template>
  <div> 组件 B </div> </template> <script> import { findComponentUpward } from '../utils/assist.js'; export default { name: 'componentB', mounted () { const comA = findComponentUpward(this, 'componentA'); if (comA) { console.log(comA.name); // Aresn comA.sayHello(); // Hello, Vue.js } } } </script>

Find up all the specified component --findComponentsUpward

// 由一个组件,向上找到所有的指定组件
function findComponentsUpward (context, componentName) { let parents = []; const parent = context.$parent; if (parent) { if (parent.$options.name === componentName) parents.push(parent); return parents.concat(findComponentsUpward(parent, componentName)); } else { return []; } } export { findComponentsUpward };

Down to find the nearest specified component --findComponentDownward

// 由一个组件,向下找到最近的指定组件
function findComponentDownward (context, componentName) { const childrens = context.$children; let children = null; if (childrens.length) { for (const child of childrens) { const name = child.$options.name; if (name === componentName) { children = child; break; } else { children = findComponentDownward(child, componentName); if (children) break; } } } return children; } export { findComponentDownward };

Down to find all of the specified components --findComponentsDownward

// 由一个组件,向下找到所有指定的组件
function findComponentsDownward (context, componentName) { return context.$children.reduce((components, child) => { if (child.$options.name === componentName) components.push(child); const foundChilds = findComponentsDownward(child, componentName); return components.concat(foundChilds); }, []); } export { findComponentsDownward };

Find the specified component brother components --findBrothersComponents

// 由一个组件,找到指定组件的兄弟组件
function findBrothersComponents (context, componentName, exceptMe = true) { let res = context.$parent.$children.filter(item => { return item.$options.name === componentName; }); let index = res.findIndex(item => item._uid === context._uid); if (exceptMe) res.splice(index, 1); return res; } export { findBrothersComponents };

Compared to other four functions, findBrothersComponents more than one parameter exceptMe, whether itself except the default is true. Looking brothers assembly method is to first get context.children, that is, all the subcomponents of a parent component, there is currently included in itself, all will have a third parameter exceptMe. Vue.js when rendering component, the component will be to add a built-in property _uid each, this _uid is not repeated, we can take this from a series of brothers components exclude themselves out.

Event Bus

Sometimes the need for communication between the two components, but not a parent-child relationship to each other component. In some simple scenarios, you can use an empty bus Vue instance as an event center (central event bus):

 //中央事件总线
    var bus=new Vue();

    var app=new Vue({ el:'#app', template:` <div> <brother1></brother1> <brother2></brother2> </div> ` }) // 在组件 brother1 的 methods 方法中触发事件 bus.$emit('say-hello', 'world') // 在组件 brother2 的 created 钩子函数中监听事件 bus.$on('say-hello', function (arg) { console.log('hello ' + arg); // hello world })

Data exchange between the processing component vuex

If the business logic complexity, need to deal with some common data among many components, only this time on top of that some of the methods may not be conducive to the maintenance of the project, vuex approach is pulled out of some of these public data out, and then the other components on It can read and write to the common data, so that to achieve the purpose of decoupling.

Guess you like

Origin www.cnblogs.com/chris-oil/p/12297586.html