动态组件 & 异步组件

之前学习的都是父子组件传值的话题, 一句话总结就是, 常规数据通过属性传, dom 结构通过插槽 slot 来传. 而本篇则关注如何通过数据去控制组件的显示问题, 如咱经常用到的页面切换呀, Tab 栏切换之类的, 就会涉及到组件的显示和隐藏以及同步或者异步任务的问题啦.

动态组件

即可根据数据变化, 结合 component 标签 动态切换组件显示.

<!DOCTYPE html>
<html lang="en">
<head>
<title>动态组件的引入</title>
<script src="https://unpkg.com/vue@3"></script>
</head>
<body>
<div id="root"></div>
<script>
const app = Vue.createApp({
// 组件1 是一个输入框
app.component('input-item', {
template: `
<input />
`
})
// 组件2 是一个div显示文本
app.component('common-item', {
template: `<div>hello, world</div>`
})

const vm = app.mount('#root')

</script>
</body>

</html>

需求就是希望能通过数据 data ( ) 去控制两个组件的显示和隐藏. 其靠咱朴素的写法实现如下:

<!DOCTYPE html>
<html lang="en">

<head>
<title>动态组件-朴素实现</title>
<script src="https://unpkg.com/vue@3"></script>
</head>

<body>
<div id="root"></div>
<script>
const app = Vue.createApp({
data () {
return { current: 'input-item' }
},
methods: {
handleClick () {
if (this.current === 'input-item') {
this.current = 'common-item'
} else {
this.current = 'input-item'
}
}
},
template: `
<input-item v-show="current === 'input-item'" />
<common-item v-show="current === 'common-item'" />
<button @click="handleClick">切换</button>
`
})

app.component('input-item', {
template: `
<input />
`
})

app.component('common-item', {
template: `<div>hello, world</div>`
})

const vm = app.mount('#root')

</script>
</body>

</html>

这样写的缺点在于有点复杂和冗余, 为简洁起见, vue 就封装了一个名为 component 标签来优化这个写法:

// 用: 
template: `
<component :is="current" />
<button @click="handleClick">切换</button>
`

// 来替换
template: `
<input-item v-show="current === 'input-item'" />
<common-item v-show="current === 'common-item'" />
<button @click="handleClick">切换</button>
`

针对再切换来组件, 还可以通过外套一个 keep-alive 的标签实现之前组件数据的临时缓存.

template: `
<keep-alive>
<component :is="current" />
</keep-alive>
<button @click="handleClick">切换</button>
`

异步组件

先还是要区分"同步和异步"的概念, 计算机中的同步和我们现实生活是恰好相反的.在现实生活中, "俺同时在开会和想她" 这种同步的一心多用, 在计算机中叫 "异步"; "我打开电脑再摸鱼" 这种有先后顺序的, 在计算机中叫 "同步".

更形象一点从来显示一波同步组件, 即当父组件调用的时候, 子组件就会按顺序执行, 这就是同步.

<!DOCTYPE html>
<html lang="en">

<head>
<title>同步组件</title>
<script src="https://unpkg.com/vue@3"></script>
</head>

<body>
<div id="root"></div>
<script>
const app = Vue.createApp({
template: `
<Son />
`
})

app.component('Son', {
template: `<div>我是同步组件, 父组件调用的时候就会按顺序执行</div>`
})

const vm = app.mount('#root')

</script>
</body>

</html>

则异步组件就是不按顺序从上到下执行, 可是延迟或者同时进行, 哎呀异步任务吗, 这个有啥可解释的.

<!DOCTYPE html>
<html lang="en">

<head>
<title>异步组件</title>
<script src="https://unpkg.com/vue@3"></script>
</head>

<body>
<div id="root"></div>
<script>
const app = Vue.createApp({
template: `
<Son />
<async-item />
`
})

// 同步组件
app.component('Son', {
template: `<div>我是同步组件</div>`
})

// 异步组件, 这里以每隔3秒执行一波测试
app.component('async-item', Vue.defineAsyncComponent(
() => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve({
template: `<div>我是一个异步组件</div>`
})
}, 2000);
})
}
))



const vm = app.mount('#root')

</script>
</body>

</html>

小结

  • 复习组件传值技巧: 常规数据通过属性传, dom 结构通过插槽 slot 传
  • 动态组件的理解是通过数据来控制组件的显示, 可通过 component 和 keep-alive 标签实现
  • 计算机世界的同步即按顺序执行任务, 异步则可以同时进行多个处理 "既想她, 也想他"
  • 异步组件实现可以通过 Vue.defineAsyncComponent ( ) 加一个 Promise 来实现呀

耐心和恒心, 总会获得回报的.