1, Component and reuse
Attention
- Hump naming is not supported for tag names representing components. It is recommended to use - separator to separate words
- The props attribute of the subcomponent does not support hump when receiving data in HTML. It is recommended to use the - separator to separate words
- The custom event of transmitting data from child to parent does not support hump, nor does it support - it is recommended to use lowercase
- The content of the component must be wrapped with div, otherwise it cannot be rendered to the page
- Modifying props properties does not affect the data of the parent component, but if you want to modify props, you'd better modify it through the parent component, otherwise an error will be reported
- Data of Vue instances cannot be accessed inside the component.
1. Global component registration
//Global component registration: components registered globally can be used in the HTML code corresponding to any Vue instance <div> <my-component></my-component> </div> ---------------------------------------- Vue.component("my-component",{ template:"<div>Here is the content of the component</div>" }) const app = new Vue({ el:"#app "/ / to use a global component, you need to mount the DOM first, otherwise the component cannot be used in HTML code })
The following is the rendering:
2. Local component registration
(1) Register within the Vue root instance
(1)stay Vue In an instance of, you can use components To register the component content, so that the registered component can only be registered in the current Vue Instance corresponding HTML Used in code. -------------------------------------------------------------- <div id="app"> <my-child></my-child> </div> -------------------------------------------------------------- let child = { template: "<div>Here are the subcomponents</div>" } let app = new Vue({ el: '#app', components: { "my-child": child //In the components option, key is the name of the component and value is the component } });
(2) Register child components within the parent component
(1)Components can also be used components To nest registered components. <div id="app"> <my-father></my-father> </div> ------------------------------------- let child = { template: "<div>This is a subcomponent</div>" } let father = { template: ` <div> This is the parent component <my-child></my-child>//Registered subcomponents are used here </div> `, components: { 'my-child': child //The child component registered in the parent component cannot be used in the HTML corresponding to the Vue instance, but only in the parent component } } let app = new Vue({ el: '#app', components: { 'my-father': father } });
The following is the rendered structure diagram
3. Use template label
- Using the template tag template can make the code not bloated
el: '#app', components: { 'my-component':{ template:"<div>When there is too much component code, it will become bloated. You can use it at this time template label</div>" } }
- Use template
<div id="app"> <mycpn></mycpn> </div> <template id="my-template"> <div> This is used template Label components </div> </template> ------------------------------------------- let myTemplate = { template: "#my-template" } //Note: the template attribute corresponds to the id of the template tag let app = new Vue({ el: '#app', components: { mycpn: myTemplate } });
4.HTML syntax restricts the use of components
Explanation: only specific tags can be used in some tags. For example, table can only use TR and th. In this case, special attributes can be used to mount components
1.First, look at mounting without special properties <div id="app"> <table> <tbody> <my-component></my-component> </tbody> </table> </div> ----------------------------------------- Vue.component("my-component", { template: "<div>Here is the content of the component</div>" })
DOM diagram
Mount with special properties <div id="app"> <table> <tbody is="my-component"></tbody> </table> </div> ------------------------------------- Vue.component("my-component", { template: "<div></div>" })
DOM diagram
5. Component properties
- A component is a closed space. It has the template attribute. It can also have other attributes like vue instances, such as methods, data, computed, etc
- The data of vue instance cannot be accessed inside the component, so the component needs to have its own data, but it is different from the data of vue instance. The data inside the component must be a function and should return an object, in which the data is saved
<div id="app"> <my-component></my-component> </div> -------------------------------- Vue.component("my-component", { template: "<div>{{message}}</div>", data: function () { return { message: "Component content" } } })
- About why data needs to be a function
<div id="app"> <my-component></my-component> <my-component></my-component> </div> <template id="cpn"> <div> <p>Counter:{{count}}</p> <button @click="increment">+</button> <button @click="decrement">-</button> </div> </template> -------------------------------------------- Vue.component("my-component", { template: "#cpn", data() { return { count: 0 } }, methods: { increment() { this.count++; }, decrement() { this.count--; } } }) /* Whenever a component is used in HTML (in this example, the component is my component), the data function will be called once and an object will be returned, When modifying the data of the first counter, the data of the second counter will not be changed. Although the data saved by the objects they return are the same, the memory addresses of the objects are different and will not affect each other. This achieves a goal: component reuse, but modifying the data of one component will not have a chain reaction to other components. If you need a chain reaction between components, you can return an external object in return without creating an object and then return */ let obj = {count:0} data() { return obj }
2, Component communication
Explanation: component communication can be divided into parent-child component communication, brother component communication and cross level component communication
1. Pass data props from parent to child
- The main difference between the data returned by props and data functions is that props comes from the parent component, while the data of data is its own data, and the scope is the component itself. Both values can be used in the component.
- The child component cannot directly access the data of the parent component. Therefore, the parent component needs to pass the data to the child component.
(1)props uses arrays
Note: the props array is used to receive the data of the parent component. The elements in the array must be strings
- Let's first look at the basic usage. Use props to bind fixed values
<div id="app"> <my-component message="This is the data from the parent component"></my-component> //Generally, v-bind is used to bind the value of the parent component. This example is written dead. </div> <template id="cpn"> <div> {{message}} </div> </template> --------------------------------------------------------- Vue.component("my-component", { template: "#cpn", props: ["message"] })
DOM diagram
- props is used to receive the data of the parent component. When the data of the parent component changes, it will be dynamically passed to the child component.
<div id="app"> //4. Use the child component and transfer the data of the parent component vue instance to the child component, that is, cpn: through v-bind: child data = parent data <my-component :hobby="hobbies"></my-component> //These two input s are used to test the test code that will affect the child component when the parent component changes <input type="checkbox" v-model="hobbies" value="Mountain climbing">Mountain climbing <input type="checkbox" v-model="hobbies" value="play a ball">play a ball </div> //1. Create component template <template id="cpn"> <div> <ul> //5. Now that the data of the parent component has been received in the template of the child component, it can be used <li v-for="myHobby of hobby">{{myHobby}}</li> </ul> </div> </template> ------------------------------------------------------------ //2. Create a component instance and bind the component template const cpn = { template: "#cpn", props: ["hobby"] } let app = new Vue({ el: '#app', data: { hobbies: ["sing", "run", "game"]//This is the data of the parent component }, components: { //3. Use the cpn component in the vue instance. In this case, the vue instance is the parent component and cpn is the child component "my-component": cpn } });
DOM diagram
(2)props usage object (data validation)
- Data validation can verify the incoming data. If it does not meet the requirements, an error will be reported
<div id="app"> <my-cpn :message="message"></my-cpn> </div> <template id="cpnTemplate"> <div> {{message}} </div> </template> ---------------------------------------------- let cpn = { template: "#cpnTemplate", props: { message: { //Type data type for write validation type: String, //The default value here will be used when the parent component does not pass data default:"Default value", //This indicates whether data must be passed required: false, } } } /* Note: when the type is Array or Object, the default value cannot be written directly behind Instead, write the default function, which returns the default value type: Array/Object, default(){ return []/{} } */ let app = new Vue({ el: '#app', data: { message: "message", }, components: { 'my-cpn': cpn } });
2. Transfer data from child to parent
(1) Custom event $emit
- The child component passes data to the parent component with $emit
<div id="app"> /* 3.v-on You can not only listen to DOM events, but also listen to custom events. The custom event here is cpnclick, When listening to DOM events, event is automatically transmitted without writing parentheses, while custom events transmit data. The data here is product */ <cpn @cpnclick="cpnClick"></cpn> </div> <template id="cpn"> <div> //1. Traverse the sort category, listen for click events, and pass the current category <button v-for="product in sort" @click="btnClick(product)">{{product.name}}</button> </div> </template> ----------------------------------------------------- const cpn = { template: "#cpn", methods: { btnClick(product) { //2. Send data to the parent component through custom events. The first parameter is the event name and the second parameter is the data passed to the parent component this.$emit('cpnclick', product) } }, data() { return { sort: [ { id: "iPhone", name: "mobile phone" }, { id: "book", name: "book" }, ] } } } let app = new Vue({ el: '#app', methods: { cpnClick(product) { //4. This is the parent component, where the data passed by the child component has been received console.log(product.name); } }, components: { cpn, } }); //Note: custom events do not support humps and separators, and can only be all lowercase
3. v-model in component communication
(1) Use v-model to bind the data passed by the parent component
Note: because vue does not support modifying props in sub components, direct binding is not possible. You need to save the data of props into the data function of this component, and the data of the bound function is correct
<div id="app"> <cpn :test-value="parentValue"></cpn> </div> <template id="cpnTemplate"> <div> <h1>title</h1> <p>{{reValue}}</p> <p>{{testValue}}</p> //The reValue here is the same as the data output by testValue <input type="text" v-model="testValue">//An error will be reported when modifying. vue does not support modifying props in subcomponents <input type="text" v-model="reValue">//The modification will not be saved here. The modified data is data </div> </template> --------------------------------------------------- const cpn = { template: "#cpnTemplate", props: ["testValue"], data() { //Save the data received from the parent component in props to this component. return { reValue: this.testValue, } } } let app = new Vue({ el: '#app', data: { parentValue: "This is the test data" }, components: { cpn, } });
(1) When using v-model to change the data of child components, the parent component is also changed
<div id="app"> <p>Parent component data: {{total}}</p> //2. When the custom event of the sub component is input, the data bound with v-model will be assigned: the assigned value is the data passed from the custom event of the sub component <cpn v-model="total"></cpn> </div> <template id="cpn"> <div> <p>Subcomponent data: {{counter}}</p> <button @click="handleClick">+</button> </div> </template> ---------------------------------------------- const cpn = { template: "#cpn", data() { return { counter: 0 } }, methods: { handleClick() { this.counter++; //1. When the sub component data changes, an input event is generated and a data is passed this.$emit('input', this.counter); } } } let app = new Vue({ el: '#app', data: { total: 0, }, components: { cpn, } });
3, Component access
1. Central event bus
Explanation: to be added later
2. Parent chain and child component index
(1) Introduction to parent chain
$parent
//Do not use $parent to access the parent component. In fact, the child component cannot rely on the data of the parent component according to the specification, //Let alone modify it. You don't need $parent if you can //Therefore, $emit is still used for between parent and child components this.$parent.$parent.message = "Change parent message"
(2) Sub component index
$children
/* Yes, because it's unreliable to select resource elements according to the index, it's not what you want to choose after the index is changed */ this.$children[0]//Returns an array containing all subcomponents
$refs (key)
<div id="app"> <cpn ref="cpnA"></cpn> <cpn ref="cpnB"></cpn> <cpn ref="cpnC"></cpn> <button @click="enterCpn">Access subcomponents</button> </div> ------------------------------------------------- const app = new Vue({ el: '#app', methods: { enterCpn() { //$refs is an empty object at first, but after adding the ref attribute to the label when using the sub component, the corresponding component is added to the $refs object, and you can access it directly console.log(this.$refs.cpnA.message); } }, });
4, solt slot
1. Why use slots
Explanation: in order to improve the reusability and expansibility of components, the functions of components are determined externally
<template> <div> <nav>Navigation</nav> <button>Sign in</button> </div> </template> /* On the navigation bar, the login button is displayed when you are not logged in, but it is obviously inappropriate to reuse this component and display the login button after logging in At this time, the value of component reuse is reduced. At this time, you can use slot, which is to reserve a position for a part of the component What this position displays and what functions to do are determined by the outside, that is, the user */ <template> <div> <nav>Navigation</nav> <slot>What is written here depends on the specific situation</slot> </div> </template>
2. How to use slots to package components
- When using slot to encapsulate components, the same parts are extracted and written in the components, and different places are reserved as slots, that is, the commonalities are extracted and the differences are retained. No matter how reusable the components are and how many times they are reused, their structures are the same
3. How to use slots
(1) Basic use
<div id="app"> //2. The code written in the cpn tag will be displayed instead of the slot position <cpn><button>Sign in</button></cpn> </div> <template id="cpn"> <div> <nav>Navigation</nav> //1. A space is reserved here to display something or function when components are reused <slot></slot> </div> </template> ---------------------------------------- const cpn = { template: "#cpn", } const app = new Vue({ el: '#app', components: { cpn } });
DOM diagram
(2) Use slot defaults
<div id="app"> //2. When the code is written on the cpn tag, the default value of the slot will be overwritten <cpn><p>The slot is covered here button This default value</p></cpn> //3. No code is written inside the CPN tag to display the default value of the slot <cpn></cpn> </div> <template id="cpn"> <div> <p>Navigation</p> //1. When a code is written in the slot, this code is equivalent to the default value of the slot <slot><button>Sign in</button></slot> </div> </template>
DOM diagram
(3) Attention
Add: this method has a disadvantage. If a component consists of multiple slots, all slots will be assigned when assigning slots in the cpn tag. This is not the effect we want
<div id="app"> //2. When assigning a value to a slot, it will assign a value to both slots, //This is not the effect I want. I just want to assign a value to a slot. It's obviously unreasonable <cpn>1</cpn> <cpn>2</cpn> </div> <template> <div> //1. There are two slots here <slot>Navigation</slot> <slot></slot> </div> </template> //3. A named slot can be used at this time
4. Use of named slots
- Function: assign a value to a specific slot
<div id="app"> <cpn> //2. Replace the slot according to the name <span slot="left">Replaced the left slot</span> </cpn> </div> <template id="cpn"> <div> //1. Name the slot <slot name="left"><span>left</span></slot> <slot name="center"><span>middle</span></slot> <slot name="right"><span>right</span></slot> </div> </template> be careful: stay cpn When the replacement slot in the label is not replaced according to the slot name,It will only replace the unnamed slot.
(1) Attention
- When the replacement slot in the cpn tag is not replaced according to the slot name, it will only replace the slot without a name
5. Scope of compilation
Explanation: variables of corresponding components are used in the template. For example, both child components and parent components have a data called message. When message is used in the parent template, the message data of the parent component is bound. When message is used in the child template, the message of the child component is bound. The content of the parent component template is compiled within the scope of the parent component, and the content of the child component template is compiled within the scope of the child component
<div id="app"> //This is the vue instance scope. In this example, it acts as the parent component. Here, isShow uses the value true of the parent component, that is, the vue instance <cpn v-show="isShow"></cpn> </div> <template id="cpn"> //This is the scope of the subcomponent. The isShow here uses the value false of the subcomponent <div v-show="isShow"> <p>Subcomponents</p> </div> </template> -------------------------------------------------------- const cpn = { template: "#cpn", data() { return { isShow: false, } } } const app = new Vue({ el: '#app', data: { isShow: true, }, components: { cpn }
6. Scope slot
Explanation: the parent component replaces the label of the slot, but the content is provided by the child component.
Personal understanding: the data in the child component slot can be used in the parent component template, which is the function of the scope slot
<div id="app"> <cpn> /* Note: This is in the template of the parent component 5.When using the slot scope, you need to use the template template 6.scope="byChildData": The meaning of this sentence is to bind the slot of the sub component. byChildData is just a variable name, which can be written freely 7.byChildSlot: In this case, in the parent component, this value represents the child component slot, which can be understood as a reference to an object. byChildSlot is a reference and a slot is an object It can be used to access the data in the sub component slot 8.It should be noted that the data of the subcomponent cannot be accessed directly. The data of the slot is accessed here because the data in the subcomponent is bound to the slot, so it can be accessed here 9.slot="slotName": Represents the replacement of all slots called "slotName" */ <template scope="byChildSlot" slot="slotName"> {{byChildSlot.bookName}} </template> </cpn> </div> <template id="cpn"> <div> /* 1.Use slot s within the subcomponent template 2.name Attribute: name the slot 3.v-for: When traversing the data of the subcomponent itself, multiple slots called slotName will be generated 4.Use v-bind to bind the book name value to the book name variable */ <slot name="slotName" v-for="book of books" :book-name="book.name"></slot> </div> </template> ----------------------------------------------------------- const cpn = { template: "#cpn", data() { return { books: [ { name: "Data structure and algorithm" }, { name: "operating system" }, { name: "computer network" }, { name: "Principle of computer composition" } ] } } } const app = new Vue({ el: '#app', components: { cpn } });