[Vue learning notes _10] component development

Finally, the core component development of Vue!

Componentization: we divide a page into many components. Each component is used to implement a function block of the page, and each component can be subdivided. This will make the code easier to organize and manage, and more extensible.

Vue componentization: it provides an abstraction that allows us to develop independent reusable Vue components to construct applications. Any application will be abstracted into a component tree.

Supporting executable code example = > GitHub

Basic use of components

The use of components is divided into three steps:

  1. Call the Vue.extend() method to create a component constructor
  2. Call the Vue.component() method to register the component
  3. Use components within the scope of Vue instances
<div id="app">
  <!-- 3.Use components-->
  <my-cpn></my-cpn>
</div>

<script>
  //1. Create a component constructor
  const cpnC = Vue.extend({
    template: `
      <div>
        <h2>title</h2>
        <p>Content content</p>
      </div>`
  })
  // 2. Register components
  Vue.component('my-cpn',cpnC)
  const app = new Vue({
    el: '#app'
  })
</script>

Global and local components

Global component: as mentioned above, the component registered by calling Vue.component() method can be used under any Vue instance

Local component: it is mounted in a Vue instance through the components attribute and can only be used under the Vue instance

const app = new Vue({
  el: '#app',
  // Register local components
  components: {
    'my-cpn': cpnC
  }
})

Parent and child components

<script>
  //Create subcomponent constructor
  const cpnC1 = Vue.extend({
    template: `
      <div>
        <h2>Title 1</h2>
        <p>Content 1 content 1 content 1</p>
      </div>`
  })
  //Create parent component constructor
  const cpnC2 = Vue.extend({
    template: `
      <div>
        <h2>Title 2</h2>
        <p>Content 2 content 2 content 2</p>
        <cpn1></cpn1>
      </div>`,
    //Register the subcomponent cpnC1 in cpnC2
    components: {
      cpn1: cpnC1
    }
  })

  const app = new Vue({
    el: '#app',
    data: {
    },
    //Register the sub component cpnC2 in the app
    components: {
      cpn2: cpnC2
    }
  })
</script>

In the above example, cpnC2 is the parent component of cpnC1, and app is the parent component of cpnC2. You can think of Vue instances as the top-level root component.

Syntax for registering components

It mainly omits the step of calling Vue.extend() and directly uses an object instead

Syntax for registering global components

Vue.component('cpn1', {
  template: `
    <div>
      <h2>title</h2>
    </div>`
})

Syntax for registering local components

const app = new Vue({
  el: '#app',
  components: {
    'cpn2': {
      template: `
        <div>
          <h2>title</h2>
        </div>`
    }
  }
})

Separate writing method of component HTML template

Vue provides two ways to define the content of an HTML template:

  • script tag
<script type="text/x-template" id="cpn">
  <div>
    <h2>title</h2>
    <p>Content content</p>
  </div>
</script>
  • template label (common)
<template id="cpn">
  <div>
    <h2>title</h2>
    <p>Content content</p>
  </div>
</template>

When registering components, use #id to obtain HTML templates:

Vue.component('cpn',{
  template: '#cpn'
})

Note: the component template must contain a root element, generally < div >

data attribute in component

Each component has its own data and methods.

It should be noted that the data attribute of the component must be a function that returns an object with data stored inside.

<template id="cpn">
  <div>
    <h2>{{title}}</h2>
    <p>Content content</p>
  </div>
</template>

<script>
  Vue.component('cpn',{
    template: '#cpn',
    data() {
      return {
        title: 'abc'
      }
    }
  })
</script>

Why must data in a component be a function?

Because each instance of a component should not share the same data, it is necessary to define data as a function. In this way, each time a component instance is created, data will return a new object, so that each component instance has its own data.

Component communication - parent to child props attribute

Requirements: the large components of the whole page request a lot of data from the server, and the following small components are required for display. At this time, the sub component will not send a network request again, and the sub component cannot access the data of the parent component or Vue instance. Therefore, the parent component needs to pass the data to the sub component.

Step 1: when defining the child component constructor, use the props attribute to declare the data to be received from the parent component. There are two ways to the value of props:

  • String array: the array element is the data name when passing.
  • Object: the object attribute can limit the data type (type, can be user-defined type), the default value provided (default, when the type is an object or array, default must be a function and return the default value set), whether it is required to pass a value, etc.

Step 2: when using a child component, bind the parent component's data to the child component's attributes through v-bind, and then the bound attributes can be used in the child component's template like data.

<!--Parent component template-->
<div id="app">
  <!--v-bind The parent component's data Bind to properties of child components-->
  <cpn v-bind:cmovies="movies" :cmsg="msg"></cpn>
</div>

<!--Subcomponent template-->
<template id="cpn">
  <div>
    {{cmovies}}
    {{cmsg}}
  </div>
</template>

<script>
  const cpn = {
    template: '#cpn',
    //The child component uses the props attribute to declare the data that needs to be accepted from the parent component
    //props: ['cmovies', 'cmsg'],
    props: {
      //Limit data types (can be custom types)
      cmovies: Array,
      cmsg: {
        type: String,
        //Provide the default value (when the type is an object or array, default must be a function, and the default value set by return)
        default(){
          return 'Hello'
        },
        //The value must be passed
        required: true
      }
    }
  }
  
  const app = new Vue({
    el: '#app',
    data: {
      msg: 'Hi',
      movies: ['dominant sea power', 'One Piece', 'Haier brothers ']
    },
    components: {
      cpn
    }
  })
</script>

Note: if hump identification is used in props, it needs to be converted into "-" connection mode when v-bind is bound in the component

Component communication - child to parent $emit custom event

Requirement: when an event occurs in a child component, data needs to be transmitted to the parent component, which then requests a new round of data according to the received value.

Step 1: in the methods defined by the subcomponent, you can trigger a custom event through $emit and pass in parameters.

Step 2: when using a child component in the parent component, use v-on to listen to the custom events of the child component and receive the incoming parameters by default.

<!--Parent component template-->
<div id="app">
  <!--v-on Listen for custom events of subcomponents-->
  <cpn v-on:item-click="cpnClick"></cpn>
</div>

<!--Subcomponent template-->
<template id="cpn">
  <div>
    <button v-for="item in categories" @click="btnClick(item)">
      {{item.name}}
    </button>
  </div>
</template>

<script>
  //Subcomponents
  const cpn = {
    template: '#cpn',
    data() {
      return {
        categories: [
          {id: 'aaa', name: 'Popular recommendation'},
          {id: 'bbb', name: 'Mobile digital'},
          {id: 'ccc', name: 'Household appliances'}
        ]
      }
    },
    methods: {
      btnClick(item){
        //Trigger custom events in subcomponents
        this.$emit('item-click',item)
      }
    }
  }

  //Parent component
  const app = new Vue({
    el: '#app',
    data: {
    },
    methods: {
      cpnClick(item){
        console.log('cpnClick', item)
      }
    },
    components: {
      cpn
    }
  })
</script>

Note: in the tag of HTML template, v-on listener cannot recognize the hump identification, so the user-defined event needs to use "-" to connect lowercase letters.

Modify the data passed in by props (can be skipped)

The data passed in by props can only be used for display and cannot be modified in the < input > tag, otherwise an error will be reported. If there is a need to modify, there are two methods:

  • Set the data attribute, return the object initialized by the incoming props data, and then bind the data attribute in the < input > tag. However, this alone cannot change the data in the parent component. Then disassemble the v-model of < input > into v-bind and v-on, trigger a custom event in the @ input bound method, pass in the modification value, and listen for the event in the parent component, so that the data of the parent component can be modified in the event bound method. Such as the processing of number1.
  • Similarly, you need to set the data attribute first, return the object initialized by the incoming props data, and then bind the data attribute in the < input > tag. Then set the watch attribute to listen for data changes, trigger a custom event in the processing function and pass in the modification value, listen for events in the parent component, and modify the data of the parent component in the event binding method. Such as the processing of number2.
<!--Parent component template-->
<div id="app">
  <cpn :number1="num1" :number2="num2" @num1change="num1change" @num2change="num2change"></cpn>
</div>

<!--Subcomponent template-->
<template id="cpn">
  <div>
    <h2>props:{{number1}}</h2>
    <h2>data:{{dnumber1}}</h2>
    <input type="text" :value="dnumber1" @input="num1Input">
    <h2>props:{{number2}}</h2>
    <h2>data:{{dnumber2}}</h2>
    <input type="text" v-model="dnumber2">
  </div>
</template>

<script>
  //Parent component
  const app = new Vue({
    el: '#app',
    data: {
      num1: 1,
      num2: 0
    },
    methods: {
      num1change(value) {
        this.num1 = parseInt(value)
      },
      num2change(value) {
        this.num2 = parseInt(value)
      }
    },
    components: {
      //Subcomponents
      cpn: {
        template: '#cpn',
        props: {
          number1: Number,
          number2: Number
        },
        data() {
          return {
            dnumber1: this.number1,
            dnumber2: this.number2
          }
        },
        methods: {
          num1Input(event) {
            this.dnumber1 = event.target.value
            this.$emit('num1change', this.dnumber1)
          }
        },
        watch: {
          dnumber2(newValue, oldValue) {
            this.dnumber2 = newValue
            this.$emit('num2change', newValue)
          }
        }
      }
    }
  })
</script>

Component access - parent child access

this.$children: get all subcomponents, and the return value is array type

this.$refs (common): get the specified subcomponent according to the suffix. The return value is the object type. If it is not followed by the suffix, an empty object is returned by default

<div id="app">
  <!--Settings for child components in the parent component template ref suffix-->
  <cpn ref="aaa"></cpn>
</div>

<script>
  const app = new Vue({
    ...
    //Gets the specified child component in the parent component according to the ref suffix
    console.log(this.$refs.aaa);
  })
</script>

Parent access - child access

this.$parent: get the parent component. The parent component of the topmost component is the Vue instance, and the return value is the object type

this.$root: get the Vue instance of the root component, and the return value is the object type

Tags: Javascript Front-end Vue

Posted on Tue, 30 Nov 2021 15:21:50 -0500 by stevenrhiggins