Your commit message

This commit is contained in:
Jane Doe
2024-06-05 05:10:50 +08:00
parent b182234fe6
commit 06dfa7cd9d
200 changed files with 131815 additions and 0 deletions

View File

@@ -0,0 +1,31 @@
/**
* 用于加载所有内置模块
* MIT Licensed
*/
layui.define(function(){
var mods = []
,builtin = layui.cache.builtin;
layui.each(builtin, function(modName){
(modName === 'all' || modName === 'layui.all') || mods.push(modName);
});
layui.cache.startTime = new Date().getTime();
return mods;
}(), function(exports){
"use strict";
var MOD_NAME = 'all'
//外部接口
,all = {
config: {}
,time: function(){
var time = new Date().getTime() - layui.cache.startTime;
delete layui.cache.startTime;
return time;
}()
};
exports(MOD_NAME, all);
});

View File

@@ -0,0 +1,339 @@
/**
* carousel 轮播模块
* MIT Licensed
*/
layui.define(['jquery', 'lay'], function(exports){
"use strict";
var $ = layui.$;
var lay = layui.lay;
var hint = layui.hint();
var device = layui.device();
//外部接口
var carousel = {
config: {} //全局配置项
//设置全局项
,set: function(options){
var that = this;
that.config = $.extend({}, that.config, options);
return that;
}
//事件
,on: function(events, callback){
return layui.onevent.call(this, MOD_NAME, events, callback);
}
}
//字符常量
,MOD_NAME = 'carousel', ELEM = '.layui-carousel', THIS = 'layui-this', SHOW = 'layui-show', HIDE = 'layui-hide', DISABLED = 'layui-disabled'
,ELEM_ITEM = '>*[carousel-item]>*', ELEM_LEFT = 'layui-carousel-left', ELEM_RIGHT = 'layui-carousel-right', ELEM_PREV = 'layui-carousel-prev', ELEM_NEXT = 'layui-carousel-next', ELEM_ARROW = 'layui-carousel-arrow', ELEM_IND = 'layui-carousel-ind'
//构造器
,Class = function(options){
var that = this;
that.config = $.extend({}, that.config, carousel.config, options);
that.render();
};
//默认配置
Class.prototype.config = {
width: '600px'
,height: '280px'
,full: false //是否全屏
,arrow: 'hover' //切换箭头默认显示状态hover/always/none
,indicator: 'inside' //指示器位置inside/outside/none
,autoplay: true //是否自动切换
,interval: 3000 //自动切换的时间间隔不能低于800ms
,anim: '' //动画类型default/updown/fade
,trigger: 'click' //指示器的触发方式click/hover
,index: 0 //初始开始的索引
};
//轮播渲染
Class.prototype.render = function(){
var that = this;
var options = that.config;
// 若 elem 非唯一,则拆分为多个实例
var elem = $(options.elem);
if(elem.length > 1){
layui.each(elem, function(){
carousel.render($.extend({}, options, {
elem: this
}));
});
return that;
}
// 合并 lay-options 属性上的配置信息
$.extend(options, lay.options(elem[0]));
options.elem = $(options.elem);
if(!options.elem[0]) return;
that.elemItem = options.elem.find(ELEM_ITEM);
if(options.index < 0) options.index = 0;
if(options.index >= that.elemItem.length) options.index = that.elemItem.length - 1;
if(options.interval < 800) options.interval = 800;
//是否全屏模式
if(options.full){
options.elem.css({
position: 'fixed'
,width: '100%'
,height: '100%'
,zIndex: 9999
});
} else {
options.elem.css({
width: options.width
,height: options.height
});
}
options.elem.attr('lay-anim', options.anim);
//初始焦点状态
that.elemItem.eq(options.index).addClass(THIS);
//指示器等动作
if(that.elemItem.length <= 1) return;
that.indicator();
that.arrow();
that.autoplay();
that.events();
};
//重置轮播
Class.prototype.reload = function(options){
var that = this;
clearInterval(that.timer);
that.config = $.extend({}, that.config, options);
that.render();
};
//获取上一个等待条目的索引
Class.prototype.prevIndex = function(){
var that = this
,options = that.config;
var prevIndex = options.index - 1;
if(prevIndex < 0){
prevIndex = that.elemItem.length - 1;
}
return prevIndex;
};
//获取下一个等待条目的索引
Class.prototype.nextIndex = function(){
var that = this
,options = that.config;
var nextIndex = options.index + 1;
if(nextIndex >= that.elemItem.length){
nextIndex = 0;
}
return nextIndex;
};
//索引递增
Class.prototype.addIndex = function(num){
var that = this
,options = that.config;
num = num || 1;
options.index = options.index + num;
//index不能超过轮播总数量
if(options.index >= that.elemItem.length){
options.index = 0;
}
};
//索引递减
Class.prototype.subIndex = function(num){
var that = this
,options = that.config;
num = num || 1;
options.index = options.index - num;
//index不能超过轮播总数量
if(options.index < 0){
options.index = that.elemItem.length - 1;
}
};
//自动轮播
Class.prototype.autoplay = function(){
var that = this
,options = that.config;
if(!options.autoplay) return;
clearInterval(that.timer);
that.timer = setInterval(function(){
that.slide();
}, options.interval);
};
//箭头
Class.prototype.arrow = function(){
var that = this
,options = that.config;
//模板
var tplArrow = $([
'<button class="layui-icon '+ ELEM_ARROW +'" lay-type="sub">'+ (options.anim === 'updown' ? '&#xe619;' : '&#xe603;') +'</button>'
,'<button class="layui-icon '+ ELEM_ARROW +'" lay-type="add">'+ (options.anim === 'updown' ? '&#xe61a;' : '&#xe602;') +'</button>'
].join(''));
//预设基础属性
options.elem.attr('lay-arrow', options.arrow);
//避免重复插入
if(options.elem.find('.'+ELEM_ARROW)[0]){
options.elem.find('.'+ELEM_ARROW).remove();
}
options.elem.append(tplArrow);
//事件
tplArrow.on('click', function(){
var othis = $(this)
,type = othis.attr('lay-type')
that.slide(type);
});
};
// 跳转到特定下标
Class.prototype.goto = function(index){
var that = this;
var options = that.config;
if(index > options.index){
that.slide('add', index - options.index);
} else if(index < options.index){
that.slide('sub', options.index - index);
}
}
//指示器
Class.prototype.indicator = function(){
var that = this
,options = that.config;
//模板
var tplInd = that.elemInd = $(['<div class="'+ ELEM_IND +'"><ul>'
,function(){
var li = [];
layui.each(that.elemItem, function(index){
li.push('<li'+ (options.index === index ? ' class="layui-this"' : '') +'></li>');
});
return li.join('');
}()
,'</ul></div>'].join(''));
//预设基础属性
options.elem.attr('lay-indicator', options.indicator);
//避免重复插入
if(options.elem.find('.'+ELEM_IND)[0]){
options.elem.find('.'+ELEM_IND).remove();
}
options.elem.append(tplInd);
if(options.anim === 'updown'){
tplInd.css('margin-top', -(tplInd.height()/2));
}
// 事件
tplInd.find('li').on(options.trigger === 'hover' ? 'mouseover' : options.trigger, function(){
that.goto($(this).index());
});
};
//滑动切换
Class.prototype.slide = function(type, num){
var that = this
,elemItem = that.elemItem
,options = that.config
,thisIndex = options.index
,filter = options.elem.attr('lay-filter');
if(that.haveSlide) return;
//滑动方向
if(type === 'sub'){
that.subIndex(num);
elemItem.eq(options.index).addClass(ELEM_PREV);
setTimeout(function(){
elemItem.eq(thisIndex).addClass(ELEM_RIGHT);
elemItem.eq(options.index).addClass(ELEM_RIGHT);
}, 50);
} else { //默认递增滑
that.addIndex(num);
elemItem.eq(options.index).addClass(ELEM_NEXT);
setTimeout(function(){
elemItem.eq(thisIndex).addClass(ELEM_LEFT);
elemItem.eq(options.index).addClass(ELEM_LEFT);
}, 50);
}
//移除过度类
setTimeout(function(){
elemItem.removeClass(THIS + ' ' + ELEM_PREV + ' ' + ELEM_NEXT + ' ' + ELEM_LEFT + ' ' + ELEM_RIGHT);
elemItem.eq(options.index).addClass(THIS);
that.haveSlide = false; //解锁
}, 300);
//指示器焦点
that.elemInd.find('li').eq(options.index).addClass(THIS)
.siblings().removeClass(THIS);
that.haveSlide = true;
// 回调返回的参数
var params = {
index: options.index
,prevIndex: thisIndex
,item: elemItem.eq(options.index)
};
typeof options.change === 'function' && options.change(params);
layui.event.call(this, MOD_NAME, 'change('+ filter +')', params);
};
//事件处理
Class.prototype.events = function(){
var that = this
,options = that.config;
if(options.elem.data('haveEvents')) return;
//移入移出容器
options.elem.on('mouseenter', function(){
if (that.config.autoplay === 'always') return;
clearInterval(that.timer);
}).on('mouseleave', function(){
if (that.config.autoplay === 'always') return;
that.autoplay();
});
options.elem.data('haveEvents', true);
};
//核心入口
carousel.render = function(options){
return new Class(options);
};
exports(MOD_NAME, carousel);
});

View File

@@ -0,0 +1,302 @@
/**
* code
* Code 预览组件
*/
layui.define(['lay', 'util', 'element', 'form'], function(exports){
"use strict";
var $ = layui.$;
var util = layui.util;
var element = layui.element;
var form = layui.form;
// 常量
var CONST = {
ELEM_VIEW: 'layui-code-view',
ELEM_TAB: 'layui-tab',
ELEM_TITLE: 'layui-code-title',
ELEM_FULL: 'layui-code-full',
ELEM_PREVIEW: 'layui-code-preview',
ELEM_ITEM: 'layui-code-item',
ELEM_SHOW: 'layui-show'
};
// 默认参数项
var config = {
elem: '.layui-code', // 元素选择器
title: '&lt;/&gt;', // 代码栏标题
about: '', // 代码栏右上角信息
ln: true, // 代码区域是否显示行号
header: false, // 是否显示代码栏头部区域
// 默认文本
text: {
code: util.escape('</>'),
preview: 'Preview'
}
};
var trim = function(str){
return $.trim(str).replace(/^\n|\n$/, '');
};
// export api
exports('code', function(options){
var opts = options = $.extend(true, {}, config, options);
// 目标元素是否存在
options.elem = $(options.elem);
if(!options.elem[0]) return;
// 从内至外渲染
layui.each(options.elem.get().reverse(), function(index, item){
var othis = $(item);
// 合并属性上的参数,并兼容旧版本属性写法 lay-*
var options = $.extend(true, {}, opts, lay.options(item), function(obj){
var attrs = ['title', 'height', 'encode', 'skin', 'about'];
layui.each(attrs, function(i, attr){
var value = othis.attr('lay-'+ attr);
if(typeof value === 'string'){
obj[attr] = value;
}
})
return obj;
}({}));
// 获得代码
var codes = othis.data('code') || function(){
var arr = [];
var textarea = othis.children('textarea');
// 若内容放置在 textarea 中
textarea.each(function(){
arr.push(trim(this.value));
});
// 内容直接放置在元素外层
if(arr.length === 0){
arr.push(trim(othis.html()));
}
return arr;
}();
othis.data('code', codes);
// 是否开启预览
if(options.preview){
var FILTER_VALUE = 'LAY-CODE-DF-'+ index;
var layout = options.layout || ['code', 'preview'];
var isIframePreview = options.preview === 'iframe';
// 追加 Tab 组件
var elemView = $('<div class="'+ CONST.ELEM_PREVIEW +'">');
var elemTabView = $('<div class="layui-tab layui-tab-brief">');
var elemHeaderView = $('<div class="layui-tab-title">');
var elemPreviewView = $('<div class="'+ [
CONST.ELEM_ITEM,
CONST.ELEM_ITEM +'-preview',
'layui-border'
].join(' ') +'">');
var elemToolbar = $('<div class="layui-code-tools"></div>');
var elemViewHas = othis.parent('.' + CONST.ELEM_PREVIEW);
var elemTabHas = othis.prev('.'+ CONST.ELEM_TAB);
var elemPreviewViewHas = othis.next('.' + CONST.ELEM_ITEM +'-preview');
if(options.id) elemView.attr('id', options.id);
elemView.addClass(options.className);
elemTabView.attr('lay-filter', FILTER_VALUE);
// 标签头
layui.each(layout, function(i, v){
var li = $('<li lay-id="'+ v +'">');
if(i === 0) li.addClass('layui-this');
li.html(options.text[v]);
elemHeaderView.append(li);
});
// 工具栏
var tools = {
'full': {
className: 'screen-full',
title: ['最大化显示', '还原显示'],
event: function(el, type){
var elemView = el.closest('.'+ CONST.ELEM_PREVIEW);
var classNameFull = 'layui-icon-'+ this.className;
var classNameRestore = 'layui-icon-screen-restore';
var title = this.title;
var html = $('html,body');
var ELEM_SCOLLBAR_HIDE = 'layui-scollbar-hide';
if(el.hasClass(classNameFull)){
elemView.addClass(CONST.ELEM_FULL);
el.removeClass(classNameFull).addClass(classNameRestore);
el.attr('title', title[1]);
html.addClass(ELEM_SCOLLBAR_HIDE);
} else {
elemView.removeClass(CONST.ELEM_FULL);
el.removeClass(classNameRestore).addClass(classNameFull);
el.attr('title', title[0]);
html.removeClass(ELEM_SCOLLBAR_HIDE);
}
}
},
'window': {
className: 'release',
title: ['在新窗口预览'],
event: function(el, type){
util.openWin({
content: codes.join('')
});
}
}
};
elemToolbar.on('click', '>i', function(){ // 工具栏事件
var oi = $(this);
var type = oi.data('type');
typeof tools[type].event === 'function' && tools[type].event(oi, type);
typeof options.toolsEvent === 'function' && options.toolsEvent(oi, type);
});
layui.each(options.tools, function(i, v){
var className = (tools[v] && tools[v].className) || v;
var title = tools[v].title || [''];
elemToolbar.append(
'<i class="layui-icon layui-icon-'+ className +'" data-type="'+ v +'" title="'+ title[0] +'"></i>'
);
});
// 移除旧结构
if(elemTabHas[0]) elemTabHas.remove(); // 移除 tab
if(elemPreviewViewHas[0]) elemPreviewViewHas.remove(); // 移除预览区域
if(elemViewHas[0]) othis.unwrap(); // 移除外层容器
elemTabView.append(elemHeaderView); // 追加标签头
options.tools && elemTabView.append(elemToolbar); // 追加工具栏
othis.wrap(elemView).addClass(CONST.ELEM_ITEM).before(elemTabView); // 追加标签结构
// 追加预览
if(isIframePreview){
elemPreviewView.html('<iframe></iframe>');
}
// 执行预览
var run = function(thisItemBody){
var iframe = thisItemBody.children('iframe')[0];
if(isIframePreview && iframe){
iframe.srcdoc = codes.join('');
} else {
thisItemBody.html(codes.join(''));
}
// 回调的返回参数
var params = {
container: thisItemBody,
render: function(){
form.render(thisItemBody.find('.layui-form'));
element.render();
}
};
// 当前实例预览完毕后的回调
setTimeout(function(){
typeof options.done === 'function' && options.done(params);
},3);
};
if(layout[0] === 'preview'){
elemPreviewView.addClass(CONST.ELEM_SHOW);
othis.before(elemPreviewView);
run(elemPreviewView);
} else {
othis.addClass(CONST.ELEM_SHOW).after(elemPreviewView);
}
// 内容项初始化样式
options.codeStyle = [options.style, options.codeStyle].join('');
options.previewStyle = [options.style, options.previewStyle].join('');
// othis.attr('style', options.codeStyle);
elemPreviewView.attr('style', options.previewStyle);
// tab change
element.on('tab('+ FILTER_VALUE +')', function(data){
var $this = $(this);
var thisElem = $(data.elem).closest('.'+ CONST.ELEM_PREVIEW);
var elemItemBody = thisElem.find('.'+ CONST.ELEM_ITEM);
var thisItemBody = elemItemBody.eq(data.index);
elemItemBody.removeClass(CONST.ELEM_SHOW);
thisItemBody.addClass(CONST.ELEM_SHOW);
if($this.attr('lay-id') === 'preview'){
run(thisItemBody);
}
});
}
// 有序或无序列表
var listTag = options.ln ? 'ol' : 'ul';
var listElem = $('<'+ listTag +' class="layui-code-'+ listTag +'">');
// header
var headerElem = $('<div class="'+ CONST.ELEM_TITLE +'">');
// 添加组件 clasName
othis.addClass('layui-code-view layui-box');
// 自定义风格
if(options.skin){
if(options.skin === 'notepad') options.skin = 'dark';
othis.removeClass('layui-code-dark layui-code-light');
othis.addClass('layui-code-'+ options.skin);
}
// code
var html = util.escape(codes.join(''));
// 转义 HTML 标签
if(options.encode) html = util.escape(html);
html = html.replace(/[\r\t\n]+/g, '</li><li>'); // 转义换行符
// 生成列表
othis.html(listElem.html('<li>' + html + '</li>'));
// 创建 header
if(options.header && !othis.children('.'+ CONST.ELEM_TITLE)[0]){
headerElem.html(options.title + (
options.about
? '<div class="layui-code-about">' + options.about + '</div>'
: ''
));
othis.prepend(headerElem);
}
// 所有实例渲染完毕后的回调
if(options.elem.length === index + 1){
typeof options.allDone === 'function' && options.allDone();
}
// 按行数适配左边距
(function(autoIncNums){
if(autoIncNums > 0){
listElem.css('margin-left', autoIncNums + 'px');
}
})(Math.floor(listElem.find('li').length/100));
// 限制 Code 最大高度
if(options.height){ // 兼容旧版本
listElem.css('max-height', options.height);
}
// Code 内容区域样式
listElem.attr('style', options.codeStyle);
});
});
});
// 若为源码版,则自动加载该组件依赖的 css 文件
if(!layui['layui.all']){
layui.addcss('modules/code.css?v=3', 'skincodecss');
}

View File

@@ -0,0 +1,749 @@
/**
* colorpicker
* 颜色选择组件
*/
layui.define(['jquery', 'lay'], function(exports){
"use strict";
var $ = layui.$;
var lay = layui.lay;
var hint = layui.hint();
var device = layui.device();
var clickOrMousedown = (device.mobile ? 'click' : 'mousedown');
//外部接口
var colorpicker = {
config: {}
,index: layui.colorpicker ? (layui.colorpicker.index + 10000) : 0
//设置全局项
,set: function(options){
var that = this;
that.config = $.extend({}, that.config, options);
return that;
}
//事件
,on: function(events, callback){
return layui.onevent.call(this, 'colorpicker', events, callback);
}
};
// 操作当前实例
var thisModule = function(){
var that = this;
var options = that.config;
var id = options.id;
thisModule.that[id] = that; // 记录当前实例对象
return {
config: options
};
}
//字符常量
,MOD_NAME = 'colorpicker', SHOW = 'layui-show', THIS = 'layui-this', ELEM = 'layui-colorpicker'
,ELEM_MAIN = '.layui-colorpicker-main', ICON_PICKER_DOWN = 'layui-icon-down', ICON_PICKER_CLOSE = 'layui-icon-close'
,PICKER_TRIG_SPAN = 'layui-colorpicker-trigger-span', PICKER_TRIG_I = 'layui-colorpicker-trigger-i', PICKER_SIDE = 'layui-colorpicker-side', PICKER_SIDE_SLIDER = 'layui-colorpicker-side-slider'
,PICKER_BASIS = 'layui-colorpicker-basis', PICKER_ALPHA_BG = 'layui-colorpicker-alpha-bgcolor', PICKER_ALPHA_SLIDER = 'layui-colorpicker-alpha-slider', PICKER_BASIS_CUR = 'layui-colorpicker-basis-cursor', PICKER_INPUT = 'layui-colorpicker-main-input'
//RGB转HSB
,RGBToHSB = function(rgb){
var hsb = {h:0, s:0, b:0};
var min = Math.min(rgb.r, rgb.g, rgb.b);
var max = Math.max(rgb.r, rgb.g, rgb.b);
var delta = max - min;
hsb.b = max;
hsb.s = max !== 0 ? 255*delta/max : 0;
if(hsb.s !== 0){
if(rgb.r == max){ // 因 rgb 中返回的数字为 string 类型
hsb.h = (rgb.g - rgb.b) / delta;
}else if(rgb.g == max){
hsb.h = 2 + (rgb.b - rgb.r) / delta;
}else{
hsb.h = 4 + (rgb.r - rgb.g) / delta;
}
}else{
hsb.h = -1;
}
if(max === min){
hsb.h = 0;
}
hsb.h *= 60;
if(hsb.h < 0) {
hsb.h += 360;
}
hsb.s *= 100/255;
hsb.b *= 100/255;
return hsb;
}
//HEX转HSB
,HEXToHSB = function(hex){
hex = hex.indexOf('#') > -1 ? hex.substring(1) : hex;
if(hex.length === 3){
var num = hex.split("");
hex = num[0]+num[0]+num[1]+num[1]+num[2]+num[2]
}
hex = parseInt(hex, 16);
var rgb = {r:hex >> 16, g:(hex & 0x00FF00) >> 8, b:(hex & 0x0000FF)};
return RGBToHSB(rgb);
}
//HSB转RGB
,HSBToRGB = function(hsb){
var rgb = {};
var h = hsb.h;
var s = hsb.s*255/100;
var b = hsb.b*255/100;
if(s === 0){
rgb.r = rgb.g = rgb.b = b;
}else{
var t1 = b;
var t2 = (255 - s) * b /255;
var t3 = (t1 - t2) * (h % 60) /60;
if(h === 360) h = 0;
if(h < 60) {rgb.r=t1; rgb.b=t2; rgb.g=t2+t3}
else if(h < 120) {rgb.g=t1; rgb.b=t2; rgb.r=t1-t3}
else if(h < 180) {rgb.g=t1; rgb.r=t2; rgb.b=t2+t3}
else if(h < 240) {rgb.b=t1; rgb.r=t2; rgb.g=t1-t3}
else if(h < 300) {rgb.b=t1; rgb.g=t2; rgb.r=t2+t3}
else if(h < 360) {rgb.r=t1; rgb.g=t2; rgb.b=t1-t3}
else {rgb.r=0; rgb.g=0; rgb.b=0}
}
return {r:Math.round(rgb.r), g:Math.round(rgb.g), b:Math.round(rgb.b)};
}
//HSB转HEX
,HSBToHEX = function(hsb){
var rgb = HSBToRGB(hsb);
var hex = [
rgb.r.toString(16)
,rgb.g.toString(16)
,rgb.b.toString(16)
];
$.each(hex, function(nr, val){
if(val.length === 1){
hex[nr] = '0' + val;
}
});
return hex.join('');
}
//转化成所需rgb格式
,RGBSTo = function(rgbs){
var regexp = /[0-9]{1,3}/g;
var re = rgbs.match(regexp) || [];
return {r:re[0], g:re[1], b:re[2]};
}
,$win = $(window)
,$doc = $(document)
//构造器
,Class = function(options){
var that = this;
that.index = ++colorpicker.index;
that.config = $.extend({}, that.config, colorpicker.config, options);
that.render();
};
//默认配置
Class.prototype.config = {
color: '' //默认颜色,默认没有
,size: null //选择器大小
,alpha: false //是否开启透明度
,format: 'hex' //颜色显示/输入格式,可选 rgb,hex
,predefine: false //预定义颜色是否开启
,colors: [ //默认预定义颜色列表
'#16baaa', '#16b777', '#1E9FFF', '#FF5722', '#FFB800', '#01AAED', '#999', '#c00', '#ff8c00','#ffd700'
,'#90ee90', '#00ced1', '#1e90ff', '#c71585', 'rgb(0, 186, 189)', 'rgb(255, 120, 0)', 'rgb(250, 212, 0)', '#393D49', 'rgba(0,0,0,.5)', 'rgba(255, 69, 0, 0.68)', 'rgba(144, 240, 144, 0.5)', 'rgba(31, 147, 255, 0.73)'
]
};
//初始颜色选择框
Class.prototype.render = function(){
var that = this;
var options = that.config;
// 若 elem 非唯一,则拆分为多个实例
var elem = $(options.elem);
if(elem.length > 1){
layui.each(elem, function(){
colorpicker.render($.extend({}, options, {
elem: this
}));
});
return that;
}
// 合并 lay-options 属性上的配置信息
$.extend(options, lay.options(elem[0]));
//颜色选择框对象
var elemColorBox = $(['<div class="layui-unselect layui-colorpicker">'
,'<span '+ (options.format == 'rgb' && options.alpha
? 'class="layui-colorpicker-trigger-bgcolor"'
: '') +'>'
,'<span class="layui-colorpicker-trigger-span" '
,'lay-type="'+ (options.format == 'rgb' ? (options.alpha ? 'rgba' : 'torgb') : '') +'" '
,'style="'+ function(){
var bgstr = '';
if(options.color){
bgstr = options.color;
if((options.color.match(/[0-9]{1,3}/g) || []).length > 3){ //需要优化
if(!(options.alpha && options.format == 'rgb')){
bgstr = '#' + HSBToHEX(RGBToHSB(RGBSTo(options.color)))
}
}
return 'background: '+ bgstr;
}
return bgstr;
}() +'">'
,'<i class="layui-icon layui-colorpicker-trigger-i '+ (options.color
? ICON_PICKER_DOWN
: ICON_PICKER_CLOSE) +'"></i>'
,'</span>'
,'</span>'
,'</div>'].join(''))
//初始化颜色选择框
var elem = options.elem = $(options.elem);
options.size && elemColorBox.addClass('layui-colorpicker-'+ options.size); //初始化颜色选择框尺寸
// 插入颜色选择框
elem.addClass('layui-inline').html(
that.elemColorBox = elemColorBox
);
// 初始化 id 属性 - 优先取 options > 元素 id > 自增索引
options.id = 'id' in options ? options.id : (
elem.attr('id') || that.index
);
// 获取背景色值
that.color = that.elemColorBox.find('.'+ PICKER_TRIG_SPAN)[0].style.background;
// 相关事件
that.events();
};
//渲染颜色选择器
Class.prototype.renderPicker = function(){
var that = this
,options = that.config
,elemColorBox = that.elemColorBox[0]
//颜色选择器对象
,elemPicker = that.elemPicker = $(['<div id="layui-colorpicker'+ that.index +'" data-index="'+ that.index +'" class="layui-anim layui-anim-downbit layui-colorpicker-main">'
//颜色面板
,'<div class="layui-colorpicker-main-wrapper">'
,'<div class="layui-colorpicker-basis">'
,'<div class="layui-colorpicker-basis-white"></div>'
,'<div class="layui-colorpicker-basis-black"></div>'
,'<div class="layui-colorpicker-basis-cursor"></div>'
,'</div>'
,'<div class="layui-colorpicker-side">'
,'<div class="layui-colorpicker-side-slider"></div>'
,'</div>'
,'</div>'
//透明度条块
,'<div class="layui-colorpicker-main-alpha '+ (options.alpha ? SHOW : '') +'">'
,'<div class="layui-colorpicker-alpha-bgcolor">'
,'<div class="layui-colorpicker-alpha-slider"></div>'
,'</div>'
,'</div>'
//预设颜色列表
,function(){
if(options.predefine){
var list = ['<div class="layui-colorpicker-main-pre">'];
layui.each(options.colors, function(i, v){
list.push(['<div class="layui-colorpicker-pre'+ ((v.match(/[0-9]{1,3}/g) || []).length > 3
? ' layui-colorpicker-pre-isalpha'
: '') +'">'
,'<div style="background:'+ v +'"></div>'
,'</div>'].join(''));
});
list.push('</div>');
return list.join('');
} else {
return '';
}
}()
//底部表单元素区域
,'<div class="layui-colorpicker-main-input">'
,'<div class="layui-inline">'
,'<input type="text" class="layui-input">'
,'</div>'
,'<div class="layui-btn-container">'
,'<button class="layui-btn layui-btn-primary layui-btn-sm" colorpicker-events="clear">清空</button>'
,'<button class="layui-btn layui-btn-sm" colorpicker-events="confirm">确定</button>'
,'</div'
,'</div>'
,'</div>'].join(''))
,elemColorBoxSpan = that.elemColorBox.find('.' + PICKER_TRIG_SPAN)[0];
//如果当前点击的颜色盒子已经存在选择器,则关闭
if($(ELEM_MAIN)[0] && $(ELEM_MAIN).data('index') == that.index){
that.removePicker(Class.thisElemInd);
} else { //插入颜色选择器
that.removePicker(Class.thisElemInd);
$('body').append(elemPicker);
}
// 记录当前执行的实例索引
colorpicker.thisId = options.id;
Class.thisElemInd = that.index; //记录最新打开的选择器索引
Class.thisColor = elemColorBox.style.background //记录最新打开的选择器颜色选中值
that.position();
that.pickerEvents();
};
//颜色选择器移除
Class.prototype.removePicker = function(index){
var that = this;
var options = that.config;
var elem = $('#layui-colorpicker'+ (index || that.index));
if(elem[0]){
elem.remove();
delete colorpicker.thisId;
// 面板关闭后的回调
typeof options.close === 'function' && options.close(that.color);
}
return that;
};
//定位算法
Class.prototype.position = function(){
var that = this
,options = that.config;
lay.position(that.bindElem || that.elemColorBox[0], that.elemPicker[0], {
position: options.position
,align: 'center'
});
return that;
};
//颜色选择器赋值
Class.prototype.val = function(){
var that = this
,options = that.config
,elemColorBox = that.elemColorBox.find('.' + PICKER_TRIG_SPAN)
,elemPickerInput = that.elemPicker.find('.' + PICKER_INPUT)
,e = elemColorBox[0]
,bgcolor = e.style.backgroundColor;
//判断是否有背景颜色
if(bgcolor){
//转化成hsb格式
var hsb = RGBToHSB(RGBSTo(bgcolor))
,type = elemColorBox.attr('lay-type');
//同步滑块的位置及颜色选择器的选择
that.select(hsb.h, hsb.s, hsb.b);
//如果格式要求为rgb
if(type === 'torgb'){
elemPickerInput.find('input').val(bgcolor);
}
//如果格式要求为rgba
if(type === 'rgba'){
var rgb = RGBSTo(bgcolor);
//如果开启透明度而没有设置,则给默认值
if((bgcolor.match(/[0-9]{1,3}/g) || []).length === 3){
elemPickerInput.find('input').val('rgba('+ rgb.r +', '+ rgb.g +', '+ rgb.b +', 1)');
that.elemPicker.find('.'+ PICKER_ALPHA_SLIDER).css("left", 280);
} else {
elemPickerInput.find('input').val(bgcolor);
var left = bgcolor.slice(bgcolor.lastIndexOf(",") + 1, bgcolor.length - 1) * 280;
that.elemPicker.find('.'+ PICKER_ALPHA_SLIDER).css("left", left);
}
//设置span背景色
that.elemPicker.find('.'+ PICKER_ALPHA_BG)[0].style.background = 'linear-gradient(to right, rgba('+ rgb.r +', '+ rgb.g +', '+ rgb.b +', 0), rgb('+ rgb.r +', '+ rgb.g +', '+ rgb.b +'))';
}
}else{
//如果没有背景颜色则默认到最初始的状态
that.select(0,100,100);
elemPickerInput.find('input').val("");
that.elemPicker.find('.'+ PICKER_ALPHA_BG)[0].style.background = '';
that.elemPicker.find('.'+ PICKER_ALPHA_SLIDER).css("left", 280);
}
};
//颜色选择器滑动 / 点击
Class.prototype.side = function(){
var that = this
,options = that.config
,span = that.elemColorBox.find('.' + PICKER_TRIG_SPAN)
,type = span.attr('lay-type')
,side = that.elemPicker.find('.' + PICKER_SIDE)
,slider = that.elemPicker.find('.' + PICKER_SIDE_SLIDER)
,basis = that.elemPicker.find('.' + PICKER_BASIS)
,choose = that.elemPicker.find('.' + PICKER_BASIS_CUR)
,alphacolor = that.elemPicker.find('.' + PICKER_ALPHA_BG)
,alphaslider = that.elemPicker.find('.' + PICKER_ALPHA_SLIDER)
,_h = slider[0].offsetTop/180*360
,_b = 100 - (choose[0].offsetTop + 3)/180*100
,_s = (choose[0].offsetLeft + 3)/260*100
,_a = Math.round(alphaslider[0].offsetLeft/280*100)/100
,i = that.elemColorBox.find('.' + PICKER_TRIG_I)
,pre = that.elemPicker.find('.layui-colorpicker-pre').children('div')
,change = function(x,y,z,a){
that.select(x, y, z);
var rgb = HSBToRGB({h:x, s:y, b:z});
var color = HSBToHEX({h:x, s:y, b:z});
var elemInput = that.elemPicker.find('.' + PICKER_INPUT).find('input');
i.addClass(ICON_PICKER_DOWN).removeClass(ICON_PICKER_CLOSE);
span[0].style.background = 'rgb('+ rgb.r +', '+ rgb.g +', '+ rgb.b +')';
if(type === 'torgb'){
elemInput.val('rgb('+ rgb.r +', '+ rgb.g +', '+ rgb.b +')');
} else if(type === 'rgba'){
var left = a * 280;
alphaslider.css("left", left);
elemInput.val('rgba('+ rgb.r +', '+ rgb.g +', '+ rgb.b +', '+ a +')');
span[0].style.background = 'rgba('+ rgb.r +', '+ rgb.g +', '+ rgb.b +', '+ a +')';
alphacolor[0].style.background = 'linear-gradient(to right, rgba('+ rgb.r +', '+ rgb.g +', '+ rgb.b +', 0), rgb('+ rgb.r +', '+ rgb.g +', '+ rgb.b +'))'
} else {
elemInput.val('#'+ color);
}
//回调更改的颜色
options.change && options.change(that.elemPicker.find('.' + PICKER_INPUT).find('input').val());
}
//拖拽元素
,elemMove = $(['<div class="layui-auxiliar-moving" id="LAY-colorpicker-moving"></div>'].join(''))
,createMoveElem = function(call){
$('#LAY-colorpicker-moving')[0] || $('body').append(elemMove);
elemMove.on('mousemove', call);
elemMove.on('mouseup', function(){
elemMove.remove();
}).on('mouseleave', function(){
elemMove.remove();
});
};
//右侧主色选择
slider.on('mousedown', function(e){
var oldtop = this.offsetTop
,oldy = e.clientY;
var move = function(e){
var top = oldtop + (e.clientY - oldy)
,maxh = side[0].offsetHeight;
if(top < 0)top = 0;
if(top > maxh)top = maxh;
var h = top/180*360;
_h = h;
change(h, _s, _b, _a);
e.preventDefault();
};
createMoveElem(move);
//layui.stope(e);
e.preventDefault();
});
side.on('click', function(e){
var top = e.clientY - $(this).offset().top;
if(top < 0)top = 0;
if(top > this.offsetHeight)top = this.offsetHeight;
var h = top/180*360;
_h = h;
change(h, _s, _b, _a);
e.preventDefault();
});
//中间小圆点颜色选择
choose.on('mousedown', function(e){
var oldtop = this.offsetTop
,oldleft = this.offsetLeft
,oldy = e.clientY
,oldx = e.clientX;
var move = function(e){
var top = oldtop + (e.clientY - oldy)
,left = oldleft + (e.clientX - oldx)
,maxh = basis[0].offsetHeight - 3
,maxw = basis[0].offsetWidth - 3;
if(top < -3)top = -3;
if(top > maxh)top = maxh;
if(left < -3)left = -3;
if(left > maxw)left = maxw;
var s = (left + 3)/260*100
,b = 100 - (top + 3)/180*100;
_b = b;
_s = s;
change(_h, s, b, _a);
e.preventDefault();
};
layui.stope(e);
createMoveElem(move);
e.preventDefault();
});
basis.on('mousedown', function(e){
var top = e.clientY - $(this).offset().top - 3 + $win.scrollTop()
,left = e.clientX - $(this).offset().left - 3 + $win.scrollLeft()
if(top < -3)top = -3;
if(top > this.offsetHeight - 3)top = this.offsetHeight - 3;
if(left < -3)left = -3;
if(left > this.offsetWidth - 3)left = this.offsetWidth - 3;
var s = (left + 3)/260*100
,b = 100 - (top + 3)/180*100;
_b = b;
_s = s;
change(_h, s, b, _a);
layui.stope(e);
e.preventDefault();
choose.trigger(e, 'mousedown');
});
//底部透明度选择
alphaslider.on('mousedown', function(e){
var oldleft = this.offsetLeft
,oldx = e.clientX;
var move = function(e){
var left = oldleft + (e.clientX - oldx)
,maxw = alphacolor[0].offsetWidth;
if(left < 0)left = 0;
if(left > maxw)left = maxw;
var a = Math.round(left /280*100) /100;
_a = a;
change(_h, _s, _b, a);
e.preventDefault();
};
createMoveElem(move);
e.preventDefault();
});
alphacolor.on('click', function(e){
var left = e.clientX - $(this).offset().left
if(left < 0)left = 0;
if(left > this.offsetWidth)left = this.offsetWidth;
var a = Math.round(left /280*100) /100;
_a = a;
change(_h, _s, _b, a);
e.preventDefault();
});
//预定义颜色选择
pre.each(function(){
$(this).on('click', function(){
$(this).parent('.layui-colorpicker-pre').addClass('selected').siblings().removeClass('selected');
var color = this.style.backgroundColor
,hsb = RGBToHSB(RGBSTo(color))
,a = color.slice(color.lastIndexOf(",") + 1, color.length - 1),left;
_h = hsb.h;
_s = hsb.s;
_b = hsb.b;
if((color.match(/[0-9]{1,3}/g) || []).length === 3) a = 1;
_a = a;
left = a * 280;
change(hsb.h, hsb.s, hsb.b, a);
})
});
};
//颜色选择器hsb转换
Class.prototype.select = function(h, s, b, type){
var that = this;
var options = that.config;
var hex = HSBToHEX({h:h, s:100, b:100});
var color = HSBToHEX({h:h, s:s, b:b});
var sidetop = h/360*180;
var top = 180 - b/100*180 - 3;
var left = s/100*260 - 3;
that.elemPicker.find('.' + PICKER_SIDE_SLIDER).css("top", sidetop); //滑块的top
that.elemPicker.find('.' + PICKER_BASIS)[0].style.background = '#' + hex; //颜色选择器的背景
//选择器的top left
that.elemPicker.find('.' + PICKER_BASIS_CUR).css({
"top": top
,"left": left
});
// if(type === 'change') return;
// 选中的颜色
// that.elemPicker.find('.' + PICKER_INPUT).find('input').val('#'+ color);
};
Class.prototype.pickerEvents = function(){
var that = this
,options = that.config
,elemColorBoxSpan = that.elemColorBox.find('.' + PICKER_TRIG_SPAN) //颜色盒子
,elemPickerInput = that.elemPicker.find('.' + PICKER_INPUT + ' input') //颜色选择器表单
,pickerEvents = {
//清空
clear: function(othis){
elemColorBoxSpan[0].style.background ='';
that.elemColorBox.find('.' + PICKER_TRIG_I).removeClass(ICON_PICKER_DOWN).addClass(ICON_PICKER_CLOSE);
that.color = '';
options.done && options.done('');
that.removePicker();
}
//确认
,confirm: function(othis, change){
var value = elemPickerInput.val()
,colorValue
,hsb;
if(value.indexOf(',') > -1){
hsb = RGBToHSB(RGBSTo(value));
that.select(hsb.h, hsb.s, hsb.b);
elemColorBoxSpan[0].style.background = (colorValue = '#' + HSBToHEX(hsb));
if((value.match(/[0-9]{1,3}/g) || []).length > 3 && elemColorBoxSpan.attr('lay-type') === 'rgba'){
var left = value.slice(value.lastIndexOf(",") + 1, value.length - 1) * 280;
that.elemPicker.find('.' + PICKER_ALPHA_SLIDER).css("left", left);
elemColorBoxSpan[0].style.background = value;
colorValue = value;
}
} else {
hsb = HEXToHSB(value);
elemColorBoxSpan[0].style.background = (colorValue = '#' + HSBToHEX(hsb));
that.elemColorBox.find('.' + PICKER_TRIG_I).removeClass(ICON_PICKER_CLOSE).addClass(ICON_PICKER_DOWN);
}
if(change === 'change'){
that.select(hsb.h, hsb.s, hsb.b, change);
options.change && options.change(colorValue);
return;
}
that.color = value;
options.done && options.done(value);
that.removePicker();
}
};
//选择器面板点击事件
that.elemPicker.on('click', '*[colorpicker-events]', function(){
var othis = $(this)
,attrEvent = othis.attr('colorpicker-events');
pickerEvents[attrEvent] && pickerEvents[attrEvent].call(this, othis);
});
//输入框事件
elemPickerInput.on('keyup', function(e){
var othis = $(this);
pickerEvents.confirm.call(this, othis, e.keyCode === 13 ? null : 'change');
});
}
// 颜色选择器输入
Class.prototype.events = function(){
var that = this;
var options = that.config;
// 弹出颜色选择器
that.elemColorBox.on('click' , function(){
that.renderPicker();
if($(ELEM_MAIN)[0]){
that.val();
that.side();
}
});
};
//全局事件
(function(){
//绑定关闭控件事件
$doc.on(clickOrMousedown, function(e){
if(!colorpicker.thisId) return;
var that = thisModule.getThis(colorpicker.thisId);
if(!that) return;
var options = that.config;
var elemColorBoxSpan = that.elemColorBox.find('.' + PICKER_TRIG_SPAN);
//如果点击的元素是颜色框
if($(e.target).hasClass(ELEM)
|| $(e.target).parents('.'+ELEM)[0]
) return;
//如果点击的元素是选择器
if($(e.target).hasClass(ELEM_MAIN.replace(/\./g, ''))
|| $(e.target).parents(ELEM_MAIN)[0]
) return;
if(!that.elemPicker) return;
if(that.color){
var hsb = RGBToHSB(RGBSTo(that.color));
that.select(hsb.h, hsb.s, hsb.b);
} else {
that.elemColorBox.find('.' + PICKER_TRIG_I).removeClass(ICON_PICKER_DOWN).addClass(ICON_PICKER_CLOSE);
}
elemColorBoxSpan[0].style.background = that.color || '';
// 取消选择的回调
typeof options.cancel === 'function' && options.cancel(that.color);
// 移除面板
that.removePicker();
});
//自适应定位
$win.on('resize', function(){
if(!colorpicker.thisId) return;
var that = thisModule.getThis(colorpicker.thisId);
if(!that) return;
if(!that.elemPicker || !$(ELEM_MAIN)[0]){
return false;
}
that.position();
});
})();
// 记录所有实例
thisModule.that = {}; // 记录所有实例对象
// 获取当前实例对象
thisModule.getThis = function(id){
var that = thisModule.that[id];
if(!that) hint.error(id ? (MOD_NAME +' instance with ID \''+ id +'\' not found') : 'ID argument required');
return that;
};
//核心入口
colorpicker.render = function(options){
var inst = new Class(options);
return thisModule.call(inst);
};
exports(MOD_NAME, colorpicker);
});

View File

@@ -0,0 +1,134 @@
/**
* MODULE_DEMO_NAME 模块组件通用结构
* MIT Licensed
*/
layui.define([''], function(exports){
"use strict";
var $ = layui.$
//模块名
,MOD_NAME = 'MODULE_DEMO_NAME'
,MOD_INDEX = 'layui_'+ MOD_NAME +'_index' //模块索引名
//外部接口
,MODULE_DEMO_NAME = {
config: {}
,index: layui[MOD_NAME] ? (layui[MOD_NAME].index + 10000) : 0
//设置全局项
,set: function(options){
var that = this;
that.config = $.extend({}, that.config, options);
return that;
}
//事件
,on: function(events, callback){
return layui.onevent.call(this, MOD_NAME, events, callback);
}
}
//操作当前实例
,thisModule = function(){
var that = this
,options = that.config
,id = options.id || that.index;
thisModule.that[id] = that; //记录当前实例对象
return {
config: options
//重置实例
,reload: function(options){
that.reload.call(that, options);
}
}
}
//字符常量
,STR_ELEM = 'layui-MODULE_DEMO_NAME', STR_HIDE = 'layui-hide', STR_DISABLED = 'layui-disabled', STR_NONE = 'layui-none'
//主模板
,TPL_MAIN = [''].join('')
//构造器
,Class = function(options){
var that = this;
that.index = ++MODULE_DEMO_NAME.index;
that.config = $.extend({}, that.config, MODULE_DEMO_NAME.config, options);
that.render();
};
//默认配置
Class.prototype.config = {
};
//重载实例
Class.prototype.reload = function(options){
var that = this;
//防止数组深度合并
layui.each(options, function(key, item){
if(layui.type(item) === 'array') delete that.config[key];
});
that.config = $.extend(true, {}, that.config, options);
that.render();
};
//渲染
Class.prototype.render = function(){
var that = this
,options = that.config;
//解析模板
var thisElem = that.elem = $(laytpl(TPL_MAIN).render({
data: options
,index: that.index //索引
}));
var othis = options.elem = $(options.elem);
if(!othis[0]) return;
that.events(); //事件
};
//事件
Class.prototype.events = function(){
var that = this
,options = that.config;
};
//记录所有实例
thisModule.that = {}; //记录所有实例对象
//获取当前实例对象
thisModule.getThis = function(id){
var that = thisModule.that[id];
if(!that) hint.error(id ? (MOD_NAME +' instance with ID \''+ id +'\' not found') : 'ID argument required');
return that
};
//重载实例
MODULE_DEMO_NAME.reload = function(id, options){
var that = thisModule.that[id];
that.reload(options);
return thisModule.call(that);
};
//核心入口
MODULE_DEMO_NAME.render = function(options){
var inst = new Class(options);
return thisModule.call(inst);
};
exports(MOD_NAME, MODULE_DEMO_NAME);
});

View File

@@ -0,0 +1,563 @@
/**
* dropdown
* 下拉菜单组件
*/
layui.define(['jquery', 'laytpl', 'lay'], function(exports){
"use strict";
var $ = layui.$
,laytpl = layui.laytpl
,hint = layui.hint()
,device = layui.device()
,clickOrMousedown = (device.mobile ? 'touchstart' : 'mousedown')
//模块名
,MOD_NAME = 'dropdown'
,MOD_INDEX = 'layui_'+ MOD_NAME +'_index' //模块索引名
//外部接口
,dropdown = {
config: {}
,index: layui[MOD_NAME] ? (layui[MOD_NAME].index + 10000) : 0
//设置全局项
,set: function(options){
var that = this;
that.config = $.extend({}, that.config, options);
return that;
}
//事件
,on: function(events, callback){
return layui.onevent.call(this, MOD_NAME, events, callback);
}
}
//操作当前实例
,thisModule = function(){
var that = this;
var options = that.config;
var id = options.id;
thisModule.that[id] = that; //记录当前实例对象
return {
config: options
//重置实例
,reload: function(options){
that.reload.call(that, options);
}
,close: function () {
that.remove()
}
}
}
//字符常量
,STR_ELEM = 'layui-dropdown', STR_HIDE = 'layui-hide', STR_DISABLED = 'layui-disabled', STR_NONE = 'layui-none'
,STR_ITEM_UP = 'layui-menu-item-up', STR_ITEM_DOWN = 'layui-menu-item-down', STR_MENU_TITLE = 'layui-menu-body-title', STR_ITEM_GROUP = 'layui-menu-item-group', STR_ITEM_PARENT = 'layui-menu-item-parent', STR_ITEM_DIV = 'layui-menu-item-divider', STR_ITEM_CHECKED = 'layui-menu-item-checked', STR_ITEM_CHECKED2 = 'layui-menu-item-checked2', STR_MENU_PANEL = 'layui-menu-body-panel', STR_MENU_PANEL_L = 'layui-menu-body-panel-left', STR_ELEM_SHADE = 'layui-dropdown-shade'
,STR_GROUP_TITLE = '.'+ STR_ITEM_GROUP + '>.'+ STR_MENU_TITLE
//构造器
,Class = function(options){
var that = this;
that.index = ++dropdown.index;
that.config = $.extend({}, that.config, dropdown.config, options);
that.init();
};
//默认配置
Class.prototype.config = {
trigger: 'click' //事件类型
,content: '' //自定义菜单内容
,className: '' //自定义样式类名
,style: '' //设置面板 style 属性
,show: false //是否初始即显示菜单面板
,isAllowSpread: true //是否允许菜单组展开收缩
,isSpreadItem: true //是否初始展开子菜单
,data: [] //菜单数据结构
,delay: 300 //延迟关闭的毫秒数,若 trigger 为 hover 时才生效
,shade: 0 // 遮罩
};
//重载实例
Class.prototype.reload = function(options){
var that = this;
that.config = $.extend({}, that.config, options);
that.init(true);
};
// 初始化准备
Class.prototype.init = function(rerender){
var that = this;
var options = that.config;
// 若 elem 非唯一
var elem = $(options.elem);
if(elem.length > 1){
layui.each(elem, function(){
dropdown.render($.extend({}, options, {
elem: this
}));
});
return that;
}
// 合并 lay-options 属性上的配置信息
$.extend(options, lay.options(elem[0]));
// 若重复执行 render则视为 reload 处理
if(!rerender && elem[0] && elem.data(MOD_INDEX)){
var newThat = thisModule.getThis(elem.data(MOD_INDEX));
if(!newThat) return;
return newThat.reload(options);
}
options.elem = $(options.elem);
// 初始化 id 属性 - 优先取 options > 元素 id > 自增索引
options.id = 'id' in options ? options.id : (
elem.attr('id') || that.index
);
if(options.show) that.render(rerender); // 初始即显示
that.events(); // 事件
};
//渲染
Class.prototype.render = function(rerender){
var that = this
,options = that.config
,elemBody = $('body')
//默认菜单内容
,getDefaultView = function(){
var elemUl = $('<ul class="layui-menu layui-dropdown-menu"></ul>');
if(options.data.length > 0 ){
eachItemView(elemUl, options.data)
} else {
elemUl.html('<li class="layui-menu-item-none">no menu</li>');
}
return elemUl;
}
//遍历菜单项
,eachItemView = function(views, data){
//var views = [];
layui.each(data, function(index, item){
//是否存在子级
var isChild = item.child && item.child.length > 0
,isSpreadItem = ('isSpreadItem' in item) ? item.isSpreadItem : options.isSpreadItem
,title = item.templet
? laytpl(item.templet).render(item)
: (options.templet ? laytpl(options.templet).render(item) : item.title)
//初始类型
,type = function(){
if(isChild){
item.type = item.type || 'parent';
}
if(item.type){
return ({
group: 'group'
,parent: 'parent'
,'-': '-'
})[item.type] || 'parent';
}
return '';
}();
if(type !== '-' && (!item.title && !item.id && !isChild)) return;
//列表元素
var viewLi = $(['<li'+ function(){
var className = {
group: 'layui-menu-item-group'+ (
options.isAllowSpread ? (
isSpreadItem ? ' layui-menu-item-down' : ' layui-menu-item-up'
) : ''
)
,parent: STR_ITEM_PARENT
,'-': 'layui-menu-item-divider'
};
if(isChild || type){
return ' class="'+ className[type] +'"';
}
return item.disabled ? ' class="'+ STR_DISABLED +'"' : '';
}() +'>'
//标题区
,function(){
//是否超文本
var viewText = ('href' in item) ? (
'<a href="'+ item.href +'" target="'+ (item.target || '_self') +'">'+ title +'</a>'
) : title;
//是否存在子级
if(isChild){
return '<div class="'+ STR_MENU_TITLE +'">'+ viewText + function(){
if(type === 'parent'){
return '<i class="layui-icon layui-icon-right"></i>';
} else if(type === 'group' && options.isAllowSpread){
return '<i class="layui-icon layui-icon-'+ (isSpreadItem ? 'up' : 'down') +'"></i>';
} else {
return '';
}
}() +'</div>'
}
return '<div class="'+ STR_MENU_TITLE +'">'+ viewText +'</div>';
}()
,'</li>'].join(''));
viewLi.data('item', item);
//子级区
if(isChild){
var elemPanel = $('<div class="layui-panel layui-menu-body-panel"></div>')
,elemUl = $('<ul></ul>');
if(type === 'parent'){
elemPanel.append(eachItemView(elemUl, item.child));
viewLi.append(elemPanel);
} else {
viewLi.append(eachItemView(elemUl, item.child));
}
}
views.append(viewLi);
});
return views;
}
//主模板
,TPL_MAIN = ['<div class="layui-dropdown layui-border-box layui-panel layui-anim layui-anim-downbit">'
,'</div>'].join('');
//如果是右键事件,则每次触发事件时,将允许重新渲染
if(options.trigger === 'contextmenu' || lay.isTopElem(options.elem[0])) rerender = true;
//判断是否已经打开了下拉菜单面板
if(!rerender && options.elem.data(MOD_INDEX +'_opened')) return;
//记录模板对象
that.elemView = $(TPL_MAIN);
that.elemView.append(options.content || getDefaultView());
//初始化某些属性
if(options.className) that.elemView.addClass(options.className);
if(options.style) that.elemView.attr('style', options.style);
//记录当前执行的实例索引
dropdown.thisId = options.id;
//插入视图
that.remove(); //移除非当前绑定元素的面板
elemBody.append(that.elemView);
options.elem.data(MOD_INDEX +'_opened', true);
//遮罩
var shade = options.shade ? ('<div class="'+ STR_ELEM_SHADE +'" style="'+ ('z-index:'+ (that.elemView.css('z-index')-1) +'; background-color: ' + (options.shade[1] || '#000') + '; opacity: ' + (options.shade[0] || options.shade)) +'"></div>') : '';
that.elemView.before(shade);
//坐标定位
that.position();
thisModule.prevElem = that.elemView; //记录当前打开的元素,以便在下次关闭
thisModule.prevElem.data('prevElem', options.elem); //将当前绑定的元素,记录在打开元素的 data 对象中
//阻止全局事件
that.elemView.find('.layui-menu').on(clickOrMousedown, function(e){
layui.stope(e);
});
//触发菜单列表事件
that.elemView.find('.layui-menu li').on('click', function(e){
var othis = $(this);
var data = othis.data('item') || {};
var isChild = data.child && data.child.length > 0;
var isClickAllScope = options.clickScope === 'all'; // 是否所有父子菜单均触发点击事件
if(data.disabled) return; // 菜单项禁用状态
// 普通菜单项点击后的回调及关闭面板
if((!isChild || isClickAllScope) && data.type !== '-'){
var ret = typeof options.click === 'function'
? options.click(data, othis)
: null;
ret === false || (isChild || that.remove());
layui.stope(e);
}
});
//触发菜单组展开收缩
that.elemView.find(STR_GROUP_TITLE).on('click', function(e){
var othis = $(this)
,elemGroup = othis.parent()
,data = elemGroup.data('item') || {}
if(data.type === 'group' && options.isAllowSpread){
thisModule.spread(elemGroup);
}
});
//如果是鼠标移入事件,则鼠标移出时自动关闭
if(options.trigger === 'mouseenter'){
that.elemView.on('mouseenter', function(){
clearTimeout(thisModule.timer);
}).on('mouseleave', function(){
that.delayRemove();
});
}
// 组件打开完毕的事件
typeof options.ready === 'function' && options.ready(
that.elemView,
options.elem
);
};
//位置定位
Class.prototype.position = function(obj){
var that = this
,options = that.config;
lay.position(options.elem[0], that.elemView[0], {
position: options.position
,e: that.e
,clickType: options.trigger === 'contextmenu' ? 'right' : null
,align: options.align || null
});
};
//删除视图
Class.prototype.remove = function(){
var that = this
,options = that.config
,elemPrev = thisModule.prevElem;
//若存在已打开的面板元素,则移除
if(elemPrev){
elemPrev.data('prevElem') && (
elemPrev.data('prevElem').data(MOD_INDEX +'_opened', false)
);
elemPrev.remove();
}
lay('.' + STR_ELEM_SHADE).remove();
};
//延迟删除视图
Class.prototype.delayRemove = function(){
var that = this
,options = that.config;
clearTimeout(thisModule.timer);
thisModule.timer = setTimeout(function(){
that.remove();
}, options.delay);
};
//事件
Class.prototype.events = function(){
var that = this
,options = that.config;
//如果传入 hover则解析为 mouseenter
if(options.trigger === 'hover') options.trigger = 'mouseenter';
//解除上一个事件
if(that.prevElem) that.prevElem.off(options.trigger, that.prevElemCallback);
//记录被绑定的元素及回调
that.prevElem = options.elem;
that.prevElemCallback = function(e){
clearTimeout(thisModule.timer);
that.e = e;
that.render();
e.preventDefault();
};
//触发元素事件
options.elem.on(options.trigger, that.prevElemCallback);
//如果是鼠标移入事件
if(options.trigger === 'mouseenter'){
//直行鼠标移出事件
options.elem.on('mouseleave', function(){
that.delayRemove();
});
}
};
//记录所有实例
thisModule.that = {}; //记录所有实例对象
//获取当前实例对象
thisModule.getThis = function(id){
var that = thisModule.that[id];
if(!that) hint.error(id ? (MOD_NAME +' instance with ID \''+ id +'\' not found') : 'ID argument required');
return that;
};
//设置菜单组展开和收缩状态
thisModule.spread = function(othis){
//菜单组展开和收缩
var elemIcon = othis.children('.'+ STR_MENU_TITLE).find('.layui-icon');
if(othis.hasClass(STR_ITEM_UP)){
othis.removeClass(STR_ITEM_UP).addClass(STR_ITEM_DOWN);
elemIcon.removeClass('layui-icon-down').addClass('layui-icon-up');
} else {
othis.removeClass(STR_ITEM_DOWN).addClass(STR_ITEM_UP);
elemIcon.removeClass('layui-icon-up').addClass('layui-icon-down')
}
};
//全局事件
;!function(){
var _WIN = $(window)
,_DOC = $(document);
//自适应定位
_WIN.on('resize', function(){
if(!dropdown.thisId) return;
var that = thisModule.getThis(dropdown.thisId);
if(!that) return;
if(!that.elemView[0] || !$('.'+ STR_ELEM)[0]){
return false;
}
var options = that.config;
if(options.trigger === 'contextmenu'){
that.remove();
} else {
that.position();
}
});
//点击任意处关闭
_DOC.on(clickOrMousedown, function(e){
if(!dropdown.thisId) return;
var that = thisModule.getThis(dropdown.thisId)
if(!that) return;
var options = that.config;
//如果触发的是绑定的元素,或者属于绑定元素的子元素,则不关闭
//满足条件:当前绑定的元素不是 body document或者不是鼠标右键事件
if(!(lay.isTopElem(options.elem[0]) || options.trigger === 'contextmenu')){
if(
e.target === options.elem[0] ||
options.elem.find(e.target)[0] ||
(that.elemView && e.target === that.elemView[0]) ||
(that.elemView && that.elemView.find(e.target)[0])
) return;
}
that.remove();
});
//基础菜单的静态元素事件
var ELEM_LI = '.layui-menu:not(.layui-dropdown-menu) li';
_DOC.on('click', ELEM_LI, function(e){
var othis = $(this)
,parent = othis.parents('.layui-menu').eq(0)
,isChild = othis.hasClass(STR_ITEM_GROUP) || othis.hasClass(STR_ITEM_PARENT)
,filter = parent.attr('lay-filter') || parent.attr('id')
,options = lay.options(this);
//非触发元素
if(othis.hasClass(STR_ITEM_DIV)) return;
//非菜单组
if(!isChild){
//选中
parent.find('.'+ STR_ITEM_CHECKED).removeClass(STR_ITEM_CHECKED); //清除选中样式
parent.find('.'+ STR_ITEM_CHECKED2).removeClass(STR_ITEM_CHECKED2); //清除父级菜单选中样式
othis.addClass(STR_ITEM_CHECKED); //添加选中样式
othis.parents('.'+ STR_ITEM_PARENT).addClass(STR_ITEM_CHECKED2); //添加父级菜单选中样式
options.title = options.title || $.trim(othis.children('.'+ STR_MENU_TITLE).text());
//触发事件
layui.event.call(this, MOD_NAME, 'click('+ filter +')', options);
}
});
//基础菜单的展开收缩事件
_DOC.on('click', (ELEM_LI + STR_GROUP_TITLE), function(e){
var othis = $(this)
,elemGroup = othis.parents('.'+ STR_ITEM_GROUP +':eq(0)')
,options = lay.options(elemGroup[0]);
if(('isAllowSpread' in options) ? options.isAllowSpread : true){
thisModule.spread(elemGroup);
}
});
//判断子级菜单是否超出屏幕
var ELEM_LI_PAR = '.layui-menu .'+ STR_ITEM_PARENT
_DOC.on('mouseenter', ELEM_LI_PAR, function(e){
var othis = $(this)
,elemPanel = othis.find('.'+ STR_MENU_PANEL);
if(!elemPanel[0]) return;
var rect = elemPanel[0].getBoundingClientRect();
//是否超出右侧屏幕
if(rect.right > _WIN.width()){
elemPanel.addClass(STR_MENU_PANEL_L);
//不允许超出左侧屏幕
rect = elemPanel[0].getBoundingClientRect();
if(rect.left < 0){
elemPanel.removeClass(STR_MENU_PANEL_L);
}
}
//是否超出底部屏幕
if(rect.bottom > _WIN.height()){
elemPanel.eq(0).css('margin-top', -(rect.bottom - _WIN.height() + 5));
}
}).on('mouseleave', ELEM_LI_PAR, function(e){
var othis = $(this)
,elemPanel = othis.children('.'+ STR_MENU_PANEL);
elemPanel.removeClass(STR_MENU_PANEL_L);
elemPanel.css('margin-top', 0);
});
}();
// 关闭面板
dropdown.close = function(id){
var that = thisModule.getThis(id);
if(!that) return this;
that.remove();
return thisModule.call(that);
};
// 重载实例
dropdown.reload = function(id, options){
var that = thisModule.getThis(id);
if(!that) return this;
that.reload(options);
return thisModule.call(that);
};
// 核心入口
dropdown.render = function(options){
var inst = new Class(options);
return thisModule.call(inst);
};
exports(MOD_NAME, dropdown);
});

View File

@@ -0,0 +1,538 @@
/**
* element
* 常用元素操作组件
*/
layui.define('jquery', function(exports){
'use strict';
var $ = layui.$;
var hint = layui.hint();
var device = layui.device();
var MOD_NAME = 'element';
var THIS = 'layui-this';
var SHOW = 'layui-show';
var TITLE = '.layui-tab-title';
var Element = function(){
this.config = {};
};
// 全局设置
Element.prototype.set = function(options){
var that = this;
$.extend(true, that.config, options);
return that;
};
// 表单事件
Element.prototype.on = function(events, callback){
return layui.onevent.call(this, MOD_NAME, events, callback);
};
// 外部 Tab 新增
Element.prototype.tabAdd = function(filter, options){
var tabElem = $('.layui-tab[lay-filter='+ filter +']');
var titElem = tabElem.children(TITLE);
var barElem = titElem.children('.layui-tab-bar');
var contElem = tabElem.children('.layui-tab-content');
var li = '<li'+ function(){
var layAttr = [];
layui.each(options, function(key, value){
if(/^(title|content)$/.test(key)) return;
layAttr.push('lay-'+ key +'="'+ value +'"');
});
if(layAttr.length > 0) layAttr.unshift(''); //向前插,预留空格
return layAttr.join(' ');
}() +'>'+ (options.title || 'unnaming') +'</li>';
barElem[0] ? barElem.before(li) : titElem.append(li);
contElem.append('<div class="layui-tab-item">'+ (options.content || '') +'</div>');
call.hideTabMore(true);
call.tabAuto();
return this;
};
// 外部 Tab 删除
Element.prototype.tabDelete = function(filter, layid){
var tabElem = $('.layui-tab[lay-filter='+ filter +']');
var titElem = tabElem.children(TITLE);
var liElem = titElem.find('>li[lay-id="'+ layid +'"]');
call.tabDelete(null, liElem);
return this;
};
// 外部 Tab 切换
Element.prototype.tabChange = function(filter, layid){
var tabElem = $('.layui-tab[lay-filter='+ filter +']');
var titElem = tabElem.children(TITLE);
var liElem = titElem.find('>li[lay-id="'+ layid +'"]');
call.tabClick.call(liElem[0], {
liElem: liElem
});
return this;
};
// 自定义 Tab 选项卡
Element.prototype.tab = function(options){
options = options || {};
dom.on('click', options.headerElem, function(e){
var index = $(this).index();
call.tabClick.call(this, {
index: index,
options: options
});
});
};
// 动态改变进度条
Element.prototype.progress = function(filter, percent){
var ELEM = 'layui-progress';
var elem = $('.'+ ELEM +'[lay-filter='+ filter +']');
var elemBar = elem.find('.'+ ELEM +'-bar');
var text = elemBar.find('.'+ ELEM +'-text');
elemBar.css('width', function(){
return /^.+\/.+$/.test(percent)
? (new Function('return '+ percent)() * 100) + '%'
: percent;
}).attr('lay-percent', percent);
text.text(percent);
return this;
};
var NAV_ELEM = '.layui-nav';
var NAV_ITEM = 'layui-nav-item';
var NAV_BAR = 'layui-nav-bar';
var NAV_TREE = 'layui-nav-tree';
var NAV_CHILD = 'layui-nav-child';
var NAV_CHILD_C = 'layui-nav-child-c';
var NAV_MORE = 'layui-nav-more';
var NAV_DOWN = 'layui-icon-down';
var NAV_ANIM = 'layui-anim layui-anim-upbit';
// 基础事件体
var call = {
// Tab 点击
tabClick: function(obj){
obj = obj || {};
var options = obj.options || {};
var othis = obj.liElem || $(this);
var parents = options.headerElem
? othis.parent()
: othis.parents('.layui-tab').eq(0);
var item = options.bodyElem
? $(options.bodyElem)
: parents.children('.layui-tab-content').children('.layui-tab-item');
var elemA = othis.find('a');
var isJump = elemA.attr('href') !== 'javascript:;' && elemA.attr('target') === '_blank'; // 是否存在跳转
var unselect = typeof othis.attr('lay-unselect') === 'string'; // 是否禁用选中
var filter = parents.attr('lay-filter');
// 下标
var index = 'index' in obj
? obj.index
: othis.parent().children('li').index(othis);
// 执行切换
if(!(isJump || unselect)){
othis.addClass(THIS).siblings().removeClass(THIS);
item.eq(index).addClass(SHOW).siblings().removeClass(SHOW);
}
layui.event.call(this, MOD_NAME, 'tab('+ filter +')', {
elem: parents,
index: index
});
}
// Tab 删除
,tabDelete: function(e, othis){
var li = othis || $(this).parent();
var index = li.index();
var tabElem = li.closest('.layui-tab');
var item = tabElem.children('.layui-tab-content').children('.layui-tab-item');
var filter = tabElem.attr('lay-filter');
if(li.hasClass(THIS)){
if (li.next()[0] && li.next().is('li')){
call.tabClick.call(li.next()[0], {
index: index + 1
});
} else if (li.prev()[0] && li.prev().is('li')){
call.tabClick.call(li.prev()[0], null, index - 1);
}
}
li.remove();
item.eq(index).remove();
setTimeout(function(){
call.tabAuto();
}, 50);
layui.event.call(this, MOD_NAME, 'tabDelete('+ filter +')', {
elem: tabElem,
index: index
});
}
// Tab 自适应
,tabAuto: function(){
var SCROLL = 'layui-tab-scroll', MORE = 'layui-tab-more', BAR = 'layui-tab-bar'
,CLOSE = 'layui-tab-close', that = this;
$('.layui-tab').each(function(){
var othis = $(this)
,title = othis.children('.layui-tab-title')
,item = othis.children('.layui-tab-content').children('.layui-tab-item')
,STOPE = 'lay-stope="tabmore"'
,span = $('<span class="layui-unselect layui-tab-bar" '+ STOPE +'><i '+ STOPE +' class="layui-icon">&#xe61a;</i></span>');
if(that === window && device.ie != 8){
call.hideTabMore(true)
}
// 开启关闭图标
if(othis.attr('lay-allowclose')){
title.find('li').each(function(){
var li = $(this);
if(!li.find('.'+CLOSE)[0]){
var close = $('<i class="layui-icon layui-icon-close layui-unselect '+ CLOSE +'"></i>');
close.on('click', call.tabDelete);
li.append(close);
}
});
}
if(typeof othis.attr('lay-unauto') === 'string') return;
// 响应式
if(title.prop('scrollWidth') > title.outerWidth()+1){
if(title.find('.'+BAR)[0]) return;
title.append(span);
othis.attr('overflow', '');
span.on('click', function(e){
title[this.title ? 'removeClass' : 'addClass'](MORE);
this.title = this.title ? '' : '收缩';
});
} else {
title.find('.'+BAR).remove();
othis.removeAttr('overflow');
}
});
}
// 隐藏更多 Tab
,hideTabMore: function(e){
var tsbTitle = $('.layui-tab-title');
if(e === true || $(e.target).attr('lay-stope') !== 'tabmore'){
tsbTitle.removeClass('layui-tab-more');
tsbTitle.find('.layui-tab-bar').attr('title','');
}
}
//点击一级菜单
/*
,clickThis: function(){
var othis = $(this), parents = othis.parents(NAV_ELEM)
,filter = parents.attr('lay-filter')
,elemA = othis.find('a')
,unselect = typeof othis.attr('lay-unselect') === 'string';
if(othis.find('.'+NAV_CHILD)[0]) return;
if(!(elemA.attr('href') !== 'javascript:;' && elemA.attr('target') === '_blank') && !unselect){
parents.find('.'+THIS).removeClass(THIS);
othis.addClass(THIS);
}
layui.event.call(this, MOD_NAME, 'nav('+ filter +')', othis);
}
)
*/
//点击菜单 - a标签触发
,clickThis: function(){
var othis = $(this)
,parents = othis.parents(NAV_ELEM)
,filter = parents.attr('lay-filter')
,parent = othis.parent()
,child = othis.siblings('.'+NAV_CHILD)
,unselect = typeof parent.attr('lay-unselect') === 'string'; //是否禁用选中
if(!(othis.attr('href') !== 'javascript:;' && othis.attr('target') === '_blank') && !unselect){
if(!child[0]){
parents.find('.'+THIS).removeClass(THIS);
parent.addClass(THIS);
}
}
//如果是垂直菜单
if(parents.hasClass(NAV_TREE)){
child.removeClass(NAV_ANIM);
//如果有子菜单,则展开
if(child[0]){
parent[child.css('display') === 'none' ? 'addClass': 'removeClass'](NAV_ITEM+'ed');
if(parents.attr('lay-shrink') === 'all'){
parent.siblings().removeClass(NAV_ITEM + 'ed');
}
}
}
layui.event.call(this, MOD_NAME, 'nav('+ filter +')', othis);
}
//点击子菜单选中
/*
,clickChild: function(){
var othis = $(this), parents = othis.parents(NAV_ELEM)
,filter = parents.attr('lay-filter');
parents.find('.'+THIS).removeClass(THIS);
othis.addClass(THIS);
layui.event.call(this, MOD_NAME, 'nav('+ filter +')', othis);
}
*/
//折叠面板
,collapse: function(){
var othis = $(this), icon = othis.find('.layui-colla-icon')
,elemCont = othis.siblings('.layui-colla-content')
,parents = othis.parents('.layui-collapse').eq(0)
,filter = parents.attr('lay-filter')
,isNone = elemCont.css('display') === 'none';
//是否手风琴
if(typeof parents.attr('lay-accordion') === 'string'){
var show = parents.children('.layui-colla-item').children('.'+SHOW);
show.siblings('.layui-colla-title').children('.layui-colla-icon').html('&#xe602;');
show.removeClass(SHOW);
}
elemCont[isNone ? 'addClass' : 'removeClass'](SHOW);
icon.html(isNone ? '&#xe61a;' : '&#xe602;');
layui.event.call(this, MOD_NAME, 'collapse('+ filter +')', {
title: othis
,content: elemCont
,show: isNone
});
}
};
// 初始化元素操作
Element.prototype.init = function(type, filter){
var that = this, elemFilter = function(){
return filter ? ('[lay-filter="' + filter +'"]') : '';
}(), items = {
// Tab 选项卡
tab: function(){
call.tabAuto.call({});
}
//导航菜单
,nav: function(){
var TIME = 200, timer = {}, timerMore = {}, timeEnd = {}, NAV_TITLE = 'layui-nav-title'
//滑块跟随
,follow = function(bar, nav, index){
var othis = $(this), child = othis.find('.'+NAV_CHILD);
if(nav.hasClass(NAV_TREE)){
//无子菜单时跟随
if(!child[0]){
var thisA = othis.children('.'+ NAV_TITLE);
bar.css({
top: othis.offset().top - nav.offset().top
,height: (thisA[0] ? thisA : othis).outerHeight()
,opacity: 1
});
}
} else {
child.addClass(NAV_ANIM);
//若居中对齐
if(child.hasClass(NAV_CHILD_C)) child.css({
left: -(child.outerWidth() - othis.width())/2
});
//滑块定位
if(child[0]){ //若有子菜单,则滑块消失
bar.css({
left: bar.position().left + bar.width()/2
,width: 0
,opacity: 0
});
} else { //bar 跟随
bar.css({
left: othis.position().left + parseFloat(othis.css('marginLeft'))
,top: othis.position().top + othis.height() - bar.height()
});
}
//渐显滑块并适配宽度
timer[index] = setTimeout(function(){
bar.css({
width: child[0] ? 0 : othis.width()
,opacity: child[0] ? 0 : 1
});
}, device.ie && device.ie < 10 ? 0 : TIME);
//显示子菜单
clearTimeout(timeEnd[index]);
if(child.css('display') === 'block'){
clearTimeout(timerMore[index]);
}
timerMore[index] = setTimeout(function(){
child.addClass(SHOW);
othis.find('.'+NAV_MORE).addClass(NAV_MORE+'d');
}, 300);
}
};
//遍历导航
$(NAV_ELEM + elemFilter).each(function(index){
var othis = $(this)
,bar = $('<span class="'+ NAV_BAR +'"></span>')
,itemElem = othis.find('.'+NAV_ITEM);
//hover 滑动效果
if(!othis.find('.'+NAV_BAR)[0]){
othis.append(bar);
(othis.hasClass(NAV_TREE)
? itemElem.find('dd,>.'+ NAV_TITLE)
: itemElem).on('mouseenter', function(){
follow.call(this, bar, othis, index);
}).on('mouseleave', function(){ //鼠标移出
//是否为垂直导航
if(othis.hasClass(NAV_TREE)){
bar.css({
height: 0
,opacity: 0
});
} else {
//隐藏子菜单
clearTimeout(timerMore[index]);
timerMore[index] = setTimeout(function(){
othis.find('.'+NAV_CHILD).removeClass(SHOW);
othis.find('.'+NAV_MORE).removeClass(NAV_MORE+'d');
}, 300);
}
});
othis.on('mouseleave', function(){
clearTimeout(timer[index])
timeEnd[index] = setTimeout(function(){
if(!othis.hasClass(NAV_TREE)){
bar.css({
width: 0
,left: bar.position().left + bar.width()/2
,opacity: 0
});
}
}, TIME);
});
}
//展开子菜单
itemElem.find('a').each(function(){
var thisA = $(this)
,parent = thisA.parent()
,child = thisA.siblings('.'+NAV_CHILD);
//输出小箭头
if(child[0] && !thisA.children('.'+NAV_MORE)[0]){
thisA.append('<i class="layui-icon '+ NAV_DOWN +' '+ NAV_MORE +'"></i>');
}
thisA.off('click', call.clickThis).on('click', call.clickThis); //点击菜单
});
});
}
//面包屑
,breadcrumb: function(){
var ELEM = '.layui-breadcrumb';
$(ELEM + elemFilter).each(function(){
var othis = $(this)
,ATTE_SPR = 'lay-separator'
,separator = othis.attr(ATTE_SPR) || '/'
,aNode = othis.find('a');
if(aNode.next('span['+ ATTE_SPR +']')[0]) return;
aNode.each(function(index){
if(index === aNode.length - 1) return;
$(this).after('<span '+ ATTE_SPR +'>'+ separator +'</span>');
});
othis.css('visibility', 'visible');
});
}
//进度条
,progress: function(){
var ELEM = 'layui-progress';
$('.' + ELEM + elemFilter).each(function(){
var othis = $(this)
,elemBar = othis.find('.layui-progress-bar')
,percent = elemBar.attr('lay-percent');
elemBar.css('width', function(){
return /^.+\/.+$/.test(percent)
? (new Function('return '+ percent)() * 100) + '%'
: percent;
});
if(othis.attr('lay-showpercent')){
setTimeout(function(){
elemBar.html('<span class="'+ ELEM +'-text">'+ percent +'</span>');
},350);
}
});
}
//折叠面板
,collapse: function(){
var ELEM = 'layui-collapse';
$('.' + ELEM + elemFilter).each(function(){
var elemItem = $(this).find('.layui-colla-item')
elemItem.each(function(){
var othis = $(this)
,elemTitle = othis.find('.layui-colla-title')
,elemCont = othis.find('.layui-colla-content')
,isNone = elemCont.css('display') === 'none';
//初始状态
elemTitle.find('.layui-colla-icon').remove();
elemTitle.append('<i class="layui-icon layui-colla-icon">'+ (isNone ? '&#xe602;' : '&#xe61a;') +'</i>');
//点击标题
elemTitle.off('click', call.collapse).on('click', call.collapse);
});
});
}
};
return items[type] ? items[type]() : layui.each(items, function(index, item){
item();
});
};
Element.prototype.render = Element.prototype.init;
var element = new Element();
var dom = $(document);
$(function(){
element.render();
});
dom.on('click', '.layui-tab-title li', call.tabClick); // Tab 切换
dom.on('click', call.hideTabMore); // 隐藏展开的 Tab
$(window).on('resize', call.tabAuto); // 自适应
exports(MOD_NAME, element);
});

View File

@@ -0,0 +1,176 @@
/**
* flow 流加载组件
*/
layui.define('jquery', function(exports){
"use strict";
var $ = layui.$, Flow = function(options){}
,ELEM_MORE = 'layui-flow-more'
,ELEM_LOAD = '<i class="layui-anim layui-anim-rotate layui-anim-loop layui-icon ">&#xe63e;</i>';
//主方法
Flow.prototype.load = function(options){
var that = this, page = 0, lock, isOver, lazyimg, timer;
options = options || {};
var elem = $(options.elem); if(!elem[0]) return;
var scrollElem = $(options.scrollElem || document); //滚动条所在元素
var mb = options.mb || 50; //与底部的临界距离
var isAuto = 'isAuto' in options ? options.isAuto : true; //是否自动滚动加载
var end = options.end || '没有更多了'; //“末页”显示文案
//滚动条所在元素是否为document
var notDocument = options.scrollElem && options.scrollElem !== document;
//加载更多
var ELEM_TEXT = '<cite>加载更多</cite>'
,more = $('<div class="layui-flow-more"><a href="javascript:;">'+ ELEM_TEXT +'</a></div>');
if(!elem.find('.layui-flow-more')[0]){
elem.append(more);
}
//加载下一个元素
var next = function(html, over){
html = $(html);
more.before(html);
over = over == 0 ? true : null;
over ? more.html(end) : more.find('a').html(ELEM_TEXT);
isOver = over;
lock = null;
lazyimg && lazyimg();
};
//触发请求
var done = function(){
lock = true;
more.find('a').html(ELEM_LOAD);
typeof options.done === 'function' && options.done(++page, next);
};
done();
//不自动滚动加载
more.find('a').on('click', function(){
var othis = $(this);
if(isOver) return;
lock || done();
});
//如果允许图片懒加载
if(options.isLazyimg){
var lazyimg = that.lazyimg({
elem: options.elem + ' img'
,scrollElem: options.scrollElem
});
}
if(!isAuto) return that;
scrollElem.on('scroll', function(){
var othis = $(this), top = othis.scrollTop();
if(timer) clearTimeout(timer);
if(isOver || !elem.width()) return; //如果已经结束,或者元素处于隐藏状态,则不执行滚动加载
timer = setTimeout(function(){
//计算滚动所在容器的可视高度
var height = notDocument ? othis.height() : $(window).height();
//计算滚动所在容器的实际高度
var scrollHeight = notDocument
? othis.prop('scrollHeight')
: document.documentElement.scrollHeight;
//临界点
if(scrollHeight - top - height <= mb){
lock || done();
}
}, 100);
});
return that;
};
//图片懒加载
Flow.prototype.lazyimg = function(options){
var that = this, index = 0, haveScroll;
options = options || {};
var scrollElem = $(options.scrollElem || document); //滚动条所在元素
var elem = options.elem || 'img';
//滚动条所在元素是否为document
var notDocument = options.scrollElem && options.scrollElem !== document;
//显示图片
var show = function(item, height){
var start = scrollElem.scrollTop(), end = start + height;
var elemTop = notDocument ? function(){
return item.offset().top - scrollElem.offset().top + start;
}() : item.offset().top;
/* 始终只加载在当前屏范围内的图片 */
if(elemTop >= start && elemTop <= end){
if(item.attr('lay-src')){
var src = item.attr('lay-src');
layui.img(src, function(){
var next = that.lazyimg.elem.eq(index);
item.attr('src', src).removeAttr('lay-src');
/* 当前图片加载就绪后,检测下一个图片是否在当前屏 */
next[0] && render(next);
index++;
}, function(){
var next = that.lazyimg.elem.eq(index);
item.removeAttr('lay-src');
});
}
}
}, render = function(othis, scroll){
//计算滚动所在容器的可视高度
var height = notDocument ? (scroll||scrollElem).height() : $(window).height();
var start = scrollElem.scrollTop(), end = start + height;
that.lazyimg.elem = $(elem);
if(othis){
show(othis, height);
} else {
//计算未加载过的图片
for(var i = 0; i < that.lazyimg.elem.length; i++){
var item = that.lazyimg.elem.eq(i), elemTop = notDocument ? function(){
return item.offset().top - scrollElem.offset().top + start;
}() : item.offset().top;
show(item, height);
index = i;
//如果图片的top坐标超出了当前屏则终止后续图片的遍历
if(elemTop > end) break;
}
}
};
render();
if(!haveScroll){
var timer;
scrollElem.on('scroll', function(){
var othis = $(this);
if(timer) clearTimeout(timer)
timer = setTimeout(function(){
render(null, othis);
}, 50);
});
haveScroll = true;
}
return render;
};
//暴露接口
exports('flow', new Flow());
});

View File

@@ -0,0 +1,958 @@
/**
* form 表单组件
*/
layui.define(['lay', 'layer', 'util'], function(exports){
"use strict";
var $ = layui.$;
var layer = layui.layer;
var util = layui.util;
var hint = layui.hint();
var device = layui.device();
var MOD_NAME = 'form', ELEM = '.layui-form', THIS = 'layui-this';
var SHOW = 'layui-show', HIDE = 'layui-hide', DISABLED = 'layui-disabled';
var Form = function(){
this.config = {
verify: {
required: [
/[\S]+/
,'必填项不能为空'
]
,phone: [
/^1\d{10}$/
,'请输入正确的手机号'
]
,email: [
/^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/
,'邮箱格式不正确'
]
,url: [
/^(#|(http(s?)):\/\/|\/\/)[^\s]+\.[^\s]+$/
,'链接格式不正确'
]
,number: function(value){
if(!value || isNaN(value)) return '只能填写数字'
}
,date: [
/^(\d{4})[-\/](\d{1}|0\d{1}|1[0-2])([-\/](\d{1}|0\d{1}|[1-2][0-9]|3[0-1]))*$/
,'日期格式不正确'
]
,identity: [
/(^\d{15}$)|(^\d{17}(x|X|\d)$)/
,'请输入正确的身份证号'
]
}
,autocomplete: null // 全局 autocomplete 状态。null 表示不干预
};
};
// 全局设置
Form.prototype.set = function(options){
var that = this;
$.extend(true, that.config, options);
return that;
};
// 验证规则设定
Form.prototype.verify = function(settings){
var that = this;
$.extend(true, that.config.verify, settings);
return that;
};
// 获取指定表单对象
Form.prototype.getFormElem = function(filter){
return $(ELEM + function(){
return filter ? ('[lay-filter="' + filter +'"]') : '';
}());
};
// 表单事件
Form.prototype.on = function(events, callback){
return layui.onevent.call(this, MOD_NAME, events, callback);
};
// 赋值/取值
Form.prototype.val = function(filter, object){
var that = this
,formElem = that.getFormElem(filter);
// 遍历
formElem.each(function(index, item){
var itemForm = $(this);
// 赋值
layui.each(object, function(key, value){
var itemElem = itemForm.find('[name="'+ key +'"]')
,type;
// 如果对应的表单不存在,则不执行
if(!itemElem[0]) return;
type = itemElem[0].type;
// 如果为复选框
if(type === 'checkbox'){
itemElem[0].checked = value;
} else if(type === 'radio') { // 如果为单选框
itemElem.each(function(){
if(this.value == value ){
this.checked = true
}
});
} else { // 其它类型的表单
itemElem.val(value);
}
});
});
form.render(null, filter);
// 返回值
return that.getValue(filter);
};
// 取值
Form.prototype.getValue = function(filter, itemForm){
itemForm = itemForm || this.getFormElem(filter);
var nameIndex = {} // 数组 name 索引
,field = {}
,fieldElem = itemForm.find('input,select,textarea') // 获取所有表单域
layui.each(fieldElem, function(_, item){
var othis = $(this)
,init_name; // 初始 name
item.name = (item.name || '').replace(/^\s*|\s*&/, '');
if(!item.name) return;
// 用于支持数组 name
if(/^.*\[\]$/.test(item.name)){
var key = item.name.match(/^(.*)\[\]$/g)[0];
nameIndex[key] = nameIndex[key] | 0;
init_name = item.name.replace(/^(.*)\[\]$/, '$1['+ (nameIndex[key]++) +']');
}
if(/^(checkbox|radio)$/.test(item.type) && !item.checked) return; // 复选框和单选框未选中,不记录字段
field[init_name || item.name] = item.value;
});
return field;
};
// 表单控件渲染
Form.prototype.render = function(type, filter){
var that = this;
var options = that.config;
var elemForm = $(ELEM + function(){
return filter ? ('[lay-filter="' + filter +'"]') : '';
}());
var items = {
// 输入框
input: function(elem){
var inputs = elem || elemForm.find('input,textarea');
// 初始化全局的 autocomplete
options.autocomplete && inputs.attr('autocomplete', options.autocomplete);
// 初始化输入框动态点缀
elemForm.find('input[lay-affix],textarea[lay-affix]').each(function(){
var othis = $(this);
var affix = othis.attr('lay-affix');
var CLASS_SUFFIX = 'layui-input-suffix';
var CLASS_AFFIX = 'layui-input-affix';
var disabled = othis.is('[disabled]') || othis.is('[readonly]');
// 根据是否空值来显示或隐藏元素
var showAffix = function(elem, value){
elem = $(elem);
if(!elem[0]) return;
elem[$.trim(value) ? 'removeClass' : 'addClass'](HIDE);
};
// 渲染动态点缀内容
var renderAffix = function(opts){
opts = $.extend({}, (affixOptions[affix] || {
value: affix
}), opts, lay.options(othis[0]));
var elemAffix = $('<div class="'+ CLASS_AFFIX +'">');
var elemIcon = $('<i class="layui-icon layui-icon-'+ opts.value + (
opts.disabled ? (' '+ DISABLED) : ''
) +'"></i>');
elemAffix.append(elemIcon);
if(opts.split) elemAffix.addClass('layui-input-split');
// 移除旧的元素
var hasElemAffix = othis.next('.'+ CLASS_AFFIX);
if(hasElemAffix[0]) hasElemAffix.remove();
// 是否已经存在后缀元素
var hasElemSuffix = othis.next('.'+ CLASS_SUFFIX);
if(hasElemSuffix[0]){
hasElemAffix = hasElemSuffix.find('.'+ CLASS_AFFIX);
if(hasElemAffix[0]) hasElemAffix.remove();
hasElemSuffix.prepend(elemAffix);
othis.css('padding-right', function(){
var paddingRight = othis.closest('.layui-input-group')[0]
? 0
: hasElemSuffix.outerWidth();
return paddingRight + elemAffix.outerWidth()
});
} else {
elemAffix.addClass(CLASS_SUFFIX);
othis.after(elemAffix);
}
opts.show === 'auto' && showAffix(elemAffix, othis.val());
// 输入事件
othis.on('input propertychange', function(){
var value = this.value;
opts.show === 'auto' && showAffix(elemAffix, value);
});
// 点击动态后缀事件
elemIcon.on('click', function(){
var inputFilter = othis.attr('lay-filter');
if($(this).hasClass(DISABLED)) return;
typeof opts.click === 'function' && opts.click.call(this, othis, opts);
// 对外事件
layui.event.call(this, MOD_NAME, 'input-affix('+ inputFilter +')', {
elem: othis[0],
affix: affix,
options: opts
});
});
};
// 动态点缀配置项
var affixOptions = {
eye: { // 密码显隐
value: 'eye-invisible',
click: function(elem, opts){ // 事件
var SHOW_NAME = 'LAY_FORM_INPUT_AFFIX_SHOW';
var isShow = elem.data(SHOW_NAME);
elem.attr('type', isShow ? 'password' : 'text').data(SHOW_NAME, !isShow);
renderAffix({
value: isShow ? 'eye-invisible' : 'eye'
});
}
},
clear: { // 内容清除
value: 'clear',
click: function(elem){
elem.val('').focus();
showAffix($(this).parent(), null);
},
show: 'auto', // 根据输入框值是否来显示或隐藏点缀图标
disabled: disabled // 跟随输入框禁用状态
}
};
renderAffix();
});
}
// 下拉选择框
,select: function(elem){
var TIPS = '请选择', CLASS = 'layui-form-select', TITLE = 'layui-select-title'
,NONE = 'layui-select-none', initValue = '', thatInput
,selects = elem || elemForm.find('select')
// 隐藏 select
,hide = function(e, clear){
if(!$(e.target).parent().hasClass(TITLE) || clear){
$('.'+CLASS).removeClass(CLASS+'ed ' + CLASS+'up');
thatInput && initValue && thatInput.val(initValue);
}
thatInput = null;
}
// 各种事件
,events = function(reElem, disabled, isSearch){
var select = $(this)
,title = reElem.find('.' + TITLE)
,input = title.find('input')
,dl = reElem.find('dl')
,dds = dl.children('dd')
,dts = dl.children('dt') // select分组dt元素
,index = this.selectedIndex // 当前选中的索引
,nearElem; // select 组件当前选中的附近元素,用于辅助快捷键功能
if(disabled) return;
// 搜索项
var laySearch = select.attr('lay-search');
// 展开下拉
var showDown = function(){
var top = reElem.offset().top + reElem.outerHeight() + 5 - $win.scrollTop()
,dlHeight = dl.outerHeight();
index = select[0].selectedIndex; // 获取最新的 selectedIndex
reElem.addClass(CLASS+'ed');
dds.removeClass(HIDE);
dts.removeClass(HIDE);
nearElem = null;
// 初始选中样式
dds.removeClass(THIS);
index >= 0 && dds.eq(index).addClass(THIS);
// 上下定位识别
if(top + dlHeight > $win.height() && top >= dlHeight){
reElem.addClass(CLASS + 'up');
}
followScroll();
}
// 隐藏下拉
,hideDown = function(choose){
reElem.removeClass(CLASS+'ed ' + CLASS+'up');
input.blur();
nearElem = null;
if(choose) return;
notOption(input.val(), function(none){
var selectedIndex = select[0].selectedIndex;
// 未查询到相关值
if(none){
initValue = $(select[0].options[selectedIndex]).html(); // 重新获得初始选中值
// 如果是第一项,且文本值等于 placeholder则清空初始值
if(selectedIndex === 0 && initValue === input.attr('placeholder')){
initValue = '';
};
// 如果有选中值,则将输入框纠正为该值。否则清空输入框
input.val(initValue || '');
}
});
}
// 定位下拉滚动条
,followScroll = function(){
var thisDd = dl.children('dd.'+ THIS);
if(!thisDd[0]) return;
var posTop = thisDd.position().top
,dlHeight = dl.height()
,ddHeight = thisDd.height();
// 若选中元素在滚动条不可见底部
if(posTop > dlHeight){
dl.scrollTop(posTop + dl.scrollTop() - dlHeight + ddHeight - 5);
}
// 若选择玄素在滚动条不可见顶部
if(posTop < 0){
dl.scrollTop(posTop + dl.scrollTop() - 5);
}
};
// 点击标题区域
title.on('click', function(e){
reElem.hasClass(CLASS+'ed') ? (
hideDown()
) : (
hide(e, true),
showDown()
);
dl.find('.'+NONE).remove();
});
// 点击箭头获取焦点
title.find('.layui-edge').on('click', function(){
input.focus();
});
// select 中 input 键盘事件
input.on('keyup', function(e){ // 键盘松开
var keyCode = e.keyCode;
// Tab键展开
if(keyCode === 9){
showDown();
}
}).on('keydown', function(e){ // 键盘按下
var keyCode = e.keyCode;
// Tab键隐藏
if(keyCode === 9){
hideDown();
}
// 标注 dd 的选中状态
var setThisDd = function(prevNext, thisElem1){
var nearDd, cacheNearElem
e.preventDefault();
// 得到当前队列元素
var thisElem = function(){
var thisDd = dl.children('dd.'+ THIS);
// 如果是搜索状态,且按 Down 键,且当前可视 dd 元素在选中元素之前,
// 则将当前可视 dd 元素的上一个元素作为虚拟的当前选中元素,以保证递归不中断
if(dl.children('dd.'+ HIDE)[0] && prevNext === 'next'){
var showDd = dl.children('dd:not(.'+ HIDE +',.'+ DISABLED +')')
,firstIndex = showDd.eq(0).index();
if(firstIndex >=0 && firstIndex < thisDd.index() && !showDd.hasClass(THIS)){
return showDd.eq(0).prev()[0] ? showDd.eq(0).prev() : dl.children(':last');
}
}
if(thisElem1 && thisElem1[0]){
return thisElem1;
}
if(nearElem && nearElem[0]){
return nearElem;
}
return thisDd;
// return dds.eq(index);
}();
cacheNearElem = thisElem[prevNext](); // 当前元素的附近元素
nearDd = thisElem[prevNext]('dd:not(.'+ HIDE +')'); // 当前可视元素的 dd 元素
// 如果附近的元素不存在,则停止执行,并清空 nearElem
if(!cacheNearElem[0]) return nearElem = null;
// 记录附近的元素,让其成为下一个当前元素
nearElem = thisElem[prevNext]();
// 如果附近不是 dd ,或者附近的 dd 元素是禁用状态,则进入递归查找
if((!nearDd[0] || nearDd.hasClass(DISABLED)) && nearElem[0]){
return setThisDd(prevNext, nearElem);
}
nearDd.addClass(THIS).siblings().removeClass(THIS); // 标注样式
followScroll(); // 定位滚动条
};
if(keyCode === 38) setThisDd('prev'); // Up 键
if(keyCode === 40) setThisDd('next'); // Down 键
// Enter 键
if(keyCode === 13){
e.preventDefault();
dl.children('dd.'+THIS).trigger('click');
}
});
// 检测值是否不属于 select 项
var notOption = function(value, callback, origin){
var num = 0;
layui.each(dds, function(){
var othis = $(this);
var text = othis.text();
// 是否区分大小写
if(laySearch !== 'cs'){
text = text.toLowerCase();
value = value.toLowerCase();
}
// 匹配
var not = text.indexOf(value) === -1;
if(value === '' || (origin === 'blur') ? value !== text : not) num++;
origin === 'keyup' && othis[not ? 'addClass' : 'removeClass'](HIDE);
});
// 处理 select 分组元素
origin === 'keyup' && layui.each(dts, function(){
var othis = $(this)
,thisDds = othis.nextUntil('dt').filter('dd') // 当前分组下的dd元素
,allHide = thisDds.length == thisDds.filter('.' + HIDE).length; // 当前分组下所有dd元素都隐藏了
othis[allHide ? 'addClass' : 'removeClass'](HIDE);
});
var none = num === dds.length;
return callback(none), none;
};
// 搜索匹配
var search = function(e){
var value = this.value, keyCode = e.keyCode;
if(keyCode === 9 || keyCode === 13
|| keyCode === 37 || keyCode === 38
|| keyCode === 39 || keyCode === 40
){
return false;
}
notOption(value, function(none){
if(none){
dl.find('.'+NONE)[0] || dl.append('<p class="'+ NONE +'">无匹配项</p>');
} else {
dl.find('.'+NONE).remove();
}
}, 'keyup');
// 当搜索值清空时
if(value === ''){
// 取消选中项
select.val('');
dl.find('.'+ THIS).removeClass(THIS);
(select[0].options[0] || {}).value || dl.children('dd:eq(0)').addClass(THIS);
dl.find('.'+ NONE).remove();
}
followScroll(); // 定位滚动条
};
if(isSearch){
input.on('input propertychange', search).on('blur', function(e){
var selectedIndex = select[0].selectedIndex;
thatInput = input; // 当前的 select 中的 input 元素
initValue = $(select[0].options[selectedIndex]).html(); // 重新获得初始选中值
// 如果是第一项,且文本值等于 placeholder则清空初始值
if(selectedIndex === 0 && initValue === input.attr('placeholder')){
initValue = '';
};
setTimeout(function(){
notOption(input.val(), function(none){
initValue || input.val(''); // none && !initValue
}, 'blur');
}, 200);
});
}
// 选择
dds.on('click', function(){
var othis = $(this), value = othis.attr('lay-value');
var filter = select.attr('lay-filter'); // 获取过滤器
if(othis.hasClass(DISABLED)) return false;
if(othis.hasClass('layui-select-tips')){
input.val('');
} else {
input.val(othis.text());
othis.addClass(THIS);
}
othis.siblings().removeClass(THIS);
select.val(value).removeClass('layui-form-danger');
layui.event.call(this, MOD_NAME, 'select('+ filter +')', {
elem: select[0]
,value: value
,othis: reElem
});
hideDown(true);
return false;
});
reElem.find('dl>dt').on('click', function(e){
return false;
});
$(document).off('click', hide).on('click', hide); // 点击其它元素关闭 select
}
// 初始渲染 select 组件选项
selects.each(function(index, select){
var othis = $(this)
,hasRender = othis.next('.'+CLASS)
,disabled = this.disabled
,value = select.value
,selected = $(select.options[select.selectedIndex]) // 获取当前选中项
,optionsFirst = select.options[0];
if(typeof othis.attr('lay-ignore') === 'string') return othis.show();
var isSearch = typeof othis.attr('lay-search') === 'string'
,placeholder = optionsFirst ? (
optionsFirst.value ? TIPS : (optionsFirst.innerHTML || TIPS)
) : TIPS;
// 替代元素
var reElem = $(['<div class="'+ (isSearch ? '' : 'layui-unselect ') + CLASS
,(disabled ? ' layui-select-disabled' : '') +'">'
,'<div class="'+ TITLE +'">'
,('<input type="text" placeholder="'+ util.escape($.trim(placeholder)) +'" '
+('value="'+ util.escape($.trim(value ? selected.html() : '')) +'"') // 默认值
+((!disabled && isSearch) ? '' : ' readonly') // 是否开启搜索
+' class="layui-input'
+(isSearch ? '' : ' layui-unselect')
+ (disabled ? (' ' + DISABLED) : '') +'">') // 禁用状态
,'<i class="layui-edge"></i></div>'
,'<dl class="layui-anim layui-anim-upbit'+ (othis.find('optgroup')[0] ? ' layui-select-group' : '') +'">'
,function(options){
var arr = [];
layui.each(options, function(index, item){
var tagName = item.tagName.toLowerCase();
if(index === 0 && !item.value && tagName !== 'optgroup'){
arr.push('<dd lay-value="" class="layui-select-tips">'+ $.trim(item.innerHTML || TIPS) +'</dd>');
} else if(tagName === 'optgroup'){
arr.push('<dt>'+ item.label +'</dt>');
} else {
arr.push('<dd lay-value="'+ util.escape(item.value) +'" class="'+ (value === item.value ? THIS : '') + (item.disabled ? (' '+DISABLED) : '') +'">'+ $.trim(item.innerHTML) +'</dd>');
}
});
arr.length === 0 && arr.push('<dd lay-value="" class="'+ DISABLED +'">没有选项</dd>');
return arr.join('');
}(othis.find('*')) +'</dl>'
,'</div>'].join(''));
hasRender[0] && hasRender.remove(); // 如果已经渲染则Rerender
othis.after(reElem);
events.call(this, reElem, disabled, isSearch);
});
}
// 复选框/开关
,checkbox: function(elem){
var CLASS = {
"checkbox": ['layui-form-checkbox', 'layui-form-checked', 'checkbox'],
"switch": ['layui-form-switch', 'layui-form-onswitch', 'switch']
};
var checks = elem || elemForm.find('input[type=checkbox]');
// 风格
var skins = {
"primary": true, // 默认风格
"tag": true, // 标签风格
"switch": true // 开关风格
};
// 事件
var events = function(reElem, RE_CLASS){
var check = $(this);
// 勾选
reElem.on('click', function(){
var filter = check.attr('lay-filter') // 获取过滤器
var title = (check.attr('title')||'').split('|');
if(check[0].disabled) return;
check[0].checked ? (
check[0].checked = false
,reElem.removeClass(RE_CLASS[1]).find('em').text(title[1])
) : (
check[0].checked = true
,reElem.addClass(RE_CLASS[1]).find('em').text(title[0])
);
layui.event.call(check[0], MOD_NAME, RE_CLASS[2]+'('+ filter +')', {
elem: check[0]
,value: check[0].value
,othis: reElem
});
});
};
// 遍历复选框
checks.each(function(index, check){
var othis = $(this);
var skin = othis.attr('lay-skin') || 'primary';
var title = $.trim(check.title || function(){ // 向下兼容 lay-text 属性
return check.title = othis.attr('lay-text') || '';
}()).split('|');
var disabled = this.disabled;
if(!skins[skin]) skin = 'primary'; // 若非内置风格,则强制为默认风格
var RE_CLASS = CLASS[skin] || CLASS.checkbox;
if(typeof othis.attr('lay-ignore') === 'string') return othis.show();
// 替代元素
var hasRender = othis.next('.' + RE_CLASS[0])
,reElem = $(['<div class="layui-unselect '+ RE_CLASS[0]
,(check.checked ? (' '+ RE_CLASS[1]) : '') // 选中状态
,(disabled ? ' layui-checkbox-disabled '+ DISABLED : '') // 禁用状态
,'"'
,(skin ? ' lay-skin="'+ skin +'"' : '') // 风格
,'>'
,function(){ // 不同风格的内容
var type = {
// 复选框
"checkbox": [
(title[0] ? ('<span>'+ util.escape(title[0]) +'</span>') : '')
,'<i class="layui-icon layui-icon-ok"></i>'
].join(''),
// 开关
"switch": '<em>'+ ((check.checked ? title[0] : title[1]) || '') +'</em><i></i>'
};
return type[skin] || type['checkbox'];
}()
,'</div>'].join(''));
hasRender[0] && hasRender.remove(); // 如果已经渲染则Rerender
othis.after(reElem);
events.call(this, reElem, RE_CLASS);
});
}
// 单选框
,radio: function(elem){
var CLASS = 'layui-form-radio', ICON = ['&#xe643;', '&#xe63f;']
,radios = elem || elemForm.find('input[type=radio]')
,events = function(reElem){
var radio = $(this), ANIM = 'layui-anim-scaleSpring';
reElem.on('click', function(){
var name = radio[0].name, forms = radio.parents(ELEM);
var filter = radio.attr('lay-filter'); // 获取过滤器
var sameRadio = forms.find('input[name='+ name.replace(/(\.|#|\[|\])/g, '\\$1') +']'); // 找到相同name的兄弟
if(radio[0].disabled) return;
layui.each(sameRadio, function(){
var next = $(this).next('.'+CLASS);
this.checked = false;
next.removeClass(CLASS+'ed');
next.find('.layui-icon').removeClass(ANIM).html(ICON[1]);
});
radio[0].checked = true;
reElem.addClass(CLASS+'ed');
reElem.find('.layui-icon').addClass(ANIM).html(ICON[0]);
layui.event.call(radio[0], MOD_NAME, 'radio('+ filter +')', {
elem: radio[0]
,value: radio[0].value
,othis: reElem
});
});
};
radios.each(function(index, radio){
var othis = $(this), hasRender = othis.next('.' + CLASS), disabled = this.disabled;
if(typeof othis.attr('lay-ignore') === 'string') return othis.show();
hasRender[0] && hasRender.remove(); // 如果已经渲染则Rerender
// 替代元素
var reElem = $(['<div class="layui-unselect '+ CLASS
,(radio.checked ? (' '+CLASS+'ed') : '') // 选中状态
,(disabled ? ' layui-radio-disabled '+DISABLED : '') +'">' // 禁用状态
,'<i class="layui-anim layui-icon">'+ ICON[radio.checked ? 0 : 1] +'</i>'
,'<div>'+ function(){
var title = util.escape(radio.title || '');
if(typeof othis.next().attr('lay-radio') === 'string'){
title = othis.next().html();
// othis.next().remove();
}
return title
}() +'</div>'
,'</div>'].join(''));
othis.after(reElem);
events.call(this, reElem);
});
}
};
// 执行所有渲染项
var renderItem = function(){
layui.each(items, function(index, item){
item();
});
};
// jquery 对象
if (layui.type(type) === 'object') {
// 若对象为表单域容器
if($(type).is(ELEM)){
elemForm = $(type);
renderItem();
} else { // 对象为表单项
type.each(function (index, item) {
var elem = $(item);
if (!elem.closest(ELEM).length) {
return; // 若不在 layui-form 容器中直接跳过
}
if (item.tagName === 'SELECT') {
items['select'](elem);
} else if (item.tagName === 'INPUT') {
var itemType = item.type;
if (itemType === 'checkbox' || itemType === 'radio') {
items[itemType](elem);
} else {
items['input'](elem);
}
}
});
}
} else {
type ? (
items[type] ? items[type]() : hint.error('不支持的 "'+ type + '" 表单渲染')
) : renderItem();
}
return that;
};
// 主动触发验证 -- elem 即要验证的区域表单选择器 / return true or false
Form.prototype.validate = function(elem){
var that = this;
var stop = null; // 验证不通过状态
var verify = form.config.verify; // 验证规则
var DANGER = 'layui-form-danger'; // 警示样式
elem = $(elem);
// 节点不存在可视为 true
if(!elem[0]) return !0;
// 若节点不存在特定属性,则查找容器内有待验证的子节点
if(elem.attr('lay-verify') === undefined){
// 若校验的是一个不带验证规则的容器,校验内部的 lay-verify 节点
if (that.validate(elem.find('*[lay-verify]')) === false) {
return false;
}
}
// 开始校验
layui.each(elem, function(_, item){
var othis = $(this);
var verifyStr = othis.attr('lay-verify') || '';
var vers = verifyStr.split('|');
var verType = othis.attr('lay-vertype'); // 提示方式
var value = othis.val();
othis.removeClass(DANGER); // 移除警示样式
// 遍历元素绑定的验证规则
layui.each(vers, function(_, thisVer){
var isTrue; // 是否命中校验
var errorText = ''; // 错误提示文本
var rule = verify[thisVer]; // 获取校验规则
// 匹配验证规则
if(rule){
var isTrue = typeof rule === 'function'
? errorText = rule(value, item)
: !rule[0].test(value);
// 是否属于美化替换后的表单元素
var isForm2Elem = item.tagName.toLowerCase() === 'select' || (
/^(checkbox|radio)$/.test(item.type)
);
errorText = errorText || rule[1];
if(thisVer === 'required'){
errorText = othis.attr('lay-reqtext') || errorText;
}
// 若为必填项或者非空命中校验,则阻止提交,弹出提示
if(isTrue){
// 提示层风格
if(verType === 'tips'){
layer.tips(errorText, function(){
if(typeof othis.attr('lay-ignore') !== 'string'){
if(isForm2Elem){
return othis.next();
}
}
return othis;
}(), {tips: 1});
} else if(verType === 'alert') {
layer.alert(errorText, {title: '提示', shadeClose: true});
}
// 若返回的为字符或数字,则自动弹出默认提示框;否则由 verify 方法中处理提示
else if(/\bstring|number\b/.test(typeof errorText)){
layer.msg(errorText, {icon: 5, shift: 6});
}
setTimeout(function(){
(isForm2Elem ? othis.next().find('input') : item).focus();
}, 7);
othis.addClass(DANGER);
return stop = true;
}
}
});
if(stop) return stop;
});
return !stop;
};
// 提交表单并校验
var submit = Form.prototype.submit = function(filter, callback){
var field = {}; // 字段集合
var button = $(this); // 当前触发的按钮
// 表单域 lay-filter 属性值
var layFilter = typeof filter === 'string'
? filter
: button.attr('lay-filter');
// 当前所在表单域
var elem = this.getFormElem
? this.getFormElem(layFilter)
: button.parents(ELEM).eq(0);
// 获取需要校验的元素
var verifyElem = elem.find('*[lay-verify]');
// 开始校验
if(!form.validate(verifyElem)) return false;
// 获取当前表单值
field = form.getValue(null, elem);
// 返回的参数
var params = {
elem: this.getFormElem ? (window.event && window.event.target) : this // 触发事件的对象
,form: this.getFormElem ? elem[0] : button.parents('form')[0] // 当前所在的 form 元素,如果存在的话
,field: field // 当前表单数据
};
// 回调
typeof callback === 'function' && callback(params);
// 事件
return layui.event.call(this, MOD_NAME, 'submit('+ layFilter +')', params);
};
var form = new Form();
var $dom = $(document);
var $win = $(window);
// 初始自动完成渲染
$(function(){
form.render();
});
// 表单 reset 重置渲染
$dom.on('reset', ELEM, function(){
var filter = $(this).attr('lay-filter');
setTimeout(function(){
form.render(null, filter);
}, 50);
});
// 表单提交事件
$dom.on('submit', ELEM, submit)
.on('click', '*[lay-submit]', submit);
exports(MOD_NAME, form);
});

10981
static/layui/modules/jquery.js vendored Normal file

File diff suppressed because it is too large Load Diff

436
static/layui/modules/lay.js Normal file
View File

@@ -0,0 +1,436 @@
/** lay 基础模块 | MIT Licensed */
;!function(window){ //gulp build: lay-header
"use strict";
var MOD_NAME = 'lay' //模块名
,document = window.document
//DOM查找
,lay = function(selector){
return new LAY(selector);
}
// DOM 构造器
,LAY = function(selector){
var index = 0;
var nativeDOM = typeof selector === 'object' ? function(){
// 仅适配简单元素对象
return layui.isArray(selector) ? selector : [selector];
}() : (
this.selector = selector,
document.querySelectorAll(selector || null)
);
for(; index < nativeDOM.length; index++){
this.push(nativeDOM[index]);
}
};
/*
lay 对象操作
*/
LAY.prototype = [];
LAY.prototype.constructor = LAY;
//普通对象深度扩展
lay.extend = function(){
var ai = 1
,length
,args = arguments
,clone = function(target, obj){
target = target || (layui.type(obj) === 'array' ? [] : {}); //目标对象
for(var i in obj){
//如果值为普通对象,则进入递归,继续深度合并
target[i] = (obj[i] && obj[i].constructor === Object)
? clone(target[i], obj[i])
: obj[i];
}
return target;
}
args[0] = typeof args[0] === 'object' ? args[0] : {};
length = args.length
for(; ai < length; ai++){
if(typeof args[ai] === 'object'){
clone(args[0], args[ai]);
}
}
return args[0];
};
//lay 模块版本
lay.v = '1.0.8';
//ie版本
lay.ie = function(){
var agent = navigator.userAgent.toLowerCase();
return (!!window.ActiveXObject || "ActiveXObject" in window) ? (
(agent.match(/msie\s(\d+)/) || [])[1] || '11' //由于 ie11 并没有 msie 的标识
) : false;
}();
/**
* 获取 layui 常见方法,以便用于组件单独版
*/
lay.layui = layui || {};
lay.getPath = layui.cache.dir; //获取当前 JS 所在目录
lay.stope = layui.stope; //中止冒泡
lay.each = function(){ //遍历
layui.each.apply(layui, arguments);
return this;
};
//数字前置补零
lay.digit = function(num, length){
if(!(typeof num === 'string' || typeof num === 'number')) return '';
var str = '';
num = String(num);
length = length || 2;
for(var i = num.length; i < length; i++){
str += '0';
}
return num < Math.pow(10, length) ? str + num : num;
};
//创建元素
lay.elem = function(elemName, attr){
var elem = document.createElement(elemName);
lay.each(attr || {}, function(key, value){
elem.setAttribute(key, value);
});
return elem;
};
//当前页面是否存在滚动条
lay.hasScrollbar = function(){
return document.body.scrollHeight > (window.innerHeight || document.documentElement.clientHeight);
};
//元素定位
lay.position = function(elem, elemView, obj){
if(!elemView) return;
obj = obj || {};
//如果绑定的是 document 或 body 元素,则直接获取鼠标坐标
if(elem === document || elem === lay('body')[0]){
obj.clickType = 'right';
}
//绑定绑定元素的坐标
var rect = obj.clickType === 'right' ? function(){
var e = obj.e || window.event || {};
return {
left: e.clientX
,top: e.clientY
,right: e.clientX
,bottom: e.clientY
}
}() : elem.getBoundingClientRect()
,elemWidth = elemView.offsetWidth //控件的宽度
,elemHeight = elemView.offsetHeight //控件的高度
//滚动条高度
,scrollArea = function(type){
type = type ? 'scrollLeft' : 'scrollTop';
return document.body[type] | document.documentElement[type];
}
//窗口宽高
,winArea = function(type){
return document.documentElement[type ? 'clientWidth' : 'clientHeight']
}, margin = 5, left = rect.left, top = rect.bottom;
//相对元素居中
if(obj.align === 'center'){
left = left - (elemWidth - elem.offsetWidth)/2;
} else if(obj.align === 'right'){
left = left - elemWidth + elem.offsetWidth;
}
//判断右侧是否超出边界
if(left + elemWidth + margin > winArea('width')){
left = winArea('width') - elemWidth - margin; //如果超出右侧,则将面板向右靠齐
}
//左侧是否超出边界
if(left < margin) left = margin;
//判断底部和顶部是否超出边界
if(top + elemHeight + margin > winArea()){
//优先顶部是否有足够区域显示完全
if(rect.top > elemHeight + margin){
top = rect.top - elemHeight - margin*2; //顶部有足够的区域显示
} else {
//如果面板是鼠标右键弹出,且顶部没有足够区域显示,则将面板向底部靠齐
if(obj.clickType === 'right'){
top = winArea() - elemHeight - margin*2;
if(top < 0) top = 0; //不能溢出窗口顶部
} else {
top = margin; // 位置计算逻辑完备性处理
}
}
}
//定位类型
var position = obj.position;
if(position) elemView.style.position = position;
//设置坐标
elemView.style.left = left + (position === 'fixed' ? 0 : scrollArea(1)) + 'px';
elemView.style.top = top + (position === 'fixed' ? 0 : scrollArea()) + 'px';
//防止页面无滚动条时,又因为弹出面板而出现滚动条导致的坐标计算偏差
if(!lay.hasScrollbar()){
var rect1 = elemView.getBoundingClientRect();
//如果弹出面板的溢出窗口底部,则表示将出现滚动条,此时需要重新计算坐标
if(!obj.SYSTEM_RELOAD && (rect1.bottom + margin) > winArea()){
obj.SYSTEM_RELOAD = true;
setTimeout(function(){
lay.position(elem, elemView, obj);
}, 50);
}
}
};
// 获取元素上的属性配置项
lay.options = function(elem, opts){
opts = typeof opts === 'object' ? opts : {attr: opts};
if(elem === document) return {};
var othis = lay(elem);
var attrName = opts.attr || 'lay-options';
var attrValue = othis.attr(attrName);
try {
return new Function('return '+ (attrValue || '{}'))();
} catch(ev) {
layui.hint().error(opts.errorText || [
attrName + '="'+ attrValue + '"',
'\n parseerror: '+ ev
].join('\n'), 'error');
return {};
}
};
//元素是否属于顶级元素document 或 body
lay.isTopElem = function(elem){
var topElems = [document, lay('body')[0]]
,matched = false;
lay.each(topElems, function(index, item){
if(item === elem){
return matched = true
}
});
return matched;
};
//追加字符
LAY.addStr = function(str, new_str){
str = str.replace(/\s+/, ' ');
new_str = new_str.replace(/\s+/, ' ').split(' ');
lay.each(new_str, function(ii, item){
if(!new RegExp('\\b'+ item + '\\b').test(str)){
str = str + ' ' + item;
}
});
return str.replace(/^\s|\s$/, '');
};
//移除值
LAY.removeStr = function(str, new_str){
str = str.replace(/\s+/, ' ');
new_str = new_str.replace(/\s+/, ' ').split(' ');
lay.each(new_str, function(ii, item){
var exp = new RegExp('\\b'+ item + '\\b')
if(exp.test(str)){
str = str.replace(exp, '');
}
});
return str.replace(/\s+/, ' ').replace(/^\s|\s$/, '');
};
//查找子元素
LAY.prototype.find = function(selector){
var that = this;
var index = 0, arr = []
,isObject = typeof selector === 'object';
this.each(function(i, item){
var nativeDOM = isObject ? item.contains(selector) : item.querySelectorAll(selector || null);
for(; index < nativeDOM.length; index++){
arr.push(nativeDOM[index]);
}
that.shift();
});
if(!isObject){
that.selector = (that.selector ? that.selector + ' ' : '') + selector
}
lay.each(arr, function(i, item){
that.push(item);
});
return that;
};
//DOM遍历
LAY.prototype.each = function(fn){
return lay.each.call(this, this, fn);
};
//添加css类
LAY.prototype.addClass = function(className, type){
return this.each(function(index, item){
item.className = LAY[type ? 'removeStr' : 'addStr'](item.className, className)
});
};
//移除 css 类
LAY.prototype.removeClass = function(className){
return this.addClass(className, true);
};
//是否包含 css 类
LAY.prototype.hasClass = function(className){
var has = false;
this.each(function(index, item){
if(new RegExp('\\b'+ className +'\\b').test(item.className)){
has = true;
}
});
return has;
};
//添加或获取 css style
LAY.prototype.css = function(key, value){
var that = this
,parseValue = function(v){
return isNaN(v) ? v : (v +'px');
};
return (typeof key === 'string' && value === undefined) ? function(){
if(that.length > 0) return that[0].style[key];
}() : that.each(function(index, item){
typeof key === 'object' ? lay.each(key, function(thisKey, thisValue){
item.style[thisKey] = parseValue(thisValue);
}) : item.style[key] = parseValue(value);
});
};
//添加或获取宽度
LAY.prototype.width = function(value){
var that = this;
return value === undefined ? function(){
if(that.length > 0) return that[0].offsetWidth; //此处还需做兼容
}() : that.each(function(index, item){
that.css('width', value);
});
};
//添加或获取高度
LAY.prototype.height = function(value){
var that = this;
return value === undefined ? function(){
if(that.length > 0) return that[0].offsetHeight; //此处还需做兼容
}() : that.each(function(index, item){
that.css('height', value);
});
};
//添加或获取属性
LAY.prototype.attr = function(key, value){
var that = this;
return value === undefined ? function(){
if(that.length > 0) return that[0].getAttribute(key);
}() : that.each(function(index, item){
item.setAttribute(key, value);
});
};
//移除属性
LAY.prototype.removeAttr = function(key){
return this.each(function(index, item){
item.removeAttribute(key);
});
};
//设置或获取 HTML 内容
LAY.prototype.html = function(html){
var that = this;
return html === undefined ? function(){
if(that.length > 0) return that[0].innerHTML;
}() : this.each(function(index, item){
item.innerHTML = html;
});
};
//设置或获取值
LAY.prototype.val = function(value){
var that = this;
return value === undefined ? function(){
if(that.length > 0) return that[0].value;
}() : this.each(function(index, item){
item.value = value;
});
};
//追加内容
LAY.prototype.append = function(elem){
return this.each(function(index, item){
typeof elem === 'object'
? item.appendChild(elem)
: item.innerHTML = item.innerHTML + elem;
});
};
//移除内容
LAY.prototype.remove = function(elem){
return this.each(function(index, item){
elem ? item.removeChild(elem) : item.parentNode.removeChild(item);
});
};
//事件绑定
LAY.prototype.on = function(eventName, fn){
return this.each(function(index, item){
item.attachEvent ? item.attachEvent('on' + eventName, function(e){
e.target = e.srcElement;
fn.call(item, e);
}) : item.addEventListener(eventName, fn, false);
});
};
//解除事件
LAY.prototype.off = function(eventName, fn){
return this.each(function(index, item){
item.detachEvent
? item.detachEvent('on'+ eventName, fn)
: item.removeEventListener(eventName, fn, false);
});
};
//暴露 lay 到全局作用域
window.lay = lay;
//如果在 layui 体系中
if(window.layui && layui.define){
layui.define(function(exports){ //layui 加载
exports(MOD_NAME, lay);
});
}
}(window, window.document); //gulp build: lay-footer

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,314 @@
/**
* laypage 分页组件
*/
layui.define(function(exports){
"use strict";
var doc = document
,id = 'getElementById'
,tag = 'getElementsByTagName'
//字符常量
,MOD_NAME = 'laypage', DISABLED = 'layui-disabled'
//构造器
,Class = function(options){
var that = this;
that.config = options || {};
that.config.index = ++laypage.index;
that.render(true);
};
//判断传入的容器类型
Class.prototype.type = function(){
var config = this.config;
if(typeof config.elem === 'object'){
return config.elem.length === undefined ? 2 : 3;
}
};
// 分页视图
Class.prototype.view = function(){
var that = this;
var config = that.config;
// 连续页码个数
var groups = config.groups = 'groups' in config
? (Number(config.groups) || 0)
: 5;
// 排版
config.layout = typeof config.layout === 'object'
? config.layout
: ['prev', 'page', 'next'];
config.count = Number(config.count) || 0; // 数据总数
config.curr = Number(config.curr) || 1; // 当前页
// 每页条数的选择项
config.limits = typeof config.limits === 'object'
? config.limits
: [10, 20, 30, 40, 50];
// 默认条数
config.limit = Number(config.limit) || 10;
//总页数
config.pages = Math.ceil(config.count/config.limit) || 1;
// 当前页不能超过总页数
if(config.curr > config.pages){
config.curr = config.pages;
} else if(config.curr < 1) { // 当前分页不能小于 1
config.curr = 1;
}
//连续分页个数不能低于 0 且不能大于总页数
if(groups < 0){
groups = 1;
} else if (groups > config.pages){
groups = config.pages;
}
config.prev = 'prev' in config ? config.prev : '&#x4E0A;&#x4E00;&#x9875;'; //上一页文本
config.next = 'next' in config ? config.next : '&#x4E0B;&#x4E00;&#x9875;'; //下一页文本
//计算当前组
var index = config.pages > groups
? Math.ceil( (config.curr + (groups > 1 ? 1 : 0)) / (groups > 0 ? groups : 1) )
: 1
//视图片段
,views = {
//上一页
prev: function(){
return config.prev
? '<a class="layui-laypage-prev'+ (config.curr == 1 ? (' ' + DISABLED) : '') +'" data-page="'+ (config.curr - 1) +'">'+ config.prev +'</a>'
: '';
}()
//页码
,page: function(){
var pager = [];
//数据量为0时不输出页码
if(config.count < 1){
return '';
}
//首页
if(index > 1 && config.first !== false && groups !== 0){
pager.push('<a class="layui-laypage-first" data-page="1" title="&#x9996;&#x9875;">'+ (config.first || 1) +'</a>');
}
//计算当前页码组的起始页
var halve = Math.floor((groups-1)/2) //页码数等分
,start = index > 1 ? config.curr - halve : 1
,end = index > 1 ? (function(){
var max = config.curr + (groups - halve - 1);
return max > config.pages ? config.pages : max;
}()) : groups;
//防止最后一组出现“不规定”的连续页码数
if(end - start < groups - 1){
start = end - groups + 1;
}
//输出左分割符
if(config.first !== false && start > 2){
pager.push('<span class="layui-laypage-spr">&#x2026;</span>')
}
//输出连续页码
for(; start <= end; start++){
if(start === config.curr){
//当前页
pager.push('<span class="layui-laypage-curr"><em class="layui-laypage-em" '+ (/^#/.test(config.theme) ? 'style="background-color:'+ config.theme +';"' : '') +'></em><em>'+ start +'</em></span>');
} else {
pager.push('<a data-page="'+ start +'">'+ start +'</a>');
}
}
//输出输出右分隔符 & 末页
if(config.pages > groups && config.pages > end && config.last !== false){
if(end + 1 < config.pages){
pager.push('<span class="layui-laypage-spr">&#x2026;</span>');
}
if(groups !== 0){
pager.push('<a class="layui-laypage-last" title="&#x5C3E;&#x9875;" data-page="'+ config.pages +'">'+ (config.last || config.pages) +'</a>');
}
}
return pager.join('');
}()
//下一页
,next: function(){
return config.next
? '<a class="layui-laypage-next'+ (config.curr == config.pages ? (' ' + DISABLED) : '') +'" data-page="'+ (config.curr + 1) +'">'+ config.next +'</a>'
: '';
}()
//数据总数
,count: '<span class="layui-laypage-count">共 '+ config.count +' 条</span>'
//每页条数
,limit: function(){
var options = ['<span class="layui-laypage-limits"><select lay-ignore>'];
layui.each(config.limits, function(index, item){
options.push(
'<option value="'+ item +'"'
+(item === config.limit ? 'selected' : '')
+'>'+ item +' 条/页</option>'
);
});
return options.join('') +'</select></span>';
}()
//刷新当前页
,refresh: ['<a data-page="'+ config.curr +'" class="layui-laypage-refresh">'
,'<i class="layui-icon layui-icon-refresh"></i>'
,'</a>'].join('')
//跳页区域
,skip: function(){
return ['<span class="layui-laypage-skip">&#x5230;&#x7B2C;'
,'<input type="text" min="1" value="'+ config.curr +'" class="layui-input">'
,'&#x9875;<button type="button" class="layui-laypage-btn">&#x786e;&#x5b9a;</button>'
,'</span>'].join('');
}()
};
return ['<div class="layui-box layui-laypage layui-laypage-'+ (config.theme ? (
/^#/.test(config.theme) ? 'molv' : config.theme
) : 'default') +'" id="layui-laypage-'+ config.index +'">'
,function(){
var plate = [];
layui.each(config.layout, function(index, item){
if(views[item]){
plate.push(views[item])
}
});
return plate.join('');
}()
,'</div>'].join('');
};
//跳页的回调
Class.prototype.jump = function(elem, isskip){
if(!elem) return;
var that = this
,config = that.config
,childs = elem.children
,btn = elem[tag]('button')[0]
,input = elem[tag]('input')[0]
,select = elem[tag]('select')[0]
,skip = function(){
var curr = Number(input.value.replace(/\s|\D/g, ''));
if(curr){
config.curr = curr;
that.render();
}
};
if(isskip) return skip();
//页码
for(var i = 0, len = childs.length; i < len; i++){
if(childs[i].nodeName.toLowerCase() === 'a'){
laypage.on(childs[i], 'click', function(){
var curr = Number(this.getAttribute('data-page'));
if(curr < 1 || curr > config.pages) return;
config.curr = curr;
that.render();
});
}
}
//条数
if(select){
laypage.on(select, 'change', function(){
var value = this.value;
if(config.curr*value > config.count){
config.curr = Math.ceil(config.count/value);
}
config.limit = value;
that.render();
});
}
//确定
if(btn){
laypage.on(btn, 'click', function(){
skip();
});
}
};
//输入页数字控制
Class.prototype.skip = function(elem){
if(!elem) return;
var that = this, input = elem[tag]('input')[0];
if(!input) return;
laypage.on(input, 'keyup', function(e){
var value = this.value
,keyCode = e.keyCode;
if(/^(37|38|39|40)$/.test(keyCode)) return;
if(/\D/.test(value)){
this.value = value.replace(/\D/, '');
}
if(keyCode === 13){
that.jump(elem, true)
}
});
};
//渲染分页
Class.prototype.render = function(load){
var that = this
,config = that.config
,type = that.type()
,view = that.view();
if(type === 2){
config.elem && (config.elem.innerHTML = view);
} else if(type === 3){
config.elem.html(view);
} else {
if(doc[id](config.elem)){
doc[id](config.elem).innerHTML = view;
}
}
config.jump && config.jump(config, load);
var elem = doc[id]('layui-laypage-' + config.index);
that.jump(elem);
if(config.hash && !load){
location.hash = '!'+ config.hash +'='+ config.curr;
}
that.skip(elem);
};
//外部接口
var laypage = {
//分页渲染
render: function(options){
var o = new Class(options);
return o.index;
}
,index: layui.laypage ? (layui.laypage.index + 10000) : 0
,on: function(elem, even, fn){
elem.attachEvent ? elem.attachEvent('on'+ even, function(e){ //for ie
e.target = e.srcElement;
fn.call(elem, e);
}) : elem.addEventListener(even, fn, false);
return this;
}
}
exports(MOD_NAME, laypage);
});

View File

@@ -0,0 +1,158 @@
/**
* laytpl 轻量模板引擎
*/
layui.define(function(exports){
"use strict";
// 默认属性
var config = {
open: '{{', // 标签符前缀
close: '}}' // 标签符后缀
};
// 模板工具
var tool = {
escape: function(html){
var exp = /[<"'>]|&(?=#[a-zA-Z0-9]+)/g;
if(html === undefined || html === null) return '';
html += '';
if(!exp.test(html)) return html;
return html.replace(/&(?!#?[a-zA-Z0-9]+;)/g, '&amp;')
.replace(/</g, '&lt;').replace(/>/g, '&gt;')
.replace(/'/g, '&#39;').replace(/"/g, '&quot;');
}
};
// 内部方法
var inner = {
exp: function(str){
return new RegExp(str, 'g');
},
// 错误提示
error: function(e, source){
var error = 'Laytpl Error: ';
typeof console === 'object' && console.error(error + e + '\n'+ (source || ''));
return error + e;
}
};
// constructor
var Class = function(template, options){
var that = this;
that.config = that.config || {};
that.template = template;
// 简单属性合并
var extend = function(obj){
for(var i in obj){
that.config[i] = obj[i];
}
};
extend(config);
extend(options);
};
// 标签正则
Class.prototype.tagExp = function(type, _, __){
var options = this.config;
var types = [
'#([\\s\\S])+?', // js 语句
'([^{#}])*?' // 普通字段
][type || 0];
return inner.exp((_||'') + options.open + types + options.close + (__||''));
};
// 模版解析
Class.prototype.parse = function(template, data){
var that = this;
var options = that.config;
var source = template;
var jss = inner.exp('^'+ options.open +'#', '');
var jsse = inner.exp(options.close +'$', '');
// 模板必须为 string 类型
if(typeof template !== 'string') return template;
// 正则解析
template = template.replace(/\s+|\r|\t|\n/g, ' ')
.replace(inner.exp(options.open +'#'), options.open +'# ')
.replace(inner.exp(options.close +'}'), '} '+ options.close).replace(/\\/g, '\\\\')
// 不匹配指定区域的内容
.replace(inner.exp(options.open + '!(.+?)!' + options.close), function(str){
str = str.replace(inner.exp('^'+ options.open + '!'), '')
.replace(inner.exp('!'+ options.close), '')
.replace(inner.exp(options.open + '|' + options.close), function(tag){
return tag.replace(/(.)/g, '\\$1')
});
return str
})
// 匹配 JS 语法
.replace(/(?="|')/g, '\\').replace(that.tagExp(), function(str){
str = str.replace(jss, '').replace(jsse, '');
return '";' + str.replace(/\\(.)/g, '$1') + ';view+="';
})
// 匹配普通输出语句
.replace(that.tagExp(1), function(str){
var start = '"+laytpl.escape(';
if(str.replace(/\s/g, '') === options.open + options.close){
return '';
}
str = str.replace(inner.exp(options.open + '|' + options.close), '');
if(/^=/.test(str)){
str = str.replace(/^=/, '');
} else if(/^-/.test(str)){
str = str.replace(/^-/, '');
start = '"+(';
}
return start + str.replace(/\\(.)/g, '$1') + ')+"';
});
template = '"use strict";var view = "' + template + '";return view;';
try {
that.cache = template = new Function('d, laytpl', template);
return template(data, tool);
} catch(e) {
delete that.cache;
return inner.error(e, source);
}
};
// 数据渲染
Class.prototype.render = function(data, callback){
data = data || {};
var that = this;
var result = that.cache ? that.cache(data, tool) : that.parse(that.template, data);
// 返回渲染结果
typeof callback === 'function' && callback(result);
return result;
};
// 创建实例
var laytpl = function(template, options){
return new Class(template, options);
};
// 配置全局属性
laytpl.config = function(options){
options = options || {};
for(var i in options){
config[i] = options[i];
}
};
laytpl.v = '2.0.0';
// export
exports('laytpl', laytpl);
});

View File

@@ -0,0 +1,11 @@
/**
* 用于打包聚合版,该文件不会存在于构建后的目录
*/
layui.define(function(exports){
var cache = layui.cache;
layui.config({
dir: cache.dir.replace(/lay\/dest\/$/, '')
});
exports('layui.all', layui.v);
});

View File

@@ -0,0 +1,27 @@
/**
* layui 移动模块入口
* 构建后则为移动模块集合
*/
if(!layui['layui.mobile']){
layui.config({
base: layui.cache.dir + 'lay/modules/mobile/'
}).extend({
'layer-mobile': 'layer-mobile'
,'zepto': 'zepto'
,'upload-mobile': 'upload-mobile'
,'layim-mobile': 'layim-mobile'
});
}
layui.define([
'layer-mobile'
,'zepto'
,'layim-mobile'
], function(exports){
exports('mobile', {
layer: layui['layer-mobile'] //弹层
,layim: layui['layim-mobile'] //WebIM
});
});

View File

@@ -0,0 +1,225 @@
/**
* rate 评分评星组件
*/
layui.define(['jquery', 'lay'],function(exports){
"use strict";
var $ = layui.jquery;
var lay = layui.lay;
// 外部接口
var rate = {
config: {}
,index: layui.rate ? (layui.rate.index + 10000) : 0
//设置全局项
,set: function(options){
var that = this;
that.config = $.extend({}, that.config, options);
return that;
}
//事件
,on: function(events, callback){
return layui.onevent.call(this, MOD_NAME, events, callback);
}
}
// 操作当前实例
,thisRate = function(){
var that = this
,options = that.config;
return {
setvalue: function(value){
that.setvalue.call(that, value);
}
,config: options
}
}
//字符常量
,MOD_NAME = 'rate',ELEM_VIEW = 'layui-rate', ICON_RATE = 'layui-icon-rate', ICON_RATE_SOLID = 'layui-icon-rate-solid', ICON_RATE_HALF = 'layui-icon-rate-half'
,ICON_SOLID_HALF = 'layui-icon-rate-solid layui-icon-rate-half', ICON_SOLID_RATE = 'layui-icon-rate-solid layui-icon-rate', ICON_HALF_RATE = 'layui-icon-rate layui-icon-rate-half'
//构造器
,Class = function(options){
var that = this;
that.index = ++rate.index;
that.config = $.extend({}, that.config, rate.config, options);
that.render();
};
//默认配置
Class.prototype.config = {
length: 5 //初始长度
,text: false //是否显示评分等级
,readonly: false //是否只读
,half: false //是否可以半星
,value: 0 //星星选中个数
,theme: ''
};
//评分渲染
Class.prototype.render = function(){
var that = this;
var options = that.config;
// 若 elem 非唯一,则拆分为多个实例
var elem = $(options.elem);
if(elem.length > 1){
layui.each(elem, function(){
rate.render($.extend({}, options, {
elem: this
}));
});
return that;
}
// 合并 lay-options 属性上的配置信息
$.extend(options, lay.options(elem[0]));
// 自定义主题
var style = options.theme ? ('style="color: '+ options.theme + ';"') : '';
options.elem = $(options.elem);
//最大值不能大于总长度
if(options.value > options.length){
options.value = options.length;
}
//如果没有选择半星的属性,却给了小数的数值,统一向上或向下取整
if(parseInt(options.value) !== options.value){
if(!options.half){
options.value = (Math.ceil(options.value) - options.value) < 0.5 ? Math.ceil(options.value): Math.floor(options.value)
}
}
//组件模板
var temp = '<ul class="layui-rate" '+ (options.readonly ? 'readonly' : '') +'>';
for(var i = 1;i <= options.length;i++){
var item = '<li class="layui-inline"><i class="layui-icon '
+ (i>Math.floor(options.value)?ICON_RATE:ICON_RATE_SOLID)
+ '" '+ style +'></i></li>';
if(options.half&&parseInt(options.value) !== options.value&&i == Math.ceil(options.value)){
temp = temp + '<li><i class="layui-icon layui-icon-rate-half" '+ style +'></i></li>';
}else{
temp = temp +item;
}
}
temp += '</ul>' + (options.text ? ('<span class="layui-inline">'+ options.value + '星') : '') + '</span>';
//开始插入替代元素
var othis = options.elem
,hasRender = othis.next('.' + ELEM_VIEW);
//生成替代元素
hasRender[0] && hasRender.remove(); //如果已经渲染则Rerender
that.elemTemp = $(temp);
options.span = that.elemTemp.next('span');
options.setText && options.setText(options.value);
othis.html(that.elemTemp);
othis.addClass("layui-inline");
//如果不是只读,那么进行触控事件
if(!options.readonly) that.action();
};
//评分重置
Class.prototype.setvalue = function(value){
var that = this
,options = that.config ;
options.value = value ;
that.render();
};
//li触控事件
Class.prototype.action = function(){
var that = this
,options = that.config
,_ul = that.elemTemp
,wide = _ul.find("i").width();
_ul.children("li").each(function(index){
var ind = index + 1
,othis = $(this);
//点击
othis.on('click', function(e){
//将当前点击li的索引值赋给value
options.value = ind;
if(options.half){
//获取鼠标在li上的位置
var x = e.pageX - $(this).offset().left;
if(x <= wide / 2){
options.value = options.value - 0.5;
}
}
if(options.text) _ul.next("span").text(options.value + "星");
options.choose && options.choose(options.value);
options.setText && options.setText(options.value);
});
//移入
othis.on('mousemove', function(e){
_ul.find("i").each(function(){
$(this).addClass(ICON_RATE).removeClass(ICON_SOLID_HALF)
});
_ul.find("i:lt(" + ind + ")").each(function(){
$(this).addClass(ICON_RATE_SOLID).removeClass(ICON_HALF_RATE)
});
// 如果设置可选半星那么判断鼠标相对li的位置
if(options.half){
var x = e.pageX - $(this).offset().left;
if(x <= wide / 2){
othis.children("i").addClass(ICON_RATE_HALF).removeClass(ICON_RATE_SOLID)
}
}
})
//移出
othis.on('mouseleave', function(){
_ul.find("i").each(function(){
$(this).addClass(ICON_RATE).removeClass(ICON_SOLID_HALF)
});
_ul.find("i:lt(" + Math.floor(options.value) + ")").each(function(){
$(this).addClass(ICON_RATE_SOLID).removeClass(ICON_HALF_RATE)
});
//如果设置可选半星,根据分数判断是否有半星
if(options.half){
if(parseInt(options.value) !== options.value){
_ul.children("li:eq(" + Math.floor(options.value) + ")").children("i").addClass(ICON_RATE_HALF).removeClass(ICON_SOLID_RATE)
}
}
})
})
};
//事件处理
Class.prototype.events = function(){
var that = this
,options = that.config;
};
//核心入口
rate.render = function(options){
var inst = new Class(options);
return thisRate.call(inst);
};
exports(MOD_NAME, rate);
})

View File

@@ -0,0 +1,431 @@
/**
* slider 滑块组件
*/
layui.define(['jquery', 'lay'], function(exports){
'use strict';
var $ = layui.$;
var lay = layui.lay;
// 外部接口
var slider = {
config: {}
,index: layui.slider ? (layui.slider.index + 10000) : 0
// 设置全局项
,set: function(options){
var that = this;
that.config = $.extend({}, that.config, options);
return that;
}
// 事件
,on: function(events, callback){
return layui.onevent.call(this, MOD_NAME, events, callback);
}
};
// 操作当前实例
var thisSlider = function(){
var that = this
,options = that.config;
return {
setValue: function(value, index){ // 设置值
value = value > options.max ? options.max : value;
value = value < options.min ? options.min : value;
options.value = value;
return that.slide('set', value, index || 0);
}
,config: options
}
};
// 字符常量
var MOD_NAME = 'slider';
var DISABLED = 'layui-disabled';
var ELEM_VIEW = 'layui-slider';
var SLIDER_BAR = 'layui-slider-bar';
var SLIDER_WRAP = 'layui-slider-wrap';
var SLIDER_WRAP_BTN = 'layui-slider-wrap-btn';
var SLIDER_TIPS = 'layui-slider-tips';
var SLIDER_INPUT = 'layui-slider-input';
var SLIDER_INPUT_TXT = 'layui-slider-input-txt';
var SLIDER_INPUT_BTN = 'layui-slider-input-btn';
var ELEM_HOVER = 'layui-slider-hover';
// 构造器
var Class = function(options){
var that = this;
that.index = ++slider.index;
that.config = $.extend({}, that.config, slider.config, options);
that.render();
};
// 默认配置
Class.prototype.config = {
type: 'default' //滑块类型垂直vertical
,min: 0 //最小值
,max: 100 //最大值默认100
,value: 0 //初始值默认为0
,step: 1 //间隔值
,showstep: false //间隔点开启
,tips: true //文字提示,开启
,input: false //输入框,关闭
,range: false //范围选择,与输入框不能同时开启,默认关闭
,height: 200 //配合 type:"vertical" 使用默认200px
,disabled: false //滑块禁用,默认关闭
,theme: '#16baaa' //主题颜色
};
//滑块渲染
Class.prototype.render = function(){
var that = this;
var options = that.config;
// 若 elem 非唯一,则拆分为多个实例
var elem = $(options.elem);
if(elem.length > 1){
layui.each(elem, function(){
slider.render($.extend({}, options, {
elem: this
}));
});
return that;
}
// 合并 lay-options 属性上的配置信息
$.extend(options, lay.options(elem[0]));
//间隔值不能小于 1
if(options.step < 1) options.step = 1;
//最大值不能小于最小值
if(options.max < options.min) options.max = options.min + options.step;
//判断是否开启双滑块
if(options.range){
options.value = typeof(options.value) == 'object' ? options.value : [options.min, options.value];
var minValue = Math.min(options.value[0], options.value[1])
,maxValue = Math.max(options.value[0], options.value[1]);
options.value[0] = minValue > options.min ? minValue : options.min;
options.value[1] = maxValue > options.min ? maxValue : options.min;
options.value[0] = options.value[0] > options.max ? options.max : options.value[0];
options.value[1] = options.value[1] > options.max ? options.max : options.value[1];
var scaleFir = Math.floor((options.value[0] - options.min) / (options.max - options.min) * 100)
,scaleSec = Math.floor((options.value[1] - options.min) / (options.max - options.min) * 100)
,scale = scaleSec - scaleFir + '%';
scaleFir = scaleFir + '%';
scaleSec = scaleSec + '%';
} else {
//如果初始值是一个数组,则获取数组的最小值
if(typeof options.value == 'object'){
options.value = Math.min.apply(null, options.value);
}
//初始值不能小于最小值且不能大于最大值
if(options.value < options.min) options.value = options.min;
if(options.value > options.max) options.value = options.max;
var scale = Math.floor((options.value - options.min) / (options.max - options.min) * 100) + '%';
};
//如果禁用,颜色为统一的灰色
var theme = options.disabled ? '#c2c2c2' : options.theme;
//滑块
var temp = '<div class="layui-slider '+ (options.type === 'vertical' ? 'layui-slider-vertical' : '') +'">'+ (options.tips ? '<div class="'+ SLIDER_TIPS +'"></div>' : '') +
'<div class="layui-slider-bar" style="background:'+ theme +'; '+ (options.type === 'vertical' ? 'height' : 'width') +':'+ scale +';'+ (options.type === 'vertical' ? 'bottom' : 'left') +':'+ (scaleFir || 0) +';"></div><div class="layui-slider-wrap" style="'+ (options.type === 'vertical' ? 'bottom' : 'left') +':'+ (scaleFir || scale) +';">' +
'<div class="layui-slider-wrap-btn" style="border: 2px solid '+ theme +';"></div></div>'+ (options.range ? '<div class="layui-slider-wrap" style="'+ (options.type === 'vertical' ? 'bottom' : 'left') +':'+ scaleSec +';"><div class="layui-slider-wrap-btn" style="border: 2px solid '+ theme +';"></div></div>' : '') +'</div>';
var othis = $(options.elem)
,hasRender = othis.next('.' + ELEM_VIEW);
//生成替代元素
hasRender[0] && hasRender.remove(); //如果已经渲染则Rerender
that.elemTemp = $(temp);
//把数据缓存到滑块上
if(options.range){
that.elemTemp.find('.' + SLIDER_WRAP).eq(0).data('value', options.value[0]);
that.elemTemp.find('.' + SLIDER_WRAP).eq(1).data('value', options.value[1]);
}else{
that.elemTemp.find('.' + SLIDER_WRAP).data('value', options.value);
};
//插入替代元素
othis.html(that.elemTemp);
//垂直滑块
if(options.type === 'vertical'){
that.elemTemp.height(options.height + 'px');
};
//显示间断点
if(options.showstep){
var number = (options.max - options.min) / options.step, item = '';
for(var i = 1; i < number + 1; i++) {
var step = i * 100 / number;
if(step < 100){
item += '<div class="layui-slider-step" style="'+ (options.type === 'vertical' ? 'bottom' : 'left') +':'+ step +'%"></div>'
}
};
that.elemTemp.append(item);
};
//插入输入框
if(options.input && !options.range){
var elemInput = $('<div class="layui-slider-input layui-input"><div class="layui-slider-input-txt"><input type="text" class="layui-input"></div><div class="layui-slider-input-btn"><i class="layui-icon layui-icon-up"></i><i class="layui-icon layui-icon-down"></i></div></div>');
othis.css("position","relative");
othis.append(elemInput);
othis.find('.' + SLIDER_INPUT_TXT).children('input').val(options.value);
if(options.type === 'vertical'){
elemInput.css({
left: 0
,top: -48
});
} else {
that.elemTemp.css("margin-right", elemInput.outerWidth() + 15);
}
};
//给未禁止的滑块滑动事件
if(!options.disabled){
that.slide();
}else{
that.elemTemp.addClass(DISABLED);
that.elemTemp.find('.' + SLIDER_WRAP_BTN).addClass(DISABLED);
};
//划过滑块显示数值
var timer;
that.elemTemp.find('.' + SLIDER_WRAP_BTN).on('mouseover', function(){
var sliderWidth = options.type === 'vertical' ? options.height : that.elemTemp[0].offsetWidth
,sliderWrap = that.elemTemp.find('.' + SLIDER_WRAP)
,tipsLeft = options.type === 'vertical' ? (sliderWidth - $(this).parent()[0].offsetTop - sliderWrap.height()) : $(this).parent()[0].offsetLeft
,left = tipsLeft / sliderWidth * 100
,value = $(this).parent().data('value')
,tipsTxt = options.setTips ? options.setTips(value) : value;
that.elemTemp.find('.' + SLIDER_TIPS).html(tipsTxt);
clearTimeout(timer);
timer = setTimeout(function(){
if(options.type === 'vertical'){
that.elemTemp.find('.' + SLIDER_TIPS).css({
"bottom": left + '%',
"margin-bottom": "20px",
"display": "inline-block"
});
} else {
that.elemTemp.find('.' + SLIDER_TIPS).css({
"left": left + '%',
"display": "inline-block"
});
};
}, 300);
}).on('mouseout', function(){
clearTimeout(timer);
that.elemTemp.find('.' + SLIDER_TIPS).css("display", "none");
});
};
//滑块滑动
Class.prototype.slide = function(setValue, value, i){
var that = this
,options = that.config
,sliderAct = that.elemTemp
,sliderWidth = function(){
return options.type === 'vertical' ? options.height : sliderAct[0].offsetWidth
}
,sliderWrap = sliderAct.find('.' + SLIDER_WRAP)
,sliderTxt = sliderAct.next('.' + SLIDER_INPUT)
,inputValue = sliderTxt.children('.' + SLIDER_INPUT_TXT).children('input').val()
,step = 100 / ((options.max - options.min) / Math.ceil(options.step))
,change = function(offsetValue, index, from){
if(Math.ceil(offsetValue) * step > 100){
offsetValue = Math.ceil(offsetValue) * step
}else{
offsetValue = Math.round(offsetValue) * step
};
offsetValue = offsetValue > 100 ? 100: offsetValue;
offsetValue = offsetValue < 0 ? 0: offsetValue;
sliderWrap.eq(index).css((options.type === 'vertical' ?'bottom':'left'), offsetValue + '%');
var firLeft = valueTo(sliderWrap[0].offsetLeft)
,secLeft = options.range ? valueTo(sliderWrap[1].offsetLeft) : 0;
if(options.type === 'vertical'){
sliderAct.find('.' + SLIDER_TIPS).css({"bottom":offsetValue + '%', "margin-bottom":"20px"});
firLeft = valueTo(sliderWidth() - sliderWrap[0].offsetTop - sliderWrap.height());
secLeft = options.range ? valueTo(sliderWidth() - sliderWrap[1].offsetTop - sliderWrap.height()) : 0;
}else{
sliderAct.find('.' + SLIDER_TIPS).css("left",offsetValue + '%');
};
firLeft = firLeft > 100 ? 100: firLeft;
secLeft = secLeft > 100 ? 100: secLeft;
var minLeft = Math.min(firLeft, secLeft)
,wrapWidth = Math.abs(firLeft - secLeft);
if(options.type === 'vertical'){
sliderAct.find('.' + SLIDER_BAR).css({"height":wrapWidth + '%', "bottom":minLeft + '%'});
}else{
sliderAct.find('.' + SLIDER_BAR).css({"width":wrapWidth + '%', "left":minLeft + '%'});
};
var selfValue = options.min + Math.round((options.max - options.min) * offsetValue / 100);
inputValue = selfValue;
sliderTxt.children('.' + SLIDER_INPUT_TXT).children('input').val(inputValue);
sliderWrap.eq(index).data('value', selfValue);
sliderAct.find('.' + SLIDER_TIPS).html(options.setTips ? options.setTips(selfValue) : selfValue);
//如果开启范围选择,则返回数组值
if(options.range){
var arrValue = [
sliderWrap.eq(0).data('value')
,sliderWrap.eq(1).data('value')
];
if(arrValue[0] > arrValue[1]) arrValue.reverse(); //如果前面的圆点超过了后面的圆点值,则调换顺序
}
that.value = options.range ? arrValue : selfValue; // 最新值
options.change && options.change(that.value); // change 回调
// 值完成选中的事件
if(from === 'done') options.done && options.done(that.value);
}
,valueTo = function(value){
var oldLeft = value / sliderWidth() * 100 / step
,left = Math.round(oldLeft) * step;
if(value == sliderWidth()){
left = Math.ceil(oldLeft) * step;
};
return left;
}
//拖拽元素
,elemMove = $(['<div class="layui-auxiliar-moving" id="LAY-slider-moving"></div'].join(''))
,createMoveElem = function(move, up){
var upCall = function(){
up && up();
elemMove.remove();
options.done && options.done(that.value);
};
$('#LAY-slider-moving')[0] || $('body').append(elemMove);
elemMove.on('mousemove', move);
elemMove.on('mouseup', upCall).on('mouseleave', upCall);
};
//动态赋值
if(setValue === 'set') return change(value - options.min, i, 'done');
//滑块滑动
sliderAct.find('.' + SLIDER_WRAP_BTN).each(function(index){
var othis = $(this);
othis.on('mousedown', function(e){
e = e || window.event;
var oldleft = othis.parent()[0].offsetLeft
,oldx = e.clientX;
if(options.type === 'vertical'){
oldleft = sliderWidth() - othis.parent()[0].offsetTop - sliderWrap.height()
oldx = e.clientY;
};
var move = function(e){
e = e || window.event;
var left = oldleft + (options.type === 'vertical' ? (oldx - e.clientY) : (e.clientX - oldx));
if(left < 0)left = 0;
if(left > sliderWidth())left = sliderWidth();
var reaLeft = left / sliderWidth() * 100 / step;
change(reaLeft, index);
othis.addClass(ELEM_HOVER);
sliderAct.find('.' + SLIDER_TIPS).show();
e.preventDefault();
};
var up = function(){
othis.removeClass(ELEM_HOVER);
sliderAct.find('.' + SLIDER_TIPS).hide();
};
createMoveElem(move, up)
});
});
// 点击滑块
sliderAct.on('click', function(e){
var main = $('.' + SLIDER_WRAP_BTN);
var othis = $(this);
if(!main.is(event.target) && main.has(event.target).length === 0 && main.length){
var index;
var offset = options.type === 'vertical'
? (sliderWidth() - e.clientY + othis.offset().top - $(window).scrollTop())
:(e.clientX - othis.offset().left - $(window).scrollLeft());
if(offset < 0)offset = 0;
if(offset > sliderWidth()) offset = sliderWidth();
var reaLeft = offset / sliderWidth() * 100 / step;
if(options.range){
if(options.type === 'vertical'){
index = Math.abs(offset - parseInt($(sliderWrap[0]).css('bottom'))) > Math.abs(offset - parseInt($(sliderWrap[1]).css('bottom'))) ? 1 : 0;
} else {
index = Math.abs(offset - sliderWrap[0].offsetLeft) > Math.abs(offset - sliderWrap[1].offsetLeft) ? 1 : 0;
}
} else {
index = 0;
};
change(reaLeft, index, 'done');
e.preventDefault();
}
});
//点击加减输入框
sliderTxt.children('.' + SLIDER_INPUT_BTN).children('i').each(function(index){
$(this).on('click', function(){
inputValue = sliderTxt.children('.' + SLIDER_INPUT_TXT).children('input').val();
if(index == 1){ //减
inputValue = inputValue - options.step < options.min
? options.min
: Number(inputValue) - options.step;
}else{
inputValue = Number(inputValue) + options.step > options.max
? options.max
: Number(inputValue) + options.step;
};
var inputScale = (inputValue - options.min) / (options.max - options.min) * 100 / step;
change(inputScale, 0, 'done');
});
});
//获取输入框值
var getInputValue = function(){
var realValue = this.value;
realValue = isNaN(realValue) ? 0 : realValue;
realValue = realValue < options.min ? options.min : realValue;
realValue = realValue > options.max ? options.max : realValue;
this.value = realValue;
var inputScale = (realValue - options.min) / (options.max - options.min) * 100 / step;
change(inputScale, 0, 'done');
};
sliderTxt.children('.' + SLIDER_INPUT_TXT).children('input').on('keydown', function(e){
if(e.keyCode === 13){
e.preventDefault();
getInputValue.call(this);
}
}).on('change', getInputValue);
};
//事件处理
Class.prototype.events = function(){
var that = this
,options = that.config;
};
//核心入口
slider.render = function(options){
var inst = new Class(options);
return thisSlider.call(inst);
};
exports(MOD_NAME, slider);
})

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,487 @@
/**
* transfer 穿梭框组件
*/
layui.define(['laytpl', 'form'], function(exports){
"use strict";
var $ = layui.$
,laytpl = layui.laytpl
,form = layui.form
//模块名
,MOD_NAME = 'transfer'
//外部接口
,transfer = {
config: {}
,index: layui[MOD_NAME] ? (layui[MOD_NAME].index + 10000) : 0
//设置全局项
,set: function(options){
var that = this;
that.config = $.extend({}, that.config, options);
return that;
}
//事件
,on: function(events, callback){
return layui.onevent.call(this, MOD_NAME, events, callback);
}
}
//操作当前实例
,thisModule = function(){
var that = this
,options = that.config
,id = options.id || that.index;
thisModule.that[id] = that; //记录当前实例对象
thisModule.config[id] = options; //记录当前实例配置项
return {
config: options
//重置实例
,reload: function(options){
that.reload.call(that, options);
}
//获取右侧数据
,getData: function(){
return that.getData.call(that);
}
}
}
//获取当前实例配置项
,getThisModuleConfig = function(id){
var config = thisModule.config[id];
if(!config) hint.error('The ID option was not found in the '+ MOD_NAME +' instance');
return config || null;
}
//字符常量
,ELEM = 'layui-transfer', HIDE = 'layui-hide', DISABLED = 'layui-btn-disabled', NONE = 'layui-none'
,ELEM_BOX = 'layui-transfer-box', ELEM_HEADER = 'layui-transfer-header', ELEM_SEARCH = 'layui-transfer-search', ELEM_ACTIVE = 'layui-transfer-active', ELEM_DATA = 'layui-transfer-data'
//穿梭框模板
,TPL_BOX = function(obj){
obj = obj || {};
return ['<div class="layui-transfer-box" data-index="'+ obj.index +'">'
,'<div class="layui-transfer-header">'
,'<input type="checkbox" name="'+ obj.checkAllName +'" lay-filter="layTransferCheckbox" lay-type="all" lay-skin="primary" title="{{ d.data.title['+ obj.index +'] || \'list'+ (obj.index + 1) +'\' }}">'
,'</div>'
,'{{# if(d.data.showSearch){ }}'
,'<div class="layui-transfer-search">'
,'<i class="layui-icon layui-icon-search"></i>'
,'<input type="text" class="layui-input" placeholder="关键词搜索">'
,'</div>'
,'{{# } }}'
,'<ul class="layui-transfer-data"></ul>'
,'</div>'].join('');
}
//主模板
,TPL_MAIN = ['<div class="layui-transfer layui-form layui-border-box" lay-filter="LAY-transfer-{{ d.index }}">'
,TPL_BOX({
index: 0
,checkAllName: 'layTransferLeftCheckAll'
})
,'<div class="layui-transfer-active">'
,'<button type="button" class="layui-btn layui-btn-sm layui-btn-primary layui-btn-disabled" data-index="0">'
,'<i class="layui-icon layui-icon-next"></i>'
,'</button>'
,'<button type="button" class="layui-btn layui-btn-sm layui-btn-primary layui-btn-disabled" data-index="1">'
,'<i class="layui-icon layui-icon-prev"></i>'
,'</button>'
,'</div>'
,TPL_BOX({
index: 1
,checkAllName: 'layTransferRightCheckAll'
})
,'</div>'].join('')
//构造器
,Class = function(options){
var that = this;
that.index = ++transfer.index;
that.config = $.extend({}, that.config, transfer.config, options);
that.render();
};
//默认配置
Class.prototype.config = {
title: ['列表一', '列表二']
,width: 200
,height: 360
,data: [] //数据源
,value: [] //选中的数据
,showSearch: false //是否开启搜索
,id: '' //唯一索引,默认自增 index
,text: {
none: '无数据'
,searchNone: '无匹配数据'
}
};
//重载实例
Class.prototype.reload = function(options){
var that = this;
that.config = $.extend({}, that.config, options);
that.render();
};
//渲染
Class.prototype.render = function(){
var that = this
,options = that.config;
//解析模板
var thisElem = that.elem = $(laytpl(TPL_MAIN).render({
data: options
,index: that.index //索引
}));
var othis = options.elem = $(options.elem);
if(!othis[0]) return;
//初始化属性
options.data = options.data || [];
options.value = options.value || [];
// 初始化 id 属性 - 优先取 options > 元素 id > 自增索引
options.id = 'id' in options ? options.id : (
elem.attr('id') || that.index
);
that.key = options.id;
//插入组件结构
othis.html(that.elem);
//各级容器
that.layBox = that.elem.find('.'+ ELEM_BOX)
that.layHeader = that.elem.find('.'+ ELEM_HEADER)
that.laySearch = that.elem.find('.'+ ELEM_SEARCH)
that.layData = thisElem.find('.'+ ELEM_DATA);
that.layBtn = thisElem.find('.'+ ELEM_ACTIVE + ' .layui-btn');
//初始化尺寸
that.layBox.css({
width: options.width
,height: options.height
});
that.layData.css({
height: function(){
var height = options.height - that.layHeader.outerHeight();
if(options.showSearch){
height -= that.laySearch.outerHeight();
}
return height - 2;
}()
});
that.renderData(); //渲染数据
that.events(); //事件
};
//渲染数据
Class.prototype.renderData = function(){
var that = this
,options = that.config;
//左右穿梭框差异数据
var arr = [{
checkName: 'layTransferLeftCheck'
,views: []
}, {
checkName: 'layTransferRightCheck'
,views: []
}];
//解析格式
that.parseData(function(item){
//标注为 selected 的为右边的数据
var _index = item.selected ? 1 : 0
,listElem = ['<li>'
,'<input type="checkbox" name="'+ arr[_index].checkName +'" lay-skin="primary" lay-filter="layTransferCheckbox" title="'+ item.title +'"'+ (item.disabled ? ' disabled' : '') + (item.checked ? ' checked' : '') +' value="'+ item.value +'">'
,'</li>'].join('');
arr[_index].views.push(listElem);
delete item.selected;
});
that.layData.eq(0).html(arr[0].views.join(''));
that.layData.eq(1).html(arr[1].views.join(''));
that.renderCheckBtn();
}
//渲染表单
Class.prototype.renderForm = function(type){
form.render(type, 'LAY-transfer-'+ this.index);
};
//同步复选框和按钮状态
Class.prototype.renderCheckBtn = function(obj){
var that = this
,options = that.config;
obj = obj || {};
that.layBox.each(function(_index){
var othis = $(this)
,thisDataElem = othis.find('.'+ ELEM_DATA)
,allElemCheckbox = othis.find('.'+ ELEM_HEADER).find('input[type="checkbox"]')
,listElemCheckbox = thisDataElem.find('input[type="checkbox"]');
//同步复选框和按钮状态
var nums = 0
,haveChecked = false;
listElemCheckbox.each(function(){
var isHide = $(this).data('hide');
if(this.checked || this.disabled || isHide){
nums++;
}
if(this.checked && !isHide){
haveChecked = true;
}
});
allElemCheckbox.prop('checked', haveChecked && nums === listElemCheckbox.length); //全选复选框状态
that.layBtn.eq(_index)[haveChecked ? 'removeClass' : 'addClass'](DISABLED); //对应的按钮状态
//无数据视图
if(!obj.stopNone){
var isNone = thisDataElem.children('li:not(.'+ HIDE +')').length
that.noneView(thisDataElem, isNone ? '' : options.text.none);
}
});
that.renderForm('checkbox');
};
//无数据视图
Class.prototype.noneView = function(thisDataElem, text){
var createNoneElem = $('<p class="layui-none">'+ (text || '') +'</p>');
if(thisDataElem.find('.'+ NONE)[0]){
thisDataElem.find('.'+ NONE).remove();
}
text.replace(/\s/g, '') && thisDataElem.append(createNoneElem);
};
//同步 value 属性值
Class.prototype.setValue = function(){
var that = this
,options = that.config
,arr = [];
that.layBox.eq(1).find('.'+ ELEM_DATA +' input[type="checkbox"]').each(function(){
var isHide = $(this).data('hide');
isHide || arr.push(this.value);
});
options.value = arr;
return that;
};
//解析数据
Class.prototype.parseData = function(callback){
var that = this
,options = that.config
,newData = [];
layui.each(options.data, function(index, item){
//解析格式
item = (typeof options.parseData === 'function'
? options.parseData(item)
: item) || item;
newData.push(item = $.extend({}, item))
layui.each(options.value, function(index2, item2){
if(item2 == item.value){
item.selected = true;
}
});
callback && callback(item);
});
options.data = newData;
return that;
};
//获得右侧面板数据
Class.prototype.getData = function(value){
var that = this
,options = that.config
,selectedData = [];
that.setValue();
layui.each(value || options.value, function(index, item){
layui.each(options.data, function(index2, item2){
delete item2.selected;
if(item == item2.value){
selectedData.push(item2);
};
});
});
return selectedData;
};
//执行穿梭
Class.prototype.transfer = function (_index, elem) {
var that = this
,options = that.config
,thisBoxElem = that.layBox.eq(_index)
,arr = []
if (!elem) {
//通过按钮触发找到选中的进行移动
thisBoxElem.each(function(_index){
var othis = $(this)
,thisDataElem = othis.find('.'+ ELEM_DATA);
thisDataElem.children('li').each(function(){
var thisList = $(this)
,thisElemCheckbox = thisList.find('input[type="checkbox"]')
,isHide = thisElemCheckbox.data('hide');
if(thisElemCheckbox[0].checked && !isHide){
thisElemCheckbox[0].checked = false;
thisBoxElem.siblings('.'+ ELEM_BOX).find('.'+ ELEM_DATA).append(thisList.clone());
thisList.remove();
//记录当前穿梭的数据
arr.push(thisElemCheckbox[0].value);
}
that.setValue();
});
});
} else {
//双击单条记录移动
var thisList = elem
,thisElemCheckbox = thisList.find('input[type="checkbox"]')
thisElemCheckbox[0].checked = false;
thisBoxElem.siblings('.'+ ELEM_BOX).find('.'+ ELEM_DATA).append(thisList.clone());
thisList.remove();
//记录当前穿梭的数据
arr.push(thisElemCheckbox[0].value);
that.setValue();
}
that.renderCheckBtn();
//穿梭时,如果另外一个框正在搜索,则触发匹配
var siblingInput = thisBoxElem.siblings('.'+ ELEM_BOX).find('.'+ ELEM_SEARCH +' input')
siblingInput.val() === '' || siblingInput.trigger('keyup');
//穿梭时的回调
options.onchange && options.onchange(that.getData(arr), _index);
}
//事件
Class.prototype.events = function(){
var that = this
,options = that.config;
//左右复选框
that.elem.on('click', 'input[lay-filter="layTransferCheckbox"]+', function(){
var thisElemCheckbox = $(this).prev()
,checked = thisElemCheckbox[0].checked
,thisDataElem = thisElemCheckbox.parents('.'+ ELEM_BOX).eq(0).find('.'+ ELEM_DATA);
if(thisElemCheckbox[0].disabled) return;
//判断是否全选
if(thisElemCheckbox.attr('lay-type') === 'all'){
thisDataElem.find('input[type="checkbox"]').each(function(){
if(this.disabled) return;
this.checked = checked;
});
}
setTimeout(function () {
that.renderCheckBtn({stopNone: true});
}, 0)
});
// 双击穿梭
that.elem.on('dblclick', '.' + ELEM_DATA + '>li', function(event){
var elemThis = $(this)
,thisElemCheckbox = elemThis.children('input[type="checkbox"]')
,thisDataElem = elemThis.parent()
,thisBoxElem = thisDataElem.parent()
if(thisElemCheckbox[0].disabled) return;
that.transfer(thisBoxElem.data('index'), elemThis);
})
// 穿梭按钮事件
that.layBtn.on('click', function(){
var othis = $(this)
,_index = othis.data('index')
if(othis.hasClass(DISABLED)) return;
that.transfer(_index);
});
//搜索
that.laySearch.find('input').on('keyup', function(){
var value = this.value;
var thisDataElem = $(this).parents('.'+ ELEM_SEARCH).eq(0).siblings('.'+ ELEM_DATA);
var thisListElem = thisDataElem.children('li');
thisListElem.each(function(){
var thisList = $(this);
var thisElemCheckbox = thisList.find('input[type="checkbox"]');
var title = thisElemCheckbox[0].title;
// 是否区分大小写
if(options.showSearch !== 'cs'){
title = title.toLowerCase();
value = value.toLowerCase();
}
var isMatch = title.indexOf(value) !== -1;
thisList[isMatch ? 'removeClass': 'addClass'](HIDE);
thisElemCheckbox.data('hide', isMatch ? false : true);
});
that.renderCheckBtn();
//无匹配数据视图
var isNone = thisListElem.length === thisDataElem.children('li.'+ HIDE).length;
that.noneView(thisDataElem, isNone ? options.text.searchNone : '');
});
};
//记录所有实例
thisModule.that = {}; //记录所有实例对象
thisModule.config = {}; //记录所有实例配置项
//重载实例
transfer.reload = function(id, options){
var that = thisModule.that[id];
that.reload(options);
return thisModule.call(that);
};
//获得选中的数据(右侧面板)
transfer.getData = function(id){
var that = thisModule.that[id];
return that.getData();
};
//核心入口
transfer.render = function(options){
var inst = new Class(options);
return thisModule.call(inst);
};
exports(MOD_NAME, transfer);
});

View File

@@ -0,0 +1,813 @@
/**
* tree 树组件
*/
layui.define('form', function(exports){
"use strict";
var $ = layui.$
,form = layui.form
,layer = layui.layer
//模块名
,MOD_NAME = 'tree'
//外部接口
,tree = {
config: {}
,index: layui[MOD_NAME] ? (layui[MOD_NAME].index + 10000) : 0
//设置全局项
,set: function(options){
var that = this;
that.config = $.extend({}, that.config, options);
return that;
}
//事件
,on: function(events, callback){
return layui.onevent.call(this, MOD_NAME, events, callback);
}
}
//操作当前实例
,thisModule = function(){
var that = this
,options = that.config
,id = options.id || that.index;
thisModule.that[id] = that; //记录当前实例对象
thisModule.config[id] = options; //记录当前实例配置项
return {
config: options
//重置实例
,reload: function(options){
that.reload.call(that, options);
}
,getChecked: function(){
return that.getChecked.call(that);
}
,setChecked: function(id){//设置值
return that.setChecked.call(that, id);
}
}
}
//获取当前实例配置项
,getThisModuleConfig = function(id){
var config = thisModule.config[id];
if(!config) hint.error('The ID option was not found in the '+ MOD_NAME +' instance');
return config || null;
}
//字符常量
,SHOW = 'layui-show', HIDE = 'layui-hide', NONE = 'layui-none', DISABLED = 'layui-disabled'
,ELEM_VIEW = 'layui-tree', ELEM_SET = 'layui-tree-set', ICON_CLICK = 'layui-tree-iconClick'
,ICON_ADD = 'layui-icon-addition', ICON_SUB = 'layui-icon-subtraction', ELEM_ENTRY = 'layui-tree-entry', ELEM_MAIN = 'layui-tree-main', ELEM_TEXT = 'layui-tree-txt', ELEM_PACK = 'layui-tree-pack', ELEM_SPREAD = 'layui-tree-spread'
,ELEM_LINE_SHORT = 'layui-tree-setLineShort', ELEM_SHOW = 'layui-tree-showLine', ELEM_EXTEND = 'layui-tree-lineExtend'
//构造器
,Class = function(options){
var that = this;
that.index = ++tree.index;
that.config = $.extend({}, that.config, tree.config, options);
that.render();
};
//默认配置
Class.prototype.config = {
data: [] //数据
,showCheckbox: false //是否显示复选框
,showLine: true //是否开启连接线
,accordion: false //是否开启手风琴模式
,onlyIconControl: false //是否仅允许节点左侧图标控制展开收缩
,isJump: false //是否允许点击节点时弹出新窗口跳转
,edit: false //是否开启节点的操作图标
,text: {
defaultNodeName: '未命名' //节点默认名称
,none: '无数据' //数据为空时的文本提示
}
};
//重载实例
Class.prototype.reload = function(options){
var that = this;
layui.each(options, function(key, item){
if(layui.type(item) === 'array') delete that.config[key];
});
that.config = $.extend(true, {}, that.config, options);
that.render();
};
//主体渲染
Class.prototype.render = function(){
var that = this
,options = that.config;
that.checkids = [];
var temp = $('<div class="layui-tree'+ (options.showCheckbox ? " layui-form" : "") + (options.showLine ? " layui-tree-line" : "") +'" lay-filter="LAY-tree-'+ that.index +'"></div>');
that.tree(temp);
var othis = options.elem = $(options.elem);
if(!othis[0]) return;
//索引
that.key = options.id || that.index;
//插入组件结构
that.elem = temp;
that.elemNone = $('<div class="layui-tree-emptyText">'+ options.text.none +'</div>');
othis.html(that.elem);
if(that.elem.find('.layui-tree-set').length == 0){
return that.elem.append(that.elemNone);
};
//复选框渲染
if(options.showCheckbox){
that.renderForm('checkbox');
};
that.elem.find('.layui-tree-set').each(function(){
var othis = $(this);
//最外层
if(!othis.parent('.layui-tree-pack')[0]){
othis.addClass('layui-tree-setHide');
};
//没有下一个节点 上一层父级有延伸线
if(!othis.next()[0] && othis.parents('.layui-tree-pack').eq(1).hasClass('layui-tree-lineExtend')){
othis.addClass(ELEM_LINE_SHORT);
};
//没有下一个节点 外层最后一个
if(!othis.next()[0] && !othis.parents('.layui-tree-set').eq(0).next()[0]){
othis.addClass(ELEM_LINE_SHORT);
};
});
that.events();
};
//渲染表单
Class.prototype.renderForm = function(type){
form.render(type, 'LAY-tree-'+ this.index);
};
//节点解析
Class.prototype.tree = function(elem, children){
var that = this
,options = that.config
,data = children || options.data;
//遍历数据
layui.each(data, function(index, item){
var hasChild = item.children && item.children.length > 0
,packDiv = $('<div class="layui-tree-pack" '+ (item.spread ? 'style="display: block;"' : '') +'></div>')
,entryDiv = $(['<div data-id="'+ item.id +'" class="layui-tree-set'+ (item.spread ? " layui-tree-spread" : "") + (item.checked ? " layui-tree-checkedFirst" : "") +'">'
,'<div class="layui-tree-entry">'
,'<div class="layui-tree-main">'
//箭头
,function(){
if(options.showLine){
if(hasChild){
return '<span class="layui-tree-iconClick layui-tree-icon"><i class="layui-icon '+ (item.spread ? "layui-icon-subtraction" : "layui-icon-addition") +'"></i></span>';
}else{
return '<span class="layui-tree-iconClick"><i class="layui-icon layui-icon-file"></i></span>';
};
}else{
return '<span class="layui-tree-iconClick"><i class="layui-tree-iconArrow '+ (hasChild ? "": HIDE) +'"></i></span>';
};
}()
//复选框
,function(){
return options.showCheckbox ? '<input type="checkbox" name="'+ (item.field || ('layuiTreeCheck_'+ item.id)) +'" same="layuiTreeCheck" lay-skin="primary" '+ (item.disabled ? "disabled" : "") +' value="'+ item.id +'">' : '';
}()
//节点
,function(){
if(options.isJump && item.href){
return '<a href="'+ item.href +'" target="_blank" class="'+ ELEM_TEXT +'">'+ (item.title || item.label || options.text.defaultNodeName) +'</a>';
}else{
return '<span class="'+ ELEM_TEXT + (item.disabled ? ' '+ DISABLED : '') +'">'+ (item.title || item.label || options.text.defaultNodeName) +'</span>';
}
}()
,'</div>'
//节点操作图标
,function(){
if(!options.edit) return '';
var editIcon = {
add: '<i class="layui-icon layui-icon-add-1" data-type="add"></i>'
,update: '<i class="layui-icon layui-icon-edit" data-type="update"></i>'
,del: '<i class="layui-icon layui-icon-delete" data-type="del"></i>'
}, arr = ['<div class="layui-btn-group layui-tree-btnGroup">'];
if(options.edit === true){
options.edit = ['update', 'del']
}
if(typeof options.edit === 'object'){
layui.each(options.edit, function(i, val){
arr.push(editIcon[val] || '')
});
return arr.join('') + '</div>';
}
}()
,'</div></div>'].join(''));
//如果有子节点,则递归继续生成树
if(hasChild){
entryDiv.append(packDiv);
that.tree(packDiv, item.children);
};
elem.append(entryDiv);
//若有前置节点,前置节点加连接线
if(entryDiv.prev('.'+ELEM_SET)[0]){
entryDiv.prev().children('.layui-tree-pack').addClass('layui-tree-showLine');
};
//若无子节点,则父节点加延伸线
if(!hasChild){
entryDiv.parent('.layui-tree-pack').addClass('layui-tree-lineExtend');
};
//展开节点操作
that.spread(entryDiv, item);
//选择框
if(options.showCheckbox){
item.checked && that.checkids.push(item.id);
that.checkClick(entryDiv, item);
}
//操作节点
options.edit && that.operate(entryDiv, item);
});
};
//展开节点
Class.prototype.spread = function(elem, item){
var that = this
,options = that.config
,entry = elem.children('.'+ELEM_ENTRY)
,elemMain = entry.children('.'+ ELEM_MAIN)
,elemIcon = entry.find('.'+ ICON_CLICK)
,elemText = entry.find('.'+ ELEM_TEXT)
,touchOpen = options.onlyIconControl ? elemIcon : elemMain //判断展开通过节点还是箭头图标
,state = '';
//展开收缩
touchOpen.on('click', function(e){
var packCont = elem.children('.'+ELEM_PACK)
,iconClick = touchOpen.children('.layui-icon')[0] ? touchOpen.children('.layui-icon') : touchOpen.find('.layui-tree-icon').children('.layui-icon');
//若没有子节点
if(!packCont[0]){
state = 'normal';
}else{
if(elem.hasClass(ELEM_SPREAD)){
elem.removeClass(ELEM_SPREAD);
packCont.slideUp(200);
iconClick.removeClass(ICON_SUB).addClass(ICON_ADD);
}else{
elem.addClass(ELEM_SPREAD);
packCont.slideDown(200);
iconClick.addClass(ICON_SUB).removeClass(ICON_ADD);
//是否手风琴
if(options.accordion){
var sibls = elem.siblings('.'+ELEM_SET);
sibls.removeClass(ELEM_SPREAD);
sibls.children('.'+ELEM_PACK).slideUp(200);
sibls.find('.layui-tree-icon').children('.layui-icon').removeClass(ICON_SUB).addClass(ICON_ADD);
};
};
};
});
//点击回调
elemText.on('click', function(){
var othis = $(this);
//判断是否禁用状态
if(othis.hasClass(DISABLED)) return;
//判断展开收缩状态
if(elem.hasClass(ELEM_SPREAD)){
state = options.onlyIconControl ? 'open' : 'close';
} else {
state = options.onlyIconControl ? 'close' : 'open';
}
//点击产生的回调
options.click && options.click({
elem: elem
,state: state
,data: item
});
});
};
//计算复选框选中状态
Class.prototype.setCheckbox = function(elem, item, elemCheckbox){
var that = this
,options = that.config
,checked = elemCheckbox.prop('checked');
if(elemCheckbox.prop('disabled')) return;
//同步子节点选中状态
if(typeof item.children === 'object' || elem.find('.'+ELEM_PACK)[0]){
var childs = elem.find('.'+ ELEM_PACK).find('input[same="layuiTreeCheck"]');
childs.each(function(){
if(this.disabled) return; //不可点击则跳过
this.checked = checked;
});
};
//同步父节点选中状态
var setParentsChecked = function(thisNodeElem){
//若无父节点,则终止递归
if(!thisNodeElem.parents('.'+ ELEM_SET)[0]) return;
var state
,parentPack = thisNodeElem.parent('.'+ ELEM_PACK)
,parentNodeElem = parentPack.parent()
,parentCheckbox = parentPack.prev().find('input[same="layuiTreeCheck"]');
//如果子节点有任意一条选中,则父节点为选中状态
if(checked){
parentCheckbox.prop('checked', checked);
} else { //如果当前节点取消选中,则根据计算“兄弟和子孙”节点选中状态,来同步父节点选中状态
parentPack.find('input[same="layuiTreeCheck"]').each(function(){
if(this.checked){
state = true;
}
});
//如果兄弟子孙节点全部未选中,则父节点也应为非选中状态
state || parentCheckbox.prop('checked', false);
}
//向父节点递归
setParentsChecked(parentNodeElem);
};
setParentsChecked(elem);
that.renderForm('checkbox');
};
//复选框选择
Class.prototype.checkClick = function(elem, item){
var that = this
,options = that.config
,entry = elem.children('.'+ ELEM_ENTRY)
,elemMain = entry.children('.'+ ELEM_MAIN);
//点击复选框
elemMain.on('click', 'input[same="layuiTreeCheck"]+', function(e){
layui.stope(e); //阻止点击节点事件
var elemCheckbox = $(this).prev()
,checked = elemCheckbox.prop('checked');
if(elemCheckbox.prop('disabled')) return;
that.setCheckbox(elem, item, elemCheckbox);
//复选框点击产生的回调
options.oncheck && options.oncheck({
elem: elem
,checked: checked
,data: item
});
});
};
//节点操作
Class.prototype.operate = function(elem, item){
var that = this
,options = that.config
,entry = elem.children('.'+ ELEM_ENTRY)
,elemMain = entry.children('.'+ ELEM_MAIN);
entry.children('.layui-tree-btnGroup').on('click', '.layui-icon', function(e){
layui.stope(e); //阻止节点操作
var type = $(this).data("type")
,packCont = elem.children('.'+ELEM_PACK)
,returnObj = {
data: item
,type: type
,elem:elem
};
//增加
if(type == 'add'){
//若节点本身无子节点
if(!packCont[0]){
//若开启连接线,更改图标样式
if(options.showLine){
elemMain.find('.'+ICON_CLICK).addClass('layui-tree-icon');
elemMain.find('.'+ICON_CLICK).children('.layui-icon').addClass(ICON_ADD).removeClass('layui-icon-file');
//若未开启连接线,显示箭头
}else{
elemMain.find('.layui-tree-iconArrow').removeClass(HIDE);
};
//节点添加子节点容器
elem.append('<div class="layui-tree-pack"></div>');
};
//新增节点
var key = options.operate && options.operate(returnObj)
,obj = {};
obj.title = options.text.defaultNodeName;
obj.id = key;
that.tree(elem.children('.'+ELEM_PACK), [obj]);
//放在新增后面,因为要对元素进行操作
if(options.showLine){
//节点本身无子节点
if(!packCont[0]){
//遍历兄弟节点,判断兄弟节点是否有子节点
var siblings = elem.siblings('.'+ELEM_SET), num = 1
,parentPack = elem.parent('.'+ELEM_PACK);
layui.each(siblings, function(index, i){
if(!$(i).children('.'+ELEM_PACK)[0]){
num = 0;
};
});
//若兄弟节点都有子节点
if(num == 1){
//兄弟节点添加连接线
siblings.children('.'+ELEM_PACK).addClass(ELEM_SHOW);
siblings.children('.'+ELEM_PACK).children('.'+ELEM_SET).removeClass(ELEM_LINE_SHORT);
elem.children('.'+ELEM_PACK).addClass(ELEM_SHOW);
//父级移除延伸线
parentPack.removeClass(ELEM_EXTEND);
//同层节点最后一个更改线的状态
parentPack.children('.'+ELEM_SET).last().children('.'+ELEM_PACK).children('.'+ELEM_SET).last().addClass(ELEM_LINE_SHORT);
}else{
elem.children('.'+ELEM_PACK).children('.'+ELEM_SET).addClass(ELEM_LINE_SHORT);
};
}else{
//添加延伸线
if(!packCont.hasClass(ELEM_EXTEND)){
packCont.addClass(ELEM_EXTEND);
};
//子节点添加延伸线
elem.find('.'+ELEM_PACK).each(function(){
$(this).children('.'+ELEM_SET).last().addClass(ELEM_LINE_SHORT);
});
//如果前一个节点有延伸线
if(packCont.children('.'+ELEM_SET).last().prev().hasClass(ELEM_LINE_SHORT)){
packCont.children('.'+ELEM_SET).last().prev().removeClass(ELEM_LINE_SHORT);
}else{
//若之前的没有,说明处于连接状态
packCont.children('.'+ELEM_SET).last().removeClass(ELEM_LINE_SHORT);
};
//若是最外层,要始终保持相连的状态
if(!elem.parent('.'+ELEM_PACK)[0] && elem.next()[0]){
packCont.children('.'+ELEM_SET).last().removeClass(ELEM_LINE_SHORT);
};
};
};
if(!options.showCheckbox) return;
//若开启复选框,同步新增节点状态
if(elemMain.find('input[same="layuiTreeCheck"]')[0].checked){
var packLast = elem.children('.'+ELEM_PACK).children('.'+ELEM_SET).last();
packLast.find('input[same="layuiTreeCheck"]')[0].checked = true;
};
that.renderForm('checkbox');
//修改
}else if(type == 'update'){
var text = elemMain.children('.'+ ELEM_TEXT).html();
elemMain.children('.'+ ELEM_TEXT).html('');
//添加输入框,覆盖在文字上方
elemMain.append('<input type="text" class="layui-tree-editInput">');
//获取焦点
elemMain.children('.layui-tree-editInput').val(text).focus();
//嵌入文字移除输入框
var getVal = function(input){
var textNew = input.val().trim();
textNew = textNew ? textNew : options.text.defaultNodeName;
input.remove();
elemMain.children('.'+ ELEM_TEXT).html(textNew);
//同步数据
returnObj.data.title = textNew;
//节点修改的回调
options.operate && options.operate(returnObj);
};
//失去焦点
elemMain.children('.layui-tree-editInput').blur(function(){
getVal($(this));
});
//回车
elemMain.children('.layui-tree-editInput').on('keydown', function(e){
if(e.keyCode === 13){
e.preventDefault();
getVal($(this));
};
});
//删除
} else {
layer.confirm('确认删除该节点 "<span style="color: #999;">'+ (item.title || '') +'</span>" 吗?', function(index){
options.operate && options.operate(returnObj); //节点删除的回调
returnObj.status = 'remove'; //标注节点删除
layer.close(index);
//若删除最后一个,显示空数据提示
if(!elem.prev('.'+ELEM_SET)[0] && !elem.next('.'+ELEM_SET)[0] && !elem.parent('.'+ELEM_PACK)[0]){
elem.remove();
that.elem.append(that.elemNone);
return;
};
//若有兄弟节点
if(elem.siblings('.'+ELEM_SET).children('.'+ELEM_ENTRY)[0]){
//若开启复选框
if(options.showCheckbox){
//若开启复选框,进行下步操作
var elemDel = function(elem){
//若无父结点,则不执行
if(!elem.parents('.'+ELEM_SET)[0]) return;
var siblingTree = elem.siblings('.'+ELEM_SET).children('.'+ELEM_ENTRY)
,parentTree = elem.parent('.'+ELEM_PACK).prev()
,checkState = parentTree.find('input[same="layuiTreeCheck"]')[0]
,state = 1, num = 0;
//若父节点未勾选
if(checkState.checked == false){
//遍历兄弟节点
siblingTree.each(function(i, item1){
var input = $(item1).find('input[same="layuiTreeCheck"]')[0]
if(input.checked == false && !input.disabled){
state = 0;
};
//判断是否全为不可勾选框
if(!input.disabled){
num = 1;
};
});
//若有可勾选选择框并且已勾选
if(state == 1 && num == 1){
//勾选父节点
checkState.checked = true;
that.renderForm('checkbox');
//向上遍历祖先节点
elemDel(parentTree.parent('.'+ELEM_SET));
};
};
};
elemDel(elem);
};
//若开启连接线
if(options.showLine){
//遍历兄弟节点,判断兄弟节点是否有子节点
var siblings = elem.siblings('.'+ELEM_SET), num = 1
,parentPack = elem.parent('.'+ELEM_PACK);
layui.each(siblings, function(index, i){
if(!$(i).children('.'+ELEM_PACK)[0]){
num = 0;
};
});
//若兄弟节点都有子节点
if(num == 1){
//若节点本身无子节点
if(!packCont[0]){
//父级去除延伸线,因为此时子节点里没有空节点
parentPack.removeClass(ELEM_EXTEND);
siblings.children('.'+ELEM_PACK).addClass(ELEM_SHOW);
siblings.children('.'+ELEM_PACK).children('.'+ELEM_SET).removeClass(ELEM_LINE_SHORT);
};
//若为最后一个节点
if(!elem.next()[0]){
elem.prev().children('.'+ELEM_PACK).children('.'+ELEM_SET).last().addClass(ELEM_LINE_SHORT);
}else{
parentPack.children('.'+ELEM_SET).last().children('.'+ELEM_PACK).children('.'+ELEM_SET).last().addClass(ELEM_LINE_SHORT);
};
//若为最外层最后一个节点,去除前一个结点的连接线
if(!elem.next()[0] && !elem.parents('.'+ELEM_SET)[1] && !elem.parents('.'+ELEM_SET).eq(0).next()[0]){
elem.prev('.'+ELEM_SET).addClass(ELEM_LINE_SHORT);
};
}else{
//若为最后一个节点且有延伸线
if(!elem.next()[0] && elem.hasClass(ELEM_LINE_SHORT)){
elem.prev().addClass(ELEM_LINE_SHORT);
};
};
};
}else{
//若无兄弟节点
var prevDiv = elem.parent('.'+ELEM_PACK).prev();
//若开启了连接线
if(options.showLine){
prevDiv.find('.'+ICON_CLICK).removeClass('layui-tree-icon');
prevDiv.find('.'+ICON_CLICK).children('.layui-icon').removeClass(ICON_SUB).addClass('layui-icon-file');
//父节点所在层添加延伸线
var pare = prevDiv.parents('.'+ELEM_PACK).eq(0);
pare.addClass(ELEM_EXTEND);
//兄弟节点最后子节点添加延伸线
pare.children('.'+ELEM_SET).each(function(){
$(this).children('.'+ELEM_PACK).children('.'+ELEM_SET).last().addClass(ELEM_LINE_SHORT);
});
}else{
//父节点隐藏箭头
prevDiv.find('.layui-tree-iconArrow').addClass(HIDE);
};
//移除展开属性
elem.parents('.'+ELEM_SET).eq(0).removeClass(ELEM_SPREAD);
//移除节点容器
elem.parent('.'+ELEM_PACK).remove();
};
elem.remove();
});
};
});
};
//部分事件
Class.prototype.events = function(){
var that = this
,options = that.config
,checkWarp = that.elem.find('.layui-tree-checkedFirst');
//初始选中
that.setChecked(that.checkids);
//搜索
that.elem.find('.layui-tree-search').on('keyup', function(){
var input = $(this)
,val = input.val()
,pack = input.nextAll()
,arr = [];
//遍历所有的值
pack.find('.'+ ELEM_TEXT).each(function(){
var entry = $(this).parents('.'+ELEM_ENTRY);
//若值匹配,加一个类以作标识
if($(this).html().indexOf(val) != -1){
arr.push($(this).parent());
var select = function(div){
div.addClass('layui-tree-searchShow');
//向上父节点渲染
if(div.parent('.'+ELEM_PACK)[0]){
select(div.parent('.'+ELEM_PACK).parent('.'+ELEM_SET));
};
};
select(entry.parent('.'+ELEM_SET));
};
});
//根据标志剔除
pack.find('.'+ELEM_ENTRY).each(function(){
var parent = $(this).parent('.'+ELEM_SET);
if(!parent.hasClass('layui-tree-searchShow')){
parent.addClass(HIDE);
};
});
if(pack.find('.layui-tree-searchShow').length == 0){
that.elem.append(that.elemNone);
};
//节点过滤的回调
options.onsearch && options.onsearch({
elem: arr
});
});
//还原搜索初始状态
that.elem.find('.layui-tree-search').on('keydown', function(){
$(this).nextAll().find('.'+ELEM_ENTRY).each(function(){
var parent = $(this).parent('.'+ELEM_SET);
parent.removeClass('layui-tree-searchShow '+ HIDE);
});
if($('.layui-tree-emptyText')[0]) $('.layui-tree-emptyText').remove();
});
};
//得到选中节点
Class.prototype.getChecked = function(){
var that = this
,options = that.config
,checkId = []
,checkData = [];
//遍历节点找到选中索引
that.elem.find('.layui-form-checked').each(function(){
checkId.push($(this).prev()[0].value);
});
//遍历节点
var eachNodes = function(data, checkNode){
layui.each(data, function(index, item){
layui.each(checkId, function(index2, item2){
if(item.id == item2){
var cloneItem = $.extend({}, item);
delete cloneItem.children;
checkNode.push(cloneItem);
if(item.children){
cloneItem.children = [];
eachNodes(item.children, cloneItem.children);
}
return true
}
});
});
};
eachNodes($.extend({}, options.data), checkData);
return checkData;
};
//设置选中节点
Class.prototype.setChecked = function(checkedId){
var that = this
,options = that.config;
//初始选中
that.elem.find('.'+ELEM_SET).each(function(i, item){
var thisId = $(this).data('id')
,input = $(item).children('.'+ELEM_ENTRY).find('input[same="layuiTreeCheck"]')
,reInput = input.next();
//若返回数字
if(typeof checkedId === 'number'){
if(thisId.toString() == checkedId.toString()){
if(!input[0].checked){
reInput.click();
};
return false;
};
}
//若返回数组
else if(typeof checkedId === 'object'){
layui.each(checkedId, function(index, value){
if(value.toString() == thisId.toString() && !input[0].checked){
reInput.click();
return true;
}
});
};
});
};
//记录所有实例
thisModule.that = {}; //记录所有实例对象
thisModule.config = {}; //记录所有实例配置项
//重载实例
tree.reload = function(id, options){
var that = thisModule.that[id];
that.reload(options);
return thisModule.call(that);
};
//获得选中的节点数据
tree.getChecked = function(id){
var that = thisModule.that[id];
return that.getChecked();
};
//设置选中节点
tree.setChecked = function(id, checkedId){
var that = thisModule.that[id];
return that.setChecked(checkedId);
};
//核心入口
tree.render = function(options){
var inst = new Class(options);
return thisModule.call(inst);
};
exports(MOD_NAME, tree);
})

View File

@@ -0,0 +1,598 @@
/**
* upload
* 上传组件
*/
layui.define(['lay','layer'], function(exports){
"use strict";
var $ = layui.$
,layer = layui.layer
,device = layui.device()
//外部接口
,upload = {
config: {} //全局配置项
//设置全局项
,set: function(options){
var that = this;
that.config = $.extend({}, that.config, options);
return that;
}
//事件
,on: function(events, callback){
return layui.onevent.call(this, MOD_NAME, events, callback);
}
}
//操作当前实例
,thisUpload = function(){
var that = this;
return {
upload: function(files){
that.upload.call(that, files);
}
,reload: function(options){
that.reload.call(that, options);
}
,config: that.config
}
}
//字符常量
,MOD_NAME = 'upload', ELEM = 'layui-upload', THIS = 'layui-this', SHOW = 'layui-show', HIDE = 'layui-hide', DISABLED = 'layui-disabled'
,ELEM_FILE = 'layui-upload-file', ELEM_FORM = 'layui-upload-form', ELEM_IFRAME = 'layui-upload-iframe', ELEM_CHOOSE = 'layui-upload-choose', ELEM_DRAG = 'layui-upload-drag'
//构造器
,Class = function(options){
var that = this;
that.config = $.extend({}, that.config, upload.config, options);
that.render();
};
//默认配置
Class.prototype.config = {
accept: 'images' //允许上传的文件类型images/file/video/audio
,exts: '' //允许上传的文件后缀名
,auto: true //是否选完文件后自动上传
,bindAction: '' //手动上传触发的元素
,url: '' //上传地址
,force: '' //强制规定返回的数据格式,目前只支持是否强制 json
,field: 'file' //文件字段名
,acceptMime: '' //筛选出的文件类型,默认为所有文件
,method: 'post' //请求上传的 http 类型
,data: {} //请求上传的额外参数
,drag: true //是否允许拖拽上传
,size: 0 //文件限制大小,默认不限制
,number: 0 //允许同时上传的文件数,默认不限制
,multiple: false //是否允许多文件上传不支持ie8-9
};
//初始渲染
Class.prototype.render = function(options){
var that = this
,options = that.config;
options.elem = $(options.elem);
options.bindAction = $(options.bindAction);
that.file();
that.events();
};
//追加文件域
Class.prototype.file = function(){
var that = this
,options = that.config
,elemFile = that.elemFile = $([
'<input class="'+ ELEM_FILE +'" type="file" accept="'+ options.acceptMime +'" name="'+ options.field +'"'
,(options.multiple ? ' multiple' : '')
,'>'
].join(''))
,next = options.elem.next();
if(next.hasClass(ELEM_FILE) || next.hasClass(ELEM_FORM)){
next.remove();
}
//包裹ie8/9容器
if(device.ie && device.ie < 10){
options.elem.wrap('<div class="layui-upload-wrap"></div>');
}
that.isFile() ? (
that.elemFile = options.elem
,options.field = options.elem[0].name
) : options.elem.after(elemFile);
//初始化ie8/9的Form域
if(device.ie && device.ie < 10){
that.initIE();
}
};
//ie8-9初始化
Class.prototype.initIE = function(){
var that = this
,options = that.config
,iframe = $('<iframe id="'+ ELEM_IFRAME +'" class="'+ ELEM_IFRAME +'" name="'+ ELEM_IFRAME +'" frameborder="0"></iframe>')
,elemForm = $(['<form target="'+ ELEM_IFRAME +'" class="'+ ELEM_FORM +'" method="post" key="set-mine" enctype="multipart/form-data" action="'+ options.url +'">'
,'</form>'].join(''));
//插入iframe
$('#'+ ELEM_IFRAME)[0] || $('body').append(iframe);
//包裹文件域
if(!options.elem.next().hasClass(ELEM_FORM)){
that.elemFile.wrap(elemForm);
//追加额外的参数
options.elem.next('.'+ ELEM_FORM).append(function(){
var arr = [];
layui.each(options.data, function(key, value){
value = typeof value === 'function' ? value() : value;
arr.push('<input type="hidden" name="'+ key +'" value="'+ value +'">')
});
return arr.join('');
}());
}
};
//异常提示
Class.prototype.msg = function(content){
return layer.msg(content, {
icon: 2
,shift: 6
});
};
//判断绑定元素是否为文件域本身
Class.prototype.isFile = function(){
var elem = this.config.elem[0];
if(!elem) return;
return elem.tagName.toLocaleLowerCase() === 'input' && elem.type === 'file'
}
//预读图片信息
Class.prototype.preview = function(callback){
var that = this;
if(window.FileReader){
layui.each(that.chooseFiles, function(index, file){
var reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = function(){
callback && callback(index, file, this.result);
}
});
}
};
// 执行上传
Class.prototype.upload = function(files, type){
var that = this;
var options = that.config;
var elemFile = that.elemFile[0];
// 获取文件队列
var getFiles = function(){
return files || that.files || that.chooseFiles || elemFile.files;
};
//高级浏览器处理方式,支持跨域
var ajaxSend = function(){
var successful = 0;
var failed = 0
var items = getFiles();
var allDone = function(){ // 多文件全部上传完毕的回调
if(options.multiple && successful + failed === that.fileLength){
typeof options.allDone === 'function' && options.allDone({
total: that.fileLength
,successful: successful
,failed: failed
});
}
};
layui.each(items, function(index, file){
var formData = new FormData();
//追加额外的参数
layui.each(options.data, function(key, value){
value = typeof value === 'function' ? value() : value;
formData.append(key, value);
});
//最后添加 file 到表单域
formData.append(options.field, file);
//提交文件
var opts = {
url: options.url
,type: 'post' //统一采用 post 上传
,data: formData
,contentType: false
,processData: false
,dataType: 'json'
,headers: options.headers || {}
//成功回调
,success: function(res){
successful++;
done(index, res);
allDone();
}
//异常回调
,error: function(e){
failed++;
that.msg('Request URL is abnormal: '+ (e.statusText || 'error'));
error(index);
allDone();
}
};
//进度条
if(typeof options.progress === 'function'){
opts.xhr = function(){
var xhr = $.ajaxSettings.xhr();
//上传进度
xhr.upload.addEventListener("progress", function (obj) {
if(obj.lengthComputable){
var percent = Math.floor((obj.loaded/obj.total)* 100); //百分比
options.progress(percent, (options.item ? options.item[0] : options.elem[0]) , obj, index);
}
});
return xhr;
}
}
$.ajax(opts);
});
}
//低版本 IE 处理方式,不支持跨域
,iframeSend = function(){
var iframe = $('#'+ ELEM_IFRAME);
that.elemFile.parent().submit();
//获取响应信息
clearInterval(Class.timer);
Class.timer = setInterval(function() {
var res, iframeBody = iframe.contents().find('body');
try {
res = iframeBody.text();
} catch(e) {
that.msg('Cross-domain requests are not supported');
clearInterval(Class.timer);
error();
}
if(res){
clearInterval(Class.timer);
iframeBody.html('');
done(0, res);
}
}, 30);
}
//统一回调
,done = function(index, res){
that.elemFile.next('.'+ ELEM_CHOOSE).remove();
elemFile.value = '';
if(options.force === 'json'){
if(typeof res !== 'object'){
try {
res = JSON.parse(res);
} catch(e){
res = {};
return that.msg('Please return JSON data format');
}
}
}
typeof options.done === 'function' && options.done(res, index || 0, function(files){
that.upload(files);
});
}
//统一网络异常回调
,error = function(index){
if(options.auto){
elemFile.value = '';
}
typeof options.error === 'function' && options.error(index || 0, function(files){
that.upload(files);
});
}
,exts = options.exts
,check ,value = function(){
var arr = [];
layui.each(files || that.chooseFiles, function(i, item){
arr.push(item.name);
});
return arr;
}()
//回调返回的参数
,args = {
//预览
preview: function(callback){
that.preview(callback);
}
//上传
,upload: function(index, file){
var thisFile = {};
thisFile[index] = file;
that.upload(thisFile);
}
//追加文件到队列
,pushFile: function(){
that.files = that.files || {};
layui.each(that.chooseFiles, function(index, item){
that.files[index] = item;
});
return that.files;
}
//重置文件
,resetFile: function(index, file, filename){
var newFile = new File([file], filename);
that.files = that.files || {};
that.files[index] = newFile;
}
}
//提交上传
,send = function(){
//上传前的回调 - 如果回调函数明确返回false则停止上传(#pulls55)
if(options.before && (options.before(args) === false)) return;
//IE兼容处理
if(device.ie){
return device.ie > 9 ? ajaxSend() : iframeSend();
}
ajaxSend();
}
//文件类型名称
,typeName = ({
file: '文件'
,images: '图片'
,video: '视频'
,audio: '音频'
})[options.accept] || '文件';
//校验文件格式
value = value.length === 0
? ((elemFile.value.match(/[^\/\\]+\..+/g)||[]) || '')
: value;
if(value.length === 0) return;
//根据文件类型校验
switch(options.accept){
case 'file': //一般文件
layui.each(value, function(i, item){
if(exts && !RegExp('.\\.('+ exts +')$', 'i').test(escape(item))){
return check = true;
}
});
break;
case 'video': //视频文件
layui.each(value, function(i, item){
if(!RegExp('.\\.('+ (exts || 'avi|mp4|wma|rmvb|rm|flash|3gp|flv') +')$', 'i').test(escape(item))){
return check = true;
}
});
break;
case 'audio': //音频文件
layui.each(value, function(i, item){
if(!RegExp('.\\.('+ (exts || 'mp3|wav|mid') +')$', 'i').test(escape(item))){
return check = true;
}
});
break;
default: //图片文件
layui.each(value, function(i, item){
if(!RegExp('.\\.('+ (exts || 'jpg|png|gif|bmp|jpeg') +')$', 'i').test(escape(item))){
return check = true;
}
});
break;
}
//校验失败提示
if(check){
that.msg('选择的'+ typeName +'中包含不支持的格式');
return elemFile.value = '';
}
//选择文件的回调
if(type === 'choose' || options.auto){
options.choose && options.choose(args);
if(type === 'choose'){
return;
}
}
//检验文件数量
that.fileLength = function(){
var length = 0;
var items = getFiles();
layui.each(items, function(){
length++;
});
return length;
}();
if(options.number && that.fileLength > options.number){
return that.msg(
'同时最多只能上传: '+ options.number + ' 个文件'
+'<br>您当前已经选择了: '+ that.fileLength +' 个文件'
);
}
// 检验文件大小
if(options.size > 0 && !(device.ie && device.ie < 10)){
var limitSize;
layui.each(getFiles(), function(index, file){
if(file.size > 1024*options.size){
var size = options.size/1024;
size = size >= 1 ? (size.toFixed(2) + 'MB') : options.size + 'KB'
elemFile.value = '';
limitSize = size;
}
});
if(limitSize) return that.msg('文件大小不能超过 '+ limitSize);
}
send();
};
//重置方法
Class.prototype.reload = function(options){
options = options || {};
delete options.elem;
delete options.bindAction;
var that = this
,options = that.config = $.extend({}, that.config, upload.config, options)
,next = options.elem.next();
//更新文件域相关属性
next.attr({
name: options.name
,accept: options.acceptMime
,multiple: options.multiple
});
};
//事件处理
Class.prototype.events = function(){
var that = this;
var options = that.config;
// 设置当前选择的文件队列
var setChooseFile = function(files){
that.chooseFiles = {};
layui.each(files, function(i, item){
var time = new Date().getTime();
that.chooseFiles[time + '-' + i] = item;
});
};
// 设置选择的文本
var setChooseText = function(files, filename){
var elemFile = that.elemFile
,item = options.item ? options.item : options.elem
,value = files.length > 1
? files.length + '个文件'
: ((files[0] || {}).name || (elemFile[0].value.match(/[^\/\\]+\..+/g)||[]) || '');
if(elemFile.next().hasClass(ELEM_CHOOSE)){
elemFile.next().remove();
}
that.upload(null, 'choose');
if(that.isFile() || options.choose) return;
elemFile.after('<span class="layui-inline '+ ELEM_CHOOSE +'">'+ value +'</span>');
};
// 合并 lay-options/lay-data 属性配置项
var extendAttrs = function(){
var othis = $(this);
var data = othis.attr('lay-data') || othis.attr('lay-options'); // 优先兼容旧版本
if(data){
that.config = $.extend({}, options, lay.options(this, {
attr: othis.attr('lay-data') ? 'lay-data' : null
}));
}
};
//点击上传容器
options.elem.off('upload.start').on('upload.start', function(){
var othis = $(this);
extendAttrs.call(this);
that.config.item = othis;
that.elemFile[0].click();
});
//拖拽上传
if(!(device.ie && device.ie < 10)){
options.elem.off('upload.over').on('upload.over', function(){
var othis = $(this)
othis.attr('lay-over', '');
})
.off('upload.leave').on('upload.leave', function(){
var othis = $(this)
othis.removeAttr('lay-over');
})
.off('upload.drop').on('upload.drop', function(e, param){
var othis = $(this);
var files = param.originalEvent.dataTransfer.files || [];
othis.removeAttr('lay-over');
extendAttrs.call(this);
setChooseFile(files);
options.auto ? that.upload() : setChooseText(files); //是否自动触发上传
});
}
//文件选择
that.elemFile.off('upload.change').on('upload.change', function(){
var files = this.files || [];
extendAttrs.call(this);
setChooseFile(files);
options.auto ? that.upload() : setChooseText(files); //是否自动触发上传
});
//手动触发上传
options.bindAction.off('upload.action').on('upload.action', function(){
that.upload();
});
//防止事件重复绑定
if(options.elem.data('haveEvents')) return;
that.elemFile.on('change', function(){
$(this).trigger('upload.change');
});
options.elem.on('click', function(){
if(that.isFile()) return;
$(this).trigger('upload.start');
});
if(options.drag){
options.elem.on('dragover', function(e){
e.preventDefault();
$(this).trigger('upload.over');
}).on('dragleave', function(e){
$(this).trigger('upload.leave');
}).on('drop', function(e){
e.preventDefault();
$(this).trigger('upload.drop', e);
});
}
options.bindAction.on('click', function(){
$(this).trigger('upload.action');
});
options.elem.data('haveEvents', true);
};
//核心入口
upload.render = function(options){
var inst = new Class(options);
return thisUpload.call(inst);
};
exports(MOD_NAME, upload);
});

View File

@@ -0,0 +1,338 @@
/**
* util 工具组件
*/
layui.define('jquery', function(exports){
"use strict";
var $ = layui.$;
var hint = layui.hint();
// 外部接口
var util = {
// 固定块
fixbar: function(options){
var ELEM = 'layui-fixbar';
var $doc = $(document);
// 默认可选项
options = $.extend(true, {
target: 'body', // fixbar 的插入目标选择器
bars: [], // bar 信息
default: true, // 是否显示默认 bar
margin: 160, // 出现 top bar 的滚动条高度临界值
duration: 320 // top bar 等动画时长(毫秒)
}, options);
// 目标元素对象
var $target = $(options.target);
// 滚动条所在元素对象
var $scroll = options.scroll
? $(options.scroll)
: $(options.target === 'body' ? $doc : $target)
// 是否提供默认图标
if(options.default){
// 兼容旧版本的一些属性
if(options.bar1){
options.bars.push({
type: 'bar1',
icon: 'layui-icon-chat'
});
}
if(options.bar2){
options.bars.push({
type: 'bar2',
icon: 'layui-icon-help'
});
}
// 默认 top bar
options.bars.push({
type: 'top',
icon: 'layui-icon-top'
});
}
var elem = $('<ul>').addClass(ELEM);
var elemTopBar;
// 遍历生成 bars 节点
layui.each(options.bars, function(i, item){
var elemBar = $('<li class="layui-icon">');
// 设置 bar 相关属性
elemBar.addClass(item.icon).attr({
'lay-type': item.type,
'style': item.style || ('background-color: '+ options.bgcolor)
}).html(item.content);
// bar 点击事件
elemBar.on('click', function(){
var type = $(this).attr('lay-type');
if(type === 'top'){
(
options.target === 'body'
? $('html,body')
: $scroll
).animate({
scrollTop : 0
}, options.duration);
}
typeof options.click === 'function' && options.click.call(this, type);
});
// 自定义任意事件
if(layui.type(options.on) === 'object'){
layui.each(options.on, function(eventName, callback){
elemBar.on(eventName, function(){
var type = $(this).attr('lay-type');
typeof callback === 'function' && callback.call(this, type);
});
})
}
// 获得 top bar 节点
if(item.type === 'top'){
elemBar.addClass('layui-fixbar-top');
elemTopBar = elemBar;
}
elem.append(elemBar); // 插入 bar 节点
});
// 若目标元素已存在 fixbar则移除旧的节点
$target.find('.'+ ELEM).remove();
// 向目标元素插入 fixbar 节点
typeof options.css === 'object' && elem.css(options.css);
$target.append(elem);
// top bar 的显示隐藏
if(elemTopBar){
var lock;
var setTopBar = (function setTopBar(){
var top = $scroll.scrollTop();
if(top >= options.margin){
lock || (elemTopBar.show(), lock = 1);
} else {
lock && (elemTopBar.hide(), lock = 0);
}
return setTopBar;
})();
}
// 根据 scrollbar 设置 fixbar 相关状态
var timer;
$scroll.on('scroll', function(){
if(!setTopBar) return;
clearTimeout(timer);
timer = setTimeout(function(){
setTopBar();
}, 100);
});
}
//倒计时
,countdown: function(endTime, serverTime, callback){
var that = this
,type = typeof serverTime === 'function'
,end = new Date(endTime).getTime()
,now = new Date((!serverTime || type) ? new Date().getTime() : serverTime).getTime()
,count = end - now
,time = [
Math.floor(count/(1000*60*60*24)) //天
,Math.floor(count/(1000*60*60)) % 24 //时
,Math.floor(count/(1000*60)) % 60 //分
,Math.floor(count/1000) % 60 //秒
];
if(type) callback = serverTime;
var timer = setTimeout(function(){
that.countdown(endTime, now + 1000, callback);
}, 1000);
callback && callback(count > 0 ? time : [0,0,0,0], serverTime, timer);
if(count <= 0) clearTimeout(timer);
return timer;
}
//某个时间在当前时间的多久前
,timeAgo: function(time, onlyDate){
var that = this
,arr = [[], []]
,stamp = new Date().getTime() - new Date(time).getTime();
//返回具体日期
if(stamp > 1000*60*60*24*31){
stamp = new Date(time);
arr[0][0] = that.digit(stamp.getFullYear(), 4);
arr[0][1] = that.digit(stamp.getMonth() + 1);
arr[0][2] = that.digit(stamp.getDate());
//是否输出时间
if(!onlyDate){
arr[1][0] = that.digit(stamp.getHours());
arr[1][1] = that.digit(stamp.getMinutes());
arr[1][2] = that.digit(stamp.getSeconds());
}
return arr[0].join('-') + ' ' + arr[1].join(':');
}
//30天以内返回“多久前”
if(stamp >= 1000*60*60*24){
return ((stamp/1000/60/60/24)|0) + ' 天前';
} else if(stamp >= 1000*60*60){
return ((stamp/1000/60/60)|0) + ' 小时前';
} else if(stamp >= 1000*60*3){ //3分钟以内为刚刚
return ((stamp/1000/60)|0) + ' 分钟前';
} else if(stamp < 0){
return '未来';
} else {
return '刚刚';
}
}
//数字前置补零
,digit: function(num, length){
var str = '';
num = String(num);
length = length || 2;
for(var i = num.length; i < length; i++){
str += '0';
}
return num < Math.pow(10, length) ? str + (num|0) : num;
}
//转化为日期格式字符
,toDateString: function(time, format){
//若 null 或空字符,则返回空字符
if(time === null || time === '') return '';
var that = this
,date = new Date(function(){
if(!time) return;
return isNaN(time) ? time : (typeof time === 'string' ? parseInt(time) : time)
}() || new Date())
,ymd = [
that.digit(date.getFullYear(), 4)
,that.digit(date.getMonth() + 1)
,that.digit(date.getDate())
]
,hms = [
that.digit(date.getHours())
,that.digit(date.getMinutes())
,that.digit(date.getSeconds())
];
if(!date.getDate()) return hint.error('Invalid Msec for "util.toDateString(Msec)"'), '';
format = format || 'yyyy-MM-dd HH:mm:ss';
return format.replace(/yyyy/g, ymd[0])
.replace(/MM/g, ymd[1])
.replace(/dd/g, ymd[2])
.replace(/HH/g, hms[0])
.replace(/mm/g, hms[1])
.replace(/ss/g, hms[2]);
}
//转义 html
,escape: function(html){
var exp = /[<"'>]|&(?=#[a-zA-Z0-9]+)/g;
if(html === undefined || html === null) return '';
html += '';
if(!exp.test(html)) return html;
return html.replace(/&(?!#?[a-zA-Z0-9]+;)/g, '&amp;')
.replace(/</g, '&lt;').replace(/>/g, '&gt;')
.replace(/'/g, '&#39;').replace(/"/g, '&quot;');
}
//还原转义的 html
,unescape: function(html){
if(html === undefined || html === null) html = '';
html += '';
return html.replace(/\&amp;/g, '&')
.replace(/\&lt;/g, '<').replace(/\&gt;/g, '>')
.replace(/\&#39;/g, '\'').replace(/\&quot;/g, '"');
}
// 打开新窗口
,openWin: function(options){
var win;
options = options || {};
win = options.window || window.open((options.url || ''), options.target, options.specs);
if(options.url) return;
win.document.open('text/html', 'replace');
win.document.write(options.content || '');
win.document.close();
}
//让指定的元素保持在可视区域
,toVisibleArea: function(options){
options = $.extend({
margin: 160 //触发动作的边界值
,duration: 200 //动画持续毫秒数
,type: 'y' //触发方向x 水平、y 垂直
}, options);
if(!options.scrollElem[0] || !options.thisElem[0]) return;
var scrollElem = options.scrollElem //滚动元素
,thisElem = options.thisElem //目标元素
,vertical = options.type === 'y' //是否垂直方向
,SCROLL_NAME = vertical ? 'scrollTop' : 'scrollLeft' //滚动方法
,OFFSET_NAME = vertical ? 'top' : 'left' //坐标方式
,scrollValue = scrollElem[SCROLL_NAME]() //当前滚动距离
,size = scrollElem[vertical ? 'height' : 'width']() //滚动元素的尺寸
,scrollOffet = scrollElem.offset()[OFFSET_NAME] //滚动元素所处位置
,thisOffset = thisElem.offset()[OFFSET_NAME] - scrollOffet //目标元素当前的所在位置
,obj = {};
//边界满足条件
if(thisOffset > size - options.margin || thisOffset < options.margin){
obj[SCROLL_NAME] = thisOffset - size/2 + scrollValue
scrollElem.animate(obj, options.duration);
}
}
//批量事件
,event: function(attr, obj, eventType){
var _body = $('body');
eventType = eventType || 'click';
//记录事件回调集合
obj = util.event[attr] = $.extend(true, util.event[attr], obj) || {};
//清除委托事件
util.event.UTIL_EVENT_CALLBACK = util.event.UTIL_EVENT_CALLBACK || {};
_body.off(eventType, '*['+ attr +']', util.event.UTIL_EVENT_CALLBACK[attr])
//绑定委托事件
util.event.UTIL_EVENT_CALLBACK[attr] = function(){
var othis = $(this)
,key = othis.attr(attr);
(typeof obj[key] === 'function') && obj[key].call(this, othis);
};
//清除旧事件,绑定新事件
_body.on(eventType, '*['+ attr +']', util.event.UTIL_EVENT_CALLBACK[attr]);
return obj;
}
};
util.on = util.event;
// DOM 尺寸变化该创意来自http://benalman.com/projects/jquery-resize-plugin/
/*
!function(a,b,c){"$:nomunge";function l(){f=b[g](function(){d.each(function(){var b=a(this),c=b.width(),d=b.height(),e=a.data(this,i);(c!==e.w||d!==e.h)&&b.trigger(h,[e.w=c,e.h=d])}),l()},e[j])}var f,d=a([]),e=a.resize=a.extend(a.resize,{}),g="setTimeout",h="resize",i=h+"-special-event",j="delay",k="throttleWindow";e[j]=250,e[k]=!0,a.event.special[h]={setup:function(){if(!e[k]&&this[g])return!1;var b=a(this);d=d.add(b),a.data(this,i,{w:b.width(),h:b.height()}),1===d.length&&l()},teardown:function(){if(!e[k]&&this[g])return!1;var b=a(this);d=d.not(b),b.removeData(i),d.length||clearTimeout(f)},add:function(b){function f(b,e,f){var g=a(this),h=a.data(this,i)||{};h.w=e!==c?e:g.width(),h.h=f!==c?f:g.height(),d.apply(this,arguments)}if(!e[k]&&this[g])return!1;var d;return a.isFunction(b)?(d=b,f):(d=b.handler,b.handler=f,void 0)}}}($,window);
*/
// 输出接口
exports('util', util);
});