vue基础第六天
组件进阶
动态组件
多个组件使用同一个挂载点,并动态切换,这就是动态组件
使用vue内置的component组件 配合is属性实现相应功能(改变is的属性值为要显示的组件名即可)
<template>
<div>
<button @click="componentName = 'UserInfo'">个人信息</button>
<button @click="componentName = 'UserName'">账号登录</button>
<!-- vue内置标签 component 是动态组件挂载点, 会根据绑定的 is 属性显示名字对应的组件 -->
<component :is="componentName" />
</div>
</template>
<script>
import UserInfo from '@/components/UserInfo.vue'
import UserName from '@/components/UserName.vue'
export default {
data() {
return {
componentName: 'UserInfo'
}
},
components: {
UserInfo,
UserName
}
}
</script>
<style>
</style>
组件缓存
组件切换会导致组件被频繁销毁和重新创建, 性能不高
使用vue内置的keep-alive组件,可以让包裹的组件保存在内存中不被销毁,页面更快呈现 性能更高
<!-- vue内置的keep-alive组件把要缓存的组件包起来 不会频繁的创建和销毁组件,页面呈现更快 -->
<keep-alive>
<!-- vue内置标签 component是动态组件挂载点 会根据绑定的 is 属性显示名字对应的组件 -->
<component :is="isShow" />
</keep-alive>
组件缓存生命周期:
被缓存的组件不再创建和销毁, 而是激活和非激活
- activated - 激活
- deactivated - 失去激活状态
keep-alive可以提高组件的性能, 内部包裹的标签不会被销毁和重新创建, 触发激活和非激活的生命周期方法
组件插槽
通过 slot 标签, 让组件内可以接收不同的标签结构显示
给组件插入什么标签, 组件就显示什么标签
语法口诀:
- 组件内用占位
- 使用组件时夹着的地方, 传入标签替换slot
插槽默认内容
如果外面不给传, 想给个默认显示内容
语法:
夹着内容默认显示内容, 如果不给插槽slot传东西, 则使用夹着的内容在原地显示
插槽与默认值示例:
子组件 - src/components/TopBar.vue
<template>
<div class="box">
<div class="left"></div>
<div class="right">
<!-- <TopBar/> -->
<!-- <slot/>插槽占位符 -->
<!-- 单<slot/>标签-->
<!-- <slot /> -->
<slot>
<!--<slot></slot> 双标签 没有传入的替换标签 可设置在双标签内设置默认内容 -->
<button>返回</button>
</slot>
</div>
</div>
</template>
<script>
export default {};
</script>
<style lang="less" scoped>
.box {
display: flex;
justify-content: space-between;
padding: 10px 30px;
border: 1px solid #ccc;
}
button {
border: none;
background-color: orange;
margin-left: 10px;
padding: 5px 5px;
color: #fff;
}
</style>
父组件 - app.vue:
<template>
<div>
<!-- <TopBar/> -->
<!-- TopBar改用双标签 包裹要传入替换slot的标签 -->
<h2>员工</h2>
<TopBar>
<button>新增</button>
<button>查看</button>
</TopBar>
<h2>薪资</h2>
<TopBar>
<button>报表</button>
</TopBar>
<h2>无替换</h2>
<TopBar/>
</div>
</template>
<script>
import TopBar from "./components/TopBar.vue";
export default {
components: {
TopBar,
},
};
</script>
<style>
</style>
具名插槽:
一个组件内有2处以上需要外部传入标签的地方
语法:
-
slot使用name属性区分名字
-
template配合v-slot:名字来分发对应标签
v-slot:可以简化成#
具名插槽示例:
子组件 - src/components/TopBar.vue
<div class="left">
<slot name="left"/>
</div>
<div class="right">
<!-- <TopBar/> -->
<!-- <slot/>插槽占位符 -->
<!-- 单<slot/>标签-->
<!-- <slot /> -->
<slot>
<slot name="right">
<!--<slot></slot> 双标签 没有传入的替换标签 可设置在双标签内设置默认内容 -->
<button>返回</button>
</slot>
</div>
父组件 - app.vue:
<template>
<div>
<!-- 🚨🚨🚨v-solt: 可以简化成# -->
<TopBar>
<template #left>
员工概览
</template>
<template #right>
<button>新增</button>
<button>查看</button>
</template>
</TopBar>
<TopBar>
<template v-slot:left>
薪资
</template>
<template v-slot:right>
<button>报表</button>
</template>
</TopBar>
<h2>无替换</h2>
<TopBar>
<!-- 不传内容,显示子组件默认设置 -->
</TopBar>
</div>
</template>
作用域插槽
使用插槽时, 想使用子组件内变量
口诀:
-
子组件, 在slot上绑定属性和子组件内的值
-
使用组件, 传入自定义标签, 用template和v-slot="自定义变量名"
-
scope变量名自动绑定slot上所有属性和值 scope = {row: defaultObj}
子组件 - src/components/TopBar.vue
<slot :row="monthList" name="left">
{{monthList.first}} 报表
</slot>
父组件 - app.vue:
<template v-slot:left="scope">
{{scope.row.second}} 报表
</template>
总结:组件内变量绑定在slot上, 然后使用组件v-slot="变量" 变量上就会绑定slot身上属性和值
作用域插槽可以让组件更加灵活的适用于不同的场景和项目
子组件 -- MyTabe.vue:
<template>
<table>
<tr>
<slot name="thead">
<th>姓名</th>
<th>年龄</th>
<th>头像</th>
</slot>
</tr>
<tr v-for="(item, index) in data" :key="index">
<!-- 每一行有多少列,各自显示什么内容 对于一个灵活的表格组件来说,应该有使用者最终决定 -->
<!-- ❗⚠️⚠️:row即v-bind:row ❗⚠️⚠️:row="item"即 绑定属性=值 -->
<slot :row="item" name="tbody">
<td>{{ item.name }}</td>
<td>{{ item.age }}</td>
<td><img :src="item.headImgUrl" alt="" /></td>
</slot>
<!-- 由于遍历在子组件,item只有在这里能够拿到 但是具体渲染又在父组件,所以要将每一行的数据往父组件传 -->
</tr>
</table>
</template>
<script>
export default {
props: ["data"],
};
</script>
<style>
table {
border: 1px solid #000;
}
img {
width: 100px;
}
tr,
td {
border: 1px solid #000;
}
</style>
父组件 -- app.vue:
<template>
<div>
<MyTable :data="list">
<!-- 🚨⚠️🚨组件标签 包住template标签 -->
<!-- 🚨⚠️🚨具名插槽 的名是写在template标签上 -->
<template #thead>
<th>姓名</th>
<th>年龄</th>
<th>头像</th>
</template>
<!-- =后面的scope(名字可自定义)为接收到子组件传来的属性 scope = 子组件内slot标签上绑定的row属性 (row=item) -->
<template v-slot:tbody="scope">
<td>{{ scope.row.name }}</td>
<td>{{ scope.row.age }}</td>
<td><img :src="scope.row.headImgUrl" alt="" /></td>
</template>
</MyTable>
</div>
</template>
<script>
import MyTable from "./components/MyTable.vue";
export default {
data() {
return {
list: [
{
name: "小传同学",
age: 18,
headImgUrl:
"http://yun.itheima.com/Upload/./Images/20210303/603f2d2153241.jpg",
},
{
name: "小黑同学",
age: 25,
headImgUrl:
"http://yun.itheima.com/Upload/./Images/20210304/6040b101a18ef.jpg",
},
{
name: "智慧同学",
age: 21,
headImgUrl:
"http://yun.itheima.com/Upload/./Images/20210302/603e0142e535f.jpg",
},
],
};
},
components: {
MyTable,
},
};
</script>
<style>
</style>
自定义指令
除了核心功能默认内置的指令 (v-model 和 v-show),Vue 也允许注册自定义指令。 v-xxx
自定义指令注册
在Vue内置指令满足不了需求时, 可以自己定义使用。获取标签, 扩展额外的功能
全局注册指令
在main.js用 Vue.directive()方法来进行注册, 以后随便哪个.vue文件里都可以直接用全局注册的指令
局部注册指令
只能在当前文件使用
注册和使用示例:
<template>
<div>
<!-- 使用自定义指令是跟普通指令一样,千万注意--🚨🚨🚨 要加上v-前缀!! -->
<input v-showdom type="text" /> <br>
<input type="text" /> <br>
<input v-autoFocus type="text" />
</div>
</template>
<script>
export default {
//局部指令注册
directives: {
//指令名字(字符串)
showdom: {
//配置对象 可以指定使用这个指令的元素,在不同生命周期执行的函数
//在这些钩子函数的形参中,默认第一可以获取元素本身,第二可以传参
//自定义指令常用的钩子函数 inserted 和 update
inserted(el) {
console.log("显示了", el);
},
},
autoFocus: {
inserted(el) {
//focus() 自动聚焦
el.focus();
},
},
},
};
</script>
<style>
</style>
自定义指令 - 传值
语法:
- 在标签上使用v-指令名=" '值' " -- 传参
示例:
<template>
<div>
<!-- 使用自定义指令是跟普通指令一样,千万注意--🚨🚨🚨 要加上v-前缀!! -->
<input v-showdom type="text" /> <br />
<input type="text" /> <br />
<input v-autoFocus="'orange'" type="text" />
</div>
</template>
<script>
export default {
directives: {
showdom: {
inserted(el) {
console.log("显示了", el);
},
},
autoFocus: {
//第一个参数el 是元素本身。 第二个参数color是使用时传回的内容
inserted(el, color) {
//focus() 自动聚焦
el.focus();
console.log(color.value);
el.style.backgroundColor = color.value
},
},
},
};
</script>
<style>
</style>
🚨🚨🚨指令值变化触发自定义指令的update方法而非inserted方法