Bootstrap

【Vue】自定义指令、插槽

目录

自定义指令

是什么

作用

使用方法

定义

使用 

自定义指令配合绑定数据

语法

自定义指令的简写

语法

使用时机

插槽

什么是插槽

默认(匿名)插槽

​编辑插槽的默认值

具名插槽

使用方法

简写

使用示例 

作用域插槽


自定义指令

是什么

  • 内置指令:是vue3自带的,比如:v-model、v-for、v-if....我们可以直接使用。
  • 自定义指令:相对内置指令而言,我们自己编写的指令,当内置指令无法满足需求的时候,就可以自己编写的指令。

作用

封装一段公共的DOM操作的代码。

与ref属性操作DOM的区别:

  1. ref是作用在单个标签上的,代码无法复用
  2. 自定义指令可以把一段公共的DOM操作代码封装起来,进行复用

使用方法

定义

main.js -> app.directive('指令名',{

        mounted(el){

                //el就是指令所在的DOM元素

        }

})

示例:在main.js文件中

const app=createApp(App)

app.directive('jujiao',{
    mounted(el){
        el.focus()
    }
})

app.mount('#app')

使用 

<XXX v-指令名>

<template>
    <input type="text" v-jujiao/>
</template>

自定义指令配合绑定数据

语法

1、在绑定指令时,可以通过“等号”的形式为指令绑定具体的参数值

<template>
    <div v-color="colorStr">
        Hello World
    </div>
</template>

<script setup>
    import { ref } from 'vue'

    const colorStr = ref('blue')
</script>

2、通过binding.value可以拿到指令值,指令值修改会触发updated钩子

app.directive('color',{
     //mouted钩子只负责初次渲染,后续指令所在表达式的值变了,该函数不会执行,因此需要引入updated钩子
    mounted(el,binding){
        //el就是指令所在的DOM元素
        //binding:指令绑定的信息对象,通过binding.value获取表达式结果
        el.style.color=binding.value
    },
    updated(el,binding){
        el.style.color=binding.value
    }
})

自定义指令的简写

将上面提到指令的mounted()和updated()两个钩子进行合写,用一个函数来代替,并且这个函数会在mounted()和updated()时机都会执行。

语法

app.directive('color',(el,binding)=>{
    el.style.color=binding.value
})

使用时机

  1. 当自定义指令绑定数据,那么就可以简写(简写的本质=mounted()+updated())
  2. 当自定义指令没有绑定数据,那么就采用非简写的方式。

插槽

什么是插槽

        本质就是一个占位符,今后可以给这个占位符传入想要的组件结构,从而大大提高组件的灵活性和可复用性。

默认(匿名)插槽

作用

让组件内部的一些结构支持自定义

语法

  1. 在使用组件的时候,把组件写成双标签
  2. 在双标签之间传入想展示的结构,从而替换占位的slot组件

子组件

<script setup></script>
<template>
	<div class="dialog">
		<div class="dialog-header">
			<h3>友情提示</h3>
			<span class="close">✖️</span>
		</div>
		<div class="dialog-content">
			<!-- 1. 在组件内标签不确定位置用 slot 组件 -->
			<slot></slot>
		</div>
		<div class="dialog-footer">
			<button>取消</button>
			<button>确认</button>
		</div>
	</div>
</template>

<style scoped>
	* {
		margin: 0;
		padding: 0;
	}
	.dialog {
		width: 470px;
		height: 230px;
		padding: 0 25px;
		background-color: #ffffff;
		margin: 40px auto;
		border-radius: 5px;
	}
	.dialog-header {
		height: 70px;
		line-height: 70px;
		font-size: 20px;
		border-bottom: 1px solid #ccc;
		position: relative;
	}
	.dialog-header .close {
		position: absolute;
		right: 0px;
		top: 0px;
		cursor: pointer;
	}
	.dialog-content {
		height: 80px;
		font-size: 18px;
		padding: 15px 0;
	}
	.dialog-footer {
		display: flex;
		justify-content: flex-end;
	}
	.dialog-footer button {
		width: 65px;
		height: 35px;
		background-color: #ffffff;
		border: 1px solid #e1e3e9;
		cursor: pointer;
		outline: none;
		margin-left: 10px;
		border-radius: 3px;
	}
	.dialog-footer button:last-child {
		background-color: #007acc;
		color: #fff;
	}
