二.数据输入(动态)
前言
动态组件,即组件可以作为一个变量传入到某个组件中根据一些条件,动态地切换某个组件,或动态地选择渲染某个组件
- 下拉菜单组件应该由两部分组成:
- 选中项的文本
- 待选菜单(默认隐藏)
- 它的主要功能包括:
- 鼠标经过下拉菜单组件,显示待选菜单
- 鼠标滑出下拉菜单组件,隐藏待选菜单
- 鼠标点击待选菜单中的条目,选中项文本更新,组件派发 change 事件
1. 动态组件
使用 Render 或 Function Render 可以解决动态切换组件的需求,不过那是基于一个 JS 对象(Render 函数),而 Vue.js 提供了另外一个内置组件<component>
和is
特性,可以更好地实现动态组件。
父组件中一个
<component>
和is
的基本用法示例:vue<template> <div> <button @click="handleChange("A")">显示 a 组件</button> <button @click="handleChange("B")">显示 b 组件</button> <button @click="handleChange("C")">显示 c 组件</button> <component :is="component"></component> <!-- 这里的is动态绑定的是一个组件对象(Object),它直接指向 a/b/c 三个组件中的一个 --> </div> </template> <script> import componentA from './components/a.vue' import componentB from './components/b.vue' import componentC from './components/c.vue' const com = {A:componentA,B:componentB,C:componentC} export default { data (){ return { component: com['A'] } }, methods: { handleChange(component){ this.component = com[component] } } } </script>
- 子组件:a.vue
vue<template> <div> 子组件:a.vue </div> </template>
- 子组件:b.vue
vue<template> <div> 子组件:b.vue </div> </template>
- 子组件:c.vue
vue<template> <div> 子组件:c.vue </div> </template>
除了直接绑定一个 Object,还可以是一个 String,比如标签名,组件名。
2. 实现一个动态组件
下面的这个组件,将原生按钮 button 进行了封装,如果传入了prop:to
,它会渲染为一个<a>
标签,用于打开这个链接地址,如果没有传入to
,就当做普通的 button 使用。
- 封装组件:button.vue
vue<template> <component :is="tagName" v-bind="tagProps"> <slot></slot> </component> </template> <script> export default{ props:{ to:{ type:String, default:' }, target:{ type:String, default:"_self" } }, computed:{ tagName(){ return this.to === ''?'button':'a' // 动态渲染不同的标签 }, tagProps(){ // 如果是链接,把这些属性绑定到component上 let props = {} if(this.to){ props = { target:this.target, href:this.to } } return props } } } </script>
使用组件:
vue<template> <div> <my-button>普通组件</my-button> <my-button to="https://123.com">链接按钮</my-button> <my-button to="https://123.com" target="_blank"> 新窗口打开链接按钮 </my-button> </div> </template> <script> import myButton from "../component/button.vue"; export default { components: { myButton }, }; </script>
最终会渲染出一个原生button
按钮和两个原生的链接a
,且第二个点击会在新窗口中打开链接。
my-button 组件中component
is
绑定的就是一个标签名称 button/a,并且通过v-bind
将一些额外的属性全部绑定到component
上,
再回到第一个 a/b/c 组件的切换狩猎,如果这类组件,频繁切换,实际上组件是会重新渲染的,比如我们在组件 A 里加两个生命周期。
- a.vue
vue<template> <div>组件A</div> </template> <script> export default { mounted() { console.log("组件创建了"); // 只要切换到 A 组件,`mounted`就会触发一次, }, beforeDestory() { console.log("组件销毁了"); // 切换到其他组件,`beforeDesotory`也会触发一次,说明组件在重新渲染,这样有可能导致性能问题。 }, }; </script>
使用
keep-alive
只有mounted
触发了,如果不离开当前页面,切换其他组件beforeDestory
不会触发vue<template> <keep-alive> <component :is="component"></component> <!-- 为了避免组件的重复渲染,使用`<keep-alive>`,这样组件就会被缓存起来 --> </keep-alive> </template>
keep-alive 还有一些额外的 props 可以配置
- include:字符串或正则表达式,只有名称匹配的组件会被缓存
- exclude:字符串或正则表达式,任何名称匹配的组件都不会被缓存
- max:数字,最多可以缓存多少组件实例
总结
合理使用动态组件可以让我们写出的代码更加简洁,减少冗余代码