Seasons123 / blog-FE

web前端相关issue is my blog :lollipop:
2 stars 0 forks source link

alibaba笔试题:带遮罩效果的弹窗实现 #102

Closed Seasons123 closed 5 years ago

Seasons123 commented 5 years ago

源码

<!DOCTYPE html>
<html>
<head>
    <title>js制作带有遮罩弹出层实现登录小窗口</title>
    <script>
        window.onload = function(){
            document.getElementById("btn_showlogin").onclick = shogMinLogin;
            document.getElementById("close_minilogin").onclick = closeLogin;
            document.getElementById("firstLine").onmousedown = moveLogin;
            /* 显示登录窗口 */
            function shogMinLogin(){
                var mini_login = document.getElementsByClassName("mini_login")[0];
                var cover = document.getElementsByClassName("cover")[0];
                mini_login.style.display = "block";
                cover.style.display = "block";

                mini_login.style.left = (document.body.scrollWidth - mini_login.scrollWidth) / 2 + "px";
                mini_login.style.top = (document.body.scrollHeight - mini_login.scrollHeight) / 2 + "px";
            }

            /* 关闭登录窗口 */
            function closeLogin(){
                var mini_login = document.getElementsByClassName("mini_login")[0];
                var cover = document.getElementsByClassName("cover")[0];
                mini_login.style.display = "none";
                cover.style.display = "none";
            }

            /* 移动登录窗口 */
            function moveLogin(event){
                var moveable = true;

                //获取事件源
                event = event ? event : window.event;
                var clientX = event.clientX;
                var clientY = event.clientY;

                var mini_login = document.getElementById("mini_login");
                console.log(mini_login);
                var top = parseInt(mini_login.style.top);
                var left = parseInt(mini_login.style.left);//鼠标拖动
                document.onmousemove = function(event){
                    if(moveable){
                        event = event ? event : window.event;
                        var y = top + event.clientY - clientY;
                        var x = left + event.clientX - clientX;
                        if(x>0 && y>0){
                            mini_login.style.top = y + "px";
                            mini_login.style.left = x + "px";
                        }
                    }
                }
                //鼠标弹起
                document.onmouseup = function(){
                    moveable = false;
                }
            }
        };
    </script>

    <style>
        /* 弹出 样式 */
        .mini_login{
            display:none;
            position:absolute;
            z-index:2;
            background:white;
        }
        .mini_login .item{
            width:320px;
            margin:0 auto;
            height:48px;
            line-height:48px;
            padding:0 20px;
        }
        /* 登录窗第一行*/
        .mini_login .firstLine{
            color:#666;
            background:#f7f7f7;
            font-size:18px;
            font-weight:bold;
            cursor:move;
        }
        .mini_login .item .login_close{
            display:inline-block;
            float:right;
            cursor:pointer;
        }

        .mini_login .item label{
            font-size:14px;
            margin-right:15px;
        }
        .mini_login .item input{
            display:inline-block;
            height:60%;
            width:70%;
        }
        /* 登录按钮 */
        .mini_login .item a.btn_login{
            display:block;
            margin:10px 10% 0;
            height:30px;
            line-height:30px;
            width:80%;
            background:#4490F7;
            color:white;
            font-size:16px;
            font-weight:bold;
            text-align:center;
        }
        /* 遮罩层样式 */
        .cover{
            display:none;
            width:100%;
            height:100%;
            position:absolute;
            top:0;
            left:0;
            z-index:1;
            background-color:#000;
            opacity:0.3;
        }
    </style>
</head>
<body>

<!-- 主体 -->
<div class="main">
    <a href="javascript:void(0)" class="btn_login" id="btn_showlogin">登录框</a>
</div>

<!-- 弹出登录小窗口 -->
<div class="mini_login" id="mini_login">
    <!-- 表单 -->
    <form action="" method="post">
        <div class="item firstLine" id="firstLine">
            <span class="login_title">我要登录</span>
            <span class="login_close" id="close_minilogin">X</span>
        </div>
        <div class="item">
            <label>用户</label>
            <input type="text" name="uname" />
        </div>
        <div class="item">
            <label>密码</label>
            <input type="password" name="upwd" />
        </div>
        <div class="item">
            <a href="javascript:void(0)" class="btn_login" onclick="">登录</a>
        </div>
    </form>
