前言
气泡组件在实际工作中非常普遍,无论是网页中还是app中,比如:





我们这里所谓气泡组件是指列表型气泡组件,这里就其dom实现,css实现,js实现做一个讨论,最后对一些细节点做一些说明,希望对各位有用
小钗最近初学CSS,这里做一个专题,便于自身CSS提升,文章有不少问题与可优化点,请各位指导
组件分类
单由气泡组件来说,他仍然属于“弹出层”类组件,也就是说其会具有这些特性:
① 布局为脱离文档流
② 可以具有mask蒙版,并且可配置点击蒙版是否关闭的特性
③ 可选的特性有点击浏览器回退关闭组件以及动画的显示与隐藏动画特性
其中比较不同的是:
① 不是居中定位
② 具有一个箭头标识,并且可以设置再上或者在下
③ 因为具有箭头,而且这个箭头是相对于一个元素的,一般意义上我们任务是相对某个按钮,所以说具有一个triggerEL
所以单从这里论述来说,我们的组件名为BubbleLayer,其应该继承与一个通用的Layer
但是,就由Layer来说,其最少会具有以下通用特性:
① 创建——create
② 显示——show
③ 隐藏——hide
④ 摧毁——destroy
而以上特性并不是Layer组件所特有的,而是所有组件所特有,所以在Layer之上还应该存在一个AbstractView的抽象组件
至此继承关系便出来了,抛开多余的接口不看,简单来说是这样的:

组件dom层面实现最简单实现
单从dom实现来说,其实一个简单的ul便可以完成任务
代码如下:
<ul class="cui-bubble-layer" style="position: absolute; top: 110px; left: 220px;">
<li data-index="0" data-flag="c">价格:¥35</li>
<li data-index="1" data-flag="c">评分:80</li>
<li data-index="2" data-flag="c">级别:5</li>
</ul>
当然这里要有相关的css
代码如下:
.cui-bubble-layer {
background: #f2f2f2;
border: #bcbcbc 1px solid;
border-radius: 3px
}
至此形成的效果是酱紫滴:

代码如下:
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>Blade Demo</title>
<meta name="viewport" content="width=device-width,initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
<meta content="telephone=no" name="format-detection" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<style type="text/css">
body, button, input, select, textarea { font: 400 14px/1.5 Arial, "Lucida Grande" ,Verdana, "Microsoft YaHei" ,hei; }
body, div, dl, dt, dd, ul, ol, li, h1, h2, h3, h4, h5, h6, pre, code, form, fieldset, legend, input, textarea, p, blockquote, th, td, hr, button, article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section { margin: 0; padding: 0; }
body { background: #f5f5f5; }
ul, ol { list-style: none; }
.cui-bubble-layer { background: #f2f2f2; border: #bcbcbc 1px solid; border-radius: 3px; }
</style>
</head>
<body>
<ul class="cui-bubble-layer" style="position: absolute; top: 110px; left: 220px;">
<li data-index="0" data-flag="c">价格:¥35</li>
<li data-index="1" data-flag="c">评分:80</li>
<li data-index="2" data-flag="c">级别:5</li>
</ul>
</body>
</html>
这个时候在为其加一个伪类,做点样式上的调整,便基本实现了,这里用到了伪类的知识点:
代码如下:
cui-bubble-layer:before {
position: absolute; content: ""; width: 10px; height: 10px; -webkit-transform: rotate(45deg);
background: #f2f2f2;
border-top: #bcbcbc 1px solid;
border-left: #bcbcbc 1px solid;
top: -6px; left: 50%; margin-left: -5px; z-index: 1;
}
这里设置了一个绝对定位的矩形框,为其两个边框设置了值,然后变形偏斜45度形成小三角,然后大家都知道了
代码如下:
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>Blade Demo</title>
<meta name="viewport" content="width=device-width,initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
<meta content="telephone=no" name="format-detection" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<style type="text/css">
body, button, input, select, textarea { font: 400 14px/1.5 Arial, "Lucida Grande" ,Verdana, "Microsoft YaHei" ,hei; }
body, div, dl, dt, dd, ul, ol, li, h1, h2, h3, h4, h5, h6, pre, code, form, fieldset, legend, input, textarea, p, blockquote, th, td, hr, button, article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section { margin: 0; padding: 0; }
body { background: #f5f5f5; }
ul, ol { list-style: none; }
.cui-bubble-layer { background: #f2f2f2; border: #bcbcbc 1px solid; border-radius: 3px; }
.cui-bubble-layer > li { padding: 5px 10px; }
.cui-bubble-layer:before { position: absolute; content: ""; width: 10px; height: 10px; -webkit-transform: rotate(45deg); background: #f2f2f2; border-top: #bcbcbc 1px solid; border-left: #bcbcbc 1px solid; top: -6px; left: 50%; margin-left: -5px; z-index: 1;</style>
</head>
<body>
<ul class="cui-bubble-layer" style="position: absolute; top: 110px; left: 220px;">
<li data-index="0" data-flag="c">价格:¥35</li>
<li data-index="1" data-flag="c">评分:80</li>
<li data-index="2" data-flag="c">级别:5</li>
</ul>
</body>
</html>

不足与扩展
上面作为基本实现,没有什么问题,但是其实际应用场景会有以下不足:
① 基本的ul层级需要一个包裹层,包裹层具有一个up或者down的class,然后在决定那个箭头是向上还是向下
② 我们这里不能使用伪类,其原因是,我们的小三角标签并不是一定在中间,其具有一定滑动的特性,也就是说,这个小三角需要被js控制其左右位置,他需要是一个标签
根据以上所述,我们的结构似乎应该是这个样子滴:
代码如下:
<section class="cui-bubble-layer up-or-down-class">
<i class="cui-icon-triangle"></i>
<ul>
<li data-index="0