index.html
<!DOCTYPE html> <html lang="zh"> <head> <Meta charset="UTF-8"> <Meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <Meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>bootstrap 4模态窗口增强插件 </title> <link rel="stylesheet" href="http://cdn.bootstrapmb.com/bootstrap/4.3.1/css/bootstrap.min.css"> <link href="./src/css/simple-bs-dialog.css" rel="stylesheet" type="text/css" /> <script src="http://cdn.bootstrapmb.com/jquery/jquery-3.3.1.min.js"></script> <script src="http://cdn.bootstrapmb.com/bootstrap/4.3.1/js/bootstrap.min.js"></script> <script src="https://cdn.jsdelivr.net/gh/google/code-prettify@master/loader/run_prettify.js"></script> <script src="./src/js/simple-bs-dialog.js"></script> <style> .login-dialog .modal-header { color: #0480be; } </style> </head> <body> <div class="container"> <h2>Make use of Bootstrap's 4 Modal in a more friendly way.</h2> <hr /> <h3>Full example</h3> <p>Full functionality of SimpleBsDialog.</p> <div class="source-code runnable"> <!-- SimpleBsDialog.show({ width: '900px', autoWidth: false, height: '30%', autoHeight: true, title: 'Simple Bootstrap 4 Dialog (v' + SimpleBsDialog.version + ')', closable: true, spinner: true, spinnerIcon: '<span class="spinner-border text-primary" role="status"></span>', closeByBackdrop: true, closeByKeyboard: true, html: '', cssClass: 'login-dialog', buttons: [{ id: 'btn-ok', label: 'OK', cssClass: 'btn-primary', action: function(dialogRef) { console.log('OK button pressed!'); dialogRef.close(); }, }, { id: 'btn-cancel', label: 'Cancel', cssClass: 'btn-warning', action: function(dialogRef) { console.log('Cancel button pressed!'); dialogRef.close(); }, }, ], onShow: function(dialogRef) { console.log('onShow'); dialogRef.getButtons().prop('disabled', true); }, onShown: function(dialogRef) { console.log('onShown'); setTimeout(function() { dialogRef.set({ 'spinner': false, }).getModalBody().html('Your content goes here...'); dialogRef.getButtons().prop('disabled', false); }, 1000); }, onHide: function(dialogRef) { console.log('onHide'); }, onHidden: function(dialogRef) { console.log('onHidden'); }, }); --> </div> <!-- Available options --> <br /> <a name="available-options"></a> <h2>Available options</h2> <hr /> <p> Please note that all options described below are <strong>optional</strong>, but you will have a weird dialog if you don't even give it a title to display. <br /> Most options can be set via init options or property setters. </p> <table class="table table-bordered"> <thead> <tr> <th> Option </th> <th> Type </th> <th> Default value </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td>width</td> <td> String or Integer </td> <td> 500 </td> <td> The dialog's width in pixels or percent. Examples: <div class="source-code runnable"> SimpleBsDialog.show({ width: '900px', }); </div> <hr /> <div class="source-code runnable"> SimpleBsDialog.show({ width: '70%', }); </div> <hr /> <div class="source-code runnable"> SimpleBsDialog.show({ width: '600', }); </div> </td> </tr> <tr> <td>autoWidth</td> <td> Boolean </td> <td> false </td> <td> Enables resizing the dialog when the document is resized. It applies only when the 'width' value is set in percent. <div class="source-code runnable"> SimpleBsDialog.show({ width: '80%', autoWidth: true, }); </div> </td> </tr> <tr> <td>height</td> <td> String or Integer </td> <td> 280 </td> <td> The dialog's height in pixels or percent. Examples: <div class="source-code runnable"> SimpleBsDialog.show({ height: '300px', }); </div> <hr /> <div class="source-code runnable"> SimpleBsDialog.show({ height: '60%', }); </div> </td> </tr> <tr> <td>autoHeight</td> <td> Boolean </td> <td> false </td> <td> Enables resizing the dialog when the document is resized. It applies only when the 'height' value is set in percent. <div class="source-code runnable"> SimpleBsDialog.show({ height: '60%', autoHeight: true, }); </div> </td> </tr> <tr> <td>title</td> <td> String </td> <td></td> <td> The dialog's title. </td> </tr> <tr> <td>closable</td> <td> Boolean </td> <td> true </td> <td> Show|hide the close button at the top right corner. </td> </tr> <tr> <td>spinner</td> <td> Boolean </td> <td> false </td> <td> Show|hide the spinner icon. </td> </tr> <tr> <td>spinnerIcon</td> <td> String </td> <td> <div class="source-code"><span class="spinner-border" role="status"></span></div> </td> <td> Set the spinner's icon. </td> </tr> <tr> <td>closeByBackdrop</td> <td> Boolean </td> <td> true </td> <td> When it's true, you can close it by clicking outside the dialog. </td> </tr> <tr> <td>closeByKeyboard</td> <td> Boolean </td> <td> true </td> <td> When it's true, you can close it by pressing the ESC key. </td> </tr> <tr> <td>html</td> <td> String </td> <td></td> <td> The dialog's content. </td> </tr> <tr> <td>cssClass</td> <td> String </td> <td></td> <td> Additional css classes that will be added to your dialog. </td> </tr> <tr> <td>buttons</td> <td> Array </td> <td></td> <td> Example: <div class="source-code runnable"> SimpleBsDialog.show({ buttons: [{ id: 'btn-ok', label: 'OK', cssClass: 'btn-primary', action: function(dialogRef) { dialogRef.close(); }, }, ], }); </div> <strong>id</strong>: optional, otherwise a random id will be generated.<br /> <strong>label</strong>: optional, the button's title.<br /> <strong>cssClass</strong>: optional, additional css class to be added to the button.<br /> <strong>action</strong>: optional, if provided, the callback will be invoked after the button is clicked, and the dialog instance will be passed to the callback function.<br /> </td> </tr> <tr> <td>onShow</td> <td> function </td> <td></td> <td> If provided, it will be invoked when the dialog is popping up. </td> </tr> <tr> <td>onShown</td> <td> function </td> <td></td> <td> If provided, it will be invoked when the dialog is popped up. </td> </tr> <tr> <td>onHide</td> <td> function </td> <td></td> <td> If provided, it will be invoked when the dialog is popping down. </td> </tr> <tr> <td>onHidden</td> <td> function </td> <td></td> <td> If provided, it will be invoked when the dialog is popped down. </td> </tr> </tbody> </table> <!-- Available methods --> <br /> <a name="available-methods"></a> <h2>Available methods</h2> <hr /> <table class="table table-bordered"> <thead> <tr> <th> Method </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td>open()</td> <td>Opens the dialog. Usage: dialogInstance.open().</td> </tr> <tr> <td>close()</td> <td>Closes the dialog. Usage: dialogInstance.close().</td> </tr> <tr> <td>get(option)</td> <td> Getter for options. You can get the following options:<br /> <strong>width, autoWidth, height, autoHeight, title, closable, spinner, spinnerIcon</strong> </td> </tr> <tr> <td>set(option, value)</td> <td> Setter for a given option. You can set the following options:<br /> <strong>width, autoWidth, height, autoHeight, title, closable, spinner, spinnerIcon</strong> </td> </tr> <tr> <td>set(options)</td> <td> Setter for many options. You can set the following options:<br /> <strong>width, autoWidth, height, autoHeight, title, closable, spinner, spinnerIcon</strong> </td> </tr> <tr> <td>getModalBody()</td> <td>Returns the raw modal body.</td> </tr> <tr> <td>getButton(id)</td> <td>Returns a button by id as a jQuery object.</td> </tr> <tr> <td>getButtons()</td> <td>Returns all available buttons as jQuery objects.</td> </tr> <tr> <td>SimpleBsDialog.show(options)</td> <td>Creates a new dialog with options, opens it and returns the dialog object.</td> </tr> <tr> <td>SimpleBsDialog.version</td> <td>Returns the current SimpleBsDialog's version.</td> </tr> </tbody> </table> <hr /> </div> <script type="text/javascript"> $(function () { $('.source-code').each(function (index) { var $section = $(this); var code = $(this).html().replace('<!--', '').replace('-->', ''); // Code preview var $codePreview = $('<pre class="prettyprint lang-javascript"></pre>'); $codePreview.text(code); $section.html($codePreview); // Run code if ($section.hasClass('runnable')) { var $button = $('<button class="btn btn-primary">Run the code</button>'); $button.on('click', { code: code }, function (event) { eval(event.data.code); }); $button.insertAfter($section); $('<div class="clearfix" style="margin-bottom: 10px;"></div>').insertAfter($button); } }); }); </script> </body> </html>
simple-bs-dialog.css
.simple-bs-dialog .modal-dialog, .simple-bs-dialog .modal-content { min-height: 200px; } .simple-bs-dialog .modal-body { min-height: 80px; } .simple-bs-dialog .modal-spinner { background: white; z-index: 1; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); }
simple-bs-dialog.js
(function(w, $) { 'use strict'; // register the main object w.SimpleBsDialog = function(options) { this.options = $.extend({}, { id: newGuid(), width: 500, autoWidth: false, height: 280, autoHeight: false, title: '', closable: true, spinner: false, spinnerIcon: '<span class="spinner-border" role="status"></span>', closeByBackdrop: true, closeByKeyboard: true, html: '', cssClass: '', buttons: [], onShow: function(dialogRef){}, onShown: function(dialogRef){}, onHide: function(dialogRef){}, onHidden: function(dialogRef){}, }, options); }; // private methods function newGuid() { return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { var r = Math.random() * 16 | 0, v = (c == 'x' ? r : r & 0x03 | 0x08); return v.toString(16); }); } function setWidth(e, init) { var width = 0; // parse width if (e.data.options.width.toString().indexOf('px') >= 0) { width = parseInt(e.data.options.width.toString().substring(0, e.data.options.width.toString().indexOf('px'))); } else if (e.data.options.width.toString().indexOf('%') >= 0) { width = parseInt((parseInt(e.data.options.width.toString().substring(0, e.data.options.width.toString().indexOf('%'))) / 100) * $(window).outerWidth(true), 10); } else { width = parseInt(e.data.options.width); } // set left $('#' + e.data.options.id).find('.modal-dialog').css({'margin-left': parseInt(($(window).outerWidth(true) - width) / 2, 10) + 'px'}); // set width if (init === true || (e.data.options.autoWidth === true && e.data.options.width.toString().indexOf('%') >= 0)) { $('#' + e.data.options.id).find('.modal-content').css({'width': width + 'px'}).find('.modal-body').css({'min-width': (width - 120) + 'px'}); } } function setHeight(e, init) { var height = 0; // parse height if (e.data.options.height.toString().indexOf('px') >= 0) { height = parseInt(e.data.options.height.toString().substring(0, e.data.options.height.toString().indexOf('px'))); } else if (e.data.options.height.toString().indexOf('%') >= 0) { height = parseInt((parseInt(e.data.options.height.toString().substring(0, e.data.options.height.toString().indexOf('%'))) / 100) * ($(window).outerHeight(true) - parseInt($('#' + e.data.options.id).find('.modal-dialog').css('margin-top'), 10)), 10); } else { height = parseInt(e.data.options.height); } // set height if (init === true || (e.data.options.autoHeight === true && e.data.options.height.toString().indexOf('%') >= 0)) { $('#' + e.data.options.id).find('.modal-content').css({'min-height': height + 'px'}).find('.modal-body').css({'min-height': (height - 120) + 'px'}); } } function setSize(e) { setWidth(e, false); setHeight(e, false); } function validOptions() { return [ 'width', 'autoWidth', 'height', 'autoHeight', 'title', 'closable', 'spinner', 'spinnerIcon', ]; } function parseCssClass(cssClass) { var cssClasses = cssClass.split(' '); if (cssClasses.length == 0) { return ''; } return ' ' + cssClasses.join(' '); } // public methods SimpleBsDialog.prototype.open = function() { // store this var dialog = this; // bootstrap dialog $('body').append('<div class="simple-bs-dialog modal fade' + parseCssClass(dialog.options.cssClass) + '" id="' + dialog.options.id + '" tabindex="-1"><div class="modal-dialog"><div class="modal-content"><div class="modal-header"><h5 class="modal-title">' + dialog.options.title + '</h5><button type="button" class="close' + (dialog.options.closable ? '' : ' d-none') + '" data-dismiss="modal">×</button></div><div class="modal-html"><div class="modal-body">' + dialog.options.html + '</div><div class="modal-spinner' + (dialog.options.spinner ? '' : ' d-none') + '">' + dialog.options.spinnerIcon + '</div></div>' + (dialog.options.buttons.length > 0 ? '<div class="modal-footer"></div>' : '') + '</div></div></div>'); // add buttons $.each(dialog.options.buttons, function(index, options) { var opts = $.extend({}, { id: newGuid(), label: '', cssClass: '', action: function(dialogRef){}, }, options); var button = $('<button type="button" class="btn btn-default' + (opts.cssClass.length > 0 ? ' ' : '') + opts.cssClass + '" id="' + opts.id + '">' + opts.label + '</button>'); button.on('click', function(e) { opts.action(dialog); }); $('#' + dialog.options.id).find('.modal-footer').append(button); }); // destroy dom element $('#' + dialog.options.id).on('show.bs.modal', function() { // initial width setWidth({ data: dialog, }, true); // initial height setHeight({ data: dialog, }, true); // set dialog's auto size $(window).on('resize', dialog, setSize); // onShow event dialog.options.onShow(dialog); }).on('shown.bs.modal', function() { // onShown event dialog.options.onShown(dialog); }).on('hide.bs.modal', function(e) { // onHide event dialog.options.onHide(dialog); }).on('hidden.bs.modal', function(e) { // cancel dialog's auto size $(window).off('resize', setSize); // remove dialog's div $('#' + dialog.options.id).remove(); // onHidden event dialog.options.onHidden(dialog); }).modal({ 'backdrop': dialog.options.closeByBackdrop, 'keyboard': dialog.options.closeByKeyboard, }); // return main object return this; } SimpleBsDialog.prototype.close = function() { $('#' + this.options.id).modal('hide'); // return main object return this; } SimpleBsDialog.prototype.get = function(option) { if (validOptions().indexOf(option) > -1) { return this.options[option]; } } SimpleBsDialog.prototype.set = function(options, value) { if (!$.isPlainObject(options) && validOptions().indexOf(options) > -1) { var option = options; options = {}; options[option] = value; } if ($.isPlainObject(options)) { // store this var dialog = this; $.each(options, function(option, value) { switch (option) { case 'width': { // new width dialog.options.width = value; // init new size setWidth({ data: dialog, }, true); break; } case 'autoWidth': { // new autoWidth dialog.options.autoWidth = value; // init new size setWidth({ data: dialog, }, true); break; } case 'height': { // new height dialog.options.height = value; // init new size setHeight({ data: dialog, }, true); break; } case 'autoHeight': { // new autoHeight dialog.options.autoHeight = value; // init new size setHeight({ data: dialog, }, true); break; } case 'title': { // update dialog's title $('#' + dialog.options.id).find('.modal-title').html(dialog.options.title = value); break; } case 'closable': { // update dialog's closable if (dialog.options.closable = value) { $('#' + dialog.options.id).find('.modal-header button.close').removeClass('d-none'); } else { $('#' + dialog.options.id).find('.modal-header button.close').addClass('d-none'); } break; } case 'spinner': { // update dialog's spinner if (dialog.options.spinner = value) { $('#' + dialog.options.id).find('.modal-spinner').removeClass('d-none'); } else { $('#' + dialog.options.id).find('.modal-spinner').addClass('d-none'); } break; } case 'spinnerIcon': { // update dialog's spinnerIcon $('#' + dialog.options.id).find('.modal-spinner').html(dialog.options.spinnerIcon = value); break; } } }); } // return main object return this; } SimpleBsDialog.prototype.getModalBody = function() { // get modal body return $('#' + this.options.id).find('.modal-body'); } SimpleBsDialog.prototype.getButton = function(id) { // get button's object return $('#' + this.options.id).find('.modal-footer button#' + id); } SimpleBsDialog.prototype.getButtons = function() { // get all the buttons' object return $('#' + this.options.id).find('.modal-footer button'); } // for lazy people SimpleBsDialog.show = function(options) { return (new SimpleBsDialog(options)).open(); } // current version SimpleBsDialog.version = '1.0.1'; }(window, jQuery));
参考:http://www.bootstrapmb.com/item/6561/preview