')
.appendto($body)
.reflow()
.css('z-index', zindex);
}
var level = $overlay.data('overlay-level') || 0;
return $overlay
.data('overlay-level', ++level)
.addclass('mdui-overlay-show');
},
/**
* 隐藏遮罩层
* @param force 是否强制隐藏遮罩
*/
hideoverlay: function (force) {
var $overlay = $('.mdui-overlay');
if (!$overlay.length) {
return;
}
var level = force ? 1 : $overlay.data('overlay-level');
if (level > 1) {
$overlay.data('overlay-level', --level);
return;
}
$overlay
.data('overlay-level', 0)
.removeclass('mdui-overlay-show')
.data('isdeleted', 1)
.transitionend(function () {
if ($overlay.data('isdeleted')) {
$overlay.remove();
}
});
},
/**
* 锁定屏幕
*/
lockscreen: function () {
// 不直接把 body 设为 box-sizing: border-box,避免污染全局样式
var newbodywidth = $body.width();
$body
.addclass('mdui-locked')
.width(newbodywidth);
var level = $body.data('lockscreen-level') || 0;
$body.data('lockscreen-level', ++level);
},
/**
* 解除屏幕锁定
* @param force 是否强制解锁屏幕
*/
unlockscreen: function (force) {
var level = force ? 1 : $body.data('lockscreen-level');
if (level > 1) {
$body.data('lockscreen-level', --level);
return;
}
$body
.data('lockscreen-level', 0)
.removeclass('mdui-locked')
.width('');
},
/**
* 函数节流
* @param fn
* @param delay
* @returns {function}
*/
throttle: function (fn, delay) {
var timer = null;
if (!delay || delay < 16) {
delay = 16;
}
return function () {
var _this = this;
var args = arguments;
if (timer === null) {
timer = settimeout(function () {
fn.apply(_this, args);
timer = null;
}, delay);
}
};
},
/**
* 生成唯一 id
* @param pluginname 插件名,若传入该参数,guid 将以该参数作为前缀
* @returns {string}
*/
guid: function (pluginname) {
function s4() {
return math.floor((1 + math.random()) * 0x10000)
.tostring(16)
.substring(1);
}
var guid = s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4();
if (pluginname) {
guid = 'mdui-' + pluginname + '-' + guid;
}
return guid;
},
});
/**
* =============================================================================
* ************ headroom.js ************
* =============================================================================
*/
mdui.headroom = (function () {
/**
* 默认参数
* @type {{}}
*/
var default = {
tolerance: 5, // 滚动条滚动多少距离开始隐藏或显示元素,{down: num, up: num},或数字
offset: 0, // 在页面顶部多少距离内滚动不会隐藏元素
initialclass: 'mdui-headroom', // 初始化时添加的类
pinnedclass: 'mdui-headroom-pinned-top', // 元素固定时添加的类
unpinnedclass: 'mdui-headroom-unpinned-top', // 元素隐藏时添加的类
};
/**
* headroom
* @param selector
* @param opts
* @constructor
*/
function headroom(selector, opts) {
var _this = this;
_this.$headroom = $(selector).eq(0);
if (!_this.$headroom.length) {
return;
}
// 已通过自定义属性实例化过,不再重复实例化
var oldinst = _this.$headroom.data('mdui.headroom');
if (oldinst) {
return oldinst;
}
_this.options = $.extend({}, default, (opts || {}));
// 数值转为 {down: bum, up: num}
var tolerance = _this.options.tolerance;
if (tolerance !== object(tolerance)) {
_this.options.tolerance = {
down: tolerance,
up: tolerance,
};
}
_this._init();
}
/**
* 初始化
* @private
*/
headroom.prototype._init = function () {
var _this = this;
_this.state = 'pinned';
_this.$headroom
.addclass(_this.options.initialclass)
.removeclass(_this.options.pinnedclass + ' ' + _this.options.unpinnedclass);
_this.inited = false;
_this.lastscrolly = 0;
_this._attachevent();
};
/**
* 监听滚动事件
* @private
*/
headroom.prototype._attachevent = function () {
var _this = this;
if (!_this.inited) {
_this.lastscrolly = window.pageyoffset;
_this.inited = true;
$window.on('scroll', function () {
_this._scroll();
});
}
};
/**
* 滚动时的处理
* @private
*/
headroom.prototype._scroll = function () {
var _this = this;
_this.rafid = window.requestanimationframe(function () {
var currentscrolly = window.pageyoffset;
var direction = currentscrolly > _this.lastscrolly ? 'down' : 'up';
var toleranceexceeded =
math.abs(currentscrolly - _this.lastscrolly) >=
_this.options.tolerance[direction];
if (
currentscrolly > _this.lastscrolly &&
currentscrolly >= _this.options.offset &&
toleranceexceeded) {
_this.unpin();
} else if (
(currentscrolly < _this.lastscrolly && toleranceexceeded) ||
currentscrolly <= _this.options.offset
) {
_this.pin();
}
_this.lastscrolly = currentscrolly;
});
};
/**
* 动画结束回调
* @param inst
*/
var transitionend = function (inst) {
if (inst.state === 'pinning') {
inst.state = 'pinned';
componentevent('pinned', 'headroom', inst, inst.$headroom);
}
if (inst.state === 'unpinning') {
inst.state = 'unpinned';
componentevent('unpinned', 'headroom', inst, inst.$headroom);
}
};
/**
* 固定住
*/
headroom.prototype.pin = function () {
var _this = this;
if (
_this.state === 'pinning' ||
_this.state === 'pinned' ||
!_this.$headroom.hasclass(_this.options.initialclass)
) {
return;
}
componentevent('pin', 'headroom', _this, _this.$headroom);
_this.state = 'pinning';
_this.$headroom
.removeclass(_this.options.unpinnedclass)
.addclass(_this.options.pinnedclass)
.transitionend(function () {
transitionend(_this);
});
};
/**
* 不固定住
*/
headroom.prototype.unpin = function () {
var _this = this;
if (
_this.state === 'unpinning' ||
_this.state === 'unpinned' ||
!_this.$headroom.hasclass(_this.options.initialclass)
) {
return;
}
componentevent('unpin', 'headroom', _this, _this.$headroom);
_this.state = 'unpinning';
_this.$headroom
.removeclass(_this.options.pinnedclass)
.addclass(_this.options.unpinnedclass)
.transitionend(function () {
transitionend(_this);
});
};
/**
* 启用
*/
headroom.prototype.enable = function () {
var _this = this;
if (!_this.inited) {
_this._init();
}
};
/**
* 禁用
*/
headroom.prototype.disable = function () {
var _this = this;
if (_this.inited) {
_this.inited = false;
_this.$headroom
.removeclass([
_this.options.initialclass,
_this.options.pinnedclass,
_this.options.unpinnedclass,
].join(' '));
$window.off('scroll', function () {
_this._scroll();
});
window.cancelanimationframe(_this.rafid);
}
};
/**
* 获取当前状态 pinning | pinned | unpinning | unpinned
*/
headroom.prototype.getstate = function () {
return this.state;
};
return headroom;
})();
/**
* =============================================================================
* ************ headroom 自定义属性 api ************
* =============================================================================
*/
$(function () {
$('[mdui-headroom]').each(function () {
var $this = $(this);
var options = parseoptions($this.attr('mdui-headroom'));
var inst = $this.data('mdui.headroom');
if (!inst) {
inst = new mdui.headroom($this, options);
$this.data('mdui.headroom', inst);
}
});
});
/**
* =============================================================================
* ************ 供 collapse、 panel 调用的折叠内容块插件 ************
* =============================================================================
*/
var collapseprivate = (function () {
/**
* 默认参数
*/
var default = {
accordion: false, // 是否使用手风琴效果
};
// 类名
var class = {
item: 'mdui-collapse-item', // item 类名
itemopen: 'mdui-collapse-item-open', // 打开状态的 item
header: 'mdui-collapse-item-header', // item 中的 header 类名
body: 'mdui-collapse-item-body', // item 中的 body 类名
};
// 命名空间
var namespace = 'collapse';
/**
* 折叠内容块
* @param selector
* @param opts
* @param classes
* @param namespace
* @constructor
*/
function collapse(selector, opts, classes, namespace) {
var _this = this;
_this.classes = $.extend({}, class, classes || {});
_this.namespace = namespace ? namespace : namespace;
// 折叠面板元素
_this.$collapse = $(selector).eq(0);
if (!_this.$collapse.length) {
return;
}
// 已通过自定义属性实例化过,不再重复实例化
var oldinst = _this.$collapse.data('mdui.' + _this.namespace);
if (oldinst) {
return oldinst;
}
_this.options = $.extend({}, default, (opts || {}));
_this.$collapse.on('click', '.' + _this.classes.header, function () {
var $item = $(this).parent('.' + _this.classes.item);
if (_this.$collapse.children($item).length) {
_this.toggle($item);
}
});
}
/**
* 指定 item 是否处于打开状态
* @param $item
* @returns {boolean}
* @private
*/
collapse.prototype._isopen = function ($item) {
return $item.hasclass(this.classes.itemopen);
};
/**
* 获取指定 item
* @param item
* @returns {*}
* @private
*/
collapse.prototype._getitem = function (item) {
var _this = this;
if (parseint(item) === item) {
// item 是索引号
return _this.$collapse.children('.' + _this.classes.item).eq(item);
}
return $(item).eq(0);
};
/**
* 动画结束回调
* @param inst
* @param $content
* @param $item
*/
var transitionend = function (inst, $content, $item) {
if (inst._isopen($item)) {
$content
.transition(0)
.height('auto')
.reflow()
.transition('');
componentevent('opened', inst.namespace, inst, $item[0]);
} else {
$content.height('');
componentevent('closed', inst.namespace, inst, $item[0]);
}
};
/**
* 打开指定面板项
* @param item 面板项的索引号或 dom 元素或 css 选择器
*/
collapse.prototype.open = function (item) {
var _this = this;
var $item = _this._getitem(item);
if (_this._isopen($item)) {
return;
}
// 关闭其他项
if (_this.options.accordion) {
_this.$collapse.children('.' + _this.classes.itemopen).each(function () {
var $tmpitem = $(this);
if ($tmpitem !== $item) {
_this.close($tmpitem);
}
});
}
var $content = $item.children('.' + _this.classes.body);
$content
.height($content[0].scrollheight)
.transitionend(function () {
transitionend(_this, $content, $item);
});
componentevent('open', _this.namespace, _this, $item[0]);
$item.addclass(_this.classes.itemopen);
};
/**
* 关闭指定项
* @param item 面板项的索引号或 dom 元素或 css 选择器
*/
collapse.prototype.close = function (item) {
var _this = this;
var $item = _this._getitem(item);
if (!_this._isopen($item)) {
return;
}
var $content = $item.children('.' + _this.classes.body);
componentevent('close', _this.namespace, _this, $item[0]);
$item.removeclass(_this.classes.itemopen);
$content
.transition(0)
.height($content[0].scrollheight)
.reflow()
.transition('')
.height('')
.transitionend(function () {
transitionend(_this, $content, $item);
});
};
/**
* 切换指定项的状态
* @param item 面板项的索引号或 dom 元素或 css 选择器或 jq 对象
*/
collapse.prototype.toggle = function (item) {
var _this = this;
var $item = _this._getitem(item);
if (_this._isopen($item)) {
_this.close($item);
} else {
_this.open($item);
}
};
/**
* 打开所有项
*/
collapse.prototype.openall = function () {
var _this = this;
_this.$collapse.children('.' + _this.classes.item).each(function () {
var $tmpitem = $(this);
if (!_this._isopen($tmpitem)) {
_this.open($tmpitem);
}
});
};
/**
* 关闭所有项
*/
collapse.prototype.closeall = function () {
var _this = this;
_this.$collapse.children('.' + _this.classes.item).each(function () {
var $tmpitem = $(this);
if (_this._isopen($tmpitem)) {
_this.close($tmpitem);
}
});
};
return collapse;
})();
/**
* =============================================================================
* ************ collapse 折叠内容块插件 ************
* =============================================================================
*/
mdui.collapse = (function () {
function collapse(selector, opts) {
return new collapseprivate(selector, opts);
}
return collapse;
})();
/**
* =============================================================================
* ************ collapse 自定义属性 ************
* =============================================================================
*/
$(function () {
$('[mdui-collapse]').each(function () {
var $this = $(this);
var options = parseoptions($this.attr('mdui-collapse'));
var inst = $this.data('mdui.collapse');
if (!inst) {
inst = new mdui.collapse($this, options);
$this.data('mdui.collapse', inst);
}
});
});
/**
* =============================================================================
* ************ table 表格 ************
* =============================================================================
*/
(function () {
/**
* 生成 checkbox 的 html 结构
* @param tag
* @returns {string}
*/
var checkboxhtml = function (tag) {
return '<' + tag + ' class="mdui-table-cell-checkbox">' +
'
' +
'' + tag + '>';
};
/**
* table 表格
* @param selector
* @constructor
*/
function table(selector) {
var _this = this;
_this.$table = $(selector).eq(0);
if (!_this.$table.length) {
return;
}
_this.init();
}
/**
* 初始化
*/
table.prototype.init = function () {
var _this = this;
_this.$throw = _this.$table.find('thead tr');
_this.$tdrows = _this.$table.find('tbody tr');
_this.$tdcheckboxs = $();
_this.selectable = _this.$table.hasclass('mdui-table-selectable');
_this.selectedrow = 0;
_this._updatethcheckbox();
_this._updatetdcheckbox();
_this._updatenumericcol();
};
/**
* 更新表格行的 checkbox
*/
table.prototype._updatetdcheckbox = function () {
var _this = this;
_this.$tdrows.each(function () {
var $tdrow = $(this);
// 移除旧的 checkbox
$tdrow.find('.mdui-table-cell-checkbox').remove();
if (!_this.selectable) {
return;
}
// 创建 dom
var $checkbox = $(checkboxhtml('td'))
.prependto($tdrow)
.find('input[type="checkbox"]');
// 默认选中的行
if ($tdrow.hasclass('mdui-table-row-selected')) {
$checkbox[0].checked = true;
_this.selectedrow++;
}
// 所有行都选中后,选中表头;否则,不选中表头
_this.$thcheckbox[0].checked = _this.selectedrow === _this.$tdrows.length;
// 绑定事件
$checkbox.on('change', function () {
if ($checkbox[0].checked) {
$tdrow.addclass('mdui-table-row-selected');
_this.selectedrow++;
} else {
$tdrow.removeclass('mdui-table-row-selected');
_this.selectedrow--;
}
// 所有行都选中后,选中表头;否则,不选中表头
_this.$thcheckbox[0].checked = _this.selectedrow === _this.$tdrows.length;
});
_this.$tdcheckboxs = _this.$tdcheckboxs.add($checkbox);
});
};
/**
* 更新表头的 checkbox
*/
table.prototype._updatethcheckbox = function () {
var _this = this;
// 移除旧的 checkbox
_this.$throw.find('.mdui-table-cell-checkbox').remove();
if (!_this.selectable) {
return;
}
_this.$thcheckbox = $(checkboxhtml('th'))
.prependto(_this.$throw)
.find('input[type="checkbox"]')
.on('change', function () {
var ischeckedall = _this.$thcheckbox[0].checked;
_this.selectedrow = ischeckedall ? _this.$tdrows.length : 0;
_this.$tdcheckboxs.each(function (i, checkbox) {
checkbox.checked = ischeckedall;
});
_this.$tdrows.each(function (i, row) {
$(row)[ischeckedall ? 'addclass' : 'removeclass']('mdui-table-row-selected');
});
});
};
/**
* 更新数值列
*/
table.prototype._updatenumericcol = function () {
var _this = this;
var $th;
var $tdrow;
_this.$throw.find('th').each(function (i, th) {
$th = $(th);
_this.$tdrows.each(function () {
$tdrow = $(this);
var method = $th.hasclass('mdui-table-col-numeric') ? 'addclass' : 'removeclass';
$tdrow.find('td').eq(i)[method]('mdui-table-col-numeric');
});
});
};
$(function () {
// 实例化表格
$('.mdui-table').each(function () {
var $table = $(this);
if (!$table.data('mdui.table')) {
$table.data('mdui.table', new table($table));
}
});
});
/**
* 更新表格
*/
mdui.updatetables = function () {
$(arguments.length ? arguments[0] : '.mdui-table').each(function () {
var $table = $(this);
var inst = $table.data('mdui.table');
if (inst) {
inst.init();
} else {
$table.data('mdui.table', new table($table));
}
});
};
})();
/**
* =============================================================================
* ************ 涟漪 ************
* =============================================================================
*
* inspired by https://github.com/nolimits4web/framework7/blob/master/src/js/fast-clicks.js
* https://github.com/nolimits4web/framework7/blob/master/license
*
* inspired by https://github.com/fians/waves
*/
(function () {
var ripple = {
/**
* 显示涟漪动画
* @param e
* @param $ripple
*/
show: function (e, $ripple) {
// 鼠标右键不产生涟漪
if (e.button === 2) {
return;
}
// 点击位置坐标
var tmp;
if ('touches' in e && e.touches.length) {
tmp = e.touches[0];
} else {
tmp = e;
}
var touchstartx = tmp.pagex;
var touchstarty = tmp.pagey;
// 涟漪位置
var offset = $ripple.offset();
var center = {
x: touchstartx - offset.left,
y: touchstarty - offset.top,
};
var height = $ripple.innerheight();
var width = $ripple.innerwidth();
var diameter = math.max(
math.pow((math.pow(height, 2) + math.pow(width, 2)), 0.5), 48
);
// 涟漪扩散动画
var translate =
'translate3d(' + (-center.x + width / 2) + 'px, ' + (-center.y + height / 2) + 'px, 0) ' +
'scale(1)';
// 涟漪的 dom 结构
$('
' +
'
')
// 缓存动画效果
.data('translate', translate)
.prependto($ripple)
.reflow()
.transform(translate);
},
/**
* 隐藏涟漪动画
*/
hide: function () {
var $ripple = $(this);
$ripple.children('.mdui-ripple-wave').each(function () {
removeripple($(this));
});
$ripple.off('touchmove touchend touchcancel mousemove mouseup mouseleave', ripple.hide);
},
};
/**
* 隐藏并移除涟漪
* @param $wave
*/
function removeripple($wave) {
if (!$wave.length || $wave.data('isremoved')) {
return;
}
$wave.data('isremoved', true);
var removetimeout = settimeout(function () {
$wave.remove();
}, 400);
var translate = $wave.data('translate');
$wave
.addclass('mdui-ripple-wave-fill')
.transform(translate.replace('scale(1)', 'scale(1.01)'))
.transitionend(function () {
cleartimeout(removetimeout);
$wave
.addclass('mdui-ripple-wave-out')
.transform(translate.replace('scale(1)', 'scale(1.01)'));
removetimeout = settimeout(function () {
$wave.remove();
}, 700);
settimeout(function () {
$wave.transitionend(function () {
cleartimeout(removetimeout);
$wave.remove();
});
}, 0);
});
}
/**
* 显示涟漪,并绑定 touchend 等事件
* @param e
*/
function showripple(e) {
if (!touchhandler.isallow(e)) {
return;
}
touchhandler.register(e);
var $ripple;
var $target = $(e.target);
// 获取含 .mdui-ripple 类的元素
if ($target.hasclass('mdui-ripple')) {
$ripple = $target;
} else {
$ripple = $target.parents('.mdui-ripple').eq(0);
}
if ($ripple.length) {
// 禁用状态的元素上不产生涟漪效果
if ($ripple[0].disabled || $ripple.attr('disabled') !== null) {
return;
}
ripple.show(e, $ripple);
$ripple.on('touchmove touchend touchcancel mousemove mouseup mouseleave', ripple.hide);
}
}
// 初始化绑定的事件
$document
.on(touchhandler.start, showripple)
.on(touchhandler.unlock, touchhandler.register);
})();
/**
* =============================================================================
* ************ text field 文本框 ************
* =============================================================================
*/
(function () {
var getprop = function (obj, prop) {
return (
typeof obj === 'object' &&
obj !== null &&
typeof obj[prop] !== 'undefined' &&
obj[prop]
) ? obj[prop] : false;
};
/**
* 输入框事件
* @param e
*/
var inputevent = function (e) {
var input = e.target;
var $input = $(input);
var event = e.type;
var value = $input.val();
// reinit 为 true 时,需要重新初始化文本框
var reinit = getprop(e.detail, 'reinit');
// domloadedevent 为 true 时,为 dom 加载完毕后自动触发的事件
var domloadedevent = getprop(e.detail, 'domloadedevent');
// 文本框类型
var type = $input.attr('type') || '';
if (['checkbox', 'button', 'submit', 'range', 'radio', 'image'].indexof(type) >= 0) {
return;
}
var $textfield = $input.parent('.mdui-textfield');
// 输入框是否聚焦
if (event === 'focus') {
$textfield.addclass('mdui-textfield-focus');
}
if (event === 'blur') {
$textfield.removeclass('mdui-textfield-focus');
}
// 输入框是否为空
if (event === 'blur' || event === 'input') {
$textfield[(value && value !== '') ? 'addclass' : 'removeclass']('mdui-textfield-not-empty');
}
// 输入框是否禁用
$textfield[input.disabled ? 'addclass' : 'removeclass']('mdui-textfield-disabled');
// 表单验证
if ((event === 'input' || event === 'blur') && !domloadedevent) {
if (input.validity) {
$textfield[input.validity.valid ? 'removeclass' : 'addclass']('mdui-textfield-invalid');
}
}
// textarea 高度自动调整
if (e.target.nodename.tolowercase() === 'textarea') {
$input.height('');
var height = input.offsetheight;
var diff = height - input.clientheight;
var scrollheight = input.scrollheight;
if (scrollheight + diff > height) {
var newareaheight = scrollheight + diff;
$input.height(newareaheight);
}
}
// 实时字数统计
if (reinit) {
$textfield
.removeclass('mdui-textfield-has-counter')
.find('.mdui-textfield-counter')
.remove();
}
var maxlength = $input.attr('maxlength');
if (maxlength) {
if (reinit || domloadedevent) {
$('
' +
' / ' + maxlength +
'
').appendto($textfield);
// 如果没有 .mdui-textfield-error 作为占位,需要增加 .mdui-textfield 的下边距,
// 使 .mdui-textfield-counter 不会覆盖在文本框上
if (!$textfield.find('.mdui-textfield-error').length) {
$textfield.addclass('mdui-textfield-has-counter');
}
}
// 字符长度,确保统计方式和 maxlength 一致
var inputed = value.length + value.split('\n').length - 1;
$textfield.find('.mdui-textfield-counter-inputed').text(inputed.tostring());
}
};
// 绑定事件
$document.on('input focus blur', '.mdui-textfield-input', { usecapture: true }, inputevent);
// 可展开文本框展开
$document.on('click', '.mdui-textfield-expandable .mdui-textfield-icon', function () {
$(this)
// 展开文本框
.parents('.mdui-textfield')
.addclass('mdui-textfield-expanded')
// 聚焦到输入框
.find('.mdui-textfield-input')[0].focus();
});
// 可展开文本框关闭
$document.on('click', '.mdui-textfield-expanded .mdui-textfield-close', function () {
$(this)
// 关闭文本框
.parents('.mdui-textfield')
.removeclass('mdui-textfield-expanded')
// 清空输入框
.find('.mdui-textfield-input')
.val('');
});
/**
* 通过 js 更新了表单内容,需要重新进行表单处理
* @param- 如果传入了 .mdui-textfield 所在的 dom 元素,则更新该文本框;否则,更新所有文本框
*/
mdui.updatetextfields = function () {
$(arguments.length ? arguments[0] : '.mdui-textfield').each(function () {
$(this)
.find('.mdui-textfield-input')
.trigger('input', {
reinit: true,
});
});
};
$(function () {
// dom 加载完后自动执行
$('.mdui-textfield-input').each(function () {
$(this).trigger('input', {
domloadedevent: true,
});
});
});
})();
/**
* =============================================================================
* ************ slider 滑块 ************
* =============================================================================
*/
(function () {
/**
* 滑块的值变更后修改滑块样式
* @param $slider
*/
var updatevaluestyle = function ($slider) {
var data = $slider.data();
var $track = data.$track;
var $fill = data.$fill;
var $thumb = data.$thumb;
var $input = data.$input;
var min = data.min;
var max = data.max;
var isdisabled = data.disabled;
var isdiscrete = data.discrete;
var $thumbtext = data.$thumbtext;
var value = $input.val();
var percent = (value - min) / (max - min) * 100;
$fill.width(percent + '%');
$track.width((100 - percent) + '%');
if (isdisabled) {
$fill.css('padding-right', '6px');
$track.css('padding-left', '6px');
}
$thumb.css('left', percent + '%');
if (isdiscrete) {
$thumbtext.text(value);
}
$slider[parsefloat(percent) === 0 ? 'addclass' : 'removeclass']('mdui-slider-zero');
};
/**
* 重新初始化
* @param $slider
*/
var reinit = function ($slider) {
var $track = $('
');
var $fill = $('
');
var $thumb = $('
');
var $input = $slider.find('input[type="range"]');
// 禁用状态
var isdisabled = $input[0].disabled;
$slider[isdisabled ? 'addclass' : 'removeclass']('mdui-slider-disabled');
// 重新填充 html
$slider.find('.mdui-slider-track').remove();
$slider.find('.mdui-slider-fill').remove();
$slider.find('.mdui-slider-thumb').remove();
$slider.append($track).append($fill).append($thumb);
// 间续型滑块
var isdiscrete = $slider.hasclass('mdui-slider-discrete');
var $thumbtext;
if (isdiscrete) {
$thumbtext = $('
');
$thumb.empty().append($thumbtext);
}
$slider.data({
$track: $track,
$fill: $fill,
$thumb: $thumb,
$input: $input,
min: $input.attr('min'), // 滑块最小值
max: $input.attr('max'), // 滑块最大值
disabled: isdisabled, // 是否禁用状态
discrete: isdiscrete, // 是否是间续型滑块
$thumbtext: $thumbtext, // 间续型滑块的数值
});
// 设置默认值
updatevaluestyle($slider);
};
var rangeselector = '.mdui-slider input[type="range"]';
$document
// 滑动滑块事件
.on('input change', rangeselector, function () {
var $slider = $(this).parent();
updatevaluestyle($slider);
})
// 开始触摸滑块事件
.on(touchhandler.start, rangeselector, function (e) {
if (!touchhandler.isallow(e)) {
return;
}
touchhandler.register(e);
if (!this.disabled) {
var $slider = $(this).parent();
$slider.addclass('mdui-slider-focus');
}
})
// 结束触摸滑块事件
.on(touchhandler.end, rangeselector, function (e) {
if (!touchhandler.isallow(e)) {
return;
}
if (!this.disabled) {
var $slider = $(this).parent();
$slider.removeclass('mdui-slider-focus');
}
})
.on(touchhandler.unlock, rangeselector, touchhandler.register);
/**
* 页面加载完后自动初始化
*/
$(function () {
$('.mdui-slider').each(function () {
reinit($(this));
});
});
/**
* 重新初始化滑块
*/
mdui.updatesliders = function () {
$(arguments.length ? arguments[0] : '.mdui-slider').each(function () {
reinit($(this));
});
};
})();
/**
* =============================================================================
* ************ fab 浮动操作按钮 ************
* =============================================================================
*/
mdui.fab = (function () {
/**
* 默认参数
* @type {{}}
*/
var default = {
trigger: 'hover', // 触发方式 ['hover', 'click']
};
/**
* 浮动操作按钮实例
* @param selector 选择器或 html 字符串或 dom 元素或 jq 对象
* @param opts
* @constructor
*/
function fab(selector, opts) {
var _this = this;
_this.$fab = $(selector).eq(0);
if (!_this.$fab.length) {
return;
}
// 已通过 data 属性实例化过,不再重复实例化
var oldinst = _this.$fab.data('mdui.fab');
if (oldinst) {
return oldinst;
}
_this.options = $.extend({}, default, (opts || {}));
_this.state = 'closed';
_this.$btn = _this.$fab.find('.mdui-fab');
_this.$dial = _this.$fab.find('.mdui-fab-dial');
_this.$dialbtns = _this.$dial.find('.mdui-fab');
if (_this.options.trigger === 'hover') {
_this.$btn
.on('touchstart mouseenter', function () {
_this.open();
});
_this.$fab
.on('mouseleave', function () {
_this.close();
});
}
if (_this.options.trigger === 'click') {
_this.$btn
.on(touchhandler.start, function () {
_this.open();
});
}
// 触摸屏幕其他地方关闭快速拨号
$document.on(touchhandler.start, function (e) {
if (!$(e.target).parents('.mdui-fab-wrapper').length) {
_this.close();
}
});
}
/**
* 打开菜单
*/
fab.prototype.open = function () {
var _this = this;
if (_this.state === 'opening' || _this.state === 'opened') {
return;
}
// 为菜单中的按钮添加不同的 transition-delay
_this.$dialbtns.each(function (index, btn) {
btn.style['transition-delay'] = btn.style['-webkit-transition-delay'] =
15 * (_this.$dialbtns.length - index) + 'ms';
});
_this.$dial.addclass('mdui-fab-dial-show');
// 如果按钮中存在 .mdui-fab-opened 的图标,则进行图标切换
if (_this.$btn.find('.mdui-fab-opened').length) {
_this.$btn.addclass('mdui-fab-opened');
}
_this.state = 'opening';
componentevent('open', 'fab', _this, _this.$fab);
// 打开顺序为从下到上逐个打开,最上面的打开后才表示动画完成
_this.$dialbtns.eq(0).transitionend(function () {
if (_this.$btn.hasclass('mdui-fab-opened')) {
_this.state = 'opened';
componentevent('opened', 'fab', _this, _this.$fab);
}
});
};
/**
* 关闭菜单
*/
fab.prototype.close = function () {
var _this = this;
if (_this.state === 'closing' || _this.state === 'closed') {
return;
}
// 为菜单中的按钮添加不同的 transition-delay
_this.$dialbtns.each(function (index, btn) {
btn.style['transition-delay'] = btn.style['-webkit-transition-delay'] = 15 * index + 'ms';
});
_this.$dial.removeclass('mdui-fab-dial-show');
_this.$btn.removeclass('mdui-fab-opened');
_this.state = 'closing';
componentevent('close', 'fab', _this, _this.$fab);
// 从上往下依次关闭,最后一个关闭后才表示动画完成
_this.$dialbtns.eq(-1).transitionend(function () {
if (!_this.$btn.hasclass('mdui-fab-opened')) {
_this.state = 'closed';
componentevent('closed', 'fab', _this, _this.$fab);
}
});
};
/**
* 切换菜单的打开状态
*/
fab.prototype.toggle = function () {
var _this = this;
if (_this.state === 'opening' || _this.state === 'opened') {
_this.close();
} else if (_this.state === 'closing' || _this.state === 'closed') {
_this.open();
}
};
/**
* 获取当前菜单状态
* @returns {'opening'|'opened'|'closing'|'closed'}
*/
fab.prototype.getstate = function () {
return this.state;
};
/**
* 以动画的形式显示浮动操作按钮
*/
fab.prototype.show = function () {
this.$fab.removeclass('mdui-fab-hide');
};
/**
* 以动画的形式隐藏浮动操作按钮
*/
fab.prototype.hide = function () {
this.$fab.addclass('mdui-fab-hide');
};
return fab;
})();
/**
* =============================================================================
* ************ fab data api ************
* =============================================================================
*/
$(function () {
// mouseenter 不冒泡,无法进行事件委托,这里用 mouseover 代替。
// 不管是 click 、 mouseover 还是 touchstart ,都先初始化。
$document.on('touchstart mousedown mouseover', '[mdui-fab]', function (e) {
var $this = $(this);
var inst = $this.data('mdui.fab');
if (!inst) {
var options = parseoptions($this.attr('mdui-fab'));
inst = new mdui.fab($this, options);
$this.data('mdui.fab', inst);
}
});
});
/**
* =============================================================================
* ************ appbar ************
* =============================================================================
* 滚动时自动隐藏应用栏
* mdui-appbar-scroll-hide
* mdui-appbar-scroll-toolbar-hide
*/
$(function () {
// 滚动时隐藏应用栏
$('.mdui-appbar-scroll-hide').each(function () {
var $this = $(this);
$this.data('mdui.headroom', new mdui.headroom($this));
});
// 滚动时只隐藏应用栏中的工具栏
$('.mdui-appbar-scroll-toolbar-hide').each(function () {
var $this = $(this);
var inst = new mdui.headroom($this, {
pinnedclass: 'mdui-headroom-pinned-toolbar',
unpinnedclass: 'mdui-headroom-unpinned-toolbar',
});
$this.data('mdui.headroom', inst);
});
});
/**
* =============================================================================
* ************ tab ************
* =============================================================================
*/
mdui.tab = (function () {
var default = {
trigger: 'click', // 触发方式 click: 鼠标点击切换 hover: 鼠标悬浮切换
//animation: false, // 切换时是否显示动画
loop: false, // 为true时,在最后一个选项卡时调用 next() 方法会回到第一个选项卡
};
// 元素是否已禁用
var isdisabled = function ($ele) {
return $ele[0].disabled || $ele.attr('disabled') !== null;
};
/**
* 选项卡
* @param selector
* @param opts
* @returns {*}
* @constructor
*/
function tab(selector, opts) {
var _this = this;
_this.$tab = $(selector).eq(0);
if (!_this.$tab.length) {
return;
}
// 已通过自定义属性实例化过,不再重复实例化
var oldinst = _this.$tab.data('mdui.tab');
if (oldinst) {
return oldinst;
}
_this.options = $.extend({}, default, (opts || {}));
_this.$tabs = _this.$tab.children('a');
_this.$indicator = $('
').appendto(_this.$tab);
_this.activeindex = false;
// 根据 url hash 获取默认激活的选项卡
var hash = location.hash;
if (hash) {
_this.$tabs.each(function (i, tab) {
if ($(tab).attr('href') === hash) {
_this.activeindex = i;
return false;
}
});
}
// 含 mdui-tab-active 的元素默认激活
if (_this.activeindex === false) {
_this.$tabs.each(function (i, tab) {
if ($(tab).hasclass('mdui-tab-active')) {
_this.activeindex = i;
return false;
}
});
}
// 默认激活第一个选项卡
if (_this.activeindex === false) {
_this.activeindex = 0;
}
// 设置激活状态选项卡
_this._setactive();
// 监听窗口大小变化事件,调整指示器位置
$window.on('resize', $.throttle(function () {
_this._setindicatorposition();
}, 100));
// 监听点击选项卡事件
_this.$tabs.each(function (i, tab) {
var $tab = $(tab);
// 点击或鼠标移入触发的事件
var clickevent = function (e) {
// 禁用状态的选项无法选中
if (isdisabled($tab)) {
e.preventdefault();
return;
}
_this.activeindex = i;
_this._setactive();
};
// 无论 trigger 是 click 还是 hover,都会响应 click 事件
$tab.on('click', clickevent);
// trigger 为 hover 时,额外响应 mouseenter 事件
if (_this.options.trigger === 'hover') {
$tab.on('mouseenter', clickevent);
}
$tab.on('click', function (e) {
// 阻止链接的默认点击动作
if ($tab.attr('href').indexof('#') === 0) {
e.preventdefault();
}
});
});
}
/**
* 设置激活状态的选项卡
*/
tab.prototype._setactive = function () {
var _this = this;
_this.$tabs.each(function (i, tab) {
var $tab = $(tab);
var targetid = $tab.attr('href');
// 设置选项卡激活状态
if (i === _this.activeindex && !isdisabled($tab)) {
if (!$tab.hasclass('mdui-tab-active')) {
componentevent('change', 'tab', _this, _this.$tab, {
index: _this.activeindex,
target: tab,
});
componentevent('show', 'tab', _this, $tab);
$tab.addclass('mdui-tab-active');
}
$(targetid).show();
_this._setindicatorposition();
} else {
$tab.removeclass('mdui-tab-active');
$(targetid).hide();
}
});
};
/**
* 设置选项卡指示器的位置
*/
tab.prototype._setindicatorposition = function () {
var _this = this;
var $activetab = _this.$tabs.eq(_this.activeindex);
if (isdisabled($activetab)) {
return;
}
var activetaboffset = $activetab.offset();
_this.$indicator.css({
left: activetaboffset.left + _this.$tab[0].scrollleft -
_this.$tab[0].getboundingclientrect().left + 'px',
width: $activetab.width() + 'px',
});
};
/**
* 切换到下一个选项卡
*/
tab.prototype.next = function () {
var _this = this;
if (_this.$tabs.length > _this.activeindex + 1) {
_this.activeindex++;
} else if (_this.options.loop) {
_this.activeindex = 0;
}
_this._setactive();
};
/**
* 切换到上一个选项卡
*/
tab.prototype.prev = function () {
var _this = this;
if (_this.activeindex > 0) {
_this.activeindex--;
} else if (_this.options.loop) {
_this.activeindex = _this.$tabs.length - 1;
}
_this._setactive();
};
/**
* 显示指定序号或指定id的选项卡
* @param index 从0开始的序号,或以#开头的id
*/
tab.prototype.show = function (index) {
var _this = this;
if (parseint(index) === index) {
_this.activeindex = index;
} else {
_this.$tabs.each(function (i, tab) {
if (tab.id === index) {
_this.activeindex = i;
return false;
}
});
}
_this._setactive();
};
/**
* 在父元素的宽度变化时,需要调用该方法重新调整指示器位置
*/
tab.prototype.handleupdate = function () {
this._setindicatorposition();
};
return tab;
})();
/**
* =============================================================================
* ************ tab 自定义属性 api ************
* =============================================================================
*/
$(function () {
$('[mdui-tab]').each(function () {
var $this = $(this);
var inst = $this.data('mdui.tab');
if (!inst) {
inst = new mdui.tab($this, parseoptions($this.attr('mdui-tab')));
$this.data('mdui.tab', inst);
}
});
});
/**
* =============================================================================
* ************ drawer 抽屉栏 ************
* =============================================================================
*
* 在桌面设备上默认显示抽屉栏,不显示遮罩层
* 在手机和平板设备上默认不显示抽屉栏,始终显示遮罩层,且覆盖导航栏
*/
mdui.drawer = (function () {
/**
* 默认参数
* @type {{}}
*/
var default = {
// 在桌面设备上是否显示遮罩层。手机和平板不受这个参数影响,始终会显示遮罩层
overlay: false,
};
var isdesktop = function () {
return $window.width() >= 1024;
};
/**
* 抽屉栏实例
* @param selector 选择器或 html 字符串或 dom 元素
* @param opts
* @constructor
*/
function drawer(selector, opts) {
var _this = this;
_this.$drawer = $(selector).eq(0);
if (!_this.$drawer.length) {
return;
}
var oldinst = _this.$drawer.data('mdui.drawer');
if (oldinst) {
return oldinst;
}
_this.options = $.extend({}, default, (opts || {}));
_this.overlay = false; // 是否显示着遮罩层
_this.position = _this.$drawer.hasclass('mdui-drawer-right') ? 'right' : 'left';
if (_this.$drawer.hasclass('mdui-drawer-close')) {
_this.state = 'closed';
} else if (_this.$drawer.hasclass('mdui-drawer-open')) {
_this.state = 'opened';
} else if (isdesktop()) {
_this.state = 'opened';
} else {
_this.state = 'closed';
}
// 浏览器窗口大小调整时
$window.on('resize', $.throttle(function () {
// 由手机平板切换到桌面时
if (isdesktop()) {
// 如果显示着遮罩,则隐藏遮罩
if (_this.overlay && !_this.options.overlay) {
$.hideoverlay();
_this.overlay = false;
$.unlockscreen();
}
// 没有强制关闭,则状态为打开状态
if (!_this.$drawer.hasclass('mdui-drawer-close')) {
_this.state = 'opened';
}
}
// 由桌面切换到手机平板时。如果抽屉栏是打开着的且没有遮罩层,则关闭抽屉栏
else {
if (!_this.overlay && _this.state === 'opened') {
// 抽屉栏处于强制打开状态,添加遮罩
if (_this.$drawer.hasclass('mdui-drawer-open')) {
$.showoverlay();
_this.overlay = true;
$.lockscreen();
$('.mdui-overlay').one('click', function () {
_this.close();
});
} else {
_this.state = 'closed';
}
}
}
}, 100));
// 绑定关闭按钮事件
_this.$drawer.find('[mdui-drawer-close]').each(function () {
$(this).on('click', function () {
_this.close();
});
});
}
/**
* 动画结束回调
* @param inst
*/
var transitionend = function (inst) {
if (inst.$drawer.hasclass('mdui-drawer-open')) {
inst.state = 'opened';
componentevent('opened', 'drawer', inst, inst.$drawer);
} else {
inst.state = 'closed';
componentevent('closed', 'drawer', inst, inst.$drawer);
}
};
/**
* 打开抽屉栏
*/
drawer.prototype.open = function () {
var _this = this;
if (_this.state === 'opening' || _this.state === 'opened') {
return;
}
_this.state = 'opening';
componentevent('open', 'drawer', _this, _this.$drawer);
if (!_this.options.overlay) {
$body.addclass('mdui-drawer-body-' + _this.position);
}
_this.$drawer
.removeclass('mdui-drawer-close')
.addclass('mdui-drawer-open')
.transitionend(function () {
transitionend(_this);
});
if (!isdesktop() || _this.options.overlay) {
_this.overlay = true;
$.showoverlay().one('click', function () {
_this.close();
});
$.lockscreen();
}
};
/**
* 关闭抽屉栏
*/
drawer.prototype.close = function () {
var _this = this;
if (_this.state === 'closing' || _this.state === 'closed') {
return;
}
_this.state = 'closing';
componentevent('close', 'drawer', _this, _this.$drawer);
if (!_this.options.overlay) {
$body.removeclass('mdui-drawer-body-' + _this.position);
}
_this.$drawer
.addclass('mdui-drawer-close')
.removeclass('mdui-drawer-open')
.transitionend(function () {
transitionend(_this);
});
if (_this.overlay) {
$.hideoverlay();
_this.overlay = false;
$.unlockscreen();
}
};
/**
* 切换抽屉栏打开/关闭状态
*/
drawer.prototype.toggle = function () {
var _this = this;
if (_this.state === 'opening' || _this.state === 'opened') {
_this.close();
} else if (_this.state === 'closing' || _this.state === 'closed') {
_this.open();
}
};
/**
* 获取抽屉栏状态
* @returns {'opening'|'opened'|'closing'|'closed'}
*/
drawer.prototype.getstate = function () {
return this.state;
};
return drawer;
})();
/**
* =============================================================================
* ************ drawer 自定义属性 api ************
* =============================================================================
*/
$(function () {
$('[mdui-drawer]').each(function () {
var $this = $(this);
var options = parseoptions($this.attr('mdui-drawer'));
var selector = options.target;
delete options.target;
var $drawer = $(selector).eq(0);
var inst = $drawer.data('mdui.drawer');
if (!inst) {
inst = new mdui.drawer($drawer, options);
$drawer.data('mdui.drawer', inst);
}
$this.on('click', function () {
inst.toggle();
});
});
});
/**
* =============================================================================
* ************ dialog 对话框 ************
* =============================================================================
*/
mdui.dialog = (function () {
/**
* 默认参数
*/
var default = {
history: true, // 监听 hashchange 事件
overlay: true, // 打开对话框时是否显示遮罩
modal: false, // 是否模态化对话框,为 false 时点击对话框外面区域关闭对话框,为 true 时不关闭
closeonesc: true, // 按下 esc 关闭对话框
closeoncancel: true, // 按下取消按钮时关闭对话框
closeonconfirm: true, // 按下确认按钮时关闭对话框
destroyonclosed: false, // 关闭后销毁
};
/**
* 遮罩层元素
*/
var $overlay;
/**
* 窗口是否已锁定
*/
var islockscreen;
/**
* 当前对话框实例
*/
var currentinst;
/**
* 队列名
* @type {string}
*/
var queuename = '__md_dialog';
/**
* 窗口宽度变化,或对话框内容变化时,调整对话框位置和对话框内的滚动条
*/
var readjust = function () {
if (!currentinst) {
return;
}
var $dialog = currentinst.$dialog;
var $dialogtitle = $dialog.children('.mdui-dialog-title');
var $dialogcontent = $dialog.children('.mdui-dialog-content');
var $dialogactions = $dialog.children('.mdui-dialog-actions');
// 调整 dialog 的 top 和 height 值
$dialog.height('');
$dialogcontent.height('');
var dialogheight = $dialog.height();
$dialog.css({
top: (($window.height() - dialogheight) / 2) + 'px',
height: dialogheight + 'px',
});
// 调整 mdui-dialog-content 的高度
$dialogcontent.height(
dialogheight -
($dialogtitle.height() || 0) -
($dialogactions.height() || 0)
);
};
/**
* hashchange 事件触发时关闭对话框
*/
var hashchangeevent = function () {
if (location.hash.substring(1).indexof('&mdui-dialog') < 0) {
currentinst.close(true);
}
};
/**
* 点击遮罩层关闭对话框
* @param e
*/
var overlayclick = function (e) {
if ($(e.target).hasclass('mdui-overlay')) {
currentinst.close();
}
};
/**
* 对话框实例
* @param selector 选择器或 html 字符串或 dom 元素
* @param opts
* @constructor
*/
function dialog(selector, opts) {
var _this = this;
// 对话框元素
_this.$dialog = $(selector).eq(0);
if (!_this.$dialog.length) {
return;
}
// 已通过 data 属性实例化过,不再重复实例化
var oldinst = _this.$dialog.data('mdui.dialog');
if (oldinst) {
return oldinst;
}
// 如果对话框元素没有在当前文档中,则需要添加
if (!$.contains($body[0], _this.$dialog[0])) {
_this.append = true;
$body.append(_this.$dialog);
}
_this.options = $.extend({}, default, (opts || {}));
_this.state = 'closed';
// 绑定取消按钮事件
_this.$dialog.find('[mdui-dialog-cancel]').each(function () {
$(this).on('click', function () {
componentevent('cancel', 'dialog', _this, _this.$dialog);
if (_this.options.closeoncancel) {
_this.close();
}
});
});
// 绑定确认按钮事件
_this.$dialog.find('[mdui-dialog-confirm]').each(function () {
$(this).on('click', function () {
componentevent('confirm', 'dialog', _this, _this.$dialog);
if (_this.options.closeonconfirm) {
_this.close();
}
});
});
// 绑定关闭按钮事件
_this.$dialog.find('[mdui-dialog-close]').each(function () {
$(this).on('click', function () {
_this.close();
});
});
}
/**
* 打开指定对话框
* @private
*/
dialog.prototype._doopen = function () {
var _this = this;
currentinst = _this;
if (!islockscreen) {
$.lockscreen();
islockscreen = true;
}
_this.$dialog.show();
readjust();
$window.on('resize', $.throttle(function () {
readjust();
}, 100));
// 打开消息框
_this.state = 'opening';
componentevent('open', 'dialog', _this, _this.$dialog);
_this.$dialog
.addclass('mdui-dialog-open')
.transitionend(function () {
if (_this.$dialog.hasclass('mdui-dialog-open')) {
_this.state = 'opened';
componentevent('opened', 'dialog', _this, _this.$dialog);
} else {
_this.state = 'closed';
componentevent('closed', 'dialog', _this, _this.$dialog);
}
});
// 不存在遮罩层元素时,添加遮罩层
if (!$overlay) {
$overlay = $.showoverlay(5100);
}
$overlay
// 点击遮罩层时是否关闭对话框
[_this.options.modal ? 'off' : 'on']('click', overlayclick)
// 是否显示遮罩层,不显示时,把遮罩层背景透明
.css('opacity', _this.options.overlay ? '' : 0);
if (_this.options.history) {
// 如果 hash 中原来就有 &mdui-dialog,先删除,避免后退历史纪录后仍然有 &mdui-dialog 导致无法关闭
var hash = location.hash.substring(1);
if (hash.indexof('&mdui-dialog') > -1) {
hash = hash.replace(/&mdui-dialog/g, '');
}
// 后退按钮关闭对话框
location.hash = hash + '&mdui-dialog';
$window.on('hashchange', hashchangeevent);
}
};
/**
* 打开对话框
*/
dialog.prototype.open = function () {
var _this = this;
if (_this.state === 'opening' || _this.state === 'opened') {
return;
}
// 如果当前有正在打开或已经打开的对话框,或队列不为空,则先加入队列,等旧对话框开始关闭时再打开
if (
(currentinst && (currentinst.state === 'opening' || currentinst.state === 'opened')) ||
queue.queue(queuename).length
) {
queue.queue(queuename, function () {
_this._doopen();
});
return;
}
_this._doopen();
};
/**
* 关闭对话框
*/
dialog.prototype.close = function () {
var _this = this;
if (_this.state === 'closing' || _this.state === 'closed') {
return;
}
currentinst = null;
_this.state = 'closing';
componentevent('close', 'dialog', _this, _this.$dialog);
// 所有对话框都关闭,且当前没有打开的对话框时,隐藏遮罩
if (queue.queue(queuename).length === 0 && $overlay) {
$.hideoverlay();
$overlay = null;
}
_this.$dialog
.removeclass('mdui-dialog-open')
.transitionend(function () {
if (!_this.$dialog.hasclass('mdui-dialog-open')) {
_this.state = 'closed';
componentevent('closed', 'dialog', _this, _this.$dialog);
_this.$dialog.hide();
// 所有对话框都关闭,且当前没有打开的对话框时,解锁屏幕
if (queue.queue(queuename).length === 0 && !currentinst && islockscreen) {
$.unlockscreen();
islockscreen = false;
}
$window.off('resize', $.throttle(function () {
readjust();
}, 100));
if (_this.options.destroyonclosed) {
_this.destroy();
}
} else {
_this.state = 'opened';
componentevent('opened', 'dialog', _this, _this.$dialog);
}
});
if (_this.options.history && queue.queue(queuename).length === 0) {
// 是否需要后退历史纪录,默认为 false。
// 为 false 时是通过 js 关闭,需要后退一个历史记录
// 为 true 时是通过后退按钮关闭,不需要后退历史记录
if (!arguments[0]) {
window.history.back();
}
$window.off('hashchange', hashchangeevent);
}
// 关闭旧对话框,打开新对话框。
// 加一点延迟,仅仅为了视觉效果更好。不加延时也不影响功能
settimeout(function () {
queue.dequeue(queuename);
}, 100);
};
/**
* 切换对话框打开/关闭状态
*/
dialog.prototype.toggle = function () {
var _this = this;
if (_this.state === 'opening' || _this.state === 'opened') {
_this.close();
} else if (_this.state === 'closing' || _this.state === 'closed') {
_this.open();
}
};
/**
* 获取对话框状态
* @returns {'opening'|'opened'|'closing'|'closed'}
*/
dialog.prototype.getstate = function () {
return this.state;
};
/**
* 销毁对话框
*/
dialog.prototype.destroy = function () {
var _this = this;
if (_this.append) {
_this.$dialog.remove();
}
_this.$dialog.removedata('mdui.dialog');
if (queue.queue(queuename).length === 0 && !currentinst) {
if ($overlay) {
$.hideoverlay();
$overlay = null;
}
if (islockscreen) {
$.unlockscreen();
islockscreen = false;
}
}
};
/**
* 对话框内容变化时,需要调用该方法来调整对话框位置和滚动条高度
*/
dialog.prototype.handleupdate = function () {
readjust();
};
// esc 按下时关闭对话框
$document.on('keydown', function (e) {
if (
currentinst &&
currentinst.options.closeonesc &&
currentinst.state === 'opened' &&
e.keycode === 27
) {
currentinst.close();
}
});
return dialog;
})();
/**
* =============================================================================
* ************ dialog data api ************
* =============================================================================
*/
$(function () {
$document.on('click', '[mdui-dialog]', function () {
var $this = $(this);
var options = parseoptions($this.attr('mdui-dialog'));
var selector = options.target;
delete options.target;
var $dialog = $(selector).eq(0);
var inst = $dialog.data('mdui.dialog');
if (!inst) {
inst = new mdui.dialog($dialog, options);
$dialog.data('mdui.dialog', inst);
}
inst.open();
});
});
/**
* =============================================================================
* ************ mdui.dialog(options) ************
* =============================================================================
*/
mdui.dialog = function (options) {
/**
* 默认参数
*/
var default = {
title: '', // 标题
content: '', // 文本
buttons: [], // 按钮
stackedbuttons: false, // 垂直排列按钮
cssclass: '', // 在 dialog 上添加的 css 类
history: true, // 监听 hashchange 事件
overlay: true, // 是否显示遮罩
modal: false, // 是否模态化对话框
closeonesc: true, // 按下 esc 时关闭对话框
destroyonclosed: true, // 关闭后销毁
onopen: function () { // 打开动画开始时的回调
},
onopened: function () { // 打开动画结束后的回调
},
onclose: function () { // 关闭动画开始时的回调
},
onclosed: function () { // 关闭动画结束时的回调
},
};
/**
* 按钮的默认参数
*/
var default_button = {
text: '', // 按钮文本
bold: false, // 按钮文本是否加粗
close: true, // 点击按钮后关闭对话框
onclick: function (inst) { // 点击按钮的回调
},
};
// 合并参数
options = $.extend({}, default, (options || {}));
$.each(options.buttons, function (i, button) {
options.buttons[i] = $.extend({}, default_button, button);
});
// 按钮的 html
var buttonshtml = '';
if (options.buttons.length) {
buttonshtml =
'
';
}
// dialog 的 html
var html =
'
' +
(options.title ? '
' + options.title + '
' : '') +
(options.content ? '
' + options.content + '
' : '') +
buttonshtml +
'
';
// 实例化 dialog
var inst = new mdui.dialog(html, {
history: options.history,
overlay: options.overlay,
modal: options.modal,
closeonesc: options.closeonesc,
destroyonclosed: options.destroyonclosed,
});
// 绑定按钮事件
if (options.buttons.length) {
inst.$dialog.find('.mdui-dialog-actions .mdui-btn').each(function (i, button) {
$(button).on('click', function () {
if (typeof options.buttons[i].onclick === 'function') {
options.buttons[i].onclick(inst);
}
if (options.buttons[i].close) {
inst.close();
}
});
});
}
// 绑定打开关闭事件
if (typeof options.onopen === 'function') {
inst.$dialog
.on('open.mdui.dialog', function () {
options.onopen(inst);
})
.on('opened.mdui.dialog', function () {
options.onopened(inst);
})
.on('close.mdui.dialog', function () {
options.onclose(inst);
})
.on('closed.mdui.dialog', function () {
options.onclosed(inst);
});
}
inst.open();
return inst;
};
/**
* =============================================================================
* ************ mdui.alert(text, title, onconfirm, options) ************
* ************ mdui.alert(text, onconfirm, options) ************
* =============================================================================
*/
mdui.alert = function (text, title, onconfirm, options) {
// title 参数可选
if (typeof title === 'function') {
title = '';
onconfirm = arguments[1];
options = arguments[2];
}
if (onconfirm === undefined) {
onconfirm = function () {};
}
if (options === undefined) {
options = {};
}
/**
* 默认参数
*/
var default = {
confirmtext: 'ok', // 按钮上的文本
history: true, // 监听 hashchange 事件
modal: false, // 是否模态化对话框,为 false 时点击对话框外面区域关闭对话框,为 true 时不关闭
closeonesc: true, // 按下 esc 关闭对话框
};
options = $.extend({}, default, options);
return mdui.dialog({
title: title,
content: text,
buttons: [
{
text: options.confirmtext,
bold: false,
close: true,
onclick: onconfirm,
},
],
cssclass: 'mdui-dialog-alert',
history: options.history,
modal: options.modal,
closeonesc: options.closeonesc,
});
};
/**
* =============================================================================
* ************ mdui.confirm(text, title, onconfirm, oncancel, options) ************
* ************ mdui.confirm(text, onconfirm, oncancel, options) ************
* =============================================================================
*/
mdui.confirm = function (text, title, onconfirm, oncancel, options) {
// title 参数可选
if (typeof title === 'function') {
title = '';
onconfirm = arguments[1];
oncancel = arguments[2];
options = arguments[3];
}
if (onconfirm === undefined) {
onconfirm = function () {};
}
if (oncancel === undefined) {
oncancel = function () {};
}
if (options === undefined) {
options = {};
}
/**
* 默认参数
*/
var default = {
confirmtext: 'ok', // 确认按钮的文本
canceltext: 'cancel', // 取消按钮的文本
history: true, // 监听 hashchange 事件
modal: false, // 是否模态化对话框,为 false 时点击对话框外面区域关闭对话框,为 true 时不关闭
closeonesc: true, // 按下 esc 关闭对话框
};
options = $.extend({}, default, options);
return mdui.dialog({
title: title,
content: text,
buttons: [
{
text: options.canceltext,
bold: false,
close: true,
onclick: oncancel,
},
{
text: options.confirmtext,
bold: false,
close: true,
onclick: onconfirm,
},
],
cssclass: 'mdui-dialog-confirm',
history: options.history,
modal: options.modal,
closeonesc: options.closeonesc,
});
};
/**
* =============================================================================
* ************ mdui.prompt(label, title, onconfirm, oncancel, options) ************
* ************ mdui.prompt(label, onconfirm, oncancel, options) ************
* =============================================================================
*/
mdui.prompt = function (label, title, onconfirm, oncancel, options) {
// title 参数可选
if (typeof title === 'function') {
title = '';
onconfirm = arguments[1];
oncancel = arguments[2];
options = arguments[3];
}
if (onconfirm === undefined) {
onconfirm = function () {};
}
if (oncancel === undefined) {
oncancel = function () {};
}
if (options === undefined) {
options = {};
}
/**
* 默认参数
*/
var default = {
confirmtext: 'ok', // 确认按钮的文本
canceltext: 'cancel', // 取消按钮的文本
history: true, // 监听 hashchange 事件
modal: false, // 是否模态化对话框,为 false 时点击对话框外面区域关闭对话框,为 true 时不关闭
closeonesc: true, // 按下 esc 关闭对话框
type: 'text', // 输入框类型,text: 单行文本框 textarea: 多行文本框
maxlength: '', // 最大输入字符数
defaultvalue: '', // 输入框中的默认文本
};
options = $.extend({}, default, options);
var content =
'
' +
(label ? '' : '') +
(options.type === 'text' ?
'' :
'') +
(options.type === 'textarea' ?
'' :
'') +
'
';
return mdui.dialog({
title: title,
content: content,
buttons: [
{
text: options.canceltext,
bold: false,
close: true,
onclick: function (inst) {
var value = inst.$dialog.find('.mdui-textfield-input').val();
oncancel(value, inst);
},
},
{
text: options.confirmtext,
bold: false,
close: true,
onclick: function (inst) {
var value = inst.$dialog.find('.mdui-textfield-input').val();
onconfirm(value, inst);
},
},
],
cssclass: 'mdui-dialog-prompt',
history: options.history,
modal: options.modal,
closeonesc: options.closeonesc,
onopen: function (inst) {
// 初始化输入框
var $input = inst.$dialog.find('.mdui-textfield-input');
mdui.updatetextfields($input);
// 聚焦到输入框
$input[0].focus();
// 如果是多行输入框,监听输入框的 input 事件,更新对话框高度
if (options.type === 'textarea') {
$input.on('input', function () {
inst.handleupdate();
});
}
// 有字符数限制时,加载完文本框后 dom 会变化,需要更新对话框高度
if (options.maxlength) {
inst.handleupdate();
}
},
});
};
/**
* =============================================================================
* ************ tooltip 工具提示 ************
* =============================================================================
*/
mdui.tooltip = (function () {
/**
* 默认参数
*/
var default = {
position: 'auto', // 提示所在位置
delay: 0, // 延迟,单位毫秒
content: '', // 提示文本,允许包含 html
};
/**
* 是否是桌面设备
* @returns {boolean}
*/
var isdesktop = function () {
return $window.width() > 1024;
};
/**
* 设置 tooltip 的位置
* @param inst
*/
function setposition(inst) {
var marginleft;
var margintop;
var position;
// 触发的元素
var targetprops = inst.$target[0].getboundingclientrect();
// 触发的元素和 tooltip 之间的距离
var targetmargin = (isdesktop() ? 14 : 24);
// tooltip 的宽度和高度
var tooltipwidth = inst.$tooltip[0].offsetwidth;
var tooltipheight = inst.$tooltip[0].offsetheight;
// tooltip 的方向
position = inst.options.position;
// 自动判断位置,加 2px,使 tooltip 距离窗口边框至少有 2px 的间距
if (['bottom', 'top', 'left', 'right'].indexof(position) === -1) {
if (
targetprops.top + targetprops.height + targetmargin + tooltipheight + 2 <
$window.height()
) {
position = 'bottom';
} else if (targetmargin + tooltipheight + 2 < targetprops.top) {
position = 'top';
} else if (targetmargin + tooltipwidth + 2 < targetprops.left) {
position = 'left';
} else if (
targetprops.width + targetmargin + tooltipwidth + 2 <
$window.width() - targetprops.left
) {
position = 'right';
} else {
position = 'bottom';
}
}
// 设置位置
switch (position) {
case 'bottom':
marginleft = -1 * (tooltipwidth / 2);
margintop = (targetprops.height / 2) + targetmargin;
inst.$tooltip.transformorigin('top center');
break;
case 'top':
marginleft = -1 * (tooltipwidth / 2);
margintop = -1 * (tooltipheight + (targetprops.height / 2) + targetmargin);
inst.$tooltip.transformorigin('bottom center');
break;
case 'left':
marginleft = -1 * (tooltipwidth + (targetprops.width / 2) + targetmargin);
margintop = -1 * (tooltipheight / 2);
inst.$tooltip.transformorigin('center right');
break;
case 'right':
marginleft = (targetprops.width / 2) + targetmargin;
margintop = -1 * (tooltipheight / 2);
inst.$tooltip.transformorigin('center left');
break;
}
var targetoffset = inst.$target.offset();
inst.$tooltip.css({
top: targetoffset.top + (targetprops.height / 2) + 'px',
left: targetoffset.left + (targetprops.width / 2) + 'px',
'margin-left': marginleft + 'px',
'margin-top': margintop + 'px',
});
}
/**
* tooltip 实例
* @param selector
* @param opts
* @constructor
*/
function tooltip(selector, opts) {
var _this = this;
_this.$target = $(selector).eq(0);
if (!_this.$target.length) {
return;
}
// 已通过 data 属性实例化过,不再重复实例化
var oldinst = _this.$target.data('mdui.tooltip');
if (oldinst) {
return oldinst;
}
_this.options = $.extend({}, default, (opts || {}));
_this.state = 'closed';
// 创建 tooltip html
var guid = $.guid('tooltip');
_this.$tooltip = $(
'
' +
_this.options.content +
'
'
).appendto($body);
// 绑定事件
_this.$target
.on('touchstart mouseenter', function (e) {
if (!touchhandler.isallow(e)) {
return;
}
touchhandler.register(e);
_this.open();
})
.on('touchend mouseleave', function (e) {
if (!touchhandler.isallow(e)) {
return;
}
_this.close();
})
.on(touchhandler.unlock, touchhandler.register);
}
/**
* 动画结束回调
* @private
*/
var transitionend = function (inst) {
if (inst.$tooltip.hasclass('mdui-tooltip-open')) {
inst.state = 'opened';
componentevent('opened', 'tooltip', inst, inst.$target);
} else {
inst.state = 'closed';
componentevent('closed', 'tooltip', inst, inst.$target);
}
};
/**
* 执行打开 tooltip
* @private
*/
tooltip.prototype._doopen = function () {
var _this = this;
_this.state = 'opening';
componentevent('open', 'tooltip', _this, _this.$target);
_this.$tooltip
.addclass('mdui-tooltip-open')
.transitionend(function () {
transitionend(_this);
});
};
/**
* 打开 tooltip
* @param opts 允许每次打开时设置不同的参数
*/
tooltip.prototype.open = function (opts) {
var _this = this;
if (_this.state === 'opening' || _this.state === 'opened') {
return;
}
var oldopts = _this.options;
// 合并 data 属性参数
$.extend(_this.options, parseoptions(_this.$target.attr('mdui-tooltip')));
if (opts) {
$.extend(_this.options, opts);
}
// tooltip 的内容有更新
if (oldopts.content !== _this.options.content) {
_this.$tooltip.html(_this.options.content);
}
setposition(_this);
if (_this.options.delay) {
_this.timeoutid = settimeout(function () {
_this._doopen();
}, _this.options.delay);
} else {
_this.timeoutid = false;
_this._doopen();
}
};
/**
* 关闭 tooltip
*/
tooltip.prototype.close = function () {
var _this = this;
if (_this.timeoutid) {
cleartimeout(_this.timeoutid);
_this.timeoutid = false;
}
if (_this.state === 'closing' || _this.state === 'closed') {
return;
}
_this.state = 'closing';
componentevent('close', 'tooltip', _this, _this.$target);
_this.$tooltip
.removeclass('mdui-tooltip-open')
.transitionend(function () {
transitionend(_this);
});
};
/**
* 切换 tooltip 状态
*/
tooltip.prototype.toggle = function () {
var _this = this;
if (_this.state === 'opening' || _this.state === 'opened') {
_this.close();
} else if (_this.state === 'closing' || _this.state === 'closed') {
_this.open();
}
};
/**
* 获取 tooltip 状态
* @returns {'opening'|'opened'|'closing'|'closed'}
*/
tooltip.prototype.getstate = function () {
return this.state;
};
/**
* 销毁 tooltip
*/
/*tooltip.prototype.destroy = function () {
var _this = this;
cleartimeout(_this.timeoutid);
$.data(_this.target, 'mdui.tooltip', null);
$.remove(_this.tooltip);
};*/
return tooltip;
})();
/**
* =============================================================================
* ************ tooltip data api ************
* =============================================================================
*/
$(function () {
// mouseenter 不能冒泡,所以这里用 mouseover 代替
$document.on('touchstart mouseover', '[mdui-tooltip]', function () {
var $this = $(this);
var inst = $this.data('mdui.tooltip');
if (!inst) {
var options = parseoptions($this.attr('mdui-tooltip'));
inst = new mdui.tooltip($this, options);
$this.data('mdui.tooltip', inst);
}
});
});
/**
* =============================================================================
* ************ snackbar ************
* =============================================================================
*/
(function () {
/**
* 当前打开着的 snackbar
*/
var currentinst;
/**
* 对列名
* @type {string}
*/
var queuename = '__md_snackbar';
var default = {
message: '', // 文本内容
timeout: 4000, // 在用户没有操作时多长时间自动隐藏
buttontext: '', // 按钮的文本
buttoncolor: '', // 按钮的颜色,支持 blue #90caf9 rgba(...)
closeonbuttonclick: true, // 点击按钮时关闭
closeonoutsideclick: true, // 触摸或点击屏幕其他地方时关闭
onclick: function () { // 在 snackbar 上点击的回调
},
onbuttonclick: function () { // 点击按钮的回调
},
onclose: function () { // 关闭动画开始时的回调
},
};
/**
* 点击 snackbar 外面的区域关闭
* @param e
*/
var closeonoutsideclick = function (e) {
var $target = $(e.target);
if (!$target.hasclass('mdui-snackbar') && !$target.parents('.mdui-snackbar').length) {
currentinst.close();
}
};
/**
* snackbar 实例
* @param opts
* @constructor
*/
function snackbar(opts) {
var _this = this;
_this.options = $.extend({}, default, (opts || {}));
// message 参数必须
if (!_this.options.message) {
return;
}
_this.state = 'closed';
_this.timeoutid = false;
// 按钮颜色
var buttoncolorstyle = '';
var buttoncolorclass = '';
if (
_this.options.buttoncolor.indexof('#') === 0 ||
_this.options.buttoncolor.indexof('rgb') === 0
) {
buttoncolorstyle = 'style="color:' + _this.options.buttoncolor + '"';
} else if (_this.options.buttoncolor !== '') {
buttoncolorclass = 'mdui-text-color-' + _this.options.buttoncolor;
}
// 添加 html
_this.$snackbar = $(
'
')
.appendto($body);
// 设置位置
_this.$snackbar
.transform('translatey(' + _this.$snackbar[0].clientheight + 'px)')
.css('left', (document.body.clientwidth - _this.$snackbar[0].clientwidth) / 2 + 'px')
.addclass('mdui-snackbar-transition');
}
/**
* 打开 snackbar
*/
snackbar.prototype.open = function () {
var _this = this;
if (_this.state === 'opening' || _this.state === 'opened') {
return;
}
// 如果当前有正在显示的 snackbar,则先加入队列,等旧 snackbar 关闭后再打开
if (currentinst) {
queue.queue(queuename, function () {
_this.open();
});
return;
}
currentinst = _this;
// 开始打开
_this.state = 'opening';
_this.$snackbar
.transform('translatey(0)')
.transitionend(function () {
if (_this.state !== 'opening') {
return;
}
_this.state = 'opened';
// 有按钮时绑定事件
if (_this.options.buttontext) {
_this.$snackbar
.find('.mdui-snackbar-action')
.on('click', function () {
_this.options.onbuttonclick();
if (_this.options.closeonbuttonclick) {
_this.close();
}
});
}
// 点击 snackbar 的事件
_this.$snackbar.on('click', function (e) {
if (!$(e.target).hasclass('mdui-snackbar-action')) {
_this.options.onclick();
}
});
// 点击 snackbar 外面的区域关闭
if (_this.options.closeonoutsideclick) {
$document.on(touchhandler.start, closeonoutsideclick);
}
// 超时后自动关闭
_this.timeoutid = settimeout(function () {
_this.close();
}, _this.options.timeout);
});
};
/**
* 关闭 snackbar
*/
snackbar.prototype.close = function () {
var _this = this;
if (_this.state === 'closing' || _this.state === 'closed') {
return;
}
if (_this.timeoutid) {
cleartimeout(_this.timeoutid);
}
if (_this.options.closeonoutsideclick) {
$document.off(touchhandler.start, closeonoutsideclick);
}
_this.state = 'closing';
_this.options.onclose();
_this.$snackbar
.transform('translatey(' + _this.$snackbar[0].clientheight + 'px)')
.transitionend(function () {
if (_this.state !== 'closing') {
return;
}
currentinst = null;
_this.state = 'closed';
_this.$snackbar.remove();
queue.dequeue(queuename);
});
};
/**
* 打开 snackbar
* @param params
*/
mdui.snackbar = function (params) {
var inst = new snackbar(params);
inst.open();
return inst;
};
})();
/**
* =============================================================================
* ************ bottom navigation 底部导航栏 ************
* =============================================================================
*/
(function () {
// 切换导航项
$document.on('click', '.mdui-bottom-nav>a', function () {
var $this = $(this);
var $bottomnav = $this.parent();
var isthis;
$bottomnav.children('a').each(function (i, item) {
isthis = $this.is(item);
if (isthis) {
componentevent('change', 'bottomnav', null, $bottomnav, {
index: i,
});
}
$(item)[isthis ? 'addclass' : 'removeclass']('mdui-bottom-nav-active');
});
});
// 滚动时隐藏 mdui-bottom-nav-scroll-hide
$('.mdui-bottom-nav-scroll-hide').each(function () {
var $this = $(this);
var inst = new mdui.headroom($this, {
pinnedclass: 'mdui-headroom-pinned-down',
unpinnedclass: 'mdui-headroom-unpinned-down',
});
$this.data('mdui.headroom', inst);
});
})();
/**
* =============================================================================
* ************ spinner 圆形进度条 ************
* =============================================================================
*/
(function () {
/**
* layer 的 html 结构
*/
var layerhtml = function () {
var i = arguments.length ? arguments[0] : false;
return '
';
};
/**
* 填充 html
* @param spinner
*/
var fillhtml = function (spinner) {
var $spinner = $(spinner);
var layer;
if ($spinner.hasclass('mdui-spinner-colorful')) {
layer = layerhtml('1') + layerhtml('2') + layerhtml('3') + layerhtml('4');
} else {
layer = layerhtml();
}
$spinner.html(layer);
};
/**
* 页面加载完后自动填充 html 结构
*/
$(function () {
$('.mdui-spinner').each(function () {
fillhtml(this);
});
});
/**
* 更新圆形进度条
*/
mdui.updatespinners = function () {
$(arguments.length ? arguments[0] : '.mdui-spinner').each(function () {
fillhtml(this);
});
};
})();
/**
* =============================================================================
* ************ expansion panel 可扩展面板 ************
* =============================================================================
*/
mdui.panel = (function () {
function panel(selector, opts) {
return new collapseprivate(selector, opts, {
item: 'mdui-panel-item',
itemopen: 'mdui-panel-item-open',
header: 'mdui-panel-item-header',
body: 'mdui-panel-item-body',
}, 'panel');
}
return panel;
})();
/**
* =============================================================================
* ************ expansion panel 自定义属性 ************
* =============================================================================
*/
$(function () {
$('[mdui-panel]').each(function () {
var $target = $(this);
var inst = $target.data('mdui.panel');
if (!inst) {
var options = parseoptions($target.attr('mdui-panel'));
inst = new mdui.panel($target, options);
$target.data('mdui.panel', inst);
}
});
});
/**
* =============================================================================
* ************ menu 菜单 ************
* =============================================================================
*/
mdui.menu = (function () {
/**
* 默认参数
*/
var default = {
position: 'auto', // 菜单位置 top、bottom、center、auto
align: 'auto', // 菜单和触发它的元素的对齐方式 left、right、center、auto
gutter: 16, // 菜单距离窗口边缘的最小距离,单位 px
fixed: false, // 是否使菜单固定在窗口,不随滚动条滚动
covered: 'auto', // 菜单是否覆盖在触发它的元素上,true、false。auto 时简单菜单覆盖,级联菜单不覆盖
submenutrigger: 'hover', // 子菜单的触发方式 hover、click
submenudelay: 200, // 子菜单的触发延时,仅在 submenutrigger 为 hover 有效
};
/**
* 调整主菜单位置
* @param _this 实例
*/
var readjust = function (_this) {
var menuleft;
var menutop;
// 菜单位置和方向
var position;
var align;
// window 窗口的宽度和高度
var windowheight = $window.height();
var windowwidth = $window.width();
// 配置参数
var gutter = _this.options.gutter;
var iscovered = _this.iscovered;
var isfixed = _this.options.fixed;
// 动画方向参数
var transformoriginx;
var transformoriginy;
// 菜单的原始宽度和高度
var menuwidth = _this.$menu.width();
var menuheight = _this.$menu.height();
var $anchor = _this.$anchor;
// 触发菜单的元素在窗口中的位置
var anchortmp = $anchor[0].getboundingclientrect();
var anchortop = anchortmp.top;
var anchorleft = anchortmp.left;
var anchorheight = anchortmp.height;
var anchorwidth = anchortmp.width;
var anchorbottom = windowheight - anchortop - anchorheight;
var anchorright = windowwidth - anchorleft - anchorwidth;
// 触发元素相对其拥有定位属性的父元素的位置
var anchoroffsettop = $anchor[0].offsettop;
var anchoroffsetleft = $anchor[0].offsetleft;
// ===============================
// ================= 自动判断菜单位置
// ===============================
if (_this.options.position === 'auto') {
// 判断下方是否放得下菜单
if (anchorbottom + (iscovered ? anchorheight : 0) > menuheight + gutter) {
position = 'bottom';
}
// 判断上方是否放得下菜单
else if (anchortop + (iscovered ? anchorheight : 0) > menuheight + gutter) {
position = 'top';
}
// 上下都放不下,居中显示
else {
position = 'center';
}
} else {
position = _this.options.position;
}
// ===============================
// ============== 自动判断菜单对齐方式
// ===============================
if (_this.options.align === 'auto') {
// 判断右侧是否放得下菜单
if (anchorright + anchorwidth > menuwidth + gutter) {
align = 'left';
}
// 判断左侧是否放得下菜单
else if (anchorleft + anchorwidth > menuwidth + gutter) {
align = 'right';
}
// 左右都放不下,居中显示
else {
align = 'center';
}
} else {
align = _this.options.align;
}
// ===============================
// ==================== 设置菜单位置
// ===============================
if (position === 'bottom') {
transformoriginy = '0';
menutop =
(iscovered ? 0 : anchorheight) +
(isfixed ? anchortop : anchoroffsettop);
} else if (position === 'top') {
transformoriginy = '100%';
menutop =
(iscovered ? anchorheight : 0) +
(isfixed ? (anchortop - menuheight) : (anchoroffsettop - menuheight));
} else {
transformoriginy = '50%';
// =====================在窗口中居中
// 显示的菜单的高度,简单菜单高度不超过窗口高度,若超过了则在菜单内部显示滚动条
// 级联菜单内部不允许出现滚动条
var menuheighttemp = menuheight;
// 简单菜单比窗口高时,限制菜单高度
if (!_this.$menu.hasclass('mdui-menu-cascade')) {
if (menuheight + gutter * 2 > windowheight) {
menuheighttemp = windowheight - gutter * 2;
_this.$menu.height(menuheighttemp);
}
}
menutop =
(windowheight - menuheighttemp) / 2 +
(isfixed ? 0 : (anchoroffsettop - anchortop));
}
_this.$menu.css('top', menutop + 'px');
// ===============================
// ================= 设置菜单对齐方式
// ===============================
if (align === 'left') {
transformoriginx = '0';
menuleft = isfixed ? anchorleft : anchoroffsetleft;
} else if (align === 'right') {
transformoriginx = '100%';
menuleft = isfixed ?
(anchorleft + anchorwidth - menuwidth) :
(anchoroffsetleft + anchorwidth - menuwidth);
} else {
transformoriginx = '50%';
//=======================在窗口中居中
// 显示的菜单的宽度,菜单宽度不能超过窗口宽度
var menuwidthtemp = menuwidth;
// 菜单比窗口宽,限制菜单宽度
if (menuwidth + gutter * 2 > windowwidth) {
menuwidthtemp = windowwidth - gutter * 2;
_this.$menu.width(menuwidthtemp);
}
menuleft =
(windowwidth - menuwidthtemp) / 2 +
(isfixed ? 0 : anchoroffsetleft - anchorleft);
}
_this.$menu.css('left', menuleft + 'px');
// 设置菜单动画方向
_this.$menu.transformorigin(transformoriginx + ' ' + transformoriginy);
};
/**
* 调整子菜单的位置
* @param $submenu
*/
var readjustsubmenu = function ($submenu) {
var $item = $submenu.parent('.mdui-menu-item');
var submenutop;
var submenuleft;
// 子菜单位置和方向
var position; // top、bottom
var align; // left、right
// window 窗口的宽度和高度
var windowheight = $window.height();
var windowwidth = $window.width();
// 动画方向参数
var transformoriginx;
var transformoriginy;
// 子菜单的原始宽度和高度
var submenuwidth = $submenu.width();
var submenuheight = $submenu.height();
// 触发子菜单的菜单项的宽度高度
var itemtmp = $item[0].getboundingclientrect();
var itemwidth = itemtmp.width;
var itemheight = itemtmp.height;
var itemleft = itemtmp.left;
var itemtop = itemtmp.top;
// ===================================
// ===================== 判断菜单上下位置
// ===================================
// 判断下方是否放得下菜单
if (windowheight - itemtop > submenuheight) {
position = 'bottom';
}
// 判断上方是否放得下菜单
else if (itemtop + itemheight > submenuheight) {
position = 'top';
}
// 默认放在下方
else {
position = 'bottom';
}
// ====================================
// ====================== 判断菜单左右位置
// ====================================
// 判断右侧是否放得下菜单
if (windowwidth - itemleft - itemwidth > submenuwidth) {
align = 'left';
}
// 判断左侧是否放得下菜单
else if (itemleft > submenuwidth) {
align = 'right';
}
// 默认放在右侧
else {
align = 'left';
}
// ===================================
// ======================== 设置菜单位置
// ===================================
if (position === 'bottom') {
transformoriginy = '0';
submenutop = '0';
} else if (position === 'top') {
transformoriginy = '100%';
submenutop = -submenuheight + itemheight;
}
$submenu.css('top', submenutop + 'px');
// ===================================
// ===================== 设置菜单对齐方式
// ===================================
if (align === 'left') {
transformoriginx = '0';
submenuleft = itemwidth;
} else if (align === 'right') {
transformoriginx = '100%';
submenuleft = -submenuwidth;
}
$submenu.css('left', submenuleft + 'px');
// 设置菜单动画方向
$submenu.transformorigin(transformoriginx + ' ' + transformoriginy);
};
/**
* 打开子菜单
* @param $submenu
*/
var opensubmenu = function ($submenu) {
readjustsubmenu($submenu);
$submenu
.addclass('mdui-menu-open')
.parent('.mdui-menu-item')
.addclass('mdui-menu-item-active');
};
/**
* 关闭子菜单,及其嵌套的子菜单
* @param $submenu
*/
var closesubmenu = function ($submenu) {
// 关闭子菜单
$submenu
.removeclass('mdui-menu-open')
// 移除激活状态的样式
.parent('.mdui-menu-item')
.removeclass('mdui-menu-item-active');
// 循环关闭嵌套的子菜单
$submenu.find('.mdui-menu').each(function () {
$(this)
.removeclass('mdui-menu-open')
.parent('.mdui-menu-item')
.removeclass('mdui-menu-item-active');
});
};
/**
* 切换子菜单状态
* @param $submenu
*/
var togglesubmenu = function ($submenu) {
if ($submenu.hasclass('mdui-menu-open')) {
closesubmenu($submenu);
} else {
opensubmenu($submenu);
}
};
/**
* 绑定子菜单事件
* @param inst 实例
*/
var bindsubmenuevent = function (inst) {
// 点击打开子菜单
inst.$menu.on('click', '.mdui-menu-item', function (e) {
var $this = $(this);
var $target = $(e.target);
// 禁用状态菜单不操作
if ($this.attr('disabled') !== null) {
return;
}
// 没有点击在子菜单的菜单项上时,不操作(点在了子菜单的空白区域、或分隔线上)
if ($target.is('.mdui-menu') || $target.is('.mdui-divider')) {
return;
}
// 阻止冒泡,点击菜单项时只在最后一级的 mdui-menu-item 上生效,不向上冒泡
if (!$target.parents('.mdui-menu-item').eq(0).is($this)) {
return;
}
// 当前菜单的子菜单
var $submenu = $this.children('.mdui-menu');
// 先关闭除当前子菜单外的所有同级子菜单
$this.parent('.mdui-menu').children('.mdui-menu-item').each(function () {
var $tmpsubmenu = $(this).children('.mdui-menu');
if (
$tmpsubmenu.length &&
(!$submenu.length || !$tmpsubmenu.is($submenu))
) {
closesubmenu($tmpsubmenu);
}
});
// 切换当前子菜单
if ($submenu.length) {
togglesubmenu($submenu);
}
});
if (inst.options.submenutrigger === 'hover') {
// 临时存储 settimeout 对象
var timeout;
var timeoutopen;
var timeoutclose;
inst.$menu.on('mouseover mouseout', '.mdui-menu-item', function (e) {
var $this = $(this);
var eventtype = e.type;
var $relatedtarget = $(e.relatedtarget);
// 禁用状态的菜单不操作
if ($this.attr('disabled') !== null) {
return;
}
// 用 mouseover 模拟 mouseenter
if (eventtype === 'mouseover') {
if (!$this.is($relatedtarget) && $.contains($this[0], $relatedtarget[0])) {
return;
}
}
// 用 mouseout 模拟 mouseleave
else if (eventtype === 'mouseout') {
if ($this.is($relatedtarget) || $.contains($this[0], $relatedtarget[0])) {
return;
}
}
// 当前菜单项下的子菜单,未必存在
var $submenu = $this.children('.mdui-menu');
// 鼠标移入菜单项时,显示菜单项下的子菜单
if (eventtype === 'mouseover') {
if ($submenu.length) {
// 当前子菜单准备打开时,如果当前子菜单正准备着关闭,不用再关闭了
var tmpclose = $submenu.data('timeoutclose.mdui.menu');
if (tmpclose) {
cleartimeout(tmpclose);
}
// 如果当前子菜单已经打开,不操作
if ($submenu.hasclass('mdui-menu-open')) {
return;
}
// 当前子菜单准备打开时,其他准备打开的子菜单不用再打开了
cleartimeout(timeoutopen);
// 准备打开当前子菜单
timeout = timeoutopen = settimeout(function () {
opensubmenu($submenu);
}, inst.options.submenudelay);
$submenu.data('timeoutopen.mdui.menu', timeout);
}
}
// 鼠标移出菜单项时,关闭菜单项下的子菜单
else if (eventtype === 'mouseout') {
if ($submenu.length) {
// 鼠标移出菜单项时,如果当前菜单项下的子菜单正准备打开,不用再打开了
var tmpopen = $submenu.data('timeoutopen.mdui.menu');
if (tmpopen) {
cleartimeout(tmpopen);
}
// 准备关闭当前子菜单
timeout = timeoutclose = settimeout(function () {
closesubmenu($submenu);
}, inst.options.submenudelay);
$submenu.data('timeoutclose.mdui.menu', timeout);
}
}
});
}
};
/**
* 菜单
* @param anchorselector 点击该元素触发菜单
* @param menuselector 菜单
* @param opts 配置项
* @constructor
*/
function menu(anchorselector, menuselector, opts) {
var _this = this;
// 触发菜单的元素
_this.$anchor = $(anchorselector).eq(0);
if (!_this.$anchor.length) {
return;
}
// 已通过自定义属性实例化过,不再重复实例化
var oldinst = _this.$anchor.data('mdui.menu');
if (oldinst) {
return oldinst;
}
_this.$menu = $(menuselector).eq(0);
// 触发菜单的元素 和 菜单必须是同级的元素,否则菜单可能不能定位
if (!_this.$anchor.siblings(_this.$menu).length) {
return;
}
_this.options = $.extend({}, default, (opts || {}));
_this.state = 'closed';
// 是否是级联菜单
_this.iscascade = _this.$menu.hasclass('mdui-menu-cascade');
// covered 参数处理
if (_this.options.covered === 'auto') {
_this.iscovered = !_this.iscascade;
} else {
_this.iscovered = _this.options.covered;
}
// 点击触发菜单切换
_this.$anchor.on('click', function () {
_this.toggle();
});
// 点击菜单外面区域关闭菜单
$document.on('click touchstart', function (e) {
var $target = $(e.target);
if (
(_this.state === 'opening' || _this.state === 'opened') &&
!$target.is(_this.$menu) &&
!$.contains(_this.$menu[0], $target[0]) &&
!$target.is(_this.$anchor) &&
!$.contains(_this.$anchor[0], $target[0])
) {
_this.close();
}
});
// 点击不含子菜单的菜单条目关闭菜单
$document.on('click', '.mdui-menu-item', function (e) {
var $this = $(this);
if (!$this.find('.mdui-menu').length && $this.attr('disabled') === null) {
_this.close();
}
});
// 绑定点击或鼠标移入含子菜单的条目的事件
bindsubmenuevent(_this);
// 窗口大小变化时,重新调整菜单位置
$window.on('resize', $.throttle(function () {
readjust(_this);
}, 100));
}
/**
* 切换菜单状态
*/
menu.prototype.toggle = function () {
var _this = this;
if (_this.state === 'opening' || _this.state === 'opened') {
_this.close();
} else if (_this.state === 'closing' || _this.state === 'closed') {
_this.open();
}
};
/**
* 动画结束回调
* @param inst
*/
var transitionend = function (inst) {
if (inst.state === 'opening') {
inst.state = 'opened';
componentevent('opened', 'menu', inst, inst.$menu);
}
if (inst.state === 'closing') {
inst.state = 'closed';
componentevent('closed', 'menu', inst, inst.$menu);
// 关闭后,恢复菜单样式到默认状态,并恢复 fixed 定位
inst.$menu.css({
top: '',
left: '',
width: '',
position: 'fixed',
});
}
};
/**
* 打开菜单
*/
menu.prototype.open = function () {
var _this = this;
if (_this.state === 'opening' || _this.state === 'opened') {
return;
}
_this.state = 'opening';
componentevent('open', 'menu', _this, _this.$menu);
// 调整菜单位置
readjust(_this);
_this.$menu
// 菜单隐藏状态使用使用 fixed 定位。
.css('position', _this.options.fixed ? 'fixed' : 'absolute')
// 打开菜单
.addclass('mdui-menu-open')
// 打开动画完成后
.transitionend(function () {
transitionend(_this);
});
};
/**
* 关闭菜单
*/
menu.prototype.close = function () {
var _this = this;
if (_this.state === 'closing' || _this.state === 'closed') {
return;
}
_this.state = 'closing';
componentevent('close', 'menu', _this, _this.$menu);
// 菜单开始关闭时,关闭所有子菜单
_this.$menu.find('.mdui-menu').each(function () {
closesubmenu($(this));
});
_this.$menu
.removeclass('mdui-menu-open')
.transitionend(function () {
transitionend(_this);
});
};
return menu;
})();
/**
* =============================================================================
* ************ menu 自定义属性 api ************
* =============================================================================
*/
$(function () {
$document.on('click', '[mdui-menu]', function () {
var $this = $(this);
var inst = $this.data('mdui.menu');
if (!inst) {
var options = parseoptions($this.attr('mdui-menu'));
var menuselector = options.target;
delete options.target;
inst = new mdui.menu($this, menuselector, options);
$this.data('mdui.menu', inst);
inst.toggle();
}
});
});
/* jshint ignore:start */
mdui.jq = $;
window.mdui = mdui;
})(window, document);
/* jshint ignore:end */