elementui源码学习之仿写一个el-tooltip
本篇文章记录仿写一个前言 什么是编程el-tooltip
组件细节,从而有助于大家更好理解饿了么ui对应组件具体工作细节。本文是elementui源码学习仿写系列的又一篇文章,后续空闲了会不断更新并仿写其他组件。源码在github上,大家可以拉下来,npm start运行跑起来,结合注释有助于更好的理解。github仓库地址如下:
https://github.com/shuirongsh...
关于什么是编程这个问题,的确有很多答案。在很久以前,在笔者刚入行的时候,被告知了这样一句话:
编程就是:规则的学习,规则的使用,规则的理解、规则的自定义
有一定的道理...
背景介绍
我们在做组件的封装时,常常会遇到一些“弹框组件”,以饿了么UI为例,比如:
el-tooltip组件
、el-popover组件
、el-popconfirm组件
、el-dropdown组件
等,这类组件在操作的时候,常常会有一个弹框出现,对于这些弹框的触发条件(或悬浮、或点击)以及位置的控制(上方、下方、左侧、右侧)等,vue团队专门封装了一个vue-popper组件
,通过props
传参以及一些事件方法的方式,去控制以达到我们想要的效果那么,
vue-popper组件
是如何实现的呢?底层原理是啥?是把popper.js
这个很优秀的库做了一层封装那么,
popper.js
是如何实现的呢?底层原理是啥?是通过js
控制弹出框dom
的位置由于
popper.js
国内资料不多,所以大家可以直接使用vue-popper组件
组件去做一些操作即可,毕竟其底层原理,也是prpper.js
el-tooltip组件
是使用了vue-popper组件
的规则vue-popper组件
是使用了popper.js库
的规则popper.js库
是使用了js和dom
的规则- 无限规则套娃...
本篇文章着眼于,中层底层原理prpper.js
官网:https://popper.js.org/、中文...
感兴趣的道友,可以空闲时间研究研究(像elementUI
和iview
和Bootstrap
和Material UI
等都用到了proper.js
)也是做的二次封装
【elementui源码学习之仿写一个el-tooltip】另:prpper.js
团队专门给react
写了一套React Popper
,vue
暂时没有,所以咱们就学习vue-popper
呗
vue-popper组件
,让我们开始学习吧tooltip组件思考 什么是tooltip组件
- tooltip组件是用来做简单的文字附带说明(提示)的气泡框组件
- 一般交互是鼠标移入显示,鼠标移出消失
- tooltip组件一般不会做复杂的交互操作,以及承载过多的文本内容
- 可以理解为是dom元素title属性功能的具体补充
- 暗黑模式tooltip,黑底白字
- 高亮模式tooltip,白底黑字
- tooltip组件的位置,在指向引用reference元素的那个方向,一般是上下左右,拓展共有12个方向
- tooltip的小三角形(一般是显示的)
- 可控制关闭开启,即符合条件hover展示,反之hover关闭
- 一般情况下tooltip都是单行内容,若内容过多,支持文字换行乃至自定义tooltip一些样式(支持插槽)
- 至于其他的需求如:tooltip显示展开的过渡动画、小箭头是否可以隐藏、以及偏移量offset、延迟出现消失等,一般情况下不会怎么更改,所以本文着眼于重点常见需求,来进行说明
一个简单的tooltip的demo 主要是使用属性选择器去控制,四个方向的tooltip和三角形小箭头。
标签的
whichPlacement属性值为"top"时
,就让其在上方,为left时
,就让其在左侧,其他方位同理demo效果图
文章图片
demo代码
复制粘贴即可使用
Document - 锐客网 body {
box-sizing: border-box;
padding: 60px 240px;
}/* 设置基本样式 */
.item {
width: fit-content;
box-sizing: border-box;
padding: 12px;
border: 2px solid #aaa;
/* 搭配伪元素,用相对定位 */
position: relative;
}/* 使用伪元素创建tooltip */
.item::after {
/* 内容为 使用 tooltipContent的属性值 */
content: attr(tooltipContent);
position: absolute;
background-color: #000;
width: fit-content;
height: auto;
padding: 6px 12px;
color: #fff;
border-radius: 12px;
/* 文字不换行 */
word-break: keep-all;
display: none;
}/* 使用伪元素创建小三角形 */
.item::before {
content: "";
position: absolute;
border-width: 6px 6px 0 6px;
border-style: solid;
border-color: transparent;
border-top-color: black;
display: none;
}/* 上下左右四个方位,使用css的属性选择器控制tooltip和小三角形 */
/* 当whichPlacement的属性值为top时,做...样式 */
/* 上方 */
[whichPlacement='top']::after {
left: 50%;
transform: translateX(-50%);
top: -100%;
}[whichPlacement='top']::before {
top: -26%;
left: 50%;
transform: translateX(-50%);
}/* 下方 */
/* 当whichPlacement的属性值为bottom时,做...样式 */
/* 关于四个方向的小三角形,可以使用旋转更改即可 */
[whichPlacement='bottom']::after {
left: 50%;
transform: translateX(-50%);
bottom: -100%;
}[whichPlacement='bottom']::before {
bottom: -28%;
left: 50%;
transform: rotate(180deg);
}/* 左侧 */
/* 当whichPlacement的属性值为left时,做...样式 */
[whichPlacement='left']::after {
top: 50%;
transform: translateY(-50%);
right: 108%;
}[whichPlacement='left']::before {
top: 50%;
transform: translateY(-50%) rotate(270deg);
left: -10.5px;
}/* 右侧 */
/* 当whichPlacement的属性值为right时,做...样式 */
[whichPlacement='right']::after {
top: 50%;
transform: translateY(-50%);
left: 108%;
}[whichPlacement='right']::before {
top: 50%;
transform: translateY(-50%) rotate(90deg);
right: -10px;
}.item:hover::after {
display: block;
}.item:hover::before {
display: block;
}
悬浮上方
悬浮下方
悬浮左侧
悬浮右侧
关于css属性选择器和attr()函数
上述代码中用到了属性选择器和attr()函数,这里简单的提一下
属性选择器
问:什么是属性选择器?
答1:
通过选取带有指定标签属性的dom元素,进行样式的设置
答2:
通过标签的属性名key和属性值value来匹配元素,从而进行样式的设置
问:举个例子呗
答:
[attr]
匹配所有具有attr
属性的元素,不用管其值是什么,如:input[type]{ ... }
,意为:只要input
标签中,包含type
属性(忽略type
属性值),都选中,并设置...
样式[attr='val']
匹配所有attr
属性值等于val
,完全精准匹配。如:input[type='text']{ ... }
,意为:只要input
标签中,有type
属性,且属性值为text
,才去选中,并匹配...
样式[attr^='val']
匹配所有attr
属性值以val
开头的(上述demo案例中就用到了,只不过其属性是我们自定义的)。模糊匹配[attr$='val']
,同上类似,^=
是以什么什么开头匹配,$=
是以什么什么结尾匹配。模糊匹配[attr*='val']
,同上类似,*=
是只要包含即可,也是模糊匹配
详见官方属性选择器介绍:https://www.w3school.com.cn/c...attr()函数
attr
是attribute
单词属性
的缩写,顾名思义,所以这个东西和属性有关css
的函数attr()
可获取被选中元素的属性值
,并且在样式文件中使用。可用在伪元素里,在伪类元素里使用,它得到的是伪元素的原始元素的值。attr()
函数可以和任何css
属性一起使用,但是除了content
外,其余都还是试验性的,所以建议:除了搭配伪元素的content
别的都不要用
悬浮上方.item::after {
/* 使用选中标签的tooltipContent属性值作为content的内容 */
content: attr(tooltipContent);
}
官方attr函数介绍:https://developer.mozilla.org...为什么要说属性选择器呢?因为封装的代码中能够用到啊
使用
vue-popper
做组件的封装
安装// CDN// NPM
npm install vue-popperjs --save
// Yarn
yarn add vue-popperjs
// Bower
bower install vue-popperjs --save
官方案例demo
Popper Content
官方demo效果图
文章图片
笔者的二次封装效果图
文章图片
使用之代码
下方代码较多,建议打开编辑器,复制粘贴代码,跑起来,阅读之
暗色模式
上方左侧上方左侧
上方中间
上方右侧上方右侧
左侧上方
左侧中间
左侧下方
右侧上方
右侧中间
右侧下方
下方左侧下方左侧
下方中间
下方右侧下方右侧
亮色模式
上方左侧上方左侧
上方中间
上方右侧上方右侧
左侧上方
左侧中间
左侧下方
右侧上方
右侧中间
右侧下方
下方左侧下方左侧
下方中间
下方右侧下方右侧
可禁用
悬浮出现
当tooltip内容多的时候,使用content插槽
内容过多时,使用插槽更便于控制样式,比如换行悬浮出现
.showTooltip {
width: 100%;
height: 100%;
box-sizing: border-box;
padding: 60px;
padding-top: 0;
padding-bottom: 120px;
.topBox {
.topReferenceDom {
border: 1px solid #999;
box-sizing: border-box;
padding: 4px 8px;
border-radius: 4px;
width: 60px;
text-align: center;
margin-right: 6px;
}
}
.leftAndRightBox {
width: 100%;
display: flex;
padding-right: 120px;
.leftBox {
margin-right: 250px;
}
.leftReferenceDom,
.rightReferenceDom {
width: 72px;
height: 60px;
line-height: 60px;
text-align: center;
border: 1px solid #999;
box-sizing: border-box;
margin: 12px 0;
}
}
.bottomBox {
.bottomReferenceDom {
border: 1px solid #999;
box-sizing: border-box;
padding: 4px 8px;
border-radius: 4px;
width: 60px;
text-align: center;
margin-right: 6px;
}
}
.item {
border: 1px solid #333;
padding: 4px;
}
}
.selfContent {
width: 120px;
color: #baf;
font-weight: 700;
}
mytooltip
封装代码{{ content }}
// 覆盖部分默认的样式(不用加/deep/ )
.popper {
box-sizing: border-box;
padding: 6px 12px;
border-radius: 3px;
color: #fff;
background-color: #333;
border: none;
}
// 设置一个tootip的外边距(也可以使用offset)
.popper[x-placement^="top"] {
margin-bottom: 12px !important;
}
.popper[x-placement^="bottom"] {
margin-top: 12px !important;
}
.popper[x-placement^="left"] {
margin-right: 12px !important;
}
.popper[x-placement^="right"] {
margin-left: 12px !important;
}
// 覆盖原有的默认三角形背景色样式
.popper[x-placement^="top"] .popper__arrow {
border-color: #333 transparent transparent transparent;
}
.popper[x-placement^="bottom"] .popper__arrow {
border-color: transparent transparent #333 transparent;
}
.popper[x-placement^="right"] .popper__arrow {
border-color: transparent #333 transparent transparent;
}
.popper[x-placement^="left"] .popper__arrow {
border-color: transparent transparent transparent #333;
}
// 加上过渡效果(搭配transition="fade")
.selfSetRootClass {
transition: all 0.6s;
}
.fade-enter,
.fade-leave-to {
opacity: 0;
}
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.6s;
}
// 亮色模式样式
.isLightPopper {
color: #333;
background-color: #fff;
filter: drop-shadow(0, 2px, 12px, 0, rgba(0, 0, 0, 0.24));
box-shadow: 0, 2px, 12px, 0, rgba(0, 0, 0, 0.24);
}
.isLightPopper[x-placement^="top"] .popper__arrow {
border-color: #fff transparent transparent transparent;
}
.isLightPopper[x-placement^="bottom"] .popper__arrow {
border-color: transparent transparent #fff transparent;
}
.isLightPopper[x-placement^="right"] .popper__arrow {
border-color: transparent #fff transparent transparent;
}
.isLightPopper[x-placement^="left"] .popper__arrow {
border-color: transparent transparent transparent #fff;
}
总结 因为
mytooltip
组件,需要使用到的vue-popper
属性和方法并不多,所以大家可以仿照笔者的方式,去看一下vue-popper
组件的代码,然后结合自己公司的业务需求,去封装一些适合自己公司的弹框组件
关于vue-popper
:https://github.com/RobinCK/vu...
当然,时间较为充裕的可以看一下popper.js
这个库
vue-popper
组件的其他二次封装的应用,如封装el-popover组件
、el-popconfirm组件
、el-dropdown组件
等,笔者会陆续更新的。不同的组件用到vue-popper
不同的属性和方法墙裂建议大家,看完以后,自己手写一下。只是看一遍,学习效果不太好
推荐阅读
- 教育|东南亚水博士,“拯救”二本大学
- #|Shiro学习与笔记
- 淘小淘上学记-网球训练队
- 自然语言处理|机器学习中的七宗罪
- 机器学习|[HITML] 哈工大2020秋机器学习Lab1实验报告
- 哈工大机器学习实验一多项式拟合正弦函数
- 数据结构与算法|哈工大《机器学习》最小二乘法曲线拟合——实验一
- 机器学习|哈工大2020机器学习实验一(多项式拟合正弦曲线)
- 笔记|哈工大机器学习Week2知识点总结
- python|哈工大 机器学习实验一 多项式拟合 含python代码