preface
- This article is followed by a note
- This is mainly a Day3-Day4 content note
4, Component development
(1) I. content overview
- Understanding componentization
- Register components
- Components and other supplements
- Component data storage
- Parent child component communication
- Pass from parent to child
- Children pass to parents
- slot
(2) Understanding componentization
1. What is componentization?
- How people deal with complex problems:
- Anyone's logical ability to process information is limited
- Therefore, when facing a very complex problem, we are unlikely to deal with a lot of content at one time.
- However, we have a natural ability to disassemble problems.
- If you divide a complex problem into many small problems that can be handled, and then put it into the whole, you will find that the big problems will be solved easily.
- Componentization is a similar idea:
- If we put all the processing logic in a page together, the processing will become very complex and is not conducive to subsequent management and expansion.
- However, if we say that a page is divided into small function blocks, and each function block completes its own independent functions, then the management and maintenance of the whole page will become very easy.
2.Vue componentization idea
- Componentization is Vue Important ideas in JS
- 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 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.
- Therefore, component is a very important chapter in Vue development, which should be studied carefully.
(3) , registration components
1. (Master) basic steps of registering components
- The use of components is divided into three steps:
- Create component constructor
- Register components
- Use components.
- Let's see how to register components through code
- View run results:
- There seems to be no difference from using a div directly.
- But we can imagine that if such information is displayed in many places, can we directly use < My CPN > < / my CPN >?
- Basic use of components (global components)
<!-- The use of components is divided into three steps: 1.Create component constructor 2.Register components 3.Use components. --> <div id="app"> <!--3.stay Vue Use components within an instance--> <my-cpn></my-cpn> <my-cpn></my-cpn> <my-cpn></my-cpn> <my-cpn></my-cpn> <!-- If there is no content in the component, it can also be written as a single label <my-cpn/> --> <div> <div> <my-cpn></my-cpn> </div> </div> </div> <my-cpn></my-cpn> <script src="../js/vue.js"></script> <script> // 1. Create component constructor object extend() without s const cpnC = Vue.extend({ // The HTML code to be displayed where the template of the custom component is used to the component // *We need a div package at the outside template: ` <div> <h2>I'm the title</h2> <p>I am the content, Ha ha ha ha</p> <p>I am the content, Hehe hehe</p> </div>` }) // 2. Registration component (global registration) // Two parameters need to be passed: // 1. Tag name of the registered component (must be quoted) // 2. Component constructor Vue.component('my-cpn', cpnC) // The above two steps need to be performed before Vue instance creation const app = new Vue({ el: '#app', data: { message: 'How do you do' } }) </script>
2. (Master) steps of registering components
- What do the steps here mean?
- 1.Vue.extend():
- Call Vue Extend () creates a component constructor.
- Usually, when creating a component constructor, the template passed in represents the template of our custom component.
- The template is the HTML code to be displayed where the component is used.
- In fact, this is written in vue2 X is almost invisible in the document. It will directly use the syntax sugar we will talk about below, but this method will still be mentioned in many materials, and this method is the basis for learning the following methods.
- 2.Vue.component():
- Call Vue Component () is to register the component constructor as a component and label it with a component name.
- Therefore, two parameters need to be passed: 1. Register the tag name of the component; 2. Component constructor
- 3. The component must be mounted under a Vue instance, otherwise it will not take effect. (see figure below)
- Let's look at the following. I used < My CPN > < / my CPN > three times
- The third time did not actually take effect:
(4) (Master) other supplementary components
1. Global and local components
- When we call Vue When component () registers a component, the registration of the component is global
- This means that the component can be used in any Vue example.
- If the registered component is mounted in an instance, it is a local component
Code:
<div id="app"> <cpn></cpn> <cpn></cpn> <cpn></cpn> </div> <div id="app2"> <cpn></cpn> </div> <script src="../js/vue.js"></script> <script> // 1. Create a component constructor const cpnC = Vue.extend({ template: ` <div> <h2>I am a global component</h2> <p>I am the content,Ha ha ha</p> </div> ` }) // 2. Register components (the component registers global components, which means that it can be used under multiple Vue instances, such as app and app2 can use cpn) // Vue.component('cpn', cpnC); // ' Label name must be enclosed in quotation marks' // Question: how can a registered component be a local component? Mount in an instance const app = new Vue({ el: '#app', data: { message: 'How do you do' }, components: { // Tag name when using component: component constructor // 'CPN': the tag name of a cpnc local component can be either with or without quotation marks cpn: cpnC } }) const app2 = new Vue({ el: '#app2' }) </script>
- Supplement: component name naming convention
- 1. All lowercase, use dashes - connect
- You must use a {dash to separate the names when referencing this custom element,
- For example, < My component name >
- 2. Or hump naming
- Both naming schemes can be used when referencing this custom element.
- In other words, < My component name > and < mycomponentname > are acceptable
2. Parent and child components
- We saw the component tree earlier:
- There is a hierarchical relationship between components
- One of the most important relationships is the parent-child component relationship
- Let's look at this hierarchical relationship through how the code is composed:
- Parent child component incorrect usage: used in Vue instances in the form of child tags
- Because when the child component is registered with the components of the parent component, Vue will compile the modules of the parent component
- The content of the template has determined the HTML to be rendered by the parent component (equivalent to the content in the child component already exists in the parent component)
- < child CPN > < / child CPN > can only be recognized in the parent component.
- Similar to this usage, < child CPN > < / child CPN > will be ignored by the browser.
- Correct usage of parent and child components: register in the components of the parent component and use the child component label in the template +
code:
<div id="app"> <cpn2></cpn2> <!-- Incorrect usage of parent-child components: in the form of child labels Vue Used in instances --> <!--<cpn1></cpn1>--> <!-- Correct writing in template Used in <cpn1></cpn1> --> </div> <script src="../js/vue.js"></script> <script> // 1. Create the first component constructor (sub component) const cpnC1 = Vue.extend({ template: ` <div> <h2>I'm Title 1</h2> <p>I am the content, Ha ha ha ha</p> </div> ` }) // 2. Create a second component constructor (parent component) const cpnC2 = Vue.extend({ // 2.2 use < cpn1 > < / cpn1 > in template template: ` <div> <h2>I'm Title 2</h2> <p>I am the content, Hehe hehe</p> <cpn1></cpn1> </div> `, // 2.1 register the sub component cpn1 in components components: { cpn1: cpnC1 } }) // root component const app = new Vue({ el: '#app', data: { message: 'How do you do' }, components: { cpn2: cpnC2 } }) </script>
3. Register component syntax
- The way to register components above may be a little cumbersome.
- To simplify this process, Vue provides a syntax sugar for registration.
- The main reason is to omit calling Vue Instead, you can directly use an object instead.
- Syntax: register global and local components:
Code:
<div id="app"> <cpn1></cpn1> <cpn2></cpn2> </div> <script src="../js/vue.js"></script> <script> // The main reason is to omit calling Vue Instead, you can directly use an object instead // 1. Syntax of global component registration // * Vue. The component tag name must be quoted Vue.component('cpn1', { template: ` <div> <h2>I'm Title 1</h2> <p>I am the content, Ha ha ha ha</p> </div> ` }) // 2. Syntax for registering local components const app = new Vue({ el: '#app', data: { message: 'How do you do' }, components: { 'cpn2': { template: ` <div> <h2>I'm Title 2</h2> <p>I am the content, Interesting</p> </div> ` } } }) </script>
4. Separate writing of template
- Just now, we simplified the registration process of Vue components through syntax sugar. Another troublesome writing method is the writing method of template module.
- If we can separate the HTML and write it, and then mount it on the corresponding component, the structure will become very clear.
- Vue provides two ways to define HTML module content:
- Use < script > tags
- Use the < template > tag
code:
<div id="app"> <cpn></cpn> <cpn></cpn> <cpn></cpn> </div> <!--1.script label, be careful:Type must be text/x-template Then set it up id --> <script type="text/x-template" id="cpn"> <div> <h2>I'm the title</h2> <p>I am the content,Ha ha ha</p> </div> </script> <!--2.template label--> <template id="cpn"> <div> <h2>I'm the title</h2> <p>I am the content,Interesting</p> </div> </template> <script src="../js/vue.js"></script> <script> // 1. Register a global component Vue.component('cpn', { template: '#cpn '/ / need to add selector }) const app = new Vue({ el: '#app', data: { message: 'How do you do' } }) </script>
- supplement
(5) . component data storage
1. Can the component access Vue instance data?
- A component is a package of a single functional module:
- This module has its own HTML template and its own data attribute.
- Where is the data stored in the component? In the Vue instance at the top level?
- Let's test whether the component can directly access the data in the Vue instance
- We find that we can't access it, and even if we can access it, if we put all the data in the Vue instance, the Vue instance will become very bloated.
- Conclusion: Vue components should have their own place to save data.
2. Storage of component data
- Where is the component's own data stored?
- The component object also has a data attribute (it can also have attributes such as methods, which we can use below)
- Only the data attribute must be a function
- And this function returns an object, which holds data
<div id="app"> <cpn></cpn> <cpn></cpn> <cpn></cpn> </div> <template id="cpn"> <div> <h2>{{title}}</h2> <p>I am the content,Interesting</p> </div> </template> <script src="../js/vue.js"></script> <script> // 1. Register a global component Vue.component('cpn', { template: '#cpn', data() { return { title: 'abc' } } }) // Components cannot directly access data in Vue instances const app = new Vue({ el: '#app', data: { message: 'How do you do', // Title: 'I'm the title' } }) </script>
3. (understand) why is it a function?
- Why does data have to be a function in a component?
- First, if it is not a function, Vue will directly report an error.
- Secondly, 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.
code:
<!--Component instance object--> <div id="app"> <cpn></cpn> <cpn></cpn> <cpn></cpn> </div> <template id="cpn"> <div> <h2>Current count: {{counter}}</h2> <button @click="increment">+</button> <button @click="decrement">-</button> </div> </template> <script src="../js/vue.js"></script> <script> // 1. Register components const obj = { counter: 0 } Vue.component('cpn', { template: '#cpn', // data() { // return { // counter: 0 // } // }, data() { // Will change together return obj }, methods: { increment() { this.counter++ }, decrement() { this.counter-- } } }) const app = new Vue({ el: '#app', data: { message: 'How do you do' } }) </script> <script> const object = { name: 'why', age: 18 } // function abc() { // Share an object // return object; // } function abc() { // Each call to the function returns a new object return { name: 'why', age: 18 } } let obj1 = abc(); let obj2 = abc(); let obj3 = abc(); obj1.name = 'kobe' console.log(obj2); console.log(obj3); </script>
- Supplement (combined with network data)
-
Object is a reference data type. If function is not used to return, the data of each component is the same address in memory. If one data changes, others also change;
-
JavaScript has only functions to form the scope (note that understanding the scope, only function {} forms the scope, and object {} and if() {} do not form the scope). When data is a function, each component instance has its own scope, and each instance is independent of each other and will not affect each other.
-
The data in the component is written as a function, and the data is defined in the form of function return value. In this way, every time the component is reused, a new data will be returned, which is similar to creating a private data space for each component instance, so that each component instance can maintain its own data.
-
If it is simply written in the form of an object, all component instances share a share of data, resulting in a result that everything will change if it changes.
-
Therefore, the data of the vue component must be a function. This is due to the features of js, which has nothing to do with the design of vue itself.
-
(6) Communication between parent and child components (data transmission)
- In the previous section, we mentioned that child components cannot reference the data of parent components or Vue instances.
- However, during development, some data often needs to be transferred from the upper layer to the lower layer:
- For example, in a page, we request a lot of data from the server.
- Some of the data is not displayed by the large components of our whole page, but by the following sub components.
- At this time, the sub component will not send a network request again, but directly let the large component (parent component) pass the data to the small component (sub component).
- How to communicate between parent and child components? Vue official mentioned
- Pass data to child components through props (parent to child)
- Send message to parent component through event (child to parent)
- In the following code, I directly regard the Vue instance as the parent component and include child components to simplify the code.
- In real development, the communication process between Vue instance and sub component is the same as that between parent component and sub component.
(7) , (Master) pass -- props from parent to child
1. Basic usage of props
- 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:
- Method 1: string array. The string in the array is the name when passing.
- Method 2: object. The object can set the type during transmission, or set the default value, etc.
- Let's first look at the simplest props delivery:
Code:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div id="app"> <!--<cpn v-bind:cmovies="movies"></cpn>--> <!-- No, v-bind Write it directly for prop Pass a static value, that is movies Not a variable, but a string --> <!--<cpn cmovies="movies" cmessage="message"></cpn>--> <!-- Step 2 passed:cmessage="message" take data The data in is passed to the subcomponent props --> <cpn :cmessage="message" :cmovies="movies"></cpn> </div> <!-- Subcomponents --> <template id="cpn"> <div> <!-- Step 3 will props The values in are displayed in subcomponents --> <ul> <li v-for="item in cmovies">{{item}}</li> </ul> <h2>{{cmessage}}</h2> </div> </template> <script src="../js/vue.js"></script> <script> // Father to son: props // -------Subcomponents------ const cpn = { template: '#cpn', // Subcomponents receive this value through prop. We can access this value in the component instance, just as we can access the value in data /* ***Step 1 * * * define props in sub components */ // ****Method 1: string array. The string in the array is the name when passing (the variable name to be referenced later) // Props: ['cmovies','cmessage '], / / do not treat the element as a string, but as an array data() { return {} } } // -----Parent component----- const app = new Vue({ el: '#app', data: { message: 'How do you do', movies: ['dominant sea power', 'One Piece', 'Haier brothers '] }, components: { cpn } }) </script> <!-- Steps: 1.Write in sub assembly props 2.Label the subassembly with v-bind <cpn v-bind:props Name defined in="Parent component data Data name"></cpn> 3.take props The values in are displayed in subcomponents --> <!-- Factory function 1,It is a function. 2,It is used to create objects. 3 ,Like a factory, the functions "produced" are "standard parts" (with the same attributes) --> </body> </html>
2.props data verification -- object writing
- Earlier, our props option was to use an array.
- We said that in addition to arrays, we can also use objects. When we need to verify the type of props, we need object writing.
- What data types are supported for validation?
- String
- Number
- Boolean
- Array
- Object
- Date
- Function
- Symbol
- When we have a custom constructor, validation also supports custom types
Code:
// ***Method 2: object. The object can set the type when passing, or set the default value, etc. - > when it is necessary to verify the type of props props: { // 1. Type restrictions // Basic type check (` null 'and ` undefined' will pass any type verification) // cmovies: Array, // cmessage: String, // Multiple possible types // propB: [String, Number], // 2. Provide some default values and required values cmessage: { type: String, default: 'aaaaaaaa', required: true // Required string }, // When the type is an object or array, the default value must be a factory function cmovies: { type: Array, default () { return { message: 'hello' } } }, // Custom validation function propF: { validator: function (value) { // This value must match one of the following strings return ['success', 'warning', 'danger'].indexOf(value) !== -1 } } },
3. Hump identification in props
- attribute names in HTML are case insensitive, so browsers interpret all uppercase characters as lowercase characters. This means that when you use the template in DOM, the prop name of camelCase (hump naming method) needs to be named with its equivalent kebab case (DASH delimited naming):
<div id="app"> <!-- v-bind Hump is not supported and needs to be replaced by - --> <cpn :c-info="info" :child-my-message="message" v-bind:class></cpn> </div> <template id="cpn"> <div> <h2>{{cInfo}}</h2> <h2>{{childMyMessage}}</h2> </div> </template> <script src="../js/vue.js"></script> <script> const cpn = { template: '#cpn', props: { // Use hump here: c-info="info" use hump there- cInfo: { type: Object, default () { return {} } }, childMyMessage: { type: String, default: '' } } } const app = new Vue({ el: '#app', data: { info: { name: 'why', age: 18, height: 1.88 }, message: 'aaaaaa' }, components: { cpn } }) </script>
- supplement
(8) , (Master) pass custom events from child to parent
1. Transfer from child to parent
- props is used to transfer data from the parent component to the child component. Another common method is that the child component transfers data or events to the parent component.
- How should we deal with it? At this time, we need to use custom events to complete.
- When do I need to customize events?
- When a child component needs to pass data to the parent component, a custom event is used.
- The v-on we learned earlier can be used not only for listening to DOM events, but also for custom events between components.
- Custom event flow:
- In the subcomponent, $emit() is used to trigger events.
- In the parent component, listen for child component events through v-on.
- Let's take a simple example:
- We have made a two button + 1 and - 1 before. Click it to modify the counter.
- The whole process of our operation is still completed in the child component, but the subsequent display is handed over to the parent component.
- In this way, we need to pass the counter in the child component to a property of the parent component, such as total.
Code:
<!--Parent component template--> <div id="app"> <!-- 3.In the parent component child tag, click v-on To listen for sub component events and add a processing method corresponding to the event --> <cpn @item-click="cpnClick"></cpn> </div> <!--Subcomponent template--> <template id="cpn"> <div> <!-- 1.Create a button in the sub component and bind a click event to the button --> <button v-for="item in categories" @click="btnClick(item)"> {{item.name}} </button> </div> </template> <script src="../js/vue.js"></script> <script> // Child to parent custom event // Subcomponents const cpn = { template: '#cpn', data() { return { categories: [{ id: 'aaa', name: 'Popular recommendation' }, { id: 'bbb', name: 'Mobile digital' }, { id: 'ccc', name: 'Household appliances' }, { id: 'ddd', name: 'Computer office' }, ] } }, methods: { btnClick(item) { // Launch events: custom events // 2. In the subcomponent, trigger the event through $emit() this.$emit('item-click', item) // be careful!!!! The $emit event name here should not be written as hump!!! In the scaffold, it can be compiled into a component object render function first } } } // Parent component const app = new Vue({ el: '#app', data: { message: 'How do you do' }, components: { cpn }, methods: { cpnClick(item) { // The parameters here are used to receive the data from the sub component console.log('cpnClick', item); } } }) </script>
2. Parent to child -- combined with two-way binding case
- demand
-
The subcomponent input is bound to v-model. When the input changes, number1 and number2 in props change, and num1 and num2 in vue instance data change
-
As soon as dnumber1 of the subcomponent data is changed, dnumber2 will be * 100. As soon as dnumber2 is changed, it will be dummy / 100
-
-
analysis
-
The previous v-model is bound to the data in vue instance data
-
If the v-model is bound to the value in props, an error will be reported (the value in props should preferably be modified through the parent component)
-
v-model does not bind the value in propsReplace with data or computedAssign Number1 and number2 to dnumber1 and dnumber2 of data respectively
-
code:
<!-- Parent component --> <div id="app"> <h3>Parent component</h3> <h3>-----num1----</h3> <h3>{{num1}}</h3> <h3> -----num2----</h3> <h3>{{num2}}</h3> <hr> <cpn :number1="num1" :number2="num2" @num1change="num1change" @num2change="num2change" /> </div> <!-- Subcomponents --> <template id="cpn"> <div> <!-- An error will be reported if it is written in this way. It should be modified by the parent component to avoid direct modification props Value of --> <!-- <input v-model="number1" type="text" /> <input v-model="number2" type="text" /> --> <h3>Subcomponents</h3> <h3> -----number1----</h3> <!-- Why? props Will change with it? -> number1 Bound is the parent component num1 --> <h2>props:{{number1}}</h2> <h2>data:{{dnumber1}}</h2> <!--<input type="text" v-model="dnumber1">--> <!-- v-model The essence of@input Incoming value --> <input type="text" :value="dnumber1" @input="num1Input"> <h3>-----number2----</h3> <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> // Subcomponents const 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 dnumber1 this.dnumber1 = this.dnumber2 / 100; this.$emit('num1change', this.dnumber1); } } } // Parent component const app = new Vue({ el: '#app', data: { num1: 1, num2: 0 }, methods: { num1change(value) { // The value passed is a string type, which needs to be converted into a number this.num1 = parseFloat(value) }, num2change(value) { this.num2 = parseFloat(value) } }, components: { cpn } }) </script>