Vue advanced (one eight two): parent-child component element acquisition and method call each other

Posted by eyespark on Tue, 08 Mar 2022 01:35:48 +0100

preface

During the development of Vue project, sometimes we need the parent component to directly access the child component, the child component to directly access the parent component, or the child component to access the root component. Sort out the following request methods:

  • Parent component accesses child component: $children or $refs
  • Child component accessing parent component: $parent
  • Sub component access root component (root Vue instance created through new Vue): $root

Parent component accessing child component

Use $children

Use this in the parent component$ What children get is an array type, which contains all sub component instances.

<div id="app">
  <cpn></cpn>
  <cpn></cpn>
  <button @click="btnClick">Button</button>
</div>

<template id="cpn">
  <div>
    <h1>I'm a subcomponent</h1>
  </div>
</template>

<script>
  let vm = new Vue({
    el: "#app",
    data: {},
    methods: {
      btnClick() {
        //1. Get all sub components, which is an array
        console.log(this.$children);

        //2. Get a component instance, and you can directly access the methods in the subcomponent and the data in the data
        this.$children[0].showMessage();
        console.log(this.$children[0].name);
      }
    },
    components: {
      cpn: {
        template: '#cpn',
        data() {
          return {
            name: 'webchang'
          }
        },
        methods: {
          showMessage() {
            console.log('I'm a subcomponent');
          }
        }
      }
    }
  });
</script>

Use $refs

The disadvantages of using $children are as follows:

When accessing sub components through $children, it is an array type, and the sub components must be accessed through the index value.

However, when there are too many subcomponents and we need to get one of them, we often can't determine its index value, and even may change.

Sometimes, when we want to explicitly obtain one of the specific components, we can use $refs

Use of $refs

By setting the ref of the child component, the parent component passes this$ refs. xxx. method_ Name (data) calls the subcomponent method, and the data parameter is optional.

The $refs and ref instructions are usually used together.

First, we add a ref attribute to the sub component, which is equivalent to binding a specific ID to a sub component.

Second, this$ Refs gets all sub components marked with ref attribute (if a sub component instance does not have ref attribute, it cannot be obtained in this way). Finally, it gets an object. The attribute name is the ref attribute of the sub component instance, and the attribute value is the component instance.

Through this$ refs. ID to access the component.

The example code is as follows:

<div id="app">
  <cpn ref="child1"></cpn>
  <cpn ref="child2"></cpn>
  
  <!-- This subcomponent instance has no ref Properties, by this.$refs This component instance cannot be obtained in this way -->
  <cpn></cpn>
  <button @click="btnClick">Button</button>
</div>

<template id="cpn">
  <div>
    <h1>I'm a subcomponent</h1>
  </div>
</template>

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
  let vm = new Vue({
    el: "#app",
    data: {
      message: "hello"
    },
    methods: {
      btnClick() {
        console.log(this.$refs)
        console.log(this.$refs.child1)
        console.log(this.$refs.child1.name)
        this.$refs.child1.showMessage('Parent component')
      }
    },
    components: {
      cpn: {
        template: '#cpn',
        data() {
          return {
            name: 'webchang'
          }
        },
        methods: {
          showMessage(value) {
            console.log("Subcomponent method called, caller:" + value)
          }
        }
      }
    }
  });
</script>

The child component calls the parent component method

Method 1: this$ parent. event

Directly in the subcomponent through this$ parent. Event to call the method of the parent component. The example code is as follows:

Parent component

<template>
  <div>
    <child></child>
  </div>
</template>
<script>
  import child from './components/dam/child';
  export default {
    components: {
      child
    },
    methods: {
      fatherMethod(value) {
        console.log("Parent component method called, caller:" + value)
      }
    }
  };
</script>

Subcomponents

<template>
  <div>
    <button @click="childMethod()">click</button>
  </div>
</template>
<script>
  export default {
    methods: {
      childMethod() {
        this.$parent.fatherMethod('Subcomponents');
      }
    }
  };
</script>

matters needing attention:

  • Although in Vue development, we allow access to parent components through $parent, we try not to do so in real development.
  • Child components should try to avoid directly accessing the data of the parent component, because the code coupling is too high.
  • If we put a child component in another component, it is likely that the parent component has no corresponding properties, which often causes problems.
  • In addition, if the state of the parent component is directly modified through $parent, the state in the parent component will become erratic, which is not conducive to debugging and maintenance.

Method 2: $emit

In the child component, $emit is used to trigger an event to the parent component, and the parent component listens to this event.

Parent component

<template>
  <div>
    <child @fatherMethod="fatherMethod"></child>
  </div>
</template>
<script>
  import child from '~/components/dam/child';
  export default {
    components: {
      child
    },
    methods: {
      fatherMethod() {
        console.log('test');
      }
    }
  };
</script>

Subcomponents

<template>
  <div>
    <button @click="childMethod()">click</button>
  </div>
</template>
<script>
  export default {
    methods: {
      childMethod() {
        this.$emit('fatherMethod');
      }
    }
  };
</script>

Method 3: transfer parameters

The parent component passes the method into the child component and calls the method directly in the child component.

Parent component

<template>
  <div>
    <child :fatherMethod="fatherMethod"></child>
  </div>
</template>
<script>
  import child from '~/components/dam/child';
  export default {
    components: {
      child
    },
    methods: {
      fatherMethod() {
        console.log('test');
      }
    }
  };
</script>

Subcomponents

<template>
  <div>
    <button @click="childMethod()">click</button>
  </div>
</template>
<script>
  export default {
    props: {
      fatherMethod: {
        type: Function,
        default: null
      }
    },
    methods: {
      childMethod() {
        if (this.fatherMethod) {
          this.fatherMethod();
        }
      }
    }
  };
</script>

Easier way to write subcomponents

<template>
  <div>
    <button @click="fatherMethod()">click</button>
  </div>
</template>
<script>
  export default {
    props: {
      fatherMethod: {
        type: Function,
        default: null
      }
    },
    methods: {
      
    }
  };
</script>

Other calling methods

Since all components will eventually be rendered as real Dom elements, you can obtain Dom element objects through js or jquery, trigger the method of element binding by simulating clicking, and cache parameters through local Cookie, localStorage or sessionStorage to realize value transmission. This method is not limited to child and parent components. It can be used as long as the components are on the same page. However, it is not recommended to use it because it does not comply with vue specification.

Component A:

<template>
  <div>    
    <h1>I'm a component A</h1>
    <button id='btn' @click='methodA()'>Point me</button>
  </div>
</template>
<script>
  export default {
    methods: {
      methodA() {     
      	var parameter= localStorage.getItem('parameter'); 
        console.log('I'm a component A method');
      }
    }
  };
</script>

Component B:

<template>
  <div>    
    <h1>I'm a component B</h1>
    <button @click='methodB(data)'>Point me</button>
  </div>
</template>
<script>
  export default {
    methods: {
      methodB(data) {
      localStorage.setItem('parameter',data); 
        $('#btn').click();// Simulation button click
        console.log('Click the simulation button to trigger A Component method');
      }
    }
  };
</script>

Topics: Javascript Vue