模拟BootStrap的弹框功能

模拟BootStrap的弹框功能

今天项目中遇到了一个需要,需要用到BootStrap的弹框功能,但因为考虑到日后可能需要改用AngularJS去进行开发,大家都知道AngularJS和BootStrap的js文件是有冲突,因为BootStrap的js文件是依赖与jQuery的,如果用AngularJS去开发,意味着需要连BootStrap都不能用,但可以用UI-BootStrap,但因为不太熟悉UI-BootStrap,不知道有没有封装到该功能,所以就打算自己写一个类似BootStrap的弹框的,顺便当锻炼以下自己,也未以后的模块化开发做做准备。废话不多说,进入主题。

首先是需要到两个文件,分别是一个js文件和css文件。

<link rel="stylesheet" href="../afa_pop/afa_pop.css">
<script src="../afa_pop/afa_pop.js">script>

因为我也的插件不依赖任何第三方插件,是原生去写的,所以应该兼容性会比较好吧。

然后调用方式:

<div class="list">
        <div>
            <p>我是弹框leftp>
            <span class="btn" id="a" data-afaPOP_target="a1" data-afaPOP_direction="left">点击我span>
            <div id="a1" data-popDiv>
                <input type="text">
                <button>确定button>
            div>
        div>
        <div>
            <p>我是弹框rightp>
            <span class="btn" data-afaPOP_target="a2" data-afaPOP_direction="right">点击我span>
            <div id="a2" data-popDiv>
                <select>
                    <option value="0">请选择option>
                    <option value="1">Aoption>
                    <option value="2">Boption>
                    <option value="3">Coption>
                select>
            div>
        div>
        <div>
            <p>我是弹框topp>
            <span class="btn" data-afaPOP_target="a3" data-afaPOP_direction="top">点击我span>
            <div id="a3" data-popDiv>
                <p>JavaScript是世界上最好的语言p>
            div>
        div>
        <div>
            <p>我是弹框bottomp>
            <span class="btn" data-afaPOP_target="a4" data-afaPOP_direction="bottom">点击我span>
            <div id="a4" data-popDiv>
                <ul>
                    <li>asdli>
                    <li>asdli>
                    <li>asdli>
                    <li>asdli>
                ul>
            div>
        div>
    div>

这里简单介绍一下对应的一些属性:

  • data-afaPOP_target - 指向弹框的id。
  • data-afaPOP_direction - 表示弹框的方向。
  • data-popDiv - 写在弹框对应的标签中,主要是给样式的。
  • data-afaClosePOP - 绑定点击后隐藏弹框的事件

暂时就这些属性去进行定义和绑定事件,因为项目中还没有发现需要补充的功能,所以暂时就这样了,当然以后有时间还是继续优化的。

其中还有一些BUG还没有时间去修改,但不影响使用…

现在把代码补全:

html


<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
    <link rel="stylesheet" href="../afa_pop/afa_pop.css">
    <style>
        .list{
            height:800px;
            width: 50%;
            overflow-y:auto;
            border:1px solid #e1e1e1;
            text-align: center;
            margin:0 auto;
        }
        .list>div{
            border-bottom:1px solid #000;
            padding:5px;
        }

    style>
head>
<body>
    <div class="list">
        <div>
            <p>我是弹框leftp>
            <span class="btn" id="a" data-afaPOP_target="a1" data-afaPOP_direction="left">点击我span>
            <div id="a1" data-popDiv>
                <input type="text">
                <button>确定button>
            div>
        div>
        <div>
            <p>我是弹框rightp>
            <span class="btn" data-afaPOP_target="a2" data-afaPOP_direction="right">点击我span>
            <div id="a2" data-popDiv>
                <select>
                    <option value="0">请选择option>
                    <option value="1">Aoption>
                    <option value="2">Boption>
                    <option value="3">Coption>
                select>
            div>
        div>
        <div>
            <p>我是弹框topp>
            <span class="btn" data-afaPOP_target="a3" data-afaPOP_direction="top">点击我span>
            <div id="a3" data-popDiv>
                <p>JavaScript是世界上最好的语言p>
            div>
        div>
        <div>
            <p>我是弹框bottomp>
            <span class="btn" data-afaPOP_target="a4" data-afaPOP_direction="bottom">点击我span>
            <div id="a4" data-popDiv>
                <ul>
                    <li>asdli>
                    <li>asdli>
                    <li>asdli>
                    <li>asdli>
                ul>
            div>
        div>
    div>
