Component development
What is componentization?
In the face of the treatment of complex problems, disassemble the problems into many small problems that can be handled, and then put them into the whole, you will find that the big problems will be solved easily.
The idea of componentization is similar:
If we implement a page with very complex page structure and logic, it will become very complex if we implement it all together, and it is not conducive to subsequent maintenance and iterative functions.
However, if we divide the page into small function blocks at this time, and each function block can complete its own independent functions, the maintenance and iteration after the whole page will also become very easy.
Advantages of component-based development: high maintainability and high reusability
Vue componentization idea
Componentization is an important idea of Vue
It provides an abstraction so that we can develop independent reusable small components to construct our applications.
Any application will be abstracted into a component tree.
Application development of componentization idea:
With the idea of componentization, we should make full use of it in future development.
Split the page into small and reusable components as much as possible.
This makes our code more convenient to organize and manage, and more extensible.
Global component
Through Vue.component('component name ', {}), global components are registered through this method, that is, they can be used in the mounting area of any newly created Vue instance after re registration.
<body> <div id="app"> <my-con></my-con> <div> <my-con></my-con> </div> </div> <my-con></my-con> </body> <script> Vue.component('my-con', { template: '<section><h3>Component title</h3><p>Component content</p></section>' }) const vm = new Vue({ el: '#app' }) </script>
In the above case, the component my con outside < div id = "app" >... < / div > is not replaced with the real page structure of the component because new Vue() is mounted on the node with id=app and is not labeled on this node, so it will not be affected by Vue.
Local component
Components registered through Vue.component are called global components. It can be used anywhere. Global registration is often not ideal. For example, if you use a build system like webpack, registering all components globally means that even if you no longer use a component, it will still be included in your final build results. This results in a needless increase in JavaScript downloaded by users.
Register local components
<body> <div id="app"> <my-con></my-con> <div> <my-con></my-con> </div> </div> <div id="app1"> <my-con1></my-con1> </div> </body> <template id="template1"> <section> <h3>Component title</h3> <p>Component content</p> </section> </template> <template id="template2"> <section> <h3>Component title B</h3> <p>Component content B</p> </section> </template> <script> var componentA = { template: '#template1' } var componentB = { template: '#template2' } const vm = new Vue({ el: '#app', components: { 'my-con': componentA } }) const vm1 = new Vue({ el: '#app1', components: { 'my-con1': componentB } }) </script>
Parent and child components
There are hierarchical relationships between components, and one of the most important relationships is parent-child component relationship.
Can components access Vue instance data?
What should a component do if it wants to use data to define its own attributes to save data?
- The component object also has a data attribute (there are also methods and other attributes, which we can use below)
- Only the data attribute must be a function, and the function returns an object that holds data
<body> <div id="app"> <my-con></my-con> <div> <my-con></my-con> </div> </div> <div id="app1"> <my-con1></my-con1> </div> </body> <template id="template1"> <section> <h3>{{title}}</h3> <p>Component content</p> </section> </template> <template id="template2"> <section> <h3>{{title}}B</h3> <p>Component content B</p> <aa></aa> </section> </template> <script> var componentA = { template: '#template1', data() { return { title: 'zujianbiaoti' } } } var componentB = { template: '#template2', data() { return { title: 'zj' } }, components: { 'aa': { template: '<div>aa</div>' } } } const vm = new Vue({ el: '#app', data: {title: 'Component title'}, components: { 'my-con': componentA } }) const vm1 = new Vue({ el: '#app1', components: { 'my-con1': componentB } }) </script>
Why does data have to be a function in a component?
The reason is that Vue allows each component object to return a new object, because if it is the same object, the components will affect each other after being used multiple times.
Communication between parent and child components
Pass from parent to child
In the component, use the option props to declare the data to be received from the parent.
There are two ways to the value of props:
String array. The string in the array is the name when passing.
Object. For an object, you can set the type (String, Number, Boolean, Array, object, Date, Function, Symbol) during transfer, or set the default value.
<body> <div id="app1"> <my-con1></my-con1> </div> </body> <template id="template2"> <section> <h3>{{title}}B</h3> <p>Component content B</p> <!-- my-con1 In component aa assembly --> <aa v-bind:parent-txt="childtxt"></aa> </section> </template> <script> var componentB = { template: '#template2', data() { return { title: 'zj', childtxt: 'child text' } }, components: { 'aa': { template: '<div>{{parentTxt}}</div>', props: ['parentTxt'] } } } const vm1 = new Vue({ el: '#app1', components: { 'my-con1': componentB } }) </script>
Children pass to parents
The parent component passes data to the child component through custom events
<body> <div id="app1"> <my-con1></my-con1> </div> </body> <template id="template2"> <section> <h3>{{title}}B</h3> <p>Component content B</p> <aa v-bind:parent-txt="childtxt" v-on:changetitle="changeTitle"></aa> </section> </template> <script> var componentB = { template: '#template2', data() { return { title: 'zj', childtxt: 'child text' } }, components: { 'aa': { template: '<div v-on:click="change">{{parentTxt}}</div>', props: ['parentTxt'], methods: { change() { this.$emit('changetitle', { a: 1 }) } } } }, methods: { changeTitle(obj) { console.log(obj) this.title = obj.a } } } const vm1 = new Vue({ el: '#app1', components: { 'my-con1': componentB } }) </script>
Case:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div id="app"> <cpn :number1="num1" :number2="num2" @num1change="num1change" @num2change="num2change"/> </div> <template id="cpn"> <div> <h2>props:{{number1}}</h2> <h2>data:{{dnumber1}}</h2> <!--<input type="text" v-model="dnumber1">--> <input type="text" :value="dnumber1" @input="num1Input"> <h2>props:{{number2}}</h2> <h2>data:{{dnumber2}}</h2> <!--<input type="text" v-model="dnumber2">--> <input type="text" :value="dnumber2" @input="num2Input"> </div> </template> <script src="../js/vue.js"></script> <script> const app = new Vue({ el: '#app', data: { num1: 1, num2: 0 }, methods: { num1change(value) { this.num1 = parseFloat(value) }, num2change(value) { this.num2 = parseFloat(value) } }, components: { cpn: { template: '#cpn', props: { number1: Number, number2: Number }, data() { return { dnumber1: this.number1, dnumber2: this.number2 } }, methods: { num1Input(event) { // 1. Assign value in input to dnnumber this.dnumber1 = event.target.value; // 2. Issue an event so that the parent component can modify the value this.$emit('num1change', this.dnumber1) // 3. Modify the value of dnumber2 at the same time this.dnumber2 = this.dnumber1 * 100; this.$emit('num2change', this.dnumber2); }, num2Input(event) { this.dnumber2 = event.target.value; this.$emit('num2change', this.dnumber2) // Also modify the value of dnumber2 this.dnumber1 = this.dnumber2 / 100; this.$emit('num1change', this.dnumber1); } } } } }) </script> </body> </html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div id="app"> <cpn :number1="num1" :number2="num2" @num1change="num1change" @num2change="num2change"/> </div> <template id="cpn"> <div> <h2>props:{{number1}}</h2> <h2>data:{{dnumber1}}</h2> <input type="text" v-model="dnumber1"> <h2>props:{{number2}}</h2> <h2>data:{{dnumber2}}</h2> <input type="text" v-model="dnumber2"> </div> </template> <script src="../js/vue.js"></script> <script> const app = new Vue({ el: '#app', data: { num1: 1, num2: 0 }, methods: { num1change(value) { this.num1 = parseFloat(value) }, num2change(value) { this.num2 = parseFloat(value) } }, components: { cpn: { template: '#cpn', props: { number1: Number, number2: Number, name: '' }, data() { return { dnumber1: this.number1, dnumber2: this.number2 } }, watch: { dnumber1(newValue) { this.dnumber2 = newValue * 100; this.$emit('num1change', newValue); }, dnumber2(newValue) { this.number1 = newValue / 100; this.$emit('num2change', newValue); } } } } }) </script> </body> </html>
Access mode of parent-child components
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 same component.
Parent component accessing child components: Using
c
h
i
l
d
r
e
n
or
children or
children or references reference
Child component accessing parent component: use $parent
Let's take a look first
c
h
i
l
d
r
e
n
of
interview
ask
t
h
i
s
.
children visit this
this.children is an array type that contains all child component objects.
Here, we take out the message status of all sub components through a traversal.
c
h
i
l
d
r
e
n
of
lack
Sink
:
through
too
children's defects: Pass
Defects of children: when accessing subcomponents through children, it is an array type, and the subcomponents must be accessed through index values.
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:
r
e
f
s
and
r
e
f
finger
order
through
often
yes
one
rise
send
use
of
.
first
before
,
I
Guys
through
too
r
e
f
to
some
one
individual
son
group
piece
Bind
set
one
individual
special
set
of
I
D
.
his
second
,
through
too
t
h
i
s
.
The refs and ref instructions are usually used together. First, we bind a specific ID to a sub component through Ref. Secondly, through this
The refs and ref instructions are usually used together. First, we bind a specific ID to a sub component through Ref. Secondly, you can access the component through this.refs.ID.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div id="app"> <cpn></cpn> <cpn></cpn> <cpn ref="aaa"></cpn> <button @click="btnClick">Button</button> </div> <template id="cpn"> <div>I am a subcomponent</div> </template> <script src="../js/vue.js"></script> <script> const app = new Vue({ el: '#app', data: { message: 'How do you do' }, methods: { btnClick() { // 1.$children // console.log(this.$children); // for (let c of this.$children) { // console.log(c.name); // c.showMessage(); // } // console.log(this.$children[3].name); // 2. $refs = > object type. The default is an empty object ref='bbb ' console.log(this.$refs.aaa.name); } }, components: { cpn: { template: '#cpn', data() { return { name: 'I'm a subcomponent name' } }, methods: { showMessage() { console.log('showMessage'); } } }, } }) </script> </body> </html>
How the child accesses the parent
If we want to directly access the parent component in the child component, we can
p
a
r
e
n
t
notes
meaning
matter
term
:
all
Tube
stay
V
u
e
open
hair
in
,
I
Guys
Allow
Promise
through
too
parent note: although in Vue development, we allow
Parent note: Although we allow parent access to parent components in Vue development, 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 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, it is even worse to directly modify the state of the parent component through $parent. Then the state of the parent component will become erratic, which is not conducive to my debugging and maintenance.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div id="app"> <cpn></cpn> </div> <template id="cpn"> <div> <h2>I am cpn assembly</h2> <ccpn></ccpn> </div> </template> <template id="ccpn"> <div> <h2>I am a subcomponent</h2> <button @click="btnClick">Button</button> </div> </template> <script src="../js/vue.js"></script> <script> const app = new Vue({ el: '#app', data: { message: 'How do you do' }, components: { cpn: { template: '#cpn', data() { return { name: 'I am cpn Component name' } }, components: { ccpn: { template: '#ccpn', methods: { btnClick() { // 1. Access parent component $parent // console.log(this.$parent); // console.log(this.$parent.name); // 2. Access the root component $root console.log(this.$root); console.log(this.$root.message); } } } } } } }) </script> </body> </html>
Modular slot
Basic use of slot
The function of the slot is to make the component more extensible. Label pairs are directly placed where the component template needs to be
<template id="cpn"> <div> <div>I'm a component </div> <slot></slot> </div> </template>
Principles of encapsulation
Extract commonness, retain individuality, and reserve slot s for parts of individuality
Use of slots
<body> <!--Parent component template--> <div id="app"> <cpn> <!--The label filled in the component will be automatically inserted into the slot--> <button>case</button> </cpn> <cpn><input type="text"></cpn> <cpn></cpn> </div> <!--Subcomponent template--> <template id="cpn"> <div> <div>I'm a component </div> <slot></slot> </div> </template> <script type="text/javascript"> var app=new Vue({ el:"#app", data:{ message:'hello world' }, methods:{ }, components:{ 'cpn':{ template:"#cpn", } }, } ); </script> </body>
Default value for slot
The tag inserted between the slot tag pairs of the template will become the default value of the slot. If the corresponding tag is not inserted between the custom component tag pairs in html, the default tag of the slot content will be used
- If there are multiple values, they will be used as replacement elements when they are put into the component for replacement at the same time
<body> <!--Parent component template--> <div id="app"> <cpn> <!--The label filled in the component will be automatically inserted into the slot--> <button>case</button> </cpn> <cpn><input type="text"></cpn> <cpn></cpn> </div> <!--Subcomponent template--> <template id="cpn"> <div> <div>I'm a component </div> <!--Sets the default label for the slot--> <slot><button>Default button in template</button></slot> </div> </template> <script type="text/javascript"> var app=new Vue({ el:"#app", data:{ message:'hello world' }, methods:{ }, components:{ 'cpn':{ template:"#cpn", } }, } ); </script> </body>
Named slots are used
When defining multiple slots, solve the problem of how to call
- Directly define a name attribute for the slot tag
- Any slot without the name attribute will be replaced. If there is a name attribute, it will be indicated to be replaced
<slot name='cneter'><span>Middle text</span></slot>
- In the custom component applied in html, when replacing a slot, set the slot attribute for the replacement tag, and the attribute value is the value of the response name defined in the template
<body> <!--Parent component template--> <div id="app"> <cpn> <span slot="center">Replaced text</span> </cpn> </div> <!--Subcomponent template--> <template id="cpn"> <div> <div>I'm a template</div> <!--Sets the default label for the slot--> <slot name='left'><span>Text on the left</span></slot> <slot name='center'><span>Middle text</span></slot> <slot name='right'><span>Text on the right</span></slot> </div> </template> <script type="text/javascript"> var app=new Vue({ el:"#app", data:{ message:'hello world' }, methods:{ }, components:{ 'cpn':{ template:"#cpn", } }, } ); </script> </body>
Compiled scope
The data compiled by the instance is always found in the instance
Component compiled data, find
<body> <!--Parent component template--> <div id="app"> <cpn v-show="isshow"> </cpn> </div> <!--Subcomponent template--> <template id="cpn"> <div> <div>I'm a template</div> </div> </template> <script type="text/javascript"> var app=new Vue({ el:"#app", data:{ isshow:true }, methods:{ }, components:{ 'cpn':{ template:"#cpn", data(){ return { isshow:false } } } }, } ); </script> </body>
Scope slot
1. [suggestion] uniformly wrap the contents of the used slot with template
2. Uniform format v-slot: [use default if there is no slot name] = [take the name of xx domain name casually and use the value from xx. Slot]
3. Syntax: sugar # slot name = action domain name
4. = the scope domain name does not have a scope slot. You can not write the scope slot. It is matched with slot: XX = ooo –
The parent component replaces the label of the slot, but the content is provided by the child component
I heard that slot copy was abandoned after Vue 2.6, but pro test 2.6 can be used
- 1. Create data in subcomponents
components:{ 'cpn':{ template:"#cpn", data(){ return { pLanguages:['javascript','java','python','c#'] } } } },
2. Create a slot in the template file, and create a custom data attribute in the slot label to point to the data of the sub component
<template id="cpn"> <div> <div> //Here, an attribute pointing to the data of sub components is defined in the slot: landata <slot :landata="pLanguages"> <ul> <li v-for="item in pLanguages">{{item}}</li> </ul> </slot> </div> </div> </template>
3. Using custom components in root in html
To use custom components, use the template template label and set the slot scope value to slot
The application data uses slot.landata, where landata is the custom attribute name set in the template
<div id="app"> <cpn> </cpn> <cpn> <!--Need to get the name of the subcomponent pLanguages--> <template slot-scope="slot"> <span v-for='item in slot.landata'>{{item}}-</span> </template> </cpn> </div>
Complete code
<body> <!--Parent component template--> <div id="app"> <cpn> </cpn> <cpn> <!--Need to get the name of the subcomponent pLanguages--> <template slot-scope="slot"> <span v-for='item in slot.landata'>{{item}}-</span> </template> </cpn> </div> <!--Subcomponent template--> <template id="cpn"> <div> <div> <slot :landata="pLanguages"> <ul> <li v-for="item in pLanguages">{{item}}</li> </ul> </slot> </div> </div> </template> <script type="text/javascript"> var app=new Vue({ el:"#app", data:{ isshow:true }, methods:{ }, components:{ 'cpn':{ template:"#cpn", data(){ return { pLanguages:['javascript','java','python','c#'] } } } }, } ); </script> </body>