自定义和插槽
一:自定义指令
自定义指令:自己定义的指令,可以封装一些dom操作,扩展额外功能
1:回顾内置指令
内置指令 - 就是之前学习过的指令,是vue自身提供的,可以参见我的这个笔记

2:自定义指令的两种写法
自定义指令方式一:全局指令注册main.js中 ->
Vue.directive('指令名称', {指令对象})
// ============ main.js ================
// 全局注册自定义指令-Vue.directive("指令名", {指定对象})
Vue.directive("focus", {
// el就是v-focus绑定的元素
// 当被绑定的元素插入到 DOM 中时……
inserted: function (el) {
// 聚焦元素
el.focus();
}
});
<!-- 一旦这个输入框插入进来页面中(DOM完成渲染),此时自动聚焦到该输入框 -->
<input v-focus type="text" v-model="name">
自定义指令方式二:局部注册,写在当前组件的export default中,只能在当前的组件中使用
export default {
// 局部注册指令
directives: {
// 指令名:指令的配置项
focus: {
// 参数:el -> 绑定v-focus指令的元素
inserted(el) {
el.focus(); // 获取焦点
}
}
}
}
3:总结一下

4:常用自定义指令实战
v-color -> 传入不同的颜色,给标签设置文字颜色

v-loading -> 实现加载中效果

<template>
<!-- 1:准备一个loading类,通过为元素定位,设置宽高100%,实现蒙层 -->
<div class="box" v-loading="isLoading">
<ul>
<!-- v-for循环展示 -->
<li v-for="item in list" :key="item.id" class="news">
<!-- 左侧内容 -->
<div class="left">
<div class="title">{{item.title}}</div>
<div class="info">
<span>{{item.source}}</span>
<span>{{item.time}}</span>
</div>
</div>
<!-- 右侧内容 -->
<div class="right">
<!-- 通过 v-bind的简写绑定属性,简写成为: -->
<img :src="item.img" alt="">
</div>
</li>
</ul>
</div>
</template>
<script>
import axios from 'axios'
export default {
name: "MyLoading",
data() {
return {
list: [],
isLoading: true // 是否显示加载中,初始值是显示加载中
}
},
// created方法,在vue实例创建完毕之后执行,一般用于请求数据
// async 关键字 表示异步请求
// await关键字表示等待异步请求结束,再执行下面的代码
async created() {
const res = await axios.get("http://hmajax.itheima.net/api/news");
// 为了模拟延迟,这里设置休眠2s
setTimeout(() => {
this.list = res.data.data;
this.isLoading = false; // 渲染出数据来了,isLoading置为false, 此时会触发自定义指令的update钩子函数
}, 2000)
},
// 自定义指令,用于实现加载中效果 -> inserted(初始化) update(更新时候的处理)
directives: {
loading: {
inserted(el, binding) {
// binding.value -> 就是绑定的值(isLoading)
binding.value ? el.classList.add("loading") : el.classList.remove("loading");
},
update(el, binding) {
binding.value ? el.classList.add("loading") : el.classList.remove("loading");
}
}
}
}
</script>
<style scoped>
/* 加载中样式 - 蒙层 */
/* 1:准备一个loading类,通过为元素定位,设置宽高100%,实现蒙层 */
.loading:before {
content: "";
position: absolute; /* 设置绝对定位 */
top: 0;
left: 0;
width: 100%;
height: 100%;
background: #fff url("../assets/loading.gif") no-repeat center;
}
.box {
width: 800px; /* 宽度 */
min-height: 500px; /* 最小高度,没有内容的时候的高度 */
border: 3px solid orange; /* 边框设置 - 3像素 实线 橘色 */
border-radius: 5px; /* 圆角 */
position: relative; /* 设置相对定位,方便后续的绝对定位 */
}
.news {
display: flex; /* 设置弹性布局 */
height: 120px;
width: 600px;
margin: 0 auto; /* 设置居中 */
padding: 20px 0; /* 内边距 */
cursor: pointer; /* 设置鼠标样式 */
}
.news .left {
flex: 1; /* 设置弹性布局为1份 */
display: flex;
flex-direction: column; /* 设置弹性布局为垂直布局 */
justify-content: space-between; /* 设置弹性布局为垂直居中 */
padding-right: 10px; /* 设置右边距 */
}
... /* 其他样式 */
</style>

二:插槽
1:默认插槽


<template>
<div class="dialog">
<div class="dialog-header">
<h3>友情提示</h3>
<span class="close">×</span>
</div>
<div class="dialog-body">
<!-- 在可定制的部分使用slot插槽占位 -->
<slot></slot>
</div>
<div class="dialog-footer">
<button class="btn-primary">确定</button>
<button class="btn-default">取消</button>
</div>
</div>
</template>
<script>
export default {
name: 'MyDialog',
data() {
return {
}
},
}
</script>
<style lang="scss" scoped>
</style>
<template>
<div class="App">
<!-- 在使用组件的时候,写入自定义的内容,将会填充slot -->
<MyDialog>我是可定制的内容,我将填充组件中的slot部分</MyDialog>
<MyDialog>我也是可定制的内容,我将填充组件中的slot部分</MyDialog>
</div>
</template>
<script>
// 1.引入组件
import MyDialog from "@/components/MyDialog.vue";
export default {
name: 'App',
components: {
MyDialog
}
}
</script>
<style lang="less" scoped>
/* 设置样式 */
.App {
width: 600px;
height: 700px;
background-color: #87ceeb;
margin: 0 auto; /* 居中 */
padding: 20px; /* 边距 */
}
</style>
2:后备内容(默认值)

3:具名插槽
在slot中通过name区分名称,然后再使用端通过template + v-slot:名字分发对应的标签

4:作用域插槽(插槽传值)

- 给slot标签,通过添加属性的方式进行传值
<slot :id="item.id" msg="我是一个消息"></slot>
- 所有添加的属性,都会被收集到一个对象中
{
id: 3
msg: "我是一个消息"
}
3:在使用端,template中通过#插槽名字="obj"接收,默认的插槽名字是default
1262

被折叠的 条评论
为什么被折叠?



