HTML5和CSS3冒泡组件如何实现,很多新手都不是很清楚。为了帮助大家解决这个问题,下面小编就给大家详细讲解一下。需要的人可以从中学习,希望你能有所收获。
组件在实际工作中非常常见,无论是在网页中还是在应用程序中,例如:
这里所谓的气泡成分是指列表气泡成分。在这里,我们将讨论它的dom实现、css实现和js实现,并* * *解释一些细节,希望对大家有用。
小柴最近是CSS的初学者。这里有一个特别的话题可以帮助她提高CSS。本文有很多问题和优化点。请引导.
组件分类
单从气泡组件来说,它还是属于“弹出层”组件,也就是说,它会有这些特点:
布局与文档流分离。
可以有蒙版蒙版,可以配置点击蒙版是否关闭。
(3)可选功能包括单击浏览器退出组件以及显示和隐藏动画功能。
其中,区别在于:
不居中定位。
带有箭头标记,可设置为向上或向下。
因为有一个箭头,这个箭头是相对于一个元素的,一般来说,我们的任务是相对于一个按钮的,所以我们有一个triggerEL。
因此,仅从这里的讨论来看,我们的组件被称为气泡层,它应该继承自一个公共层。
然而,就层而言,它至少具有以下一般特征:
创建mdashmdash创造
显示mdashmdash显示
隐藏mdashmdash隐藏
销毁mdashmdash破坏
上述特性不是图层组件所独有的,而是所有组件所独有的,因此图层上方应该有一个抽象视图的抽象组件。
这时,继承关系就出来了,把多余的接口放在一边。简单来说,是这样的:
组件dom层面实现
最简单实现
单就dom实现而言,其实一个简单的ul就能完成任务。
ulc lass=' Cui-bubble-layer ' style=' position : absolute;top:110pxleft:220pxlidata-index=' 0 ' data-flag=' c ' Price:35/Lili data-index=' 1 ' data-flag=' c ' Score:80/Lili data-index=' 2 ' data-flag=' c ' Level:5/Li/ul当然这里必须有一个。Cui-气泡层{ background: # f2f2f2border: # bcbcbc1pxsolidn
bsp; 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, h2, h3, h4, h5, h6, h7, 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, h2, h3, h4, h5, h6, h7, 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>
http://sandbox.runjs.cn/show/9ywitfn8
不足与扩展
上面作为基本实现,没有什么问题,但是其实际应用场景会有以下不足:
① 基本的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" data-flag="c">价格:¥35</li> <li data-index="1" data-flag="c">评分:80</li> <li data-index="2" data-flag="c">级别:5</li> </ul> </section>
① 根元素上我们可以设置当前应该是up还是down的样式
② i标签根据根元素的up或者down选择是向上还是向下,并且该标签可被js操作
到此,似乎整个组件便比较完全了,但是真实的情况却不是如此,怎么说了,上面的结构太局限了
该组件需要一个容器,这个容器标签应该位于ul之上,这个时候容器内部所装载的dom结构便可以不是ul而是其他什么结构了
其次,在手机上,我们可视项目在4S手机上不会超过5个,往往是4个,所以我们应该在其容器上设置类似overflow之类的可滚动属性
组件回归·最终结构
由上所述,基于其是继承至Layer的事实,我们可以形成这样的结构:
<section class="cui-pop cui-bubble-layer"> <i class="cui-pop-triangle"></i> <div class="cui-pop-head"> </div> <div class="cui-pop-body"> <ul> <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> </div> <div class="cui-pop-footer"> </div> </section>
这个也可以是我们整个弹出层类的基本结构,我们可以在此上做很多扩展,但是这里我们不扯太多,单就气泡组件做论述
就气泡组件,其结构是:
<section class="cui-pop cui-bubble-layer"> <i class="cui-pop-triangle"></i> <div class="cui-pop-body"> <ul> <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> </div> </section>
js层面的实现
这里仍然是采用的blade中的那一套继承机制,如果有不明白又有点兴趣的同学请移步:【blade的UI设计】理解前端MVC与分层思想
关于模板
因为我们这一部分的主题为重构相关,所以我们这里的关注点是CSS,我们首先生成我们的模板:
<section class="cui-pop <%=wrapperClass %> <%if(dir == 'up'){ %> <%=upClass %> <% } else { %> <%=downClass %> <% } %>"> <i class="cui-pop-triangle"></i> <div class="cui-pop-body"> <ul class="cui-pop-list <%=itemStyleClass %>"> <% for(var i = 0, len = data.length; i < len; i++) { %> <% var itemData = data[i]; %> <li data-index="<%=i%>" data-flag="c" class="<% if(index == i){ %><%=curClass %><%} %>" > <%if(typeof itemFn == 'function') { %><%=itemFn.call(itemData) %> <% } else { %><%=itemData.name%><%} %> <% } %> </ul> </div> </section>
这里给出了几个关键的定制化点:
① wrapperClass用以添加业务团队定制化的class以改变根元素的class,如此的好处是便于业务团队定制化气泡组件的样式
② 给出了项目列表Ul的可定制化className,通用单单只是方便业务团队做样式改变
③ 默认情况下返回的是传入项目的name字段,但是用户可传入一个itemFn的回调,定制化返回
以上模板基本可满足条件,如果不满足,便可把整个模板作为参数传入了
关于js实现
由于继承的实现,我们大部分工作已经被做了,我们只需要在几个关键地方编写代码即可
define(['UILayer', getAppUITemplatePath('ui.bubble.layer')], function (UILayer, template) { return _.inherit(UILayer, { propertys: function ($super) { $super(); //html模板 this.template = template; this.needMask = false; this.datamodel = { data: [], wrapperClass: 'cui-bubble-layer', upClass: 'cui-pop--triangle-up', downClass: 'cui-pop--triangle-down', curClass: 'active', itemStyleClass: '', needBorder: true, index: -1, dir: 'up' //箭头方向默认值 }; this.events = { 'click .cui-pop-list>li': 'clickAction' }; this.onClick = function (data, index, el, e) { console.log(arguments); // this.setIndex(index); }; this.width = null; //三角图标偏移量 this.triangleLeft = null; this.triangleRight = null; this.triggerEl = null; }, initialize: function ($super, opts) { $super(opts); }, createRoot: function (html) { this.$el = $(html).hide().attr('id', this.id); }, clickAction: function (e) { var el = $(e.currentTarget); var i = el.attr('data-index'); var data = this.datamodel.data[i]; this.onClick.call(this, data, i, el, e); }, initElement: function () { this.el = this.$el; this.triangleEl = this.$('.cui-pop-triangle'); this.windowWidth = $(window).width(); }, setIndex: function (i) { var curClass = this.datamodel.curClass; i = parseInt(i); if (i < 0 || i > this.datamodel.data.length || i == this.datamodel.index) return; this.datamodel.index = i; //这里不以datamodel改变引起整个dom变化了,不划算 this.$('.cui-pop-list li').removeClass(curClass); this.$('li[data-index="' + i + '"]').addClass(curClass); }, //位置定位 reposition: function () { if (!this.triggerEl) return; var offset = this.triggerEl.offset(); var step = 6, w = offset.width - step; var top = 0, left = 0, right; if (this.datamodel.dir == 'up') { top = (offset.top + offset.height + 8) + 'px'; } else { top = (offset.top - this.el.offset().height - 8) + 'px'; } left = (offset.left + 2) + 'px'; if (offset.left + (parseInt(this.width) || w) > this.windowWidth) { this.el.css({ width: this.width || w, top: top, right: '2px' }); } else { this.el.css({ width: this.width || w, top: top, left: left }); } if (this.triangleLeft) { this.triangleEl.css({ 'left': this.triangleLeft, 'right': 'auto' }); } if (this.triangleRight) { this.triangleEl.css({ 'right': this.triangleRight, 'left': 'auto' }); } }, addEvent: function ($super) { $super(); this.on('onCreate', function () { this.$el.removeClass('cui-layer'); this.$el.css({ position: 'absolute' }); }); this.on('onShow', function () { this.setzIndexTop(this.el); }); } }); });
这里开始调用的,便可做简单实现:
'click .demo1': function (e) { if (!this.demo1) { var data = [{ name: '<span class="center">普通会员</span>' }, { name: '<span class="center">vip</span>' }, { name: '<span class="center">高级vip</span>' }, { name: '<span class="center">钻石vip</span>'}]; this.list = new UIBubbleLayer({ datamodel: { data: data }, triggerEl: $(e.currentTarget), width: '150px', triangleLeft: '20px' }); } this.list.show(); }
稍作修改便可形成另一种样子:
只不过我们还得考虑这个场景的发生,在项目过多过长时我们仍需要做处理:
这里有很多办法可以处理,***个是直接传入maxHeight,如果高度超出的话便出现滚动条,第二个是动态在组件内部计算,查看组件与可视区域的关系
我们这里还是采用可视区域计算吧,于是对原组件做一些改造,加一个接口:
this.checkHeightOverflow();
就这一简单接口其实可分为几个段落的实现
***个接口为检测可视区域,这个可以被用户重写
isSizeOverflow
第二个接口是如果可视区域超出,也就是***个接口返回true时的处理逻辑
handleSizeOverflow
考虑到超出的未必是高度,所以这里height改为了Size
当然,这里会存在资源销毁的工作,所以会新增一个hide接口
isSizeOverflow: function () { if (!this.el) return false; if (this.el.height() > this.windowHeight * 0.8) return true; return false; }, handleSizeOverflow: function () { if (!this.isSizeOverflow()) return; this.listWrapper.css({ height: (parseInt(this.windowHeight * 0.8) + 'px'), overflow: 'hidden', position: 'relative' }); this.listEl.css({ position: 'absolute', width: '100%' }); //调用前需要重置位置 this.reposition(); this.scroll = new UIScroll({ wrapper: this.listWrapper, scroller: this.listEl }); }, checkSizeOverflow: function () { this.handleSizeOverflow(); }, addEvent: function ($super) { $super(); this.on('onCreate', function () { this.$el.removeClass('cui-layer'); this.$el.css({ position: 'absolute' }); }); this.on('onShow', function () { //检查可视区域是否超出; this.checkSizeOverflow(); this.setzIndexTop(this.el); }); this.on('onHide', function () { if (this.scroll) this.scroll.destroy(); }); }
到此,我们的功能也基本结束了,***实现一个定制化一点的功能,将我们的气泡组件变成黑色:
看完上述内容是否对您有帮助呢?如果还想对相关知识有进一步的了解或阅读更多相关文章,请关注行业资讯频道,感谢您对的支持。
内容来源网络,如有侵权,联系删除,本文地址:https://www.230890.com/zhan/98442.html