</style>

App.vue 

<template>
    <!-- 在使用组件的时候,给组件传入想展示的结构,从而替换掉组件内的slot组件 -->
    <MyDialog>
        <span>你确定要进行删除操作吗?</span>
    </MyDialog>
    <MyDialog>
        <span>你确定要退出本系统吗?</span>
    </MyDialog>
</template>

<script setup>
    import MyDialog from './components/MyDialog.vue';
</script>

插槽的默认值

如果未传入内容,则显示slot标签内的内容 

<slot> 我是默认内容 </slot>

默认值的生效规则:

  1. 如果没传,就显示默认值,防止页面空白
  2. 如果传入了,就会用传入的,替换掉占位的slot,从而展示实际传入的标签结构

具名插槽

一个组件内有多处结构,需要外部传入标签,进行定制,默认插槽只能定制一处内容。这是给插槽添加name属性,进行区分,添加name属性的插槽就是具名插槽。

使用方法

<slot name="插槽名"> 默认的内容</slot>

<template v-slot:插槽名> 要展示的内容</template> 

简写

<template #插槽名> 要展示的内容</template>

使用示例 

根组件

<template>
    <!-- 在使用组件的时候,给组件传入想展示的结构,从而替换掉组件内的slot组件 -->
    <MyDialog>
        <template v-slot:title>
            <span>删除确认</span>
        </template>
        <template v-slot:content>
            <span>你确定要进行删除操作吗?</span>
        </template>
    </MyDialog>
    
</template>

<script setup>
    import MyDialog from './components/MyDialog.vue';
</script>

子组件(插槽) 

<script setup></script>
<template>
	<div class="dialog">
		<div class="dialog-header">
			<slot name="title"></slot>
			<span class="close">✖️</span>
		</div>
		<div class="dialog-content">
			<!-- 1. 在组件内标签不确定位置用 slot 组件 -->
			<slot name="content"></slot>
		</div>
		<div class="dialog-footer">
			<button>取消</button>
			<button>确认</button>
		</div>
	</div>
</template>

<style scoped>
	* {
		margin: 0;
		padding: 0;
	}
	.dialog {
		width: 470px;
		height: 230px;
		padding: 0 25px;
		background-color: #ffffff;
		margin: 40px auto;
		border-radius: 5px;
	}
	.dialog-header {
		height: 70px;
		line-height: 70px;
		font-size: 20px;
		border-bottom: 1px solid #ccc;
		position: relative;
	}
	.dialog-header .close {
		position: absolute;
		right: 0px;
		top: 0px;
		cursor: pointer;
	}
	.dialog-content {
		height: 80px;
		font-size: 18px;
		padding: 15px 0;
	}
	.dialog-footer {
		display: flex;
		justify-content: flex-end;
	}
	.dialog-footer button {
		width: 65px;
		height: 35px;
		background-color: #ffffff;
		border: 1px solid #e1e3e9;
		cursor: pointer;
		outline: none;
		margin-left: 10px;
		border-radius: 3px;
	}
	.dialog-footer button:last-child {
		background-color: #007acc;
		color: #fff;
	}
</style>

作用域插槽

带数据的插槽,用slot占位的同时,还可以给slot绑定数据,也就是说数据来源于插槽,但是怎么展示这些数据由自定义结构决定。

接收插槽数据

这里的obj就代表对应slot标签绑定的所有数据的对象

<template v-slot:content="obj">
    <span>obj.a={{ obj.a }}</span>
</template>

上面是使用一个对象进行接收,我们也可以对接收的数据进行解构,直接获取指定的数据,如下:

<template v-slot:content="{a}">
    <span> a={{ a }}</span>
</template>

slot绑定数据

<div class="dialog-content">
	<slot name="content" a="123" b="456"></slot>
</div>

;