简洁的三角箭头面板(flyout-panel.js)【附demo】

简介: 最近UI上经常遇到点击一个按钮,出现一个带指向箭头的面板的情况,如图:   于是就写了个flyout-panel的组件,但此flyout-panel(飞出面板)只是个点击面板,更像tooltip,不是严格意义上的飞出面板(如我博客左侧“分享到.
最近UI上经常遇到点击一个按钮,出现一个带指向箭头的面板的情况,如图:

 

于是就写了个flyout-panel的组件,但此flyout-panel(飞出面板)只是个点击面板,更像tooltip,不是严格意义上的飞出面板(如我博客左侧“分享到...”面板),只是不太会取名字,估且先叫flyout-panel;

先上代码,再讲逻辑:

 (function (){

     var reqs = [
                "Handlebars",
                "jquery",
                "text!mr-fp/flyout-panel.html",  // 支持行内样式时需要的模板
                "css!mr-fp/flyout-panel.css" // 支持外链样式时需要的样式
            ];
    
    define(reqs , function (Handlebars,$,fpHTML) {
         var FlyOutPanel =  function(options){
             var styles = { // 面板默认样式,参数名顾名思义,标*号为必选参数
                    "panelClass" :     "flyout-panel",
                    "borderWidth" : "1px",
                    "borderColor" : "#000",
                    "bgColor" : "#fff",
                    "panelWidth" : "100px", // *
                    "panelHeight" : "100px",
                    "arrowLeft" : "50%", // *arrowLeft与arrowRight是互斥的(这里有点别扭)
                    "arrowRight" : "auto", // *当前三角箭头相对于面板的位置是left:50%
                    "arrowBorderWidth" : "10px", // *三角箭头的边宽,该三角形所在的div元素现为:20px*20px
                    "contentPadding" : "auto"
                };
             this.options = {
                    "id": "",
                    "styleInline" :  true, // 默认支持行内样式
                    "container" : document.body, // default is document.body, a dom element;
                    "content" :  null, // 面板中的内容元素,jquery元素
                    "triggerBtn" :  null, // 点击显示面板的button,juqery元素,如果未传,则要显式的为相应按钮绑定显示panel事件
                    "styles" : styles,
                    "timer" : 1000  //  默认面板显示1秒后隐藏
                };
            $.extend( true, this.options,options);
             this.styles =  this.options.styles;
             this.hideTimer =  null;
             this._create();
        };
        
        FlyOutPanel.prototype = {
            _create :  function(){
                 var tpl;
                 if( this.options.styleInline){
                     var source = $(fpHTML).html();
                     var template = Handlebars.compile(source);
                    tpl = template( this.styles);
                } else{
                    tpl = ['<div>',
                                '<div class="fp-arrow">',
                                    '<div class="fp-a1"></div>',
                                    '<div class="fp-a2"></div>',
                                '</div>',
                                '<div class="fp-content"></div>',
                            '</div>'].join('');
                }
                 var _el =  this._el = $(tpl).addClass( this.styles.panelClass);
                _el.unselectable();
                 this.containerEl = $( this.options.container).append(_el);
                 this.arrowEl = _el.find('.fp-arrow');
                _el.width( this.styles.panelWidth);
                _el.height( this.styles.panelHeight);
                 this.contentEl = _el.find('.fp-content').append( this.options.content.show());
                 this.triggerBtn = $( this.options.triggerBtn);
                 this.bindEvents();
            },
            setPosition :  function(offset){ // 设置面板的位置以及三角箭头的位置
                 var styles =  this.styles;
                 var _el =  this._el;
                 var _w= _el.width() + parseInt(styles.borderWidth)*2;
                 var arrowLeftPos = _w/2;
                
                 var arrowLeft = styles.arrowLeft,
                    arrowRight = styles.arrowRight,
                    _arrowBorderWidth = parseInt(styles.arrowBorderWidth,"10");
                console.log(arrowLeft + arrowRight);
                
                 if(!isNaN(parseInt(arrowLeft,10))){
                     var _lv = parseInt(arrowLeft,10);
                     if(arrowLeft.indexOf("%")>0){
                        arrowLeftPos = _w*_lv/100;
                    } else{
                        arrowLeftPos = _lv;
                    }
                }
                 if(!isNaN(parseInt(arrowRight,10))){
                     var _rv = parseInt(arrowRight,10);
                     if(arrowRight.indexOf("%")>0){
                        arrowLeftPos = _w*(100-_rv)/100;
                    } else{
                        arrowLeftPos = _w - _rv;
                    }
                }
                
                 if(_w - arrowLeftPos - _arrowBorderWidth <0){
                    arrowLeftPos = _w - _arrowBorderWidth;
                     this.arrowEl.css("right",_arrowBorderWidth + "px").css("left","auto");
                }
                _el.css({"top":offset.top + _arrowBorderWidth,"left":offset.left - arrowLeftPos});
                
                _el.show();
                 this.hideTimer = setTimeout( function(){
                    _el.hide();
                }, this.options.timer);
            },
            bindEvents :  function(){
                 var self =  this,
                    _el =  this._el;
                _el.bind('mouseleave.hide', function(){
                    self.hideTimer = setTimeout( function(){
                        _el.hide();
                    },self.options.timer);
                }).bind('mouseenter', function(){
                    clearTimeout(self.hideTimer);
                });
                 var btn =  this.triggerBtn;
                 if(btn && btn.length){
                    btn.bind('click.show', function(){
                         var pos = calculatePosition(btn);
                        self.setPosition(pos);
                    });
                }
                
            },
            setArrowPositon : function(){
                
            },
        };
        
         function calculatePosition($btn){
             var offset = $btn.offset(),
                top = offset.top + $btn.height(),
                left = offset.left + $btn.width() /2;
            return {'top' : top,'left' : left};
        }
        
         return FlyOutPanel;
    });    
})(); 

调用方式:

 

_createFlyoutPanels :  function(){
                     var self =  this;
                     var _el =  this.el;
                     var $eyePanel = _el.find('.eye-panel'),
                        $eyeBtn =  this._settingEl.find('.eye-btn');
                     this.eyePanel =  new FlyoutPanel({
                        "styleInline" :  false,
                        'container' :  _el,
                        'content' : $eyePanel,
                        'triggerBtn' : $eyeBtn,
                        'styles' : {
                            'panelWidth' : "160px",
                            'panelHeight' : "100px",
                        }
                    });
                    
                },

 

UI逻辑:

1,动态的创建一个带箭头的面板,将要显示的内容append进面板;

2,绑定面板事件,主要是mouseleave,mouseenter事件 

3,绑定按钮事件,主要指点击button,计算面板位置和箭头位置,显示面板;
创建带箭头的面板
箭头可以用图片实现,这里用dom来模拟,模拟方式大致是这样的: http://cssarrowplease.com/

考虑到主要是为了支持行内样式,所以就用两个div来代替:before,:after伪类生成的dom。 

两种方式生成面板的Dom结构:

var tpl;
if( this.options.styleInline){//行内样式Dom结构
     var source = $(fpHTML).html();
     var template = Handlebars.compile(source);
    tpl = template( this.styles);
} else{//外部样式Dom结构
    tpl = ['<div>',
                '<div class="fp-arrow">',
                    '<div class="fp-a1"></div>',
                    '<div class="fp-a2"></div>',
                '</div>',
                '<div class="fp-content"></div>',
            '</div>'].join('');
}
行内样式方式的html模板(handlebars template):
< script  id ="fp-template"  type ="text/x-handlebars-template" >
<div class="{{panelClass}}" style="position:fixed;border:{{borderWidth}} solid {{borderColor}};background-color:{{bgColor}};width:{{panelWidth}};height:{{panelHeight}};display:none;-moz-box-sizing : border-box;box-sizing : border-box;">
    <div class="fp-arrow" style="position:absolute;width:0;left:{{arrowLeft}};right:{{arrowRight}};">
        <div class="fp-a1" style="position:absolute;border:solid transparent;height:0;width:0;bottom:0;border-bottom-color:{{borderColor}};border-width:{{arrowBorderWidth}};left:50%;margin-left:-{{arrowBorderWidth}}"></div>
        <div class="fp-a2" style="position:absolute;border:solid transparent;height:0;width:0;bottom:-{{borderWidth}};border-bottom-color:{{bgColor}};border-width:{{arrowBorderWidth}};left:50%;margin-left:-{{arrowBorderWidth}}"></div>
    </div>
    <div class="fp-content" style="padding:{{contentPadding}}"></div>
</div>
</ script >
外部样式方式则提供一个flyout-panel.less样式文件来动态生成样式:
@borderColor: #000;
@borderWidth: 5px;
@bgColor : #fff;
@arrowBorderWidth : 10px;
@panelWidth : 100px;
@panelHeight : 100px;
@arrowOffset : 1px;
@arrowBorderWidth : 10px;
@arrowLeft : 20%;
@arrowRight : auto;
@contentPadding : auto;

.flyout-panel
{
    position
: fixed;
    border
:  @borderWidth solid @borderColor;
    display
: none;
    background
:  @bgColor;
    width 
:  @panelWidth;
    height
:  @panelHeight;
    .fp-arrow {
        position
: fixed;
        width 
:  0;
        left 
:  @arrowLeft;
        right
:  @arrowRight;
        >div{
            position
: absolute;
            border
:  solid transparent;
            height
:  0;
            width
:  0;
            bottom
: 0;
        
}
        .fa-a1
{
            border-bottom-color 
:  @borderColor;
            border-width 
:  @arrowBorderWidth;
            left
: 50%;
            margin-left
:  -@arrowBorderWidth;
        
}
        .fa-a2
{
            border-bottom-color 
:  @bgColor;
            border-width 
:  @arrowBorderWidth;
            left
: 50%;
            top
: @borderWidth;
            margin-left
:  -@arrowBorderWidth;
        
}
    }
}

 附上demo:http://flowerszhong.shop.co/flyout-panel/demo.html

 

相关文章
|
3月前
|
JavaScript 前端开发
js小功能--如何实现按住shift拖拽多选div
js小功能--如何实现按住shift拖拽多选div
31 0
|
5月前
|
JSON JavaScript 前端开发
JS实现树形菜单递归函数(折叠菜单)
JS实现树形菜单递归函数(折叠菜单)
31 0
|
7月前
|
JavaScript
js渐变导航demo效果示例(整理)
js渐变导航demo效果示例(整理)
|
7月前
|
JavaScript
js鼠标可控的表格左右滑动demo效果示例(整理)
js鼠标可控的表格左右滑动demo效果示例(整理)
|
7月前
|
JavaScript
js判断滚动条是否到底部demo效果示例(整理)
js判断滚动条是否到底部demo效果示例(整理)
|
JavaScript 前端开发
CSS进阶向--配合Vue动态样式实现“超炫酷”圆环菜单
CSS进阶向--配合Vue动态样式实现“超炫酷”圆环菜单
574 2
CSS进阶向--配合Vue动态样式实现“超炫酷”圆环菜单
|
JavaScript
JS/jQuery图片预览,支持旋转-放大-放小-全屏,例子demo
JS/jQuery图片预览,支持旋转-放大-放小-全屏,例子demo
225 0
|
JavaScript 前端开发
jQuery案例demo -- 鼠标移入显示蒙版
效果展示 效果展示.png HTML代码: 摄影小白成长记 The best preparation for tomorrow is doing your best today.
1011 0
|
Web App开发 JavaScript 前端开发

热门文章

最新文章