-
{{ item.title }}{{ item.source }} {{ item.time }}
Date: May 25, 2023
Sum: 自定义指令、插槽、商品列表、动态组件
概念:
内置指令:vue 官方提供了 v-for、v-model、v-if 等常用的内置指令。
自定义指令:Vue支持让开发者,自己注册一些指令。这些指令被称为自定义指令。
自定义指令可以封装一些 dom 操作,扩展额外功能。
类型:私有自定义指令和全局自定义指令
语法:
指令中的配置项介绍:
inserted:当指令所绑定的元素,被添加到页面当中时,会自动调用
换句话说,就是被绑定元素插入父节点时调用的钩子函数
el:使用指令的那个DOM元素
局部注册:
在每个 vue 组件中,可以在 directives 节点下声明私有自定义指令。
示例代码如下:
//在Vue组件的配置项中
directives: {
"指令名": {
inserted () {
// 可以对 el 标签,扩展额外功能
el.focus()
}
}
}
directives: {
// 自定义一个私有指令
focus: {
// 当被绑定的元素插入到 DOM 中时,自动触发 mounted 函数
mounted(el) {
el.focus() // 让被绑定的元素自动获得焦点
}
}
},
注意:自定义指令在使用的时候以v-开头,但是在声明的时候不需要加v-前缀
全局注册:
//在main.js中
Vue.directive('指令名', {
"inserted" (el) {
// 可以对 el 标签,扩展额外功能
el.focus()
}
})
全局共享的自定义指令需要通过“单页面应用程序的实例对象”进行声明,示例代码如下:
const app = Vue.createApp({})
// 注册一个全局自定义指令 `v-focue`
app.directive('focus', {
// 当被绑定的元素插入到 DOM 中时,自动触发 mounted 函数
mounted(el) {
// Focus the element
el.focus()
}
})
使用自定义指令
在使用自定义指令时,需要加上 v- 前缀。
示例代码如下:
案例:当页面加载时,让元素获取焦点(autofocus在safari浏览器有兼容性)
Code: 采用局部注册与全局注册两种方式
App.vue
自定义指令
main.js
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
// 全局注册指令
Vue.directive('focus', {
inserted(el) {
el.focus()
}
})
new Vue({
render: h => h(App),
}).$mount('#app')
**需求:**实现一个 color 指令 - 传入不同的颜色, 给标签设置文字颜色
语法:
1.在绑定指令时,可以通过“等号”的形式为指令 绑定 具体的参数值
我是内容
2.通过 binding.value 可以拿到指令值,指令值修改会 触发 update 函数
directives: {
color: {
inserted (el, binding) {
el.style.color = binding.value
},
update (el, binding) {
el.style.color = binding.value
}
}
}
updated 函数
mounted或inserted 函数只在元素第一次插入 DOM 时被调用,当 DOM 更新时 mounted或inserted 函数不会被触发。 updated函数会在每次 DOM 更新完成后被调用。
示例代码如下:
app.directive('focus', {
mounted(el) { // 第一次插入 DOM 时触发这个函数
el.focus()
},
updated(el) { // 每次 DOM 更新时都会触发 updated 函数
el.focus()
}
})
注意:在 vue2 的项目中使用自定义指令时,【 mounted -> bind 】【 updated -> update 】
函数简写
如果 mounted 和updated 函数中的逻辑完全相同,则可以简写成如下格式:
app.directive('focus', (el) => {
// 在 mounted 和 updated 时都会触发相同的业务处理
el.focus()
})
案例:
Code:
App.vue
指令的值1测试
指令的值2测试
场景:
开发过程中,发送请求需要时间,在请求的数据未回来时,页面会处于空白状态 => 用户体验不好
**需求:**封装一个 v-loading 指令,实现加载中的效果
分析:
1.本质 loading效果就是一个蒙层,盖在了盒子上
2.数据请求中,开启loading状态,添加蒙层
3.数据请求完毕,关闭loading状态,移除蒙层
实现:
1.准备一个 loading类,通过伪元素定位,设置宽高,实现蒙层
2.开启关闭 loading状态(添加移除蒙层),本质只需要添加移除类即可
3.结合自定义指令的语法进行封装复用
.loading:before {
content: "";
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
background: #fff url("./loading.gif") no-repeat center;
}
案例:
Code:
App.vue
-
{{ item.title }}
{{ item.source }}
{{ item.time }}
总结:
准备类名 loading,通过伪元素提供遮罩层
添加或移除类名,实现loading蒙层的添加移除
利用指令语法,封装 v-loading 通用指令
inserted 钩子中,binding.value 判断指令的值,设置默认状态
update 钩子中,binding.value 判断指令的值,更新类名状态
概念:
插槽(Slot)是 vue 为组件的封装者提供的能力。允许开发者在封装组件时,把不确定的、希望由用户指定的部分定义为插槽。
作用:让组件内部的一些 结构 支持 自定义
可以把插槽认为是组件封装期间,为用户预留的内容的占位符。
案例:
将需要多次显示的对话框,封装成一个组件
组件的内容部分,不希望写死,希望能使用的时候自定义。怎么办
在封装组件时,可以通过 元素定义插槽,从而为用户预留内容占位符。
注意:给插槽传入内容时,可以传入纯文本、html标签、组件
示例代码如下:
MyCom.vue
这是第一个p标签
这是最后一个p标签
App.vue
~~~用户自定义的内容~~~
没有预留插槽的内容会被丢弃
如果在封装组件时没有预留任何 插槽,则用户提供的任何自定义内容都会被丢弃。
示例代码如下:
MyCom.vue
这是第一个p标签
这是最后一个p标签
App.vue
~~~用户自定义的内容~~~
默认内容
封装组件时,可以为预留的 插槽提供后备内容(默认内容)。如果组件的使用者没有为插槽提供任何内容,则后备内容会生效。
示例代码如下:
这是第一个p标签
这是后备内容
这是最后一个p标签
案例:对话框复用
需求:一个组件内有多处结构,需要外部传入标签,进行定制
上面的弹框中有三处不同,但是默认插槽只能定制一个位置,这时候怎么办呢?
解决方案:如果在封装组件时需要预留多个插槽节点,则需要为每个 插槽指定具体的 name 名称。这种带有具体名称的插槽叫做“具名插槽”。
示例代码如下:
多个slot使用name属性区分名字
MyCom.vue
注意:没有指定 name 名称的插槽,会有隐含的名称叫做 “default”。
App.vue
为具名插槽提供内容
通过 元素上使用 v-slot 指令向具名插槽提供内容,并以 v-slot 的参数的形式提供其名称。即,template配合v-slot:名字来分发对应标签。
App 根组件
滕王阁序
test1
test2
test3
落款:王勃
案例:
Code:
App.vue
一段内容
MyDialog.vue
友情提示
✖️
具名插槽的简写形式
跟 v-on 和 v-bind 一样,v-slot 也有缩写,即把参数之前的所有内容 (v-slot:) 替换为字符 #。
例如 v-slot:header可以被重写为 #header
App.vue
App 根组件
滕王阁序
test1
test2
test3
落款:王勃
概念:在封装组件的过程中,可以为预留的 插槽绑定 props 数据,这种带有 props 数据的 叫做“作用域插槽”。
分类:
作用:定义slot 插槽的同时, 是可以传值的。给 插槽 上可以 绑定数据,将来 使用组件时可以用
案例:
案例1:封装表格组件
使用步骤:
1- 给 slot 标签, 以添加属性的方式传值
2- 所有添加的属性, 都会被收集到一个对象中
{ id: 3, msg: '测试文本' }
3- 在template中, 通过 #插槽名= "obj"
接收,默认插槽名为 default
Code:
MyTable.vue
序号
姓名
年纪
操作
{{ index + 1 }}
{{ item.name }}
{{ item.age }}
App.vue
对于Code的用法的理解:
解构作用域插槽的 Prop
作用域插槽对外提供的数据对象,可以使用解构赋值简化数据的接收过程。
示例代码如下:
效果:
需求说明:
(1) 双击显示输入框,输入框获取焦点
(2) 失去焦点,隐藏输入框
(3) 回显标签信息
(4) 内容修改,回车 → 修改标签信息
(1) 动态传递表格数据渲染
(2) 表头支持用户自定义
(3) 主体支持用户自定义
封装内容:MyTag
完成步骤:
(1) 双击显示输入框,输入框获取焦点
关键点:
1-显示输入框:v-if v-else @dbclick
2-自动聚焦: n e x t T i c k → nextTick→ nextTick→refs 获取dom 或者 自定义指令v-focus
(2) 失去焦点,隐藏输入框
关键点:
1-@blur=”isEdit = false”
Code:
App.vue
编号
名称
图片
标签
1
梨皮朱泥三绝清代小品壶经典款紫砂壶
MyTag.vue
茶具
main.js
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
// 全局注册指令
Vue.directive('focus', {
inserted(el) {
el.focus()
}
})
new Vue({
render: h => h(App),
}).$mount('#app')
(3) 回显标签信息
关键点:
1-回显的标签
回显的标签信息是父组件传递过来的
v-model实现功能(简化代码) v-model ⇒ :value 和 @input
(4) 内容修改,回车 → 修改标签信息
关键点:
1-enter子传父
子传父,将回车时,输入框的内容提交给父组件更新
由于父组件是v-model,触发事件,需要触发 input 事件
2-拿到文本框中实时的值:
e.target 指触发事件的事件源
Code:
App.vue
编号
名称
图片
标签
1
梨皮朱泥三绝清代小品壶经典款紫砂壶
MyTag.vue
{{ value }}
(1) 动态传递表格数据渲染
(2) 表头支持用户自定义
(3) 主体支持用户自定义
关键:插槽(具名插槽、作用域插槽)
Code:
App.vue
编号
名称
图片
标签
{{ index }}
{{ item.name }}
MyTable.vue
MyTag.vue同上
动态组件指的是动态切换组件的显示与隐藏。vue 提供了一个内置的 组件,专门用来实现组件的动态渲染。
① 是组件的占位符
② 通过 is 属性动态指定要渲染的组件名称
③
示例代码如下:
data() {
return {
comName: 'MyHome' // 1.当前要渲染的组件的名称
}
},
App 根组件
注意:当我们切换组件时,之前组件会被销毁(所以之前的数据也会被清空)
默认情况下,切换动态组件时无法保持组件的状态。此时可以使用 vue 内置的 组件保持动态组件的状态。
示例代码如下: