In this chapter, interviewers will often ask the following questions. Look at this article with these questions in mind. After studying, you can think about your answer again.
- What are the component categories? How do you deal with business components in real projects? What if there are reusable components?
- Component communication Besides parent-child component communication, what other modes do you know?
- Why can’t child components modify data in parent components?
- Why does a component’s data have to be a function?
- Describe the Vue lifecycle, which ones do you use? Describe their application scenarios respectively
Component based
What is a component
If you have used bootstrap before, you will be familiar with this term. In fact, we have been exposed to this term since a very early time
Typically an application blocks this in the form of a nested component tree:
Local components
Doggerel using local components: build a child to hang a child to use
Note: In the component this data must be a function that returns an object
<div id="app">
<! -- 3. Use child components -->
<App></App>
</div>
<script>
//1. Create child components
const App = {
// must be a function
data() {
return {
msg: 'I'm an App component'}},components: {
Vcontent
},
template: `
`
}
new Vue({
el: '#app'.data: {},components: {
// 2. Mount child components
App
}
})
</script>
Copy the code
Global components
Create a global component with Vue.component(component name,{}) that can be used in any template
Vue.component('Child', {template:'
I am a child component
'
})
Copy the code
Component communication
The father the son
If a web page has a blog component, it won’t work if you can’t pass it data like the title and content of a particular blog post. That’s where Prop comes in
Parent component to child component: pass data to child component via Prop
Vue.component('Child', {template:` < div > < h3 > I was a child component < / h3 > < h4 > {{childData}} < / h4 > < / div > `.props: ['childData']})const App = {
data() {
return {
msg: 'I'm the value passed in by the parent component'}},template: `
`.computed: {}}Copy the code
- Declare in the child component that props receives properties mounted on the parent component
- Can be used arbitrarily in the template of the child component
- Bind custom properties in the parent component
Child the parent
There are some features on the web page that may require us to communicate with the parent component
Child component to parent component communication: listen for child component events, using the event to throw a value
Vue.component('Child', {
template: ` < div > < h3 > I was a child component < / h3 > < h4 > {{childData}} < / h4 > < input type = "text" @ input = 'handleInput "/ > < / div > `.props: ['childData'].methods: {handleInput(e){
const val = e.target.value;
// Use $emit to trigger events for child components
this.$emit('inputHandler',val); }}})const App = {
data() {
return {
msg: 'I'm the value passed in by the parent component'.newVal:' '}},methods: {input(newVal){
// console.log(newVal);
this.newVal = newVal; }},template: ` < div > < div class = 'father' > data: {{newVal}} < / div > <! --> <Child :childData = 'MSG' @inputhandler = 'input'></Child> </div>.computed: {}}Copy the code
-
Bind custom events to children within a parent component
-
Emit native events in the child component. Emit custom events in the event function via this.$emit
The parallel component
In development, there might be unrelated component communication, such as a blog content display component, and a form submission component, and now we submit data to the blog content display component, which is a little bit cumbersome to display.
To solve this problem, we can use bus in VUE to create a central event bus
const bus = new Vue();
// Central event bus
Vue.component('B', {
data() {
return {
count: 0}},template: `
<div>{{count}}</div>
`.created(){
// $on bind event
bus.$on('add'.(n) = >{
this.count+=n;
})
}
})
Vue.component('A', {
data() {
return{}},template: '
< button@click ='handleClick'> Add to cart
.methods: {handleClick(){
// $emit triggers the event
bus.$emit('add'.1); }}})Copy the code
Communication modes of other components
Parent components provide variables, and child components inject variables through inject. No matter how deeply the components are nested
Vue.component('B', {
data() {
return {
count: 0}},inject: ['msg'].created(){
console.log(this.msg);
},
template: `
{{msg}}
`,
})
Vue.component('A', {
data() {
return{}},created(){
// console.log(this.$parent.$parent);
// console.log(this.$children);
console.log(this);
},
template: `
`
})
new Vue({
el: '#app'.data: {},components: {
// 2. Mount child components
App
}
})
Copy the code
slot
Anonymous slot
The child component defines the slot slot, but it is not named, so it can also be said to be the default slot. Anything inserted into the parent element is inserted into the slot by default
Vue.component('MBtn', {
template: ` `.props: {
type: {
type: String.defaultValue: 'default'}}})const App = {
data() {
return{}},template: ` < div > < m - BTN > login < / m - BTN > < m - BTN > register < / m - BTN > < m - BTN > submit < / m - BTN > < / div > `,}new Vue({
el: '#app'.data: {},components: {
// 2. Mount child components
App
}
})
Copy the code
A named slot
Named slots can appear in different places and have no limit on the number of times they can appear. As long as the name matches then the content will be inserted into the slot of the name
Vue.component('MBtn', {template:` `.props: {type: {type: String.defaultValue: 'default'}},methods: {clickHandle(){
this.$emit('click'); }}})const App = {
data() {
return{}},methods: {handleClick(){
alert(1);
},
handleClick2(){
alert(2); }},template: '
register
Submit
',}new Vue({
el: '#app'.data: {},components: {
App
}
})
Copy the code
Scope slot
Normally a normal slot is something that is passed in by the parent to determine the contents of the slot. But sometimes we need to get some data from a child component, and the scope slot comes in handy
Vue.component('MyComp', {
data(){
return {
data: {username:'Little Pony'}}},template: `
`
})
const App = {
data() {
return{}},template: ` <div> <MyComp> <! --> <template v-slot:default='user'> {{user.data.username}} </template> </MyComp> <MyComp> <! <template v-slot:one='user'> {{user.data.username}} </template> </MyComp> </div> ',}new Vue({
el: '#app'.data: {},components: {
App
}
})
Copy the code
Scope slot application
Let’s start with our hypothetical application common scenario. We have developed a to-do list component that is used by many modules and now require a checkbox effect to be added to completed to-do items without affecting the functionality and presentation of the modules that have been tested.
In other words, the to-do list component should satisfy the following points
- Previous data format and reference interface unchanged, normal display
- New function modules add check marks
const todoList = {
data(){
return{}},props: {todos:Array.defaultValue:[]
},
template:`
-
{{item.title}}
`
}
const App = {
data() {
return {
todoList: [{title: 'How are you, brother?'.isComplate:true.id: 1
},
{
title: 'I'm all right, buddy.'.isComplate:false.id: 2
},
{
title: 'What are you doing?'.isComplate:false.id: 3
},
{
title: 'Smoking, drinking, perming'.isComplate:true.id: 4}}},components:{
todoList
},
template: `
{{data.itemValue.title}}
`,}new Vue({
el: '#app'.data: {},components: {
App
}
})
Copy the code
The life cycle
“You don’t have to understand everything right away, but it becomes more and more valuable as you learn and use it.
When you’re working on a project and you run into this kind of problem, go back to this diagram
What is the life cycle
Each Vue instance goes through a series of initialization procedures when it is created. For example, create data from the start, initialize data, compile templates, mount Dom, update Dom as data changes, unload, and so on. We call this sequence of processes the Vue lifecycle. Vue instance is the process from creation to destruction. There are also some functions called lifecycle hooks that run along the way, which give users the opportunity to add their own code at different stages, using each hook to complete our business code.
To work with
Lifecycle hook
beforCreate
Hook events that are executed after the instance is initialized but before the instance is created
Vue.component('Test', {data(){
return {
msg:'Little Pony'}},template:`
{{msg}}
`.beforeCreate:function(){
// Before component creation
console.log(this.$data);//undefined}})Copy the code
Effect:
Data observation and event configuration are not ready before the instance is created. There is no data and no DOM generation
created
The hook that executes after the instance is created
created() {
console.log('Component Creation'.this.$data);
}
Copy the code
Effect:
After the instance is created, we can read the value of the data, but the DOM is not yet generated, so we can initiate Ajax at this point
beforeMount
The hook that fires when the compiled HTML is mounted into the corresponding virtual DOM and the page has no content. That is, this stage is interpreted as: About to mount
beforeMount(){
// is called before mounting data to the DOM
console.log('Before DOM mount'.document.getElementById('app'));
}
Copy the code
Effect:
mounted
The event hook function that executes after the compiled HTML is mounted to the page
mounted() {
console.log('DOM mount complete '.document.getElementById('app'));
}
Copy the code
Effect:
BeforeUpdate and updated
beforeUpdate() {
// Call this hook before updating the DOM. Apply: the original DOM can be retrieved
console.log('Before DOM update'.document.getElementById('app').innerHTML);
},
updated() {
// Call this hook after updating the DOM to get the latest DOM
console.log('DOM update completed '.document.getElementById('app').innerHTML);
}
Copy the code
Effect:
BeforeDestroy and destroyed
When the subcomponent switches in the V-IF condition, the group valence is in the create and destroy state
beforeDestroy() {
console.log('beforeDestroy');
},
destroyed() {
console.log('destroyed');
},
Copy the code
Activated and deactivated
The following method is called when used in conjunction with vue’s built-in
component
The
component is used to cache the current component
activated() {
console.log('Component activated');
},
deactivated() {
console.log('Component is disabled');
},
Copy the code
Components into the order
Get the DOM and child component objects
Despite prop and events, there are times when you may need to access a child component directly in JavaScript. To do this, you can use the REF feature to assign an ID reference to the child component. Such as:
const Test = {
template: '
I am testing component
'
}
const App = {
data() {
return{}},created() {
console.log(this.$refs.test); //undefined
},
mounted() {
// If the ref is mounted by the component, get the component object; if the ref is mounted by the tag, get the DOM element
console.log(this.$refs.test);
console.log(this.$refs.btn);
// Load the page so that input automatically gets focus
this.$refs.input.focus();
},
components: {
Test
},
template: `
`
}
new Vue({
el: '#app'.data: {},components: {
App
}
})
Copy the code
The use of the nextTick
Defer the callback until after the next DOM update cycle. Use the data immediately after you modify it, and then wait for DOM updates
Something you might not expect is that vue performs asynchronously when updating the DOM. Whenever it listens for data changes,Vue opens a queue and caches all data changes that occur in the same event loop. If the same wather is triggered more than once, it will only be pushed to the queue once. This removal of duplicate data while buffering is important to avoid unnecessary computation and DOM manipulation. Then, in the next event loop, “TICK,” Vue refreshes the queue and performs the actual (de-duplicated) work
<div id="app">
<h3>{{message}}</h3>
</div>
<script src="./vue.js"></script>
<script>
const vm = new Vue({
el:'#app'.data: {message:'123'
}
})
vm.message = 'new Message';// Update data
console.log(vm.$el.textContent); / / 123
Vue.nextTick(() = >{
console.log(vm.$el.textContent); //new Message
})
</script>
Copy the code
When you set vm.message = ‘new message ‘, the component does not immediately rerender. When the queue is refreshed, the component is updated in the next event loop ‘TICK’. In most cases we don’t need to worry about this process, but if you want to do something based on the updated DOM state, it can be tricky. While vue.js generally encourages developers to think in a “data-driven” way and avoid direct contact with the DOM, sometimes we have to. To wait for Vue to finish updating the DOM after the data changes, use vue.nexttick (callback) immediately after the data changes. This callback will be called after the DOM update is complete.
The application of nextTick
There is a need:
The page pull an interface, this interface to return some of the data, the data is a floating layer components depend on this page, and then I return data in interface shows the floating layer components, showing at the same time, report to some data to the background (these data is the parent component) taken from the interface, the same time, a miracle happened, although I got the data, However, when the floating layer is displayed, the data has not been updated to the component, and the failure is reported
const Pop = {
data() {
return {
isShow:false}},template:`
{{name}}
`.props: ['name'].methods: {
show(){
this.isShow = true;
alert(this.name); }}},const App = {
data() {
return {
name:' '}},created() {
// Simulate asynchronous request data
setTimeout(() = > {
this.name = 'Little Pony'.this.$refs.pop.show();
}, 2000);
},
components:{
Pop
},
template: `<pop ref='pop' :name='name'></pop>`
}
const vm = new Vue({
el: '#app'.components: {
App
}
})
Copy the code
Perfect solution:
created() {
// Simulate asynchronous request data
setTimeout(() = > {
this.name = 'Little Pony'.this.$nextTick(() = >{
this.$refs.pop.show(); })},2000);
},
Copy the code
Note on object change detection
Due to JavaScript limitations,Vue cannot detect the addition and removal of object attributes
Vue does not allow dynamic root-level reactive attributes to be added to already created instances. However, reactive attributes can be added to nested exclusives using the vue.set (Object,key,value) method
<div id="app">
<h3>
{{user.name}}{{user.age}}
<button @click='handleAdd'>Add the age</button>
</h3>
</div>
<script src="./vue.js"></script>
<script>
new Vue({
el:'#app'.data: {user:{},
},
created() {
setTimeout(() = > {
this.user = {
name:'Joe'}},1250);
},
methods: {
handleAdd(){
console.log(this);
// No response
// this.user.age = 20;
// responsive
this.$set(this.user,'age'.20); }}})</script>
Copy the code
this.$set(this.user,'age'.20);// It is just an alias for global vue.set
Copy the code
If you want to assign multiple attributes to an existing Object, you can use object.assign ()
// Add multiple attributes in a single response
this.user = Object.assign({}, this.user, {
age: 20.phone: '113131313'
})
Copy the code
Mixin lazy
Mixins provide a very flexible way to distribute reusable functionality in Vue components. A mixin object can contain any component option.
A mixin object can contain any component option. When a component uses mixin, all mixin options are “blended” into the component’s own options.
<div id="app">
{{msg}}
</div>
<script src="./vue.js"></script>
<script>
const myMixin = {
data(){
return {
msg:'123'}},created() {
this.sayHello()
},
methods: {
sayHello(){
console.log('hello mixin')}}}new Vue({
el: '#app'.data(){
return {
msg:'Little Pony'}},mixins: [myMixin]
})
Copy the code
A mixin applied
There’s a rare case where you have two components that are very similar, they share the same basic functions, and they’re different enough that you’re at a crossroads: Do I split it into two different components? Or just use one component and create enough properties to make a difference.
None of these solutions is perfect: if you split it into two components, you run the risk of updating it in both files if the functionality changes, which violates the DRY premise. On the other hand, too many attributes can quickly become confusing and unfriendly to maintainers, or even to yourself, which can frustrate you by requiring an understanding of a large context in order to use it.
Use a mix. Mixing in Vue is useful for writing functional style code, because functional programming is about making code easier to understand by reducing moving parts. Blending allows you to encapsulate a block of functions that can be used in other components of your application. If used correctly, they don’t change anything outside the scope of the function, so if you do it multiple times, you’ll always get the same value as long as it’s the same input. That’s really powerful.
We have a pair of different components that toggle a state Boolean, a modal box, and a prompt box. These prompt boxes and modal boxes have nothing in common except functionality: they look different, use different, but the logic is the same
<div id="app">
<App></App>
</div>
<script src="./vue.js"></script>
<script>
// Global mixin is called every time an instance is created
Vue.mixin({
created(){
console.log('hello from mixin!! '); }})/ / pull away
const toggleShow = {
data() {
return {
isShow: false}},methods: {
toggleShow() {
this.isShow = !this.isShow
}
}
}
const Modal = {
template: '
Modal box component
'.data() {
return{}},mixins:[toggleShow]
}
const ToolTip = {
data() {
return{}},template: '
Prompt component
'.mixins:[toggleShow]
}
const App = {
data() {
return{}},template: '
< button@click ='handleModel'> Modal box < button@click ='handleToolTip'> Prompt box
`.components: {
Modal,
ToolTip
},
methods: {
handleModel() {
this.$refs.modal.toggleShow()
},
handleToolTip() {
this.$refs.toolTip.toggleShow()
}
},
}
new Vue({
el: '#app'.data: {},
components: {
App
},
})
Copy the code