</div>
<!-- 遮罩层 -->
<div class="cover"></div>

</body>
</html>

附:images文件夹下的图片 alibaba popcentersituationone popcentersituationtwo

Seasons123 commented 5 years ago

一、使用js实现弹窗并有遮罩效果的实现思路

<!-- 主体 -->
<div class="main">
    <a href="javascript:void(0)" class="btn_login" id="btn_showlogin">登录框</a>
</div>

<!-- 弹出登录小窗口 -->
<div class="mini_login" id="mini_login">
    <!-- 弹窗的内容,如这里是表单 -->
</div>

<!-- 遮罩层 -->
<div class="cover"></div>

主要是利用display属性。 (1)初始页面并且没有点击交互时,主体的display为默认值(这里即为block,这是div的display属性),其他两个弹窗和遮罩层的display属性值为none (2)点击主体时,弹窗和遮罩的display值改为block (3)点击弹窗的关闭时,弹窗和遮罩的display值再改为none

Seasons123 commented 5 years ago

二、关于拖动小窗口的步骤 (1)鼠标在小窗口上按下 --> 拖动 --> 小窗口移动 --> 鼠标弹起 --> 小窗口停止移动 这分别代表几个事件!

鼠标按下事件 onmouserdown
鼠标移动事件 onmousemove
鼠标弹起事件 onmouseup

document.onmousemove 事件表示 在文档中鼠标移动就会触发此事件。

(2)看moveLogin函数的逻辑: 首先moveLogin函数被绑定在 id为firstLine元素 的onmousedown 事件上,就是当鼠标在firstLine元素上按下的时候,执行moveLogin函数;

然后moveLogin函数先声明了moveable=true,表示可以拖动元素了,接着把document.onmousemove事件绑定函数了,即从此之后只要移动鼠标就是触发此事件,执行函数内容,该函数先判断moveable是否为true即是否可以拖动,是则拖动,否则什么也不做;

最后moveLogin函数在document.onmouserup 事件函数中将moveable改为false,表示拖动结束。要想再次拖动必须先触发firstLine元素 的onmousedow 事件定义moveable=true

(3) clientX 事件属性返回当事件被触发时鼠标指针相对于浏览器页面(或客户区)的水平坐标。 客户区指的是当前窗口

event.clientX - clientX 鼠标在水平位置移动的距离

Seasons123 commented 5 years ago

三、弹窗居中 1、方法一实现思路:

mini_login.style.left = (document.body.scrollWidth - mini_login.scrollWidth) / 2 + "px";
mini_login.style.top = (document.body.scrollHeight - mini_login.scrollHeight) / 2 + "px";

【注】

scrollWidth:对象的实际内容的宽度,不包边线宽度,会随对象中内容超过可视区后而变大。 
clientWidth:对象内容的可视区的宽度,不包滚动条等边线,会随对象显示大小的变化而改变。 
offsetWidth:对象整体的实际宽度,包滚动条等边线,会随对象显示大小的变化而改变。

该demo就在页面中放一个textarea元素,采用默认宽高显示。 情况1:

元素内无内容或者内容不超过可视区,滚动不出现或不可用的情况下。
scrollWidth=clientWidth,两者皆为内容可视区的宽度。
offsetWidth为元素的实际宽度。
(图片见images文件夹)

情况2:

元素的内容超过可视区,滚动条出现和可用的情况下。
scrollWidth>clientWidth。
scrollWidth为实际内容的宽度。
clientWidth是内容可视区的宽度。
offsetWidth是元素的实际宽度。
(图片见images文件夹)

2、方法二实现思路:

<style type="text/css">
       //遮罩相对于body铺满屏幕,body默认的position为relative
     .cover {
         display: none;
         width: 100%;
         height: 100%;
         position: absolute;
         top: 0;
         left: 0;
         z-index: 1;
         background-color: #000;
         opacity: 0.3;
      }
    //弹窗相对于body居中,**body默认的position为relative**
     .mini_login {
       display: none;
       position: absolute;
       z-index: 2;
      width:200px;   //这里指定固定宽高,降低了点编程难度
      height:300px;
      top:50%;
      left:50%;
      margin: -150px  0  0  -100px;
      background: white;
     }
</style>

3、方法三实现思路: 弹窗样式:

display:flex;
主轴对其方式:center;
测轴对其方式:center;