body>
<script src="../afa_pop/afa_pop.js">script>
html>

css



*[data-popDiv]{visibility:hidden;background-color:#fff;border:2px solid #000;border-radius: 5px;position:absolute;z-index: 9999;padding: 12px;}
*[data-popDiv] .horn{display: block;position: absolute;width: 15px;height: 15px;z-index: 9999;background-color: #fff;-webkit-transform: rotate(-45deg);}
*[data-popDiv] .horn_left{border-bottom: 2px solid #000;border-right: 2px solid #000;}
*[data-popDiv] .horn_right{border-top: 2px solid #000;border-left: 2px solid #000;}
*[data-popDiv] .horn_top{border-top: 2px solid #000;border-right: 2px solid #000;}
*[data-popDiv] .horn_bottom{border-bottom: 2px solid #000;border-left: 2px solid #000;}
*[data-hasShowPOP = 'true']{visibility:visible;animation: afa_showPOP 0.5s;-moz-animation: afa_showPOP 0.5s;-webkit-animation: afa_showPOP 0.5s;-o-animation: afa_showPOP 0.5s;}
*[data-hasShowPOP = 'false']{visibility:hidden;animation: afa_hidePOP 0.5s;-moz-animation: afa_hidePOP 0.5s;-webkit-animation: afa_hidePOP 0.5s;-o-animation: afa_hidePOP 0.5s;}
#afa_pop_mask{top: 0;left: 0;position:fixed;width: 100%;height: 100%;z-index: 999;}
/*显示*/
@keyframes afa_showPOP
  {
      from {
          filter:alpha(opacity=0);
          -moz-opacity:0;
          opacity:0;
      }
      to {
          filter:alpha(opacity=100);
          -moz-opacity:1;
          opacity:1;
      }
  }

@-moz-keyframes afa_showPOP /* Firefox */
{
    from {
        filter:alpha(opacity=0);
        -moz-opacity:0;
        opacity:0;
    }
    to {
        filter:alpha(opacity=100);
        -moz-opacity:1;
        opacity:1;
    }
}

@-webkit-keyframes afa_showPOP /* Safari 和 Chrome */
{
    from {
        filter:alpha(opacity=0);
        -moz-opacity:0;
        opacity:0;
    }
    to {
        filter:alpha(opacity=100);
        -moz-opacity:1;
        opacity:1;
    }
}

@-o-keyframes afa_showPOP /* Opera */
{
    from {
        filter:alpha(opacity=0);
        -moz-opacity:0;
        opacity:0;
    }
    to {
        filter:alpha(opacity=100);
        -moz-opacity:1;
        opacity:1;
    }
}

/*隐藏*/
@keyframes afa_hidePOP
{
    from {
        filter:alpha(opacity=100);
        -moz-opacity:1;
        opacity:1;
    }
    to {
        filter:alpha(opacity=0);
        -moz-opacity:0;
        opacity:0;
    }
}

@-moz-keyframes afa_hidePOP /* Firefox */
{
    from {
        filter:alpha(opacity=100);
        -moz-opacity:1;
        opacity:1;
    }
    to {
        filter:alpha(opacity=0);
        -moz-opacity:0;
        opacity:0;
    }
}

@-webkit-keyframes afa_hidePOP /* Safari 和 Chrome */
{
    from {
        filter:alpha(opacity=100);
        -moz-opacity:1;
        opacity:1;
    }
    to {
        filter:alpha(opacity=0);
        -moz-opacity:0;
        opacity:0;
    }
}

@-o-keyframes afa_hidePOP /* Opera */
{
    from {
        filter:alpha(opacity=100);
        -moz-opacity:1;
        opacity:1;
    }
    to {
        filter:alpha(opacity=0);
        -moz-opacity:0;
        opacity:0;
    }
}

js

/**
 * Created by Administrator on 2016/5/3.
 */

window.onload = function(){

    //尖角的宽高,如果改变尖角宽高需要css和js同时去更改
    var hornHeight = 19,
        hornWidth = 19,
        scrollTop = 0,
        scrollLeft = 0;

    //初始化
    function init(){
        var afaPOPs = document.querySelectorAll('[data-afaPOP_target]');
        var afaClose = document.querySelectorAll('[data-afaClosePOP]');
        //循环设定位置及绑定显示隐藏事件
        for(var i = 0;i < afaPOPs.length;i++){
            var curr = afaPOPs[i],
                targetId = curr.dataset.afapop_target,
                direction = curr.dataset.afapop_direction;

            //设置尖角的位置和弹框的定位
            switch (direction){
                case 'left' : setPOPDirection.left(document.getElementById(targetId));
                    setPosition.left(curr,document.getElementById(targetId));
                    break;
                case 'right' : setPOPDirection.right(document.getElementById(targetId));
                    setPosition.right(curr,document.getElementById(targetId));
                    break;
                case 'top' : setPOPDirection.top(document.getElementById(targetId));
                    setPosition.top(curr,document.getElementById(targetId));
                    break;
                case 'bottom' : setPOPDirection.bottom(document.getElementById(targetId));
                    setPosition.bottom(curr,document.getElementById(targetId));
                    break;
            }

            //绑定事件
            !function(targetId,curr,direction){
                curr.addEventListener('click',function(){
                    //隐藏弹框
                    if(document.getElementById(targetId).getAttribute('data-hasShowPOP') == 'true'){
                        var mask = document.getElementById('afa_pop_mask');
                        if(mask){
                            document.body.removeChild(mask);
                        }
                        document.getElementById(targetId).setAttribute('data-hasShowPOP','false');
                        //显示弹框
                    }else{
                        //先隐藏所有弹框
                        closeAllPOP(function(){
                            //设置尖角的位置和弹框的定位
                            switch (direction){
                                case 'left' : setPosition.left(curr,document.getElementById(targetId));
                                    break;
                                case 'right' : setPosition.right(curr,document.getElementById(targetId));
                                    break;
                                case 'top' : setPosition.top(curr,document.getElementById(targetId));
                                    break;
                                case 'bottom' : setPosition.bottom(curr,document.getElementById(targetId));
                                    break;
                            }
                            //先创建一个mask
                            var mask = document.createElement('div');
                            mask.id = 'afa_pop_mask';
                            document.body.appendChild(mask);
                            //点击mask隐藏元素,模拟点击body
                            document.getElementById('afa_pop_mask').addEventListener('click',function(){
                                //隐藏完后删除mask
                                closeAllPOP(function(){
                                    document.body.removeChild(mask);
                                });
                            });
                            //显示对应弹框
                            document.getElementById(targetId).setAttribute('data-hasShowPOP','true');
                        });
                    }

                });
            }(targetId,curr,direction);

        }
        //循环绑定隐藏事件
        for(var n = 0;n < afaClose.length;n++){
            closePOP(afaClose[n]);
        }

    }

    //关闭所有弹框
    function closeAllPOP(callback){
        var popDivs = document.querySelectorAll('[data-popDiv]');
        for(var n =0;n 'data-hasShowPOP','false');
        }
        if(callback){
            callback();
        }
    }

    //关闭弹框事件
    function closePOP(curr){
        var id = curr.dataset.afaclosepop;
        curr.addEventListener('click',function(){
            document.getElementById(id).setAttribute('data-hasShowPOP','false');
        })
    }

    //设置尖角的位置和方向
    var setPOPDirection = {

        left : function(elem){
            var popHeight = elem.offsetHeight,
                popWidth = elem.offsetWidth,
                horn = document.createElement('span');
            horn.className = 'horn horn_left';
            elem.appendChild(horn);
            horn.style.top = (popHeight/2 - hornHeight/2) + 'px';
            horn.style.left = (popWidth - hornWidth/2)-1 + 'px';
        },
        right : function(elem){
            var popHeight = elem.offsetHeight,
                horn = document.createElement('span');
            horn.className = 'horn horn_right';
            elem.appendChild(horn);
            horn.style.top = (popHeight/2 - hornHeight/2) + 'px';
            horn.style.left = (0 - hornWidth/2) + 'px';
        },
        bottom : function(elem){
            var popWidth = elem.offsetWidth,
                horn = document.createElement('span');
            horn.className = 'horn horn_top';
            elem.appendChild(horn);
            horn.style.top = (0 - hornWidth/2) + 'px';
            horn.style.left = (popWidth/2 - hornWidth/2) + 'px';
        },
        top : function(elem){
            var popHeight = elem.offsetHeight,
                popWidth = elem.offsetWidth,
                horn = document.createElement('span');
            horn.className = 'horn horn_bottom';
            elem.appendChild(horn);
            horn.style.top = (popHeight - hornWidth/2) - 2 + 'px';
            horn.style.left = (popWidth/2 - hornWidth/2) + 'px';
        }

    };

    //设置弹框的位置
    var setPosition = {

        left : function(curr,elem){
            var elemHeight = elem.offsetHeight,
                elemWidth = elem.offsetWidth,
                currHeight = curr.offsetHeight,
                currX = curr.offsetLeft,
                currY = curr.offsetTop,
                parentScrollTop = getTop(curr),
                parentScrollLeft = getLeft(curr);
            elem.style.left = currX - elemWidth - hornWidth - parentScrollLeft + 'px';
            elem.style.top = currY - elemHeight/2 + currHeight/2 - parentScrollTop + 'px';
            //归零
            scrollTop = 0;
            scrollLeft = 0;
        },
        right : function(curr,elem){

            var elemHeight = elem.offsetHeight,
                currHeight = curr.offsetHeight,
                currWidth = curr.offsetWidth,
                currX = curr.offsetLeft,
                currY = curr.offsetTop,
                parentScrollTop = getTop(curr),
                parentScrollLeft = getLeft(curr);
            elem.style.left = currX + currWidth + hornWidth + -parentScrollLeft + 'px';
            elem.style.top = currY - elemHeight/2 + currHeight/2 - parentScrollTop + 'px';
            //归零
            scrollTop = 0;
            scrollLeft = 0;
        },
        bottom : function(curr,elem){
            var currHeight = curr.offsetHeight,
                elemWidth = elem.offsetWidth,
                currWidth = curr.offsetWidth,
                currX = curr.offsetLeft,
                currY = curr.offsetTop,
                parentScrollTop = getTop(curr),
                parentScrollLeft = getLeft(curr);
            elem.style.left = currX - elemWidth/2 + currWidth/2 - parentScrollLeft + 'px';
            elem.style.top = currY + currHeight + hornHeight - parentScrollTop + 'px';
            //归零
            scrollTop = 0;
            scrollLeft = 0;
        },
        top : function(curr,elem){
            var elemHeight = elem.offsetHeight,
                elemWidth = elem.offsetWidth,
                currWidth = curr.offsetWidth,
                currX = curr.offsetLeft,
                currY = curr.offsetTop,
                parentScrollTop = getTop(curr),
                parentScrollLeft = getLeft(curr);
            elem.style.left = currX - elemWidth/2 + currWidth/2 - parentScrollLeft + 'px';
            elem.style.top = currY - elemHeight - hornHeight - parentScrollTop + 'px';
            //归零
            scrollTop = 0;
            scrollLeft = 0;
        }

    };

    /*
    * 当父元素有可能有scrollTop和scrollLeft的时候会影响定位
    * 所以需要进行递归处理,计算当前所有父元素的scrollTop和scrollLeft
    * 最后再修正定位,保持始终是相对与窗口左上角进行定位
    *
    * */
    function getTop(e){
        if(e.parentNode != null){
            var scroll = e.parentNode.scrollTop;
            scroll = scroll == undefined ? 0 : scroll;
            scrollTop += scroll;
            getTop(e.parentNode);
        }
        return scrollTop;
    }

    function getLeft(e){
        if(e.parentNode != null){
            var scroll = e.parentNode.scrollLeft;
            scroll = scroll == undefined ? 0 : scroll;
            scrollLeft += scroll;
            getTop(e.parentNode);
        }
        return scrollLeft;
    }

    //页面加载完时自动执行
    init();

    //页面大小改变时重新计算
    window.addEventListener('resize',function(){
        init();
    });

};

如果有兴趣一起谈讨互相学习的欢迎留言,一起改改BUG,菜鸟一枚多多关注!

你可能感兴趣的:(小插件-原生JS,JavaScript,原生js)