Bootstrap中不乏很多優秀的小插件來讓界面更加漂亮。比如之前做過筆記的bootstrap-fileinput,select2,datetimepicker等都是屬於這一系列的。這些相對而言比較大一點。其他還有一些比較輕比較小的插件,也很好,特此開篇來記錄一下。
由於是基於bootstrap的插件,所以基本上所有插件都是需要bootstrap和jquery相關文件的。也就是說下面的說明中我們默認頁面上已經有了:
<link href="/static/css/bootstrap.min.css" rel="stylesheet" /> <script src="/static/js/jquery.min.js"></script> <script src="/static/js/bootstrap.min.js"></script>
■ ladda-bootstrap
轉自【http://www.cnblogs.com/landeanfen/p/5603790.html#_label3】
按鈕通常是發起ajax請求或提交表單數據的第一入口,有時候點擊按鈕發送請求之后反應會比較慢,如果用戶等不及了再按一下按鈕就導致重復請求了。這個就很僵硬了。
這個插件可以讓我們點擊按鈕之后讓按鈕出現轉菊花,並且禁用。雖說自己實現邏輯也不復雜,不過這個很好看。
這個插件在github上的地址是:【https://github.com/msurguy/ladda-bootstrap】,使用這個插件需要引入的靜態文件有:
<link href="/static/ladda-bootstrap/dist/ladda-themeless.min.css" rel="stylesheet" /> <script src="/static/ladda-bootstrap/dist/spin.min.js"></script> <script src="/static/ladda-bootstrap/dist/ladda.min.js"></script>
然后HTML是一個簡單的按鈕,但是需要加入一些class和新的屬性:
<button type="button" class="btn btn-primary ladda-button" data-style="expand-right" id="testbtn"><span class="ladda-label">測試</span></button>
然后是js初始化這個按鈕:
$(document).ready(function(){ $('#testbtn').click(function(event){ var l = Ladda.create(this); l.start(); //啟動動畫,禁用按鈕 l.setProgress(0-1); //設置進度條 /* 做這個按鈕該做的操作 */ l.stop(); //結束動畫,啟用按鈕 }); });
首先需要注意的是,Ladda.create方法的參數不是一個jquery對象而是一個DOM對象(所以我們用this而不是$(this)),這一點在click外面寫時尤其重要。比如我和一個bootstrap-table結合起來,點擊按鈕時觸發bootstrap-table的refresh事件:
$('#table').bootstrapTable({ /*其他參數*/ onLoadSuccess: function(data){ var l = Ladda.create($('#testbtn')[0]); l.stop(); } }); $('#testbtn').click(function(event){ var l = Ladda.create(this); l.start(); l.setProgress(0-1); $('#table').bootstrapTable('refresh'); //觸發refresh事件 });
然后再來看button的data-style屬性。這個屬性指出了按鈕的動畫以何種形式出現。expand-right是按鈕先擴展然后在文字右邊出現一個轉菊花。除了這個還有以下這些data-style可以選擇:
expand-left , expand-up , expand-down
zoom-in , zoom-out 文字先放大/縮小淡出,然后菊花淡入
slide-up/down/left/right 文字向指定方向划出,然后菊花淡入
此外,button也有一些屬性可以進一步定制這個組件的樣式,比如
data-spinner-color 可以指定轉菊花時菊花的顏色,值是類似於'#6600ff'這種
最后再說下,setProgress是個什么東西。這個組件其實默認會給按鈕上加上一個進度條,反映在界面上就是文字退出按鈕的時間的快慢。作為實用的話這個方法肯定是要在某個回調函數中調用的。參數設置0到1間的某個實數來體現進度條。
■ bootstrap-switch
這個插件可以幫我們方便地實現像IOS那樣風格的開關按鈕。開關這個東西,本質上是一個checkbox(分成開和關兩種狀態,多個開關之間互相不關聯)。
源碼下載:【https://github.com/Bttstrp/bootstrap-switch】
官方文檔:【http://bootstrapswitch.com/options.html】
使用:
需要引用的文件:
<link href="/static/bootstrap-switch/dist/css/bootstrap3/bootstrap-switch.min.css" rel="stylesheet" /> <script src="/static/bootstrap-switch/dist/js/bootstrap-switch.min.js"></script>
HTML:
<input type="checkbox" id="testswitch" checked />
JS:
$(document).ready(function(){ $('#testswtich').bootstrapSwtich({ size: 'mini' }); });
這是基本用法,就可以渲染出一個開關了。開關的取值和一般的checkbox一致,只需要$('#testswitch').prop('checked')或者is(':checked')來獲取true和false
事件的話和普通checkbox不同,無法通過change方法綁定事件處理函數。而是要在初始化時定義好處理函數比如有這些事件:
onSwitchChange 最主要的事件,定義開關切換狀態時觸發的事件的處理函數,綁定的函數有兩個參數,分別是事件對象event和data(該switch做完變化后的狀態,true和false)
onInit 初始化時發生的事件
綁定事件的具體方式是$('#test').bootstrapSwitch('onSwitchChange',function(event,data){...})
另外這些是初始化時的參數:
size 指定組件大小,從小到大有mini,small,normal,large等
onColor,offColor 指定開關狀態時開關的顏色,可選值有success,warning,primary,info,danger,default
onText,offText 指定開關狀態下顯示的文字,默認是ON和OFF
state 設置默認狀態下是開是關
inverse 默認情況下開在按鈕左邊關在右邊,設置inverse參數為true時倒過來
handleWidth 設置開關寬度,單位為px,可設置成'auto'
在此額外提一下(也是一個比較通用的知識點)如果不想在初始化時設置這些參數,可以在初始化方法外面進行全局設定的重寫,方法是:
$.fn.bootstrapSwitch.defaults.size = 'large';
$.fn.bootstrapSwitch.defaults.onColor = 'sucess';
■ 步驟條ystep
步驟條是開發流程、多步驟表單時常用的一種組件。ystep這個組件是由一位叫楊園的前輩(https://github.com/iyangyuan/ystep)開發的,輕量級的步驟條組件。然后我還結合了這篇文章對插件做了一些定制化的內容。
首先引入文件:
<link href="{% static 'ystep-master/css/ystep.css' %}" rel="stylesheet" /> <script src="{% static 'js/skill.js' %}"></script>
然后HTML上寫一個div:
<div id="teststep"></div>
然后是JS來初始化:
$(document).ready(function(){ $('#teststep').loadStep({ //size: 'small', size: 'large', color: 'blue', steps: [{ title: '第一步', content: '打開冰箱門' },{ title: '第二步', content: '把大象塞進冰箱' },{ title: '第三步', content: '把冰箱門帶上' },{ title: '第四步', content: '完成' } ] }).setStep(0); });
size指出了步驟條大小,只有large和small兩個選項。color是顏色風格,有blue和green兩種。steps是步驟條主題,title是步驟名稱,content是鼠標懸浮在步驟名附近時給出的關於步驟詳細內容的提示信息。
先來說說方法,setStep(n)可以將當前步驟條調整到第n步(是0開始的),getStep()獲取當前第幾步,nextStep和prevStep是前后調整。
● 自己的一些小修改
結合上面給出的第二篇文章,ystep這個組件還存在一些小缺點。其實最困擾我的還是大小問題。雖然提供了large這個選項,但是整個步驟條還是一個比較短的狀態,我想讓它變長,最好是達到100%容器的寬度。於是我在ystep.js中做出了如下修改:
/*在540行附近的large參數的函數,如果願意改small或者新增一個自定義的參數也是可以的*/ large: function($html){ var stepCount = $html.find("li").length-1, /* beg 將原來寫死的px值換成百分比 */ containerWidth = "100%"; progressWidth = "100%"; progressbarWidth = ((stepCount/(stepCount+1))*100)+"%"; /* end */ $html.css({ width: containerWidth }); $html.find(".ystep-progress").css({ width: progressWidth }); $html.find(".ystep-progress-bar").css({ width: progressbarWidth //原來progress和progress-bar長度一樣,現在應該讓progress-bar比progress略短一些,具體短多少看上面公式 }); $html.addClass("ystep-lg"); }
以及
/* 在600行附近新增調整每個步驟margin-right的值的邏輯 */ //調整步驟margin以對齊 var containerWidth = $n.width(); var fullStepCount = $baseHtml.find('li').length; var modify = ( containerWidth - fullStepCount * 100 ) / fullStepCount; $n.find('li').css('margin-right',modify+'px');
通過這樣渲染出來的步驟條,它就是一個長度可以填滿.ystep-container這個div相當一部分的步驟條了。不能做到填滿到100%是因為progress的進度邏輯和寬度邏輯是不相符的,如果progressbarWidth和progressWidth一樣保持100%,那么調用一次nextStep(或者其他方法)后進度條不會剛好走到步驟條節點上而是有所出入。如果要改進度邏輯,那么就要修改各個方法了,有點麻煩,所以走了簡單的路改寬度邏輯。
如此修改之后得到的步驟條還是有些不好的地方,就是會往左邊偏一點。想要去除這個可以看情況把#teststep這個div加上一個col-lg-offset-x的class,盡量把.ystep-container這個div調整到畫面中間。
■ 遮罩效果
在發起ajax之后等場景下,可能需要頁面出現一個所謂的遮罩效果,防止用戶在這段時間內做出多余的操作。遮罩的基本思路就是在頁面上添加一個覆蓋所有元素(從CSS的角度上來看z-index較大)的div,並添加一些提示信息和進出效果,提示信息可以分為簡單的文字提示,也可以有轉菊花等比較好看的提示,轉菊花又可以分成圖片實現(直接插入一張gif圖)和css/js實現。
雖然整體而言,自己實現遮罩起來也不困難,但是也有一些現成的組件可以使用。比如這位大神提到的一些:【http://www.cnblogs.com/landeanfen/p/5461849.html#_label2】
1. 簡單的單層遮罩
組件很簡單,就是一個js文件:

/******************************************* * * Plug-in:友好的頁面加載效果 * Author:sqinyang (sqinyang@sina.com) * Time:2015/04/20 * Explanation:隨着HTML5的流行,頁面效果越來越炫,同時也需要加載大量的插件及素材,萬惡的網速,特別對於掛在國外服務器的網站,一打開一堆素材緩緩加載,位置錯亂不齊,故編寫此方法,方便大家使用 * *********************************************/ jQuery.bootstrapLoading = { start: function (options) { var defaults = { opacity: 1, //loading頁面透明度 backgroundColor: "#fff", //loading頁面背景色 borderColor: "#bbb", //提示邊框顏色 borderWidth: 1, //提示邊框寬度 borderStyle: "solid", //提示邊框樣式 loadingTips: "Loading, please wait...", //提示文本 TipsColor: "#666", //提示顏色 delayTime: 1000, //頁面加載完成后,加載頁面漸出速度 zindex: 999, //loading頁面層次 sleep: 0 //設置掛起,等於0時則無需掛起 } var options = $.extend(defaults, options); //獲取頁面寬高 var _PageHeight = document.documentElement.clientHeight, _PageWidth = document.documentElement.clientWidth; //在頁面未加載完畢之前顯示的loading Html自定義內容 var _LoadingHtml = '<div id="loadingPage" style="position:fixed;left:0;top:0;_position: absolute;width:100%;height:' + _PageHeight + 'px;background:' + options.backgroundColor + ';opacity:' + options.opacity + ';filter:alpha(opacity=' + options.opacity * 100 + ');z-index:' + options.zindex + ';"><div id="loadingTips" style="position: absolute; cursor1: wait; width: auto;border-color:' + options.borderColor + ';border-style:' + options.borderStyle + ';border-width:' + options.borderWidth + 'px; height:80px; line-height:80px; padding-left:80px; padding-right: 5px;border-radius:10px; background: ' + options.backgroundColor + ' url(/Content/bootstrap-loading/images/loading.gif) no-repeat 5px center; color:' + options.TipsColor + ';font-size:20px;">' + options.loadingTips + '</div></div>'; //呈現loading效果 $("body").append(_LoadingHtml); //獲取loading提示框寬高 var _LoadingTipsH = document.getElementById("loadingTips").clientHeight, _LoadingTipsW = document.getElementById("loadingTips").clientWidth; //計算距離,讓loading提示框保持在屏幕上下左右居中 var _LoadingTop = _PageHeight > _LoadingTipsH ? (_PageHeight - _LoadingTipsH) / 2 : 0, _LoadingLeft = _PageWidth > _LoadingTipsW ? (_PageWidth - _LoadingTipsW) / 2 : 0; $("#loadingTips").css({ "left": _LoadingLeft + "px", "top": _LoadingTop + "px" }); //監聽頁面加載狀態 document.onreadystatechange = PageLoaded; //當頁面加載完成后執行 function PageLoaded() { if (document.readyState == "complete") { var loadingMask = $('#loadingPage'); setTimeout(function () { loadingMask.animate({ "opacity": 0 }, options.delayTime, function () { $(this).hide(); }); }, options.sleep); } } }, end: function () { $("#loadingPage").remove(); } }
然后在我們自己的頁面可以這樣調用(當然,默認已經導入了bootstrap的js和css以及jquery):
$('#test').click(function(event){ event.preventDefault(); // 顯示遮罩 $.bootstrapLoading.start({ //一些初始化參數,可以參考組件代碼中的default中的字段 loadingTips: '正在加載中...', backgroundColor: '#EEE8CD', opacity: 0.8 }); //做一些耗時操作如ajax請求等,如果是ajax那么關閉遮罩的方法end可以在complete參數指定的函數中調用 // 關閉遮罩 $.bootstrapLoading.end(); });
2. spin.js
這個組件有通過css+js實現的轉菊花效果。用到的組件文件主要有
spin.js【根據參考文中給出的提示進行了修改】:

/** * Copyright (c) 2011-2014 Felix Gnass * Licensed under the MIT license * http://spin.js.org/ * * Example: var opts = { lines: 12, // The number of lines to draw length: 7, // The length of each line width: 5, // The line thickness radius: 10, // The radius of the inner circle scale: 1.0, // Scales overall size of the spinner corners: 1, // Roundness (0..1) color: '#000', // #rgb or #rrggbb opacity: 1/4, // Opacity of the lines rotate: 0, // Rotation offset direction: 1, // 1: clockwise, -1: counterclockwise speed: 1, // Rounds per second trail: 100, // Afterglow percentage fps: 20, // Frames per second when using setTimeout() zIndex: 2e9, // Use a high z-index by default className: 'spinner', // CSS class to assign to the element top: '50%', // center vertically left: '50%', // center horizontally shadow: false, // Whether to render a shadow hwaccel: false, // Whether to use hardware acceleration (might be buggy) position: 'absolute' // Element positioning }; var target = document.getElementById('foo'); var spinner = new Spinner(opts).spin(target); */ ;(function(root, factory) { if (typeof module == 'object' && module.exports) module.exports = factory(); // CommonJS else if (typeof define == 'function' && define.amd) define(factory); // AMD module else root.Spinner = factory(); // Browser global } (this, function() { 'use strict'; var prefixes = ['webkit', 'Moz', 'ms', 'O']; // Vendor prefixes var animations = {}; // Animation rules keyed by their name var useCssAnimations; // Whether to use CSS animations or setTimeout var sheet; // A stylesheet to hold the @keyframe or VML rules /** * Utility function to create elements. If no tag name is given, * a DIV is created. Optionally properties can be passed. */ function createEl(tag, prop) { var el = document.createElement(tag || 'div'); var n; for (n in prop) el[n] = prop[n]; return el; } /** * Appends children and returns the parent. */ function ins(parent /* child1, child2, ...*/) { for (var i = 1, n = arguments.length; i < n; i++) { parent.appendChild(arguments[i]); } return parent; } /** * Creates an opacity keyframe animation rule and returns its name. * Since most mobile Webkits have timing issues with animation-delay, * we create separate rules for each line/segment. */ function addAnimation(alpha, trail, i, lines) { var name = ['opacity', trail, ~~(alpha * 100), i, lines].join('-'); var start = 0.01 + i/lines * 100; var z = Math.max(1 - (1-alpha) / trail * (100-start), alpha); var prefix = useCssAnimations.substring(0, useCssAnimations.indexOf('Animation')).toLowerCase(); var pre = prefix && '-' + prefix + '-' || ''; if (!animations[name]) { sheet.insertRule( '@' + pre + 'keyframes ' + name + '{' + '0%{opacity:' + z + '}' + start + '%{opacity:' + alpha + '}' + (start+0.01) + '%{opacity:1}' + (start+trail) % 100 + '%{opacity:' + alpha + '}' + '100%{opacity:' + z + '}' + '}', sheet.cssRules.length); animations[name] = 1; } return name; } /** * Tries various vendor prefixes and returns the first supported property. */ function vendor(el, prop) { var s = el.style; var pp; var i; prop = prop.charAt(0).toUpperCase() + prop.slice(1); if (s[prop] !== undefined) return prop; for (i = 0; i < prefixes.length; i++) { pp = prefixes[i]+prop; if (s[pp] !== undefined) return pp; } } /** * Sets multiple style properties at once. */ function css(el, prop) { for (var n in prop) { el.style[vendor(el, n) || n] = prop[n]; } return el; } /** * Fills in default values. */ function merge(obj) { for (var i = 1; i < arguments.length; i++) { var def = arguments[i]; for (var n in def) { if (obj[n] === undefined) obj[n] = def[n]; } } return obj; } /** * Returns the line color from the given string or array. */ function getColor(color, idx) { return typeof color == 'string' ? color : color[idx % color.length]; } // Built-in defaults var defaults = { lines: 12, // The number of lines to draw length: 7, // The length of each line width: 5, // The line thickness radius: 10, // The radius of the inner circle scale: 1.0, // Scales overall size of the spinner corners: 1, // Roundness (0..1) color: '#000', // #rgb or #rrggbb opacity: 1/4, // Opacity of the lines rotate: 0, // Rotation offset direction: 1, // 1: clockwise, -1: counterclockwise speed: 1, // Rounds per second trail: 100, // Afterglow percentage fps: 20, // Frames per second when using setTimeout() zIndex: 2e9, // Use a high z-index by default className: 'spinner', // CSS class to assign to the element top: '50%', // center vertically left: '50%', // center horizontally shadow: false, // Whether to render a shadow hwaccel: false, // Whether to use hardware acceleration position: 'absolute' // Element positioning }; /** The constructor */ function Spinner(o) { this.opts = merge(o || {}, Spinner.defaults, defaults); } // Global defaults that override the built-ins: Spinner.defaults = {}; merge(Spinner.prototype, { /** * Adds the spinner to the given target element. If this instance is already * spinning, it is automatically removed from its previous target b calling * stop() internally. */ spin: function(target) { this.stop(); var self = this; var o = self.opts; var el = self.el = createEl(null, {className: o.className}); css(el, { position: o.position, width: 0, zIndex: o.zIndex, left: o.left, top: o.top }); if (target) { target.insertBefore(el, target.firstChild || null); target.className = "fade"; } el.setAttribute('role', 'progressbar'); self.lines(el, self.opts); if (!useCssAnimations) { // No CSS animation support, use setTimeout() instead var i = 0; var start = (o.lines - 1) * (1 - o.direction) / 2; var alpha; var fps = o.fps; var f = fps / o.speed; var ostep = (1 - o.opacity) / (f * o.trail / 100); var astep = f / o.lines; (function anim() { i++; for (var j = 0; j < o.lines; j++) { alpha = Math.max(1 - (i + (o.lines - j) * astep) % f * ostep, o.opacity); self.opacity(el, j * o.direction + start, alpha, o); } self.timeout = self.el && setTimeout(anim, ~~(1000 / fps)); })(); } return self; }, /** * Stops and removes the Spinner. */ stop: function() { var el = this.el; if (el) { clearTimeout(this.timeout); if (el.parentNode) { var reg = new RegExp('(\\s|^)fade(\\s|$)'); el.parentNode.className = el.parentNode.className.replace(reg, ' '); el.parentNode.removeChild(el); } this.el = undefined; } return this; }, /** * Internal method that draws the individual lines. Will be overwritten * in VML fallback mode below. */ lines: function(el, o) { var i = 0; var start = (o.lines - 1) * (1 - o.direction) / 2; var seg; function fill(color, shadow) { return css(createEl(), { position: 'absolute', width: o.scale * (o.length + o.width) + 'px', height: o.scale * o.width + 'px', background: color, boxShadow: shadow, transformOrigin: 'left', transform: 'rotate(' + ~~(360/o.lines*i + o.rotate) + 'deg) translate(' + o.scale*o.radius + 'px' + ',0)', borderRadius: (o.corners * o.scale * o.width >> 1) + 'px' }); } for (; i < o.lines; i++) { seg = css(createEl(), { position: 'absolute', top: 1 + ~(o.scale * o.width / 2) + 'px', transform: o.hwaccel ? 'translate3d(0,0,0)' : '', opacity: o.opacity, animation: useCssAnimations && addAnimation(o.opacity, o.trail, start + i * o.direction, o.lines) + ' ' + 1 / o.speed + 's linear infinite' }); if (o.shadow) ins(seg, css(fill('#000', '0 0 4px #000'), {top: '2px'})); ins(el, ins(seg, fill(getColor(o.color, i), '0 0 1px rgba(0,0,0,.1)'))); } return el; }, /** * Internal method that adjusts the opacity of a single line. * Will be overwritten in VML fallback mode below. */ opacity: function(el, i, val) { if (i < el.childNodes.length) el.childNodes[i].style.opacity = val; } }); function initVML() { /* Utility function to create a VML tag */ function vml(tag, attr) { return createEl('<' + tag + ' xmlns="urn:schemas-microsoft.com:vml" class="spin-vml">', attr); } // No CSS transforms but VML support, add a CSS rule for VML elements: sheet.addRule('.spin-vml', 'behavior:url(#default#VML)'); Spinner.prototype.lines = function(el, o) { var r = o.scale * (o.length + o.width); var s = o.scale * 2 * r; function grp() { return css( vml('group', { coordsize: s + ' ' + s, coordorigin: -r + ' ' + -r }), { width: s, height: s } ); } var margin = -(o.width + o.length) * o.scale * 2 + 'px'; var g = css(grp(), {position: 'absolute', top: margin, left: margin}); var i; function seg(i, dx, filter) { ins( g, ins( css(grp(), {rotation: 360 / o.lines * i + 'deg', left: ~~dx}), ins( css( vml('roundrect', {arcsize: o.corners}), { width: r, height: o.scale * o.width, left: o.scale * o.radius, top: -o.scale * o.width >> 1, filter: filter } ), vml('fill', {color: getColor(o.color, i), opacity: o.opacity}), vml('stroke', {opacity: 0}) // transparent stroke to fix color bleeding upon opacity change ) ) ); } if (o.shadow) for (i = 1; i <= o.lines; i++) { seg(i, -2, 'progid:DXImageTransform.Microsoft.Blur(pixelradius=2,makeshadow=1,shadowopacity=.3)'); } for (i = 1; i <= o.lines; i++) seg(i); return ins(el, g); }; Spinner.prototype.opacity = function(el, i, val, o) { var c = el.firstChild; o = o.shadow && o.lines || 0; if (c && i + o < c.childNodes.length) { c = c.childNodes[i + o]; c = c && c.firstChild; c = c && c.firstChild; if (c) c.opacity = val; } }; } if (typeof document !== 'undefined') { sheet = (function() { var el = createEl('style', {type : 'text/css'}); ins(document.getElementsByTagName('head')[0], el); return el.sheet || el.styleSheet; }()); var probe = css(createEl('group'), {behavior: 'url(#default#VML)'}); if (!vendor(probe, 'transform') && probe.adj) initVML(); else useCssAnimations = vendor(probe, 'animation'); } return Spinner; }));
原生的組件不帶有遮罩,只有轉菊花。為了加上遮罩我們還要寫一個小css,命名為spin.css:
.fade { position: fixed; top: 0; right: 0; bottom: 0; left: 0; z-index: 9999; opacity: 0.8; background-color: #CDCDCD; }
然后就是調用了,當然別忘了在調用界面引入上面兩個js和css文件。由於spin.js不需要jquery,而采用javascript原生的方式調用方法,所以有些特殊。為了更清楚地說明,下面將完整寫出一整個調用頁面的情況:
{% extends 'orig/my_base.html' %} {% load static %} {% block styles %} {{ block.super }} <link href="{% static 'spinjs/spin.css' %}" rel="stylesheet" /> {% endblock %} {% block front_scripts %} {{ block.super }} <script src="{% static 'spinjs/spin.js' %}"></script> <script src="{% static 'test.js' %}"></script> {% endblock %} {% block page_content %} <button type="button" class="btn btn-default" id="req">發起ajax請求</button> <!-- spin.js的遮罩需要手動在頁面上寫上一個div,如下 --> <div id="mask"></div> {% endblock %}
然后再來看下在test.js中是如何具體調用遮罩發生方法的:
$(document).ready(function(event){ // 點擊按鈕發起請求,同時帶起遮罩 $('#req').click(function(event){ event.preventDefault(); var spinner; // 進入ajax前聲明spinner變量以使得變量得以在ajax參數中傳遞 $.ajax({ url: '/test/spinload', type: 'get', dataType: 'json', data: {}, // 遮罩的啟用在beforeSend中進行 beforeSend: function(){ var target = $('#mask')[0]; // 注意,取的是[0],或者用js的document.getElementById('mask')也行 spinner = new Spinner({ lines: 12, length: 2, width: 5, radius: 10, shadow: true, opacity: 0.1 //更多的初始化參數可以參考spin.js里面的defaults }).spin(target); // 這里就算是顯示遮罩了 }, success: function(data){ console.log(data); }, complete: function(){ target.spin(); // 隱去遮罩 } }) }) })
3. fakeLoader
fakeLoader同樣需要bootstrap和jquery的支持。這個組件嚴格來說並不是一個遮罩,而是一個提升體驗的組件。比如在網頁還在加載中或者其他一些不太好看的時候,可以放出fakeLoader,但是fakeLoader只能顯示固定秒數,不能和上面那幾個插件一樣加入某個動作的鈎子。
引入方法很簡單,就是在有bootstrap和jquery的情況下把下載【https://github.com/joaopereirawd/fakeLoader.js/tree/master/demo】來的css和js分別引用進去即可。和上面的spinjs類似的,需要在頁面上<body>中添加一個<div>,然后用這個標識的div調用fakeLoader的一些方法即可。
調用時用:
$('#mask').fakeLoader({ timeToHide: 3000 // fakeLoader隱藏的秒數。由於無鈎子控制,需要合理設置不能太大也不能太小 spinner: 'spinner4' // 有7-8種spinner,不同的“菊花”樣式,可以網上查下哪個好看 });
正如上面所說,fakeLoader無法加入鈎子,這主要是因為他沒有留出(動作結束時)隱藏fakeLoader的接口。雖然我們可以通過這樣的方式來進行手動的隱藏:
$('#mask').fakeLoader({ timeToHide: 60000, // 設置一個很長的時間,保證動作完成前fakeLoader一直在 spinner: 'spinner4' }); // 一些動作過后 $('#mask').fakeLoader({ timeToHide: 1, // 隱藏fakeLoader spinner: 'spinner4' // 設置和出現的spinner一樣,否則可能會出現出入 })
雖然這樣可以實現一次,但是如果再來一次相同的動作的話可能會導致fakeLoader無法再次出現,也就是說一次性的。。有符合場景的情況的話不妨可以用用。