前端框架之封装Vue第三方组件三个技巧
作者:红尘炼心 发布时间:2023-07-02 16:37:03
引言
在封装第三方组件中,经常会遇到一个问题,如何通过封装的组件去使用第三方组件的Attributes(属性)、Events(自定义事件)、Methods(方法)、Slots(插槽)。
当然这个问题并不是难以解决,用普通方法解决难免陷入繁琐重复的工作中,而且封装的组件代码可读性也不高。
本专栏将介绍三种技巧来使用第三方组件的Attributes(属性)、Events(自定义事件)、Slots(插槽),至于使用第三方组件的Methods(方法)的技巧还待优化。
一、使用第三方组件的属性
封装一个elementUI的el-input输入框组件称为myInput,若要在myInput组件上添加一个disabled
属性来禁用输入框,要如何实现呢?一般同学会这么做
//myInput.vue
<template>
<div>
<el-input v-model="inputVal" :disabled="disabled"></el-input>
</div>
</template>
<script>
export default {
props: {
value: {
type: String,
default: '',
},
disabled: {
type: Boolean,
default: false
}
},
computed: {
inputVal: {
get() {
return this.value;
},
set(val) {
this.$emit('input', val);
}
}
}
}
</script>
过一段时间后又要在myInput组件上添加el-input组件的其它属性,el-input组件总共有27个多属性,那该怎么呢,难道一个个用prop传进去,这样不仅繁琐而且可读性差,可以用$attrs
一步到位,先来看一下attrs
的官方定义。
$attrs
: 包含了父作用域中不作为 prop
被识别 (且获取) 的 attribute 绑定 (class 和 style 除外)。当一个组件没有声明任何prop
时,这里会包含所有父作用域的绑定 (class 和 style 除外),并且可以通过 v-bind="$attrs"
传入内部组件
//myInput.vue
<template>
<div>
<el-input v-model="input" v-bind="$attrs"></el-input>
</div>
</template>
这还不够,还得把inheritAttrs
选项设置为false
,为什么呢,来看一下inheritAttrs
选项的官方定义就明白了。
默认情况下父作用域的不被认作 props 的 attribute 绑定 (attribute bindings) 将会“回退”且作为普通的 HTML attribute 应用在子组件的根元素上。当撰写包裹一个目标元素或另一个组件的组件时,这可能不会总是符合预期行为。
通过设置 inheritAttrs
为 false
,这些默认行为将会被去掉。而通过 $attrs
可以让这些 attribute 生效,且可以通过 v-bind
显性的绑定到非根元素上。注意:这个选项不影响 class 和 style 绑定。
简单来说,把inheritAttrs
设置为false
,避免给myInput组件设置的属性被添加到myInput组件的根元素div上。
//myInput.vue
<template>
<div>
<el-input v-model="input" v-bind="$attrs"></el-input>
</div>
</template>
<script>
export default {
inheritAttrs: false,
props: {
value: {
type: String,
default: '',
},
},
computed: {
inputVal: {
get() {
return this.value;
},
set(val) {
this.$emit('input', val);
}
}
}
}
</script>
这样设置后,在myInput组件上就可以直接使用el-input组件的属性,不管后续el-input组件再增加了多少个属性。
二、使用第三方组件的自定义事件
若在myIpput组件上使用el-input组件上自定义的事件呢,可能你的第一反应是this.$emit
。
//myInput.vue
<template>
<div>
<el-input v-model="input" v-bind="$attrs" @blur="blur"></el-input>
</div>
</template>
<script>
export default {
inheritAttrs: false,
props: {
value: {
type: String,
default: '',
},
},
computed: {
inputVal: {
get() {
return this.value;
},
set(val) {
this.$emit('input', val);
}
}
},
methods: {
blur() {
this.$emit('blur')
}
}
}
</script>
<myInput v-model="value" @blur="handleBlur"></myInput>
el-input组件有4个自定义事件,还不算多,假如遇到自定义事件更多的第三方组件,要怎么办,难道一个一个添加进去,这样会增加一堆非必要的methods,其实可以用$listeners
一步到位,先来看一下$listeners
的官方定义。
$listeners
:包含了父作用域中的 (不含 .native 修饰器的) v-on 事件 * 。它可以通过 v-on="$listeners" 传入内部组件。
//myInput.vue
<template>
<div>
<el-input v-model="input" v-bind="$attrs" v-on="$listeners"></el-input>
</div>
</template>
那么在myInput组件中给el-input组件添加上v-on="$listeners"
,就可以在myInput组件上使用el-input组件自定义的事件。
三、使用第三方组件的插槽
若在myIpput组件上使用el-input组件上定义的插槽呢?这个没有多少取巧的方法,第三方组件定义多少个插槽,在封装的时候都得用slot
标签暴露出去。比如暴露el-input组件中的prefix插槽,代码如下所示:
//myInput.vue
<template>
<div>
<el-input v-model="input" v-bind="$attrs" @blur="blur">
<template #prepend>
<slot name="prepend"></slot>
</template>
</el-input>
</div>
</template>
四、使用第三方组件的方法
利用ref
来实现,首先在myInput组件中的el-input组件上添加一个ref="elInput"
属性,
//myInput.vue
<template>
<div>
<el-input ref="elInput></el-input>
</div>
</template>
<script>
export default {
mounted(){
this.elInput = this.$refs.elInput;
}
}
</script>
这里要注意父子组件的mounted
的执行时机,因为一般el-input组件是全局引入的,相当同步引入组件,此时el-input组件的mounted
会比myInput组件的mounted
先执行,所以可以在myInput组件的mounted
中把this.$refs.elInput
赋值到myInput组件的this
的一个属性上。
myInput组件如何使用el-input组件的方法分两种情况,跟myInput组件的引入有关系。
假如myInput组件是同步引入的
<template>
<div>
<myInput ref="myInput"></myInput>
</div>
</template>
<script>
import myInput from './myInput.vue';
export default {
data() {
return {
}
},
components: {
myInput,
},
mounted() {
//调用el-input组件的focus方法
this.$refs.myInput.elInput.focus();
}
}
</script>
假如myInput组件是异步引入的
<template>
<div>
<myInput ref="myInput"></myInput>
</div>
</template>
<script>
export default {
data() {
return {
}
},
components: {
myInput: () => import('./myInput.vue')
},
mounted() {
//调用el-input组件的focus方法
setTimeout(() => {
this.$refs.myInput.elInput.focus();
})
}
}
</script>
来源:https://juejin.cn/post/6943534547501858824#heading-4
猜你喜欢
- 1、什么是版本控制系统版本控制是一种记录一个或若干个文件内容变化,以便将来查阅特定版本修订情况的系统。版本控制系统不仅可以应用于软件源代码的
- 在本项目中,将会用Keras来搭建一个稍微复杂的CNN模型来破解以上的验证码。验证码如下: 利用Keras可以快速方便地搭建CNN
- 本文实例讲述了python用来获得图片exif信息的库用法。分享给大家供大家参考。具体分析如下:exif-py是一个纯python实现的获取
- 优雅的设计经常包含一些特殊的字体,而这些字体并不存在于用户的字体库中,我们并不能奢求每一个访客都是设计师。 :-)虽然CSS3标
- 在IE浏览器调试代码,我们可以选择使用 IE WebDeveloper但是我个人用惯了ff浏览器下的firebug,所以在网上搜了一下,如果
- Python 三元运算符Python 三元运算符用于根据条件选择两个值之一。它是 if-else 语句的一个缩影,它将两个值之一分配给一个变
- selenium3.0之后的版本的就不支持直接打开火狐浏览器,启动火狐浏览器报错,如下图,要想运行就需要我们单独装上驱动。3.0之前的版本,
- 面试题:索引的作用?首先建立一张数据库表:create table single_table(id int not auto_increme
- 在jQuery的官方文档中,提示用户这是一个低级的方法,应该用.data()方法来代替。$.data( element, key, valu
- openpyxl打开的文件是否需要关闭如果是只读或者只写的模式下,是需要再调用close()方法关闭workbook,正常的情况下是不需要调
- 查看当前用户拥有的系统权限 select * from user_sys_privs; 系统权限 系统管理员授予-----sys用户 cre
- 即使MyISAM表格式非常可靠(SQL语句对表做的所有改变在语句返回之前被写下),如果下列任何事件发生,你依然可以获得损坏的表:&m
- 最近写程序需要从文件中读取数据,并把读取的数据转换成向量。查阅资料之后找到了读取csv文件和txt文件两种方式,下面结合自己的实验过程,做简
- opencv读取和写入路径有汉字的处理读取图片 img_gt = cv2.imdecode(np.fromfile(path, d
- vscode 的调试功能其实提供了一键编译运行的功能(ctrl+F5),但是启动特别特别慢… 又不想安装插件,后来发现vscode 提供了一
- 今天对add_months函数进行简单总结一下:add_months 函数主要是对日期函数进行操作,在数据查询的过程中进行日期的按月增加,其
- 本文介绍基于Python中gdal模块,实现对大量栅格图像批量绘制直方图的方法。首先,明确一下本文需要实现的需求:现需对多幅栅格数据文件进行
- #/usr/bin/env/python#coding=utf-8import sys,re,time,osmaxdata = 50000
- 指令和程序计算机的硬件系统通常由五大部件构成,包括:运算器、控制器、存储器、输入设备和输出设备。其中,运算器和控制器放在一起就是我们通常所说
- 在seclists中看到一个很惊人的thread:http://seclists.org/oss-sec/2012/q2/493MySQL爆