preface
Why should there be componentization and modularization
In the process of business development of the company, the volume of the website is getting bigger and bigger, which is stacked with a large number of business logic codes. The codes of different business modules call each other and nest each other. The coupling between the codes is getting higher and higher, and the call logic will become more and more chaotic.
When a function needs to be upgraded, it often affects the whole body at the same time. Whether it is in DOM or JS logic level, we need a lot of energy to take into account the modification and adjustment of the old code, resulting in increased workload.
Overall, the sheer number of code stacks made readability, maintainability, and collaboration between different engineers very poor, and as the business grew more complex, we needed a way to keep it simple.
Change numerous for brief
The triviality of a page is reduced to the independent function of each block, and each separate block is combined, nested, and works together, which is the idea of componentization.
We can think of a page as a car, where components are individual parts that perform their own functions and are combined to form a car.
We can greatly reduce the coupling of various functions of the system, and improve the integration of internal functions. This greatly increases our readability and maintainability, reduces the coupling, reduces the complexity of our development, and improves the development efficiency. We’ll have more time to do what we love!
Designing components follows a principle: a component focuses on doing one thing and doing it well. (In steelmaking parlance: One is all, all is one)
Let’s learn the componentized development of Vue
What is a component
Components, like the js functions we normally write, have
- encapsulation
- reusability
- Single responsibility
It can extend HTML elements to encapsulate reusable HTML code, and we can think of components as custom HTML elements.
The component registration
Global registration
- through
component
Directive registers a component directly - The first parameter is the component name, and the second parameter is the component name
new Vue
Options, including data, etc component
An internal field is missingtemplate
Used to writehtml
structure- We can introduce the component as a label
- It is worth noting that we habitually name components with the big camel name
- And for the tag writing, we need to use the kebab naming convention (HTML is case insensitive)
<div id="app">
<component-a></component-a>
</div>
Copy the code
Vue.component("ComponentA", {
template: `<div>ComponentA</div>`
});
const app = new Vue({
el: '#app'
});
Copy the code
- We can also pass fields
template
The introduction of- At this point we can just use the big hump, there is no naming restriction
- use
template
It will also cause the objects within the target to be destroyedtemplate
Replace the contents of
<div id="app">I'm going to get killed</div>
Copy the code
Vue.component("ComponentA", {
template: `<div>ComponentA</div>`
})
const app = new Vue({
el: '#app'.template: `
{{msg}}
`.data: {
msg: 'hello world'}});Copy the code
Local registration
- We can declare an object through a field
components
Importing component usage
<div id="app"></div>
Copy the code
const ComponentB = {
template: `
ComponentB {{msg}}
`.data() {
return {
msg: 0}},methods: {
handleClick() {
this.msg++
}
},
}
Vue.component("ComponentA", {
components: {
ComponentB
},
template: `
ComponentA
`
})
const app = new Vue({
el: '#app'.template: `
{{msg}}
`.data: {
msg: 'hello world'}});Copy the code
Pay attention to the point
- Components must have root nodes (not required for Vue3)
- Data must be a function (because components are reusable, use functions to decouple them)
Component life cycle
What is the life cycle
The life cycle of a component is a set of hooks, also called hooks, which are common functions, from pre-mount to post-unmount
Why lifecycle
We often need to request data before mounting the component, or after adding the component, we need to enable functions under the global (window), such as timer, and we need to know when the component is unloaded. At this time, we need to use the life cycle of the component. We can think of it as the built-in component listening for events
What is the life cycle
- It consists of four sets: Create, mount, Updata, destroy, and before and after
- Through the following small case, we can clearly see how the execution order of the life cycle is, how does it work
- Components in the
mounted
Add it to view => we can see it
Vue.component("ComponentA", {
template: `
ComponentA {{count}}
`.data() {
return { count: 0}},methods: {
handleAdd() {
this.count++
}
},
beforeCreate() {
console.log('Before creation -a');
},
created() {
console.log('after creation -a');
},
beforeMount() {
console.log('Pre-mount -A');
},
mounted() {
console.log('After mount -a');
},
beforeUpdate() {
console.log('Pre-update -a');
},
updated() {
console.log('After update -a');
},
beforeDestroy() {
console.log('Pre-unloading -A');
},
destroyed() {
console.log('After uninstallation - A'); }})const app = new Vue({
el: '#app'.template: `
.data: {
handleShow: true
},
beforeCreate() {
console.log('Before creation');
},
created() {
console.log('After creation');
},
beforeMount() {
console.log('Pre-mount');
},
mounted() {
console.log('After mount'); }});Copy the code
Communication between components
How do we pass parameters inside a component? How do you return parameters? In other words, how do components work together? Let’s talk about communication between components
props
- When we need to pass parameters to a component, we use props to pass parameters
- Through the field
props
Receives parameters that are passed when referencing componentsattribute
Incoming parameters props
Can be defined as an array or object- analogy
typeScript
,props
You can also restrict the type by the key field of the object, and you can also customize the rules - Limiting types and rules prevents random parameter transmission and reduces interconnection costs
Vue.component("ComponentA", {
1 / / way
props: ['title'].2 / / way
props: {
title: {
// Define the type
type: String.// Define default values
default: 'title-default'.// Define whether a value must be passed
required: true
},
student: {
// Define the type
type: Object.// Custom rules
validator(val) {
console.log(val);
// return true passes, return false does not pass
return val.name === 'Ming'}}},template: `
ComponentA
{{title}}
`
})
const app = new Vue({
el: '#app'.template: ` < div > < component a title = "123" : student = "{name:" Ming "} "> < / component a > < / div > `
});
Copy the code
$emit
emit
The output of the js function is used by the component to emit values- call
this.$emit
The first parameter is the name of the outer received event, received as an event
Vue.component("ComponentA", {
template: `
`.methods: {
handleClick() {
this.$emit('change'.'Clicked')}}});const app = new Vue({
el: '#app'.template: `
`.methods: {
handleChange(val) {
console.log(val); }}});Copy the code
v-model
- use
v-model
To pass a value in a component, you need to create a value in the componentprops
- On a component
v-model
By default, names are usedvalue
Prop and namedinput
In the event - To avoid input controls such as checkboxes, checkboxes, etc
value
attribute
For different purposes, availablemodel
Changing the Default name
Vue.component("ComponentA", {
// model is used to change the default keyword
model: {
prop: 'milk'.event: 'change'
},
// The default is value
// props: ['value'],
props: ['milk'].template: `<div> <! -- {{value}} --> {{milk}} <button @click="handleClick">ComponentA</button> </div>`.data() {
return {
countA: 0}},methods: {
handleClick() {
// Default is input
// this.$emit('input', ++this.countA)
this.$emit('change'The + +this.countA)
}
}
});
const app = new Vue({
el: '#app'.template: `<div> {{count}} <! This count will be passed to the milk of props, and when the $emit change in the component fires and returns with a new value, Count will be updated --> <ComponentA V-model ="count"></ComponentA> </div> '.data: {
count: 0}});Copy the code
.sync
- The above
v-model
You can bind the incoming count to the component, passing$emit
Change count, but the component needs an intermediate value countA to transfer, so if we need to bind a lot of values, can we change it directly in the componentprops
Change the external count? - Directly modifying
props
You can’t becauseVue
是 Unidirectional data flowIn other words, data can only be transmitted in one direction, so as to keep data in order and maintain data uniformity - What should we do?
- We can just use it
$emit
Method that sends the new value out and changes it externally- This is cumbersome to write and requires a full circle: first pass value => change value => transfer value => external change value
- Will make our code become tedious, business will appear this logic, a large number of stacked, maintenance and reading will become poor, and components are not flexible, coupling is very strong
Vue.component("ComponentA", {
props: ['count'].template: `
{{count}}
`.methods: {
handleClick() {
this.$emit("upDateCount".this.count + 1)}}});const app = new Vue({
el: '#app'.template: `
{{count}}
`.data: {
count: 0
},
methods: {
upDateCount(val) {
console.log(val);
this.count = val; }}});Copy the code
- When a value is passed externally, define a method that modifies the value (same as React logic).
- This looks good, the coupling is reduced, one value corresponds to read and write
- But I still feel inconvenient. I still don’t like it
Vue.component("ComponentA", {
props: ['count'.'upDateCount'].template: `
{{count}}
`.methods: {
handleClick() {
this.upDateCount(this.count + 1); }}});const app = new Vue({
el: '#app'.template: `
{{count}}
`.data: {
count: 0
},
methods: {
upDateCount(val) {
this.count = val; }}});Copy the code
- sync
- This is a
Vue
Built-in grammar sugar - It drastically reduces our code, makes us feel good (cross it out), reduces code, and makes it easier to read
- This is a
Vue.component("ComponentA", {
props: ['count'].template: `
{{count}}
`.methods: {
handleClick() {
// Issue: update:propsName (received attribute)
this.$emit('update:childCount'.this.count + 1)}}});const app = new Vue({
el: '#app'.template: `<div> {{parentCount}} <! - reception: PropsName (received attribute). Sync :data --> <ComponentA :count="parentCount" :childCount. Sync ="parentCount"></ComponentA> </div>`.data: {
parentCount: 0}});Copy the code
Slot slot
- Component transfer, in addition to
props
There areslot
slot slot
The default value can be written inside- A slot is like a punch, punched inside a component and filled with what’s passed in from the outside
- Slots can be multiple, single
name
The default isdefault
When you want to define more than one you have to give it a name - Slots have their own scope. If you want to call parameters in a component when calling it, you can pass
slot
的attribute
Emitted as an object
Vue.component("ComponentA", {
template: `<div> <! -- name header slot --> <p><slot name="header">headerDefault</slot></p> <! <slot>default</slot> <slot name="default">default</slot> <! -- slot with name footer --> <! -- Slot scope, Pass out childMsg and 123 via attribute --> <p><slot name="footer" : MSG ="childMsg" num="123">footerDefault</slot></p> </div> '.data() {
return {
childMsg: 'childMsg'}}})const app = new Vue({
el: '#app'.template: `<div> <ComponentA> <! --> <template v-slot:header>{{parentMsg}}</template> <! --> slot1 <template v-slot:default>slot2</template> <! -- slot with name footer --> <! <template V-slot :footer="data">{{data.msg}} -- {{data.num}}</template> </ComponentA> </div> '.data: {
parentMsg: 'parentMsg'}});Copy the code
- Additional examples: use of scope slots, built-in for loops, external calls
Vue.component("ComponentA", {
template: `
-
`.data() {
return {
list: [{name: 'orange'.num: 12 },
{ name: 'apple'.num: 0 },
{ name: 'banana'.num: 3},]}}})const app = new Vue({
el: '#app'.template: ` < div > < component > < - this item is object, by {} deconstruction - > < template v - slot = "{item}" > {{item. The name}} - {{item. Num}} < span v - if = "!
});
Copy the code
Mixins with
mixin
Is for the reuse of components- It is just a normal object, exposed inside the component
mixins
It will be used after being introduced mixin
All arguments within the objectExactly the same as the component(including mixins)支那mixin
defective- The dependency relationship is vague and the corresponding source cannot be found
- because
mixin
You can apply it on the insidemixin
, it is difficult for us to find the fn we need in the nested relation
- because
- A, B methods ()
- The dependency relationship is vague and the corresponding source cannot be found
mixin
在Vue3
被compositionAPI
ban
const mixinB = {
mounted() {
console.log('hei~ I\'m mixinB'); }}const mixinA = {
mixins: [mixinB],
template: `<div>ComponentA</div>`.mounted() {
console.log('hei~ I\'m mixinA');
}
}
Vue.component("ComponentA", {
mixins: [mixinA]
});
Vue.component("ComponentB", {
mixins: [mixinA],
template: `<div>ComponentB</div>`
});
const app = new Vue({
el: '#app'.template: `
`
});
Copy the code
ref
- We may need the real thing sometimes
DOM
Element to perform operations such asinput
Box gets focus and stuff like that - This time we can use the special
attribute
findDOM
Vue.component("ComponentA", {
template: `<div> ComponentA <! -- attribute = ref --> <input ref="ref"/> </div>.mounted() {
// use this.$refs to find the marked ref
console.log(this.$refs.ref);
this.$refs.ref.focus(); }})const app = new Vue({
el: '#app'.template: `
`
});
Copy the code
Custom instruction
- Except for the one above
ref
In addition, we can also get real through custom commandsDOM
There are also richer configuration items that allow us to customize the Vue directives we need - Vue3 updated
directive
In the life cycle instruction, so that the instruction and component life cycle as convenient for us to remember, later free to write custom instructions when detailed interpretation
Vue.directive('focus', {
// el is the real DOM
// Binding is a configuration item that contains parameters, modifiers, etc
// Vnode is the virtual DOM of Vue
// Bind is called when the directive is first bound to an element
bind(el, binding, vnode) {
console.log(el);
console.log(binding);
console.log(vnode);
console.log('bind');
},
// Inserted Is called when the bound element is inserted into a parent (the parent is guaranteed to exist, but not necessarily already inserted into the document)
inserted(el, binding) {
console.log('inserted');
el.focus();
},
// Other lifecycle updates, componentUpdated, and unbind are available on the official website
});
Vue.component("ComponentA", {
template: `<div> ComponentA <! -- a.b and 132 + 123 can be obtained in binding --> <input V-focus. A.b ="132 + 123" /> </div>
});
const app = new Vue({
el: '#app'.template: `
`
});
Copy the code