自定義web彈窗/層:簡易風格的msg與可拖放的dialog
阿新 • • 發佈:2018-12-07
前言
做過web專案開發的人對layer彈層元件肯定不陌生,作為layUI的一個重要元件,使用簡單、介面引數豐富,功能健壯,深受廣大開發者的喜愛,作為一個熱(經)愛(常)工(劃)作(水),喜歡鑽研探索技術的程式設計師(狗),我們自己來實現一個web彈窗/層,一窺layer的本源(/手動滑稽臉),進步,從模仿開始。
首先,模仿layer的部分功能,我們先確定下我們要實現的功能:
msg
1、居中彈出、延時銷燬、自適應寬高、支援引數配置
dialog
1、可拖動
2、可最小化、最大化、關閉
3、右下角可對視窗進行縮放
4、支援多個引數配置、擴充套件
程式碼編寫
大部分的思路都在程式碼註釋裡
css樣式
/* web彈窗 */ .tip-msg { background-color: rgba(61, 61, 61, 0.93); color: #ffffff; opacity: 0; max-width: 200px; position: absolute; text-align: center; line-height: 25px; border-radius: 30px; padding: 5px 15px; display: inline-block; } .tip-shade { z-index: 9999; background-color: rgb(0, 0, 0); opacity: 0.6; position: fixed; top: 0; left: 0; width: 100%; height: 100%; } .tip-dialog { z-index: 10000; position: absolute; display: block; background: #e9e9e9; border-radius: 5px; opacity: 0; border: 1px solid #dad8d8; box-shadow: 0px 1px 20px 2px rgb(255, 221, 221); } .tip-title { cursor: move; padding: 5px; position: relative; height: 25px; border-bottom: 1px solid #dad8d8; user-select: none; } .tip-title-text { margin: 0; padding: 0; font-size: 15px; } .tip-title-btn { position: absolute; top: 5px; right: 5px; } .tip-content { padding: 8px; position: relative; word-break: break-all; font-size: 14px; overflow-x: hidden; overflow-y: auto; } .tip-resize { position: absolute; width: 15px; height: 15px; right: 0; bottom: 0; cursor: se-resize; }
js
/** * 自定義web彈窗/層:簡易風格的msg與可拖放的dialog * 依賴jquery */ var tip = { /** * 初始化 */ init: function () { var titleDiv = null;//標題元素 var dialogDiv = null;//視窗元素 var titleDown = false;//是否在標題元素按下滑鼠 var resizeDown = false;//是否在縮放元素按下滑鼠 var offset = {x: 0, y: 0};//滑鼠按下時的座標系/計算後的座標 /* 使用 on() 方法新增的事件處理程式適用於當前及未來的元素(比如由指令碼建立的新元素)。 問題:事件繫結在div上出現div移動速度跟不上滑鼠速度,導致滑鼠移動太快時會脫離div,從而無法觸發事件。 解決:把事件繫結在document文件上,無論滑鼠在怎麼移動,始終是在文件範圍之內。 */ //滑鼠在標題元素按下 $(document).on("mousedown", ".tip-title", function (e) { var event1 = e || window.event; titleDiv = $(this); dialogDiv = titleDiv.parent(); titleDown = true; offset.x = e.clientX - parseFloat(dialogDiv.css("left")); offset.y = e.clientY - parseFloat(dialogDiv.css("top")); }); //滑鼠移動 $(document).on("mousemove", function (e) { var event2 = e || window.event; var eveX = event2.clientX; // 獲取滑鼠相對於瀏覽器x軸的位置 var eveY = event2.clientY; // 獲取滑鼠相對於瀏覽器Y軸的位置 // var height = document.body.clientHeight;//表示HTML文件所在視窗的當前高度; // var width = document.body.clientWidth;//表示HTML文件所在視窗的當前寬度; var height = window.innerHeight;//瀏覽器視窗的內部高度; var width = window.innerWidth;//瀏覽器視窗的內部寬度; //在標題元素按下 if (titleDown) { //處理滾動條 if (tip.hasXScrollbar()) { height = height - tip.getScrollbarWidth(); } if (tip.hasYScrollbar()) { width = width - tip.getScrollbarWidth(); } //上邊 var top = (eveY - offset.y); if (top <= 0) { top = 0; } if (top >= (height - dialogDiv.height())) { top = height - dialogDiv.height() - 5; } //左邊 var left = (eveX - offset.x); if (left <= 0) { left = 0; } if (left >= (width - dialogDiv.width())) { left = width - dialogDiv.width() - 5; } dialogDiv.css({ "top": top + "px", "left": left + "px" }); } //在縮放元素按下 if (resizeDown) { var newWidth = (dialogDiv.resize.width + (eveX - offset.x)); if (dialogDiv.resize.initWidth >= newWidth) { newWidth = dialogDiv.resize.initWidth; } var newHeight = (dialogDiv.resize.height + (eveY - offset.y)); if (dialogDiv.resize.initHeight >= newHeight) { newHeight = dialogDiv.resize.initHeight; } dialogDiv.css("width", newWidth + "px"); dialogDiv.find(".tip-content").css("height", newHeight + "px"); } }); //滑鼠彈起 $(document).on("mouseup", function (e) { //清空物件 titleDown = false; resizeDown = false; titleDiv = null; dialogDiv = null; offset = {x: 0, y: 0}; }); //阻止按鈕事件冒泡 $(document).on("mousedown", ".tip-title-min,.tip-title-max,.tip-title-close", function (e) { e.stopPropagation();//阻止事件冒泡 }); //最小化 $(document).on("click", ".tip-title-min", function (e) { // var height = document.body.clientHeight;//表示HTML文件所在視窗的當前高度; // var width = document.body.clientWidth;//表示HTML文件所在視窗的當前寬度; var height = window.innerHeight;//瀏覽器視窗的內部高度; var width = window.innerWidth;//瀏覽器視窗的內部寬度; var $parent = $(this).parents(".tip-dialog"); //當前是否為最大化 if ($parent[0].isMax) { $parent[0].isMax = false; $parent.css({ "top": $parent[0].topMin, "left": $parent[0].leftMin, "height": $parent[0].heightMin, "width": $parent[0].widthMin }); } //當前是否為最小化 if (!$parent[0].isMin) { $parent[0].isMin = true; $parent[0].bottomMin = $parent.css("bottom"); $parent[0].leftMin = $parent.css("left"); $parent[0].heightMin = $parent.css("height"); $parent[0].widthMin = $parent.css("width"); $parent.css({ "top": "", "bottom": "5px", "left": 0, "height": "30px", "width": "95px" }); $parent.find(".tip-title-text").css("display", "none"); $parent.find(".tip-content").css("display", "none"); } else { $parent[0].isMin = false; $parent.css({ "top": $parent[0].topMin, "bottom": $parent[0].bottomMin, "left": $parent[0].leftMin, "height": $parent[0].heightMin, "width": $parent[0].widthMin }); $parent.find(".tip-title-text").css("display", "block"); $parent.find(".tip-content").css("display", "block"); } }); //最大化 $(document).on("click", ".tip-title-max", function (e) { // var height = document.body.clientHeight;//表示HTML文件所在視窗的當前高度; // var width = document.body.clientWidth;//表示HTML文件所在視窗的當前寬度; var height = window.innerHeight;//瀏覽器視窗的內部高度; var width = window.innerWidth;//瀏覽器視窗的內部寬度; var $parent = $(this).parents(".tip-dialog"); //當前是否為最小化 if ($parent[0].isMin) { $parent[0].isMin = false; $parent.css({ "top": $parent[0].topMin, "bottom": $parent[0].bottomMin, "left": $parent[0].leftMin, "height": $parent[0].heightMin, "width": $parent[0].widthMin }); $parent.find(".tip-title h2").css("display", "block"); } //當前是否為最大化 if (!$parent[0].isMax) { $parent[0].isMax = true; $parent[0].topMin = $parent.css("top"); $parent[0].leftMin = $parent.css("left"); $parent[0].heightMin = $parent.css("height"); $parent[0].widthMin = $parent.css("width"); $parent.css({ "top": 0, "left": 0, "height": height - 5 + "px", "width": width - 5 + "px" }); } else { $parent[0].isMax = false; $parent.css({ "top": $parent[0].topMin, "left": $parent[0].leftMin, "height": $parent[0].heightMin, "width": $parent[0].widthMin }); } }); //縮放 $(document).on("mousedown", ".tip-resize", function (e) { var event1 = e || window.event; dialogDiv = $(this).parent(); resizeDown = true; offset.x = e.clientX; offset.y = e.clientY; //點選時的寬高 dialogDiv.resize.width = dialogDiv.width(); dialogDiv.resize.height = dialogDiv.find(".tip-content").height(); }); //關閉 $(document).on("click", ".tip-title-close", function (e) { $(this).parents(".tip-dialog").parent().remove(); }); }, /** * 是否存在X軸方向滾動條 */ hasXScrollbar: function () { return document.body.scrollWidth > (window.innerWidth || document.documentElement.clientWidth); }, /** * 是否存在Y軸方向滾動條 */ hasYScrollbar: function () { return document.body.scrollHeight > (window.innerHeight || document.documentElement.clientHeight); }, /** * 計算滾動條的寬度 */ getScrollbarWidth: function () { /* 思路:生成一個帶滾動條的div,分析得到滾動條長度,然後過河拆橋 */ var scrollDiv = document.createElement("div"); scrollDiv.style.cssText = 'width: 99px; height: 99px; overflow: scroll; position: absolute; top: -9999px;'; document.body.appendChild(scrollDiv); var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth; document.body.removeChild(scrollDiv); return scrollbarWidth; }, /** * tip提示 * tip.msg("哈哈哈哈哈"); * tip.msg({text:"哈哈哈哈哈",time:5000}); */ msg: function (setting) { var time = setting.time || 2000; // 顯示時間(毫秒) 預設延遲2秒關閉 var text = setting.text || setting; // 文字內容 //組裝HTML var tip = "<div class='tip tip-msg'>" + text + "</div>"; //刪除舊tip $(".tip-msg").remove(); //新增到body $("body").append(tip); //獲取jq物件 var $tip = $(".tip-msg"); //動畫過渡 $tip.animate({opacity: 1}, 500); //計算位置瀏覽器視窗上下、左右居中 // var height = document.body.clientHeight;//表示HTML文件所在視窗的當前高度; var width = document.body.clientWidth;//表示HTML文件所在視窗的當前寬度; var height = window.innerHeight;//瀏覽器視窗的內部高度; // var width = window.innerWidth;//瀏覽器視窗的內部寬度; width = ((width / 2) - ($tip.css("width").replace("px", "") / 2)) / width; height = ((height / 2) - ($tip.css("height").replace("px", "") / 2)) / height; $tip.css({ "top": (height * 100) + "%", "left": (width * 100) + "%" }); //延遲刪除 setTimeout(function () { //動畫過渡 $tip.animate({opacity: 0}, 500, function () { $tip.remove(); }); }, time); }, /** * 可拖放視窗 * tip.dialog({title:"測試彈窗標題",content:"測試彈窗內容"}); * tip.dialog({title:"測試彈窗標題",content:"<h1>測試彈窗內容</h1>",offset: ['100px', '50px'],area:["200px","100px"],shade:0}); */ dialog: function (setting) { var title = setting.title || "這裡是標題"; // 標題 var content = setting.content || "這裡是內容"; // 內容 var area = setting.area || ['393px', '222px']; // 寬高 var offset = setting.offset || "auto" // 位置 上、左 var shade = setting.shade != undefined ? setting.shade : 0.7;//遮陰 為0時無遮陰物件 //組裝HTML var tip = "<div>\n" + " <!-- 遮陰層 -->\n" + " <div class=\"tip tip-shade\"></div>\n" + " <!-- 主體 -->\n" + " <div class=\"tip tip-dialog\">\n" + " <!-- 標題 -->\n" + " <div class=\"tip tip-title\">\n" + " <h2 class=\"tip tip-title-text\"></h2>\n" + " <div class=\"tip tip-title-btn\">\n" + " <button class=\"tip tip-title-min\" title=\"最小化\">--</button>\n" + " <button class=\"tip tip-title-max\" title=\"最大化\">O</button>\n" + " <button class=\"tip tip-title-close\" title=\"關閉\">X</button>\n" + " </div>\n" + " </div>\n" + " <!-- 視窗內容 -->\n" + " <div class=\"tip tip-content\"></div>\n" + " <!-- 右下角改變視窗大小 -->\n" + " <div class=\"tip tip-resize\"></div>\n" + " </div>\n" + "</div>"; var $tip = $(tip); //新增到body $("body").append($tip) //設定遮陰 $tip.find(".tip-shade").css("opacity", shade); if(shade == 0){ $tip.find(".tip-shade").css({ "width":"0", "height":"0" }); } //獲取dialog物件 $tip = $tip.find(".tip-dialog"); //標題 $tip.find(".tip-title-text").text(title); //內容 $tip.find(".tip-content").append(content); //設定初始寬高 $tip.css({ "width": area[0], }); $tip.find(".tip-content").css({ "height": area[1] }); //動畫過渡 $tip.animate({opacity: 1}, 500); //計算位置瀏覽器視窗上下、左右居中 if (offset === "auto") { // var height = document.body.clientHeight;//表示HTML文件所在視窗的當前高度; var width = document.body.clientWidth;//表示HTML文件所在視窗的當前寬度; var height = window.innerHeight;//瀏覽器視窗的內部高度; // var width = window.innerWidth;//瀏覽器視窗的內部寬度; width = ((width / 2) - ($tip.css("width").replace("px", "") / 2)) / width; height = ((height / 2) - ($tip.css("height").replace("px", "") / 2)) / height; $tip.css({ "top": (height * 100) + "%", "left": (width * 100) + "%" }); } else if (Array.isArray(offset)) { $tip.css({ "top": offset[0], "left": offset[1] }); } //初始值寬高 $tip.resize.initWidth = $tip.width(); $tip.resize.initHeight = $tip.find(".tip-content").height(); } };
呼叫
//初始化 tip.init(); // tip提示 tip.msg("哈哈哈哈哈"); tip.msg({text:"哈哈哈哈哈",time:5000}); //可拖放視窗 tip.dialog({title:"測試彈窗標題",content:"測試彈窗內容"}); tip.dialog({title:"測試彈窗標題",content:"<h1>測試彈窗內容</h1>",offset: ['100px', '50px'],area:["200px","100px"],shade:0});
效果演示
msg
彈出、銷燬有動畫效果,設定了一個max-width,超出會換行,支援引數配置
dialog
可拖動、可最小化、最大化、關閉,右下角可進行縮放,支援引數配置,發光特效
總結
實現拖拽、縮放功能,主要是監聽了document的mousedown,mousemove,mouseup事件,並對特殊元素進行特殊處理,一波騷操作,玩出了花(滑稽),從而實現我們想要的效果。
參考: