Detailed explanation and in-depth application of vue component development - Part 1 (recommended intensive reading)
The Vue 2.0 series is based on component development. This part is divided into two parts. The first part is mainly about concepts, global components and local components, the application of components in modularization, and parent-child component communication. The next part is non-parent-child component communication, the use of component slots, dynamic components and handling of component boundary conditions. Please read patiently, I believe it will give you a deeper understanding and better application of component-based development.
Detailed explanation and in-depth application of vue component development - Part 2: Part 2 address
All codes in this article have been uploaded to GitHub: A-sketch123 -VueComponent-eng
1. Concept
Component development is to split the page into reusable components as much as possible, so that our code is more convenient to organize and manage during class, and the scalability is also stronger.
We can use this component as a custom element in a Vue root instance created by new Vue. If the component is not mounted under the instance of new Vue, it will not be rendered
2. Global components and local components
Global components:
Components created with Vue.component(component name, {method})
are globally registered, which means they can be used in any newly created Vue root instance (new Vue) template after registration
The globally registered behavior must happen before the root Vue instance (via new Vue ) is created
Partial components:
Use the components
attribute under new Vue, which can only be used under the mounted new Vue instance
<body>
<div id="app">
<global-cpn></global-cpn>
<local-cpn></local-cpn>
</div>
<h2>I split two Vue instances</h2>
<div id="app2">
<global-cpn></global-cpn>
<local-cpn></local-cpn>
</div>
<!-- Define the template for the global component -->
<template id="globalCpn">
<div>
<p>I am a global component, which can be used under multiple Vue instances</p>
</div>
</template>
<script>
// 1. Register a global component, note that the global component must be defined before the vue instance is created, otherwise it cannot be displayed and an error will be reported
Vue. component('global-cpn', {
template: '#globalCpn',
});
//Define the template of the local component in the variable to make the code more tidy and standardized
var localCpn = {
template:`
<div>
<p>I am a local component, which can only be used under the mounted new Vue instance</p>
</div>
` };
const app = new Vue({
el: '#app',
//Register local components under app
components: {
'local-cpn': localCpn,
},
});
const app2 = new Vue({
el: '#app2',
});
</script>
</body>
The effect is as follows: local components cannot be rendered under the app2 instance
The reason why the data of the component must be a function
A component's data option must be a function, so each instance can maintain an independent copy of the returned object
The data attribute must be a function, and this function returns an object
, which holds the data inside. In this way, each component instance has its own scope, and different components can be independent of each other and will not affect each other
If the data of the component is an object, when multiple components share a data source, all component data will change accordingly when one data changes, so the function return should be used to return a copy of the object, so that each instance has its own role area.
data(){
return{
count:0
}
},
template template error problem
In the template template, all html needs to be wrapped into an element (div), otherwise the following error may be reported
<template id="cpn">
<div>I am a child component</div>
<input type="text">
</template>
Correct should be:
<template id="cpn">
<div>
I am child component
<input type="text">
</div>
</template>
3. Using components in the module system
In the vue-cli project, a components file is usually built to store components
<script>
//Import the file where the component is located
import Footer from "./components/Footer.vue";
export default {
components: {
Footer,
},
};
</script>
4. Parent-child components
Component communication - father to son
Props are used to pass from parent to child, and child components use props attribute to receive data from parent components, and parent components use v-bind (:
) to dynamically pass data to child components
The value of props has two ways:
Method 1: string array
, the string in the array is the name when passing
Method 2: object
, the value of props can be set in the form of an object, such as default value, type and other attributes
The case of props:
Attribute names in HTML are case-insensitive, which means that when you use templates in DOM, camelCase (camel case) prop names need to use their equivalent kebab-case (dash-separated names) Naming
: (this rule also applies to component naming, components named in camel case must also be connected with dashes when used in HTML)
Use an array of strings:
<div id="demo">
<son-cpn :father-title="title"></son-cpn>
</div>
<script>
var sonCpn = {
template: ` <h4>{{fatherTitle}}</h4> `,
//props uses an array of strings
props: ['fatherTitle'],
};
const demo = new Vue({
el: '#demo',
data: {
title: 'I am the value passed from the parent component to the child component',
},
components: {
'son-cpn': sonCpn,
},
});
</script>
use object form:
<div id="demo">
<son-cpn :names="name"></son-cpn>
</div>
<template id="cpn">
<div>
<h4>{{mes}}</h4>
<ul>
<li v-for="item in names">{{item}}</li>
</ul>
</div>
</template>
<script>
// props use object mode
var sonCpn = {
template: '#cpn',
props: {
mes: {
type: String,
default: 'No value is passed to me, I am the default value',
},
names: {
type: Array,
//// When the type is an object or an array, the default value must be a function
default() {
return ['Zhang San', 'Li Si', 'F'];
},
//Required value
required: true,
},
},
};
const demo = new Vue({
el: '#demo',
data: {
name: ['A', 'B', 'C'],
},
components: {
'son-cpn': sonCpn,
},
});
</script>
The running result mes is the default value, and names is the value passed from the parent component
Component communication - child to father
Child components pass values to parent components using custom events:
In the child component, the event is triggered by $emit()
In the parent component, listen to the child component event through v-on
this.$emit('event name') cannot use camel case (with case), because the v-on event listener will be automatically converted to all lowercase in the DOM template (because HTML is case Insensitive), such as v-on:myEvent will become v-on:myevent - making myEvent impossible to be monitored, because the name of the event that is triggered needs to exactly match the name used to listen to this event Therefore, we recommend that you always use kebab-case event names
<div id="demo">
<!-- Parent component listens to custom events -->
<son-cpn @btn-click = 'sonclick'></son-cpn>
<h4>Clicks: {{total}}</h4>
</div>
<script src="../js/vue.js"></script>
<script>
var cpn = {
template:` <button @click="btnClick()">+</button> `,
data(){
return {
count :0
}
},
methods: {
btnClick(){
this.count++
//Subcomponents send custom events
this. $emit('btn-click', this. count )
}
}
}
const demo = new Vue({
el:'#demo',
data:{
total: 0
},
components: {
'son-cpn': cpn
},
methods: {
sonclick(count){
this.total = count
}
},
})
</script>
Access method of parent-child components: $refs
If you want to directly access a specific component, you can use $refs
Use of $refs: $refs and ref directives are usually used together
First, bind a specific ID number to a subcomponent through ref
Second, through this.$refs.ID
, you can access the bound specific component
<div id="app">
<cpn ref="child1"></cpn>
<cpn ref="child2"></cpn>
<button @click="btnClick">Access subcomponents through res</button>
</div>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
methods: {
btnClick() {
//Access the data of the child component through ref
console.log(this.$refs.child1.name);
//The parent component implements by calling the method of the child component so that the parent component can focus on the input box in the child component
this.$refs.child2.sonfocus();
},
},
components: {
cpn: {
template:`
<div>I am a child component
<input ref="ipt">
</div>`,
data() {
return {
name: 'I am the name of subcomponent child1',
};
},
methods: {
sonfocus() {
// Subcomponents can also use ref to access specified elements inside themselves
this.$refs.ipt.focus();
},
},
},
},
});
</script>
Before clicking:
After clicking:
$refs will only take effect after the component renders, and they are not reactive. This is only intended as an "escape hatch" for directly manipulating child components ——you should avoid accessing $refs in templates or computed properties
In addition, the parent component can also use $children
to access the child component, which returns an array type that contains all child component objects. Note that $children
does not guarantee order, nor is it reactive.
Direct access to parent components in subcomponents can be done through $parent
(official documents strongly recommend this method) These two methods are rarely used, and will not be applied here