component是vue的一个内置组件,作用是:配合is动态渲染组件。
<component :is='组件'></component>
不同组件之间进行动态的切换
//两个子组件
var son1 = {
template: `
<div>
<h1>子组件-1</h1>
<slot>子组件-1的默认内容</slot>
</div>
`
}
var son2 = {
template: `
<div>
<h1>子组件-2</h1>
<slot>子组件-2的默认内容</slot>
</div>
`
}
<!-- 父组件 -->
<div id="app">
<button @click="change1">son1</button>
<button @click="change2">son2</button>
<component :is='state'></component>
</div>
<script>
var vm = new Vue({
el: "#app",
data() {
return {
state: 'son1'
}
},
methods: {
change1() {
this.state = 'son1'
},
change2() {
this.state = 'son2'
}
},
components: {
son1,
son2
}
})
</script>
上边代码,我们实现了两个子组件动态切换。
补充:
在vue-cli中,component经常用到的地方为tabs标签页中:
<template>
<div class="home">
<hr>
<div style="display: flex;justify-content: center;">
<button
v-for="(comp, i) in componentsList"
:key="i"
:style="[activingIndex === i ? {background: 'red', color: '#fff'} : {background: '#fff', color: '#000'}]"
@click="test(i)"
>{{i+1}}</button>
</div>
<component :is="proxy"></component>
</div>
</template>
<script>
<!--以下是三个组件,动态来切换不同的组件-->
import com from './com';
import comOne from './com_1';
import comTwo from './com_2';
export default {
name: 'Home',
components: {
com,
comOne,comTwo
},
data() {
return {
componentsList: ['com', 'comOne', 'comTwo'],
proxy: 'com',
activingIndex: 0
}
},
methods: {
test(i) {
this.activingIndex = i
switch(i) {
case 0:
this.proxy = 'com'
break;
case 1:
this.proxy = 'comOne'
break;
case 2:
this.proxy = 'comTwo'
break;
}
}
}
}
</script>
下边来看一个问题,两个组件进行切换时,一个组件显示,另一个是组件隐藏还是销毁呢?
//两个子组件
var son1 = {
template: `
<div>
<h1>子组件-1</h1>
<slot>子组件-1的默认内容</slot>
</div>
`,
beforeDestroy(){
alert('销毁子组件son1')
}
}
var son2 = {
template: `
<div>
<h1>子组件-2</h1>
<slot>子组件-2的默认内容</slot>
</div>
`,
beforeDestroy(){
alert('销毁子组件son2')
}
}
上边代码,当切换son2时,显示son1组件被销毁,所以,当两个组件进行动态切换时,组件的状态是:不断的创建与销毁的过程。
如果你想把组件的缓存下来,可以在动态组件上使用vue另一个内置组件keep-alive
<keep-alive>
<component :is='state'></component>
</keep-alive>
这样,当切换组件时,组件会被缓存下来,不会执行created 、mounted、beforeDestroy钩子函数。
父子组件执行顺序的问题:
我们在父组件和子组件son中分别定义个生命周期钩子mounted,页面加载到完成,父组件先渲染完成还是子组件先渲染完成呢?
var son = {
template: `
<div>
<h1>子组件-1</h1>
<slot>子组件-1的默认内容</slot>
</div>
`,
mounted(){
console.log('son')
}
}
var vm = new Vue({
el: "#app",
mounted(){
console.log('父组件')
},
components: {
son
}
})
输出结果:
上边代码,结果是父组件挂载完成前提:需等到子组件挂载完成后。
子组件异步渲染
上边代码,我们看到,子组件先挂载完成,父组件才能挂载完成,下边代码我们在父组件中获取子组件的dom元素,看下问题所在:
<div id="app">
<son ref='son'></son>
</div>
<script>
//子组件
var son = {
template: `
<div>
<h1>{{name}}</h1>
</div>
`,
data(){
return{
name:'lxc'
}
},
mounted(){
this.name = '呆呆君'
},
}
//父组件(根实例)
var vm = new Vue({
el: "#app",
mounted(){
console.log(this.$refs.son.$el.innerText)
},
components: {
son
}
})
</script>
上边代码,在子组件的mounted中我们修改了原来data对象中的数据,页面渲染完全没问题,但是在父组件mouted中输出子组件dom元素的内容时,不是新数据 " 呆呆君 ",而是原来的数据 "lxc" !
结论,子组件生命周期钩子mounted和父组件的mounted都是同步执行的,但是子组件渲染dom元素却是异步渲染的,所以在父组件的mounted中获取dom元素是原来的子组件数据!!!
解决上边bug,通常会在vm.$nextTick中去获取dom元素:
<div id="app">
<son ref='son'></son>
</div>
<script>
//子组件
··· ··· ···
//父组件(根实例)
var vm = new Vue({
el: "#app",
mounted(){
this.$nextTick(function(){
console.log(this.$refs.son.$el.innerText)
})
},
components: {
son
}
})
</script>
输出结果:
关于vm.$nextTick(callback)我在之前的文章中有详细讲到: