各种UI库的功能都是非常强大的,尤其对于我这种不会 css 的人来说,就更是帮了大忙了。

只是嘛,如果再封装一下的话,那么用起来就会更方便了。

那么如何封装呢?

封装三要素 —— 属性、插槽、事件、方法

可以封装,但是原生UI库提供的强大功能不能给封装没了吧,吃了回扣可是不好滴。

那么如何做到不遗漏呢?先做一个合格的传声筒。

传递属性

先看看 el-input 提供的属性:

太长了,这里只截了一半。

这么多的属性,如果一个一个都弄到 props 里面,然后再一个一个绑定上去,这就太麻烦了。

我们可以分成两部分,重要的属性做到 props 里面,其他的可以放到 $attrs 里面。

定义一个简单的组件

模板

<template>
<div>
<el-input
v-model="value" // 不能直接帮的属性
v-bind="$attrs" // 绑定其他属性。
>
</el-input>
</div>
</template>

代码

export default {
name: 'test-text',
inheritAttrs: false,
props: {
modelValue: [String, Number]
},
setup(props, ctx) {
const value = debounceRef(props, ctx.emit) return {
value
}
}
}

父组件的调用代码:

模板

<inputtext
v-model="value"
v-bind="attrs"
>
</inputtext>

代码

const value = ref('222')

const attrs = reactive({
maxlength: 10,
'show-word-limit': true,
clearable: true
})

这里 modelValue 就是 props ,maxlength、show-word-limit、clearable 就变成了 $attrs 。

然后要看 el-input 是否是根元素,如果是跟元素的话,那么会自动绑定上,不需要我们手动写 v-bind="$attrs"

如果像上面的例子不是根元素的话,需要手动写 v-bind="$attrs"

inheritAttrs

这个是指定组件是否自动绑定 $attrs 。

默认是 true,会自动把 $attrs 绑定到根元素上面,不管根元素是啥。

这里设置为 false,那么$attrs 就不会自动绑定到 div 上面了。

插槽

这个稍微复杂一点,插槽本来就有一点绕,官网的介绍又比较含混。

我们可以找到 $slots 这个东东,但是官网的介绍(https://www.vue3js.cn/docs/zh/api/instance-properties.html#slots )却是 使用 h,这个就……

不过想要传递插槽,还是需要这个。

我们先看看 el-input 的插槽的使用。

  <el-input
placeholder="请输入内容"
v-model="input3"
class="input-with-select"
>
<template #prepend>
<el-select v-model="select" placeholder="请选择">
<el-option label="餐厅名" value="1"></el-option>
<el-option label="订单号" value="2"></el-option>
<el-option label="用户电话" value="3"></el-option>
</el-select>
</template>
<template #append>
<el-button icon="el-icon-search"></el-button>
</template>
</el-input>

那么想要传递插槽的话,是不是可以这样?

   <!--传递插槽-->
<template v-slot:prepend> // 给递给el-input 的插槽
<slot name="prepend"></slot> // 接收父组件传递进来的插槽
</template>

测试可以。

那么总不会一个一个写吧,这也太麻烦了。如果能够for就好了。

等等, for?那么我们是不是可以这样。

  <!--传递插槽-->
<template
v-for="(item, key, index) in $slots"
:key="index"
v-slot:[key]
>
<slot :name="key"></slot>
</template>

测试可以。

完整代码

    <el-input
ref="refInput"
v-model="value"
v-bind="$attrs"
>
<!--传递插槽-->
<template
v-for="(item, key, index) in $slots"
:key="index"
v-slot:[key]
>
<slot :name="key"></slot>
</template>
</el-input>

传递事件

这个就简单了,啥都不用做,自动就传递出去了。el-input 是否是跟元素都可以。

测试一下:

 <inputtext
ref="refInput"
v-model="value"
v-bind="props"
@clear="clear"
@my-change="myChange"
>
  • clear 是 el-input 提供的事件,外部可以直接得到这个事件,组件内部不用做操作。
  • my-change 是自定义的事件。

方法

一直都忽略了,还有方法这个事,因为基本没用过。

使用方法嘛,就需要使用 ref,这个此 ref 非彼 ref,说不清了,还是写代码吧。

直接使用的方法

直接使用UI库组件的方法,比如 el-input 的 提供的 select:

<el-input
ref="refInput" // 注意这里的 ref
v-model="value"
v-bind="$attrs" >
</el-input>

ref 的写法,不要加冒号。

const refInput = ref(null) // 先放一个null
onMounted(() => { // 然后在 onMounted 里面才能得到值。
console.log('refinput', refInput) // 看看啥样。
refInput.value.select() // 调用方法,文本框的内容会被选中
})

先定义一个 ref,然后交给模板里的 ref,好像有点绕,这里必须使用 ref,reactive是不行滴。

在渲染后才能生效,也就是说必须在 onMounted 里面才能得到值,我们看看打印结果:(太长只能截取一部分)

很长吧。

父组件里面怎么用方法

<inputtext
ref="refInput"
v-model="value">
</el-input>
// 测试方法
const refInput = ref(null) onMounted(() => {
console.log('refinput', refInput)
// refInput.value.$refs.refInput.select()
refInput.value.refInput.select()
})

父组件里面的用法是一样的,只是需要再套一层,才能拿到自定义组件内部的UI库组件。

看看结构:

太长了,还在下面。

这个就比较近了。

话说为啥弄得这么多属性和方法事件呀?

父组件调用子组件内部的方法

上面那种方式,还可以让父组件调用子组件内部定义的方法,比如内部定义一个

   const setInput = () => {
value.value = new Date()
}

父组件可以这样调用

refInput.value.setInput()

总结

其实事件和方法,并没有封装,而是直接就可以使用的。

这是 element-plus 测试的结果,其他UI库没有测试。

插槽需要写一个 v-for 就可以实现传递,而且是通用的代码。

属性 就需要规划一下了,看设计要求,哪些放在 props里面,哪些放在attrs 里面。

Vue3 封装第三方组件(一)做一个合格的传声筒的更多相关文章

  1. 做一个合格的Team Leader -- 领导和管理基本概念 三种激励手段:恐吓、贪念、承诺

    做一个合格的Team Leader -- 基本概念 1.领导和管理   人们乐于被领导:他们不喜欢被管理,不喜欢像牛一样被驱赶或指挥.   管理者强迫人们服从他们的命令,而领导者则会带领他们一起工作. ...

  2. 用vue的抽象组件来做一个防止img标签url为空或url地址出错的验证

    看了网上文章学习了下vue的抽象组件,感觉就跟react的高阶组件一样的使用场景,只是更加面向vue的底层编程 ,网上介绍的抽象组件一般有2种用法,1 用来加防抖和节流 2 用来控制按钮是否允许点击做 ...

  3. 做一个合格的Team Leader -- 基本概念

    1.领导和管理 人们乐于被领导:他们不喜欢被管理,不喜欢像牛一样被驱赶或指挥. 管理者强迫人们服从他们的命令,而领导者则会带领他们一起工作. 管理是客观的,没有个人感情因素,它假定被管理者没有思想和感 ...

  4. 做一个合格的程序员之浅析Spring AOP源代码(十八) Spring AOP开发大作战源代码解析

    事实上上一篇文章价值非常小,也有反复造轮子的嫌疑,网上AOP的实例非常多,不胜枚举,事实上我要说的并非这个,我想要说的就是上一节中spring的配置文件: 我们这边并没实用到我们上几节分析的哪几个AO ...

  5. .Net MVC&&datatables.js&&bootstrap做一个界面的CRUD有多简单

    我们在项目开发中,做得最多的可能就是CRUD,那么我们如何在ASP.NET MVC中来做CRUD呢?如果说只是单纯实现功能,那自然是再简单不过了,可是我们要考虑如何来做得比较好维护比较好扩展,如何做得 ...

  6. .Net开发笔记(二十)创建一个需要授权的第三方组件

    在使用需要授权的软件时,注册付费的目标是软件的使用者,我们开发人员平时用到的一些第三方组件也是需要授权付费的,也就是说,付费者是开发人员,并不是系统(使用了该第三方组件)的最终使用者. 以上两者的区别 ...

  7. React-Native做一个文本输入框组件

    我又回来啦! 由于最近一直在做公司的项目,而且比较急.如今项目已经迭代到第三期,可以缓一缓了... 说实话,最近一直再用android做开发,而且时间也不宽裕,react-native有点生疏了. 好 ...

  8. VUE2.0+VUE-Router做一个图片上传预览的组件

    之前发了一篇关于自己看待前端组件化的文章,但是由于学习和实践的业务逻辑差异,所以自己练习的一些demo逻辑比较简单,打算用vue重构现在公司做的项目,所以在一些小的功能页面上使用vue来做的,现在写的 ...

  9. Blazor组件自做八 : 使用JS隔离封装屏幕键盘kioskboard.js组件

    1. 运行截图 演示地址 2. 在文件夹wwwroot/lib,添加kioskboard子文件夹,添加kioskboards.js文件 2.1 常规操作,懒加载js库, export function ...

随机推荐

  1. 1. VUE介绍

    今天开始系统学习vue前端框架. 我是有前端基础的, 刚工作那会, 哪里分那么清楚啊, 前后端我都得做, 所以, css, js, jquery, bootstrap都会点, 还系统学过ext, 哈哈 ...

  2. node_puppeteer无界爬虫

    环境:node----v14.5.0 vscode----2019 依赖库 (需要自行设置好目录结构,否则会报目录错误) const puppeteer = require("puppete ...

  3. vue之下拉菜单Dropdown的使用

    通过组件slot来设置下拉触发的元素以及需要通过具名slot为dropdown 来设置下拉菜单.默认情况下,下拉按钮只要hover即可,无需点击也会显示下拉菜单. <el-dropdown> ...

  4. springboot源码(4)

    我们上3个篇章写了springboot的自动装配.servlet组件的注入以及web容器实现内嵌的原理,现在我们来看springboot启动过程中到底做了些什么,也就是打开我们的run方法: 这里我们 ...

  5. Hexo的详细搭建过程——小白的血泪经历QAQ

    Hexo的详细搭建过程 环境要求: node.js git 这里提供Centos8.2下的安装过程: dnf module list nodejs dnf module install nodejs: ...

  6. C++的标识符的作用域与可见性

    下面是关于C++的标识符的作用域与可见性学习记录,仅供参考 标识符的作用域与可见性 作用域是一个标识符在程序正文中有效的区域. 作用域分类 ①函数原型作用域 ②局部作用域(快作用域) ③类作用域 ④文 ...

  7. LeetCode-[list-of-depth-lcci]

    特定深度节点链表-求解每一层二叉树从左到右遍历形成的链表 list-of-depth-lcci 这是关于二叉树的问题,遍历每一层的结点并且存在链表中. 可以采取队列类似于广度优先搜索的方法进行搜索.每 ...

  8. Airbnb JavaScript代码规范(完整)

    类型Types 基本数据类型 string number boolean null undefined symbol const foo = 1; let bar = foo; bar = 9; co ...

  9. Python爬虫学习二------爬虫基本原理

    爬虫是什么?爬虫其实就是获取网页的内容经过解析来获得有用数据并将数据存储到数据库中的程序. 基本步骤: 1.获取网页的内容,通过构造请求给服务器端,让服务器端认为是真正的浏览器在请求,于是返回响应.p ...

  10. WebSocket与即时通讯

    HTTP 协议有一个缺陷:通信只能由客户端发起!HTTP 协议做不到服务器主动向客户端推送信息.这种单向请求的特点,注定了如果服务器有连续的状态变化,客户端要获知就非常麻烦.我们只能使用"轮 ...