1、组件进阶之props
-
props的校验
- 普通格式:props['propA','propB'],没有数据类型的检测,不易发现错误
-
props:{ // 基础的类型检测(`null` 和 `undefined`会通过任何类型的验证 ) propA:Number, // 多个可能的类型 propB:[String,Number], //必填的字符串 propC:{ type:String, props: { // 基础的类型检查 (`null` 和 `undefined` 会通过任何类型验证) propA: Number, // 多个可能的类型 propB: [String, Number], // 必填的字符串 propC: { type: String, required: true }, // 带有默认值的数字 propD: { type: Number, default: 100 }, // 带有默认值的对象 propE: { type: Object, // 对象或数组默认值必须从一个工厂函数获取 default: function () { return { message: 'hello' } } }, // 自定义验证函数 propF: { validator: function (value) { // 这个值必须匹配下列字符串中的一个 return ['success', 'warning', 'danger'].indexOf(value) !== -1 } } }// 必须要填的 required:true } }
2、组件进阶-动态组件
多个组件使用同一个挂载点,并可以动态切换,这个就是动态组件
格式
<component :is="comName"></component>
注意点:
- is只能是动态属性 => :is="组件注册后的标签名字符串或打他变量"
- 不能直接拿组件名赋值使用
- vue内置的component组件,配合js属性,设置要显示的组件标签名字
3、组件进阶-keep-alive组件
-
背景:
- 组件切换会导致组件被频繁销毁和重新创建,大多数情况下是有自己的意义的,但也可能会导致不必要的性能损耗。
- 可以先给UserName.vue和UserInfo.vue注册created和destoryed生命周期,观察创建和销毁过程
-
keep-alive
- 使用Vue内置的keep-alive组件,可以让包裹的组件保存在内存中不被销毁
-
格式
-
使用keep-alive内置的Vue组件,让动态组件缓存而不是销毁
-
补充生命周期: 当使用keep-alive组件时,会自动补充以下两个钩子
- activated-激活
- deactivated-失去激活状态
-
<keep-alive>
<!-- vue内置的组件component, 可以动态显示组件 -->
<component :is="comName"></component>
</keep-alive>
总结:
keep-alive可以提高组件的性能,内部包裹的标签不会被销毁和重新创建,触发激活和非激活的生命周期方法
4、组件进阶-keep-alive组件-指定缓存
语法:
- include="组件名1,组件名2..."
- :include=['组件名1','组件名2']
<keep-alive include="name1,name2">
<!-- vue内置的组件component, 可以动态显示组件 -->
<component :is="comName"></component>
</keep-alive>
注意点:
匹配首页检查组件自身的name选项,如果name选项不可用,则匹配它的局部注册名称(父组件components选项的键值)
5、组件进阶-默认插槽
vue中的插槽
- 组件通过插槽传入自定义结构
- 用于实现组件的内容分发,通过slot标签,可以接收到写在组件标签内的内容
- vue提供组件插槽能力,允许开发者在封装组件时,把步确定的部分定义为插槽
格式:
在定义组件时,在template中用slot来占坑
使用时,讲组件之间的内容来填坑
6、组件进阶-具名插槽
当一个组件内有2处上需要外部传入标签的地方
格式
定义:
使用:
- <template #xxx>;
- 传入的标签可以分别派发给不同的slot位置
- v-slot一般跟template标签使用(template是html5新出标签内容模板元素,不会渲染到页面上,一般被vue解析为内容标签)
示例:
<div class="container" v-show="isShow">
<slot name="one"></slot>
<slot name="two"></slot>
</div>
简写:
==v-slot可以简化成#使用==
v-bind可以省略成:
v-on: 可以省略成@
v-slot: 可以简化成#
写法1:
<Pannel2>
<template v-slot:one>
<img src="../assets/mm.gif" alt="" />
</template>
<template v-slot:two>
<span>我是文字哦</span>
</template>
</Pannel2>
写法2:
<Pannel2>
<!-- 简化写法 -->
<template #one>
<div>
<p>寒雨连江夜入吴,</p>
<p>平明送客楚山孤。</p>
<p>洛阳亲友如相问,</p>
<p>一片冰心在玉壶。</p>
</div>
</template>
<template #two>
<img src="../assets/mm.gif" alt="" />
</template>
</Pannel2>
小结:
- slot有可以设置多个
- 定义组件时,slot的name属性起插槽名
- 使用组件时,template配合#插槽名传入具体html标签或组件
7、组件进阶-作用域插槽(难点)
详细步骤:
- 创建子组件,准备slot,在slot上绑定属性和子组件值
- 使用子组件,传入自定义标签,用template和v-slot="自定义变量名"
- 自定义变量名会自动绑定slot上所有属性,就可以使用子组件内值,并替换slot位置
示例
具名插槽,给slot绑定属性和值
1.子组件
<template>
<div style="border:1px solid #ccc; margin:5px;padding:5px">
<h2>子组件</h2>
<!-- 给slot上补充自定义的属性 -->
<slot name="content" :a="1" :b="2">
默认内容
</slot>
</div>
</template>
<script>
export default {
}
</script>
2.父组件
<template>
<div style="border:1px solid #ccc; margin:5px;padding:5px">
<h1>45-插槽-作用域插槽</h1>
<MyCom>
<!--
v-slot:插槽名="对象"
对象会自动接收这个插槽传递回来自定义属性
-->
<template v-slot:content="scope">
<!-- <h1>自定义的内容,填坑, {{scope}}</h1> -->
<h3>{{scope.a}}</h3>
<p>{{scope.b}}</p>
</template>
</MyCom>
</div>
</template>
<script>
// 父传子
// 1.传数据。 自定义属性 (父) props(子)
// 2.传结构。 在组件中写内容(父) slot (子)
import MyCom from './MyCom.vue'
export default {
components: { MyCom }
}
</script>
<style scoped>
.content{
background-color: #ccc;
}
</style>
小结
组件内变量绑定在slot上,然后使用组件v-slot:插槽名字="变量",变量上就会绑定slot传递的属性和值
8、组件进阶-作用域插槽使用场景
封装一个表格组件,在表格组件内循环产生单元格
[
{
name: "小传同学",
age: 18,
headImgUrl:
"https://www.escook.cn/vuebase/pics/1.png",
},
{
name: "小黑同学",
age: 25,
headImgUrl:
"https://www.escook.cn/vuebase/pics/2.png",
},
{
name: "智慧同学",
age: 21,
headImgUrl:
"https://www.escook.cn/vuebase/pics/3.png",
}
]
1.封装MyTable.vue
<template>
<table>
<tr>
<th>序号</th>
<th>名字</th>
<th>年龄</th>
<th>头像</th>
</tr>
<tr v-for="(item,idx) in list" :key="idx">
<td>{{idx+1}}</td>
<td>{{item.name}}</td>
<td>{{item.age}}</td>
<td>
<!-- slot name具名插槽
slot有自定义的属性,向slot传递数据,这个数据在父组件使用插槽时,能自动接收
-->
<slot name="img" :girl="item" :loveName="item.name" :img="item.headImgUrl">
<!-- 默认内容 -->
<img :src="item.headImgUrl"/>
</slot>
</td>
</tr>
</table>
</template>
<script>
export default {
props: {
list: {
type: Array,
required: true
}
}
}
</script>
2.UserTable -准备数据,传入给MyTable.vue组件里循环使用
<template>
<div style="border:1px solid #ccc; margin:5px;padding:5px">
<h1>46-插槽-作用域插槽-场景</h1>
<MyTable :list="list">
<!-- scope是一个变量名,自动接收slot上的自定义属性 -->
<template v-slot:img="scope">
<img style="display:block;border-radius:50%" :src="scope.img" />
<button @click="like(scope)">点赞</button>
<button>加好友</button>
</template>
</MyTable>
</div>
</template>
<script>
import MyTable from './MyTable.vue'
export default {
data(){
return {
list: [
{
name: "小明同学",
age: 18,
headImgUrl:
"https://www.escook.cn/vuebase/pics/1.png",
},
{
name: "小王同学",
age: 25,
headImgUrl:
"https://www.escook.cn/vuebase/pics/2.png",
},
{
name: "小美同学",
age: 21,
headImgUrl:
"https://www.escook.cn/vuebase/pics/3.png",
}
]
}
},
methods: {
like(obj){
console.log(obj)
}
},
components: { MyTable }
}
</script>
总结: 插槽可以自定义显示内容,作用域插槽可以把组件内额值取出来自定义显示内容
小结
- props允许父向子传入数据
- 插槽允许父传子传入结构
- 作用域插槽允许父向子传入自定义的数据+结构
9、自定义指令-基本使用
除了核心功能默认内置的指令(v-model 和v-show)等,Vue 也允许注册自定义指令 v-xxx
- html + css + js的复用的主要形式是组件
- 你需要对普通DOM 元素进行底层操作,这时候就会用到自定义指令
自定义指令的作用:
扩展标签额外的功能
自定义指令-定义的方式
{
data(){},
methods: {},
directives: {
focus: { // 自定义指令名
inserted(el){ // 固定配置项 - 当指令插入到标签自动触发此函数
el.focus()
}
},
},
}
示例 自动获取焦点
<template>
<div>
<input type="text" v-focus />
</div>
</template>
<script>
export default {
// 注册
directives: {
focus: { // 自定义指令名
inserted(el){ // 固定配置项 - 当指令插入到标签自动触发此函数
el.focus()
}
}
}
}
</script>
自定义指令-传值和更新
定义一个color指令-传入一个颜色,给标签设置文字颜色
directives: {
"color":{
inserted(el, binding){ // 插入时触发此函数
el.style.color = binding.value;
},
update(el, binding){ // 更新绑定的变量时触发此函数=》手动更新
el.style.color = binding.value;
}
}
}
Diewct.vue 处修改以下
<p v-color="theColor" @click="changeColor">使用v-color指令控制颜色, 点击变蓝</p>
<script>
data() {
return {
theColor: "red",
};
},
methods: {
changeColor() {
this.theColor = 'blue';
},
},
</script>
\