485 lines
13 KiB
JavaScript
485 lines
13 KiB
JavaScript
|
/*********************************************************************
|
|||
|
* Anot的原型方法定义区 *
|
|||
|
**********************************************************************/
|
|||
|
|
|||
|
function hyphen(target) {
|
|||
|
//转换为连字符线风格
|
|||
|
return target.replace(/([a-z\d])([A-Z]+)/g, '$1-$2').toLowerCase()
|
|||
|
}
|
|||
|
|
|||
|
function camelize(target) {
|
|||
|
//转换为驼峰风格
|
|||
|
if (target.indexOf('-') < 0 && target.indexOf('_') < 0) {
|
|||
|
return target //提前判断,提高getStyle等的效率
|
|||
|
}
|
|||
|
return target.replace(/[-_][^-_]/g, function(match) {
|
|||
|
return match.charAt(1).toUpperCase()
|
|||
|
})
|
|||
|
}
|
|||
|
|
|||
|
'add,remove'.replace(rword, function(method) {
|
|||
|
Anot.fn[method + 'Class'] = function(cls) {
|
|||
|
var el = this[0]
|
|||
|
//https://developer.mozilla.org/zh-CN/docs/Mozilla/Firefox/Releases/26
|
|||
|
if (cls && typeof cls === 'string' && el && el.nodeType === 1) {
|
|||
|
cls.replace(/\S+/g, function(c) {
|
|||
|
el.classList[method](c)
|
|||
|
})
|
|||
|
}
|
|||
|
return this
|
|||
|
}
|
|||
|
})
|
|||
|
|
|||
|
Anot.fn.mix({
|
|||
|
hasClass: function(cls) {
|
|||
|
var el = this[0] || {} //IE10+, chrome8+, firefox3.6+, safari5.1+,opera11.5+支持classList,chrome24+,firefox26+支持classList2.0
|
|||
|
return el.nodeType === 1 && el.classList.contains(cls)
|
|||
|
},
|
|||
|
toggleClass: function(value, stateVal) {
|
|||
|
var className,
|
|||
|
i = 0
|
|||
|
var classNames = String(value).match(/\S+/g) || []
|
|||
|
var isBool = typeof stateVal === 'boolean'
|
|||
|
while ((className = classNames[i++])) {
|
|||
|
var state = isBool ? stateVal : !this.hasClass(className)
|
|||
|
this[state ? 'addClass' : 'removeClass'](className)
|
|||
|
}
|
|||
|
return this
|
|||
|
},
|
|||
|
attr: function(name, value) {
|
|||
|
if (arguments.length === 2) {
|
|||
|
this[0].setAttribute(name, value)
|
|||
|
return this
|
|||
|
} else {
|
|||
|
return this[0].getAttribute(name)
|
|||
|
}
|
|||
|
},
|
|||
|
data: function(name, value) {
|
|||
|
name = 'data-' + hyphen(name || '')
|
|||
|
switch (arguments.length) {
|
|||
|
case 2:
|
|||
|
this.attr(name, value)
|
|||
|
return this
|
|||
|
case 1:
|
|||
|
var val = this.attr(name)
|
|||
|
return parseData(val)
|
|||
|
case 0:
|
|||
|
var ret = {}
|
|||
|
ap.forEach.call(this[0].attributes, function(attr) {
|
|||
|
if (attr) {
|
|||
|
name = attr.name
|
|||
|
if (!name.indexOf('data-')) {
|
|||
|
name = camelize(name.slice(5))
|
|||
|
ret[name] = parseData(attr.value)
|
|||
|
}
|
|||
|
}
|
|||
|
})
|
|||
|
return ret
|
|||
|
}
|
|||
|
},
|
|||
|
removeData: function(name) {
|
|||
|
name = 'data-' + hyphen(name)
|
|||
|
this[0].removeAttribute(name)
|
|||
|
return this
|
|||
|
},
|
|||
|
css: function(name, value) {
|
|||
|
if (Anot.isPlainObject(name)) {
|
|||
|
for (var i in name) {
|
|||
|
Anot.css(this, i, name[i])
|
|||
|
}
|
|||
|
} else {
|
|||
|
var ret = Anot.css(this, name, value)
|
|||
|
}
|
|||
|
return ret !== void 0 ? ret : this
|
|||
|
},
|
|||
|
position: function() {
|
|||
|
var offsetParent,
|
|||
|
offset,
|
|||
|
elem = this[0],
|
|||
|
parentOffset = {
|
|||
|
top: 0,
|
|||
|
left: 0
|
|||
|
}
|
|||
|
if (!elem) {
|
|||
|
return
|
|||
|
}
|
|||
|
if (this.css('position') === 'fixed') {
|
|||
|
offset = elem.getBoundingClientRect()
|
|||
|
} else {
|
|||
|
offsetParent = this.offsetParent() //得到真正的offsetParent
|
|||
|
offset = this.offset() // 得到正确的offsetParent
|
|||
|
if (offsetParent[0].tagName !== 'HTML') {
|
|||
|
parentOffset = offsetParent.offset()
|
|||
|
}
|
|||
|
parentOffset.top += Anot.css(offsetParent[0], 'borderTopWidth', true)
|
|||
|
parentOffset.left += Anot.css(offsetParent[0], 'borderLeftWidth', true)
|
|||
|
// Subtract offsetParent scroll positions
|
|||
|
parentOffset.top -= offsetParent.scrollTop()
|
|||
|
parentOffset.left -= offsetParent.scrollLeft()
|
|||
|
}
|
|||
|
return {
|
|||
|
top: offset.top - parentOffset.top - Anot.css(elem, 'marginTop', true),
|
|||
|
left: offset.left - parentOffset.left - Anot.css(elem, 'marginLeft', true)
|
|||
|
}
|
|||
|
},
|
|||
|
offsetParent: function() {
|
|||
|
var offsetParent = this[0].offsetParent
|
|||
|
while (offsetParent && Anot.css(offsetParent, 'position') === 'static') {
|
|||
|
offsetParent = offsetParent.offsetParent
|
|||
|
}
|
|||
|
return Anot(offsetParent || root)
|
|||
|
},
|
|||
|
bind: function(type, fn, phase) {
|
|||
|
if (this[0]) {
|
|||
|
//此方法不会链
|
|||
|
return Anot.bind(this[0], type, fn, phase)
|
|||
|
}
|
|||
|
},
|
|||
|
unbind: function(type, fn, phase) {
|
|||
|
if (this[0]) {
|
|||
|
Anot.unbind(this[0], type, fn, phase)
|
|||
|
}
|
|||
|
return this
|
|||
|
},
|
|||
|
val: function(value) {
|
|||
|
var node = this[0]
|
|||
|
if (node && node.nodeType === 1) {
|
|||
|
var get = arguments.length === 0
|
|||
|
var access = get ? ':get' : ':set'
|
|||
|
var fn = valHooks[getValType(node) + access]
|
|||
|
if (fn) {
|
|||
|
var val = fn(node, value)
|
|||
|
} else if (get) {
|
|||
|
return (node.value || '').replace(/\r/g, '')
|
|||
|
} else {
|
|||
|
node.value = value
|
|||
|
}
|
|||
|
}
|
|||
|
return get ? val : this
|
|||
|
}
|
|||
|
})
|
|||
|
|
|||
|
if (root.dataset) {
|
|||
|
Anot.fn.data = function(name, val) {
|
|||
|
name = name && camelize(name)
|
|||
|
var dataset = this[0].dataset
|
|||
|
switch (arguments.length) {
|
|||
|
case 2:
|
|||
|
dataset[name] = val
|
|||
|
return this
|
|||
|
case 1:
|
|||
|
val = dataset[name]
|
|||
|
return parseData(val)
|
|||
|
case 0:
|
|||
|
var ret = createMap()
|
|||
|
for (name in dataset) {
|
|||
|
ret[name] = parseData(dataset[name])
|
|||
|
}
|
|||
|
return ret
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
Anot.parseJSON = JSON.parse
|
|||
|
|
|||
|
var rbrace = /(?:\{[\s\S]*\}|\[[\s\S]*\])$/
|
|||
|
function parseData(data) {
|
|||
|
try {
|
|||
|
if (typeof data === 'object') return data
|
|||
|
data =
|
|||
|
data === 'true'
|
|||
|
? true
|
|||
|
: data === 'false'
|
|||
|
? false
|
|||
|
: data === 'null'
|
|||
|
? null
|
|||
|
: +data + '' === data
|
|||
|
? +data
|
|||
|
: rbrace.test(data)
|
|||
|
? JSON.parse(data)
|
|||
|
: data
|
|||
|
} catch (e) {}
|
|||
|
return data
|
|||
|
}
|
|||
|
|
|||
|
Anot.fireDom = function(elem, type, opts) {
|
|||
|
var hackEvent = DOC.createEvent('Events')
|
|||
|
hackEvent.initEvent(type, true, true)
|
|||
|
Anot.mix(hackEvent, opts)
|
|||
|
elem.dispatchEvent(hackEvent)
|
|||
|
}
|
|||
|
|
|||
|
Anot.each(
|
|||
|
{
|
|||
|
scrollLeft: 'pageXOffset',
|
|||
|
scrollTop: 'pageYOffset'
|
|||
|
},
|
|||
|
function(method, prop) {
|
|||
|
Anot.fn[method] = function(val) {
|
|||
|
var node = this[0] || {},
|
|||
|
win = getWindow(node),
|
|||
|
top = method === 'scrollTop'
|
|||
|
if (!arguments.length) {
|
|||
|
return win ? win[prop] : node[method]
|
|||
|
} else {
|
|||
|
if (win) {
|
|||
|
win.scrollTo(!top ? val : win[prop], top ? val : win[prop])
|
|||
|
} else {
|
|||
|
node[method] = val
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
)
|
|||
|
|
|||
|
function getWindow(node) {
|
|||
|
return node.window && node.document
|
|||
|
? node
|
|||
|
: node.nodeType === 9
|
|||
|
? node.defaultView
|
|||
|
: false
|
|||
|
}
|
|||
|
|
|||
|
//=============================css相关==================================
|
|||
|
|
|||
|
var cssHooks = (Anot.cssHooks = createMap())
|
|||
|
var prefixes = ['', '-webkit-', '-moz-', '-ms-'] //去掉opera-15的支持
|
|||
|
var cssMap = {
|
|||
|
float: 'cssFloat'
|
|||
|
}
|
|||
|
|
|||
|
Anot.cssNumber = oneObject(
|
|||
|
'animationIterationCount,animationIterationCount,columnCount,order,flex,flexGrow,flexShrink,fillOpacity,fontWeight,lineHeight,opacity,orphans,widows,zIndex,zoom'
|
|||
|
)
|
|||
|
|
|||
|
Anot.cssName = function(name, host, camelCase) {
|
|||
|
if (cssMap[name]) {
|
|||
|
return cssMap[name]
|
|||
|
}
|
|||
|
host = host || root.style
|
|||
|
for (var i = 0, n = prefixes.length; i < n; i++) {
|
|||
|
camelCase = camelize(prefixes[i] + name)
|
|||
|
if (camelCase in host) {
|
|||
|
return (cssMap[name] = camelCase)
|
|||
|
}
|
|||
|
}
|
|||
|
return null
|
|||
|
}
|
|||
|
|
|||
|
cssHooks['@:set'] = function(node, name, value) {
|
|||
|
node.style[name] = value
|
|||
|
}
|
|||
|
|
|||
|
cssHooks['@:get'] = function(node, name) {
|
|||
|
if (!node || !node.style) {
|
|||
|
throw new Error('getComputedStyle要求传入一个节点 ' + node)
|
|||
|
}
|
|||
|
var ret,
|
|||
|
computed = getComputedStyle(node)
|
|||
|
if (computed) {
|
|||
|
ret = name === 'filter' ? computed.getPropertyValue(name) : computed[name]
|
|||
|
if (ret === '') {
|
|||
|
ret = node.style[name] //其他浏览器需要我们手动取内联样式
|
|||
|
}
|
|||
|
}
|
|||
|
return ret
|
|||
|
}
|
|||
|
cssHooks['opacity:get'] = function(node) {
|
|||
|
var ret = cssHooks['@:get'](node, 'opacity')
|
|||
|
return ret === '' ? '1' : ret
|
|||
|
}
|
|||
|
|
|||
|
'top,left'.replace(rword, function(name) {
|
|||
|
cssHooks[name + ':get'] = function(node) {
|
|||
|
var computed = cssHooks['@:get'](node, name)
|
|||
|
return /px$/.test(computed) ? computed : Anot(node).position()[name] + 'px'
|
|||
|
}
|
|||
|
})
|
|||
|
|
|||
|
var cssShow = {
|
|||
|
position: 'absolute',
|
|||
|
visibility: 'hidden',
|
|||
|
display: 'block'
|
|||
|
}
|
|||
|
var rdisplayswap = /^(none|table(?!-c[ea]).+)/
|
|||
|
function showHidden(node, array) {
|
|||
|
//http://www.cnblogs.com/rubylouvre/archive/2012/10/27/2742529.html
|
|||
|
if (node.offsetWidth <= 0) {
|
|||
|
//opera.offsetWidth可能小于0
|
|||
|
var styles = getComputedStyle(node, null)
|
|||
|
if (rdisplayswap.test(styles['display'])) {
|
|||
|
var obj = {
|
|||
|
node: node
|
|||
|
}
|
|||
|
for (var name in cssShow) {
|
|||
|
obj[name] = styles[name]
|
|||
|
node.style[name] = cssShow[name]
|
|||
|
}
|
|||
|
array.push(obj)
|
|||
|
}
|
|||
|
var _parent = node.parentNode
|
|||
|
if (_parent && _parent.nodeType === 1) {
|
|||
|
showHidden(_parent, array)
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
'Width,Height'.replace(rword, function(name) {
|
|||
|
//fix 481
|
|||
|
var method = name.toLowerCase(),
|
|||
|
clientProp = 'client' + name,
|
|||
|
scrollProp = 'scroll' + name,
|
|||
|
offsetProp = 'offset' + name
|
|||
|
cssHooks[method + ':get'] = function(node, which, override) {
|
|||
|
var boxSizing = -4
|
|||
|
if (typeof override === 'number') {
|
|||
|
boxSizing = override
|
|||
|
}
|
|||
|
which = name === 'Width' ? ['Left', 'Right'] : ['Top', 'Bottom']
|
|||
|
var ret = node[offsetProp] // border-box 0
|
|||
|
if (boxSizing === 2) {
|
|||
|
// margin-box 2
|
|||
|
return (
|
|||
|
ret +
|
|||
|
Anot.css(node, 'margin' + which[0], true) +
|
|||
|
Anot.css(node, 'margin' + which[1], true)
|
|||
|
)
|
|||
|
}
|
|||
|
if (boxSizing < 0) {
|
|||
|
// padding-box -2
|
|||
|
ret =
|
|||
|
ret -
|
|||
|
Anot.css(node, 'border' + which[0] + 'Width', true) -
|
|||
|
Anot.css(node, 'border' + which[1] + 'Width', true)
|
|||
|
}
|
|||
|
if (boxSizing === -4) {
|
|||
|
// content-box -4
|
|||
|
ret =
|
|||
|
ret -
|
|||
|
Anot.css(node, 'padding' + which[0], true) -
|
|||
|
Anot.css(node, 'padding' + which[1], true)
|
|||
|
}
|
|||
|
return ret
|
|||
|
}
|
|||
|
cssHooks[method + '&get'] = function(node) {
|
|||
|
var hidden = []
|
|||
|
showHidden(node, hidden)
|
|||
|
var val = cssHooks[method + ':get'](node)
|
|||
|
for (var i = 0, obj; (obj = hidden[i++]); ) {
|
|||
|
node = obj.node
|
|||
|
for (var n in obj) {
|
|||
|
if (typeof obj[n] === 'string') {
|
|||
|
node.style[n] = obj[n]
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
return val
|
|||
|
}
|
|||
|
Anot.fn[method] = function(value) {
|
|||
|
//会忽视其display
|
|||
|
var node = this[0]
|
|||
|
if (arguments.length === 0) {
|
|||
|
if (node.setTimeout) {
|
|||
|
//取得窗口尺寸,IE9后可以用node.innerWidth /innerHeight代替
|
|||
|
return node['inner' + name]
|
|||
|
}
|
|||
|
if (node.nodeType === 9) {
|
|||
|
//取得页面尺寸
|
|||
|
var doc = node.documentElement
|
|||
|
//FF chrome html.scrollHeight< body.scrollHeight
|
|||
|
//IE 标准模式 : html.scrollHeight> body.scrollHeight
|
|||
|
//IE 怪异模式 : html.scrollHeight 最大等于可视窗口多一点?
|
|||
|
return Math.max(
|
|||
|
node.body[scrollProp],
|
|||
|
doc[scrollProp],
|
|||
|
node.body[offsetProp],
|
|||
|
doc[offsetProp],
|
|||
|
doc[clientProp]
|
|||
|
)
|
|||
|
}
|
|||
|
return cssHooks[method + '&get'](node)
|
|||
|
} else {
|
|||
|
return this.css(method, value)
|
|||
|
}
|
|||
|
}
|
|||
|
Anot.fn['inner' + name] = function() {
|
|||
|
return cssHooks[method + ':get'](this[0], void 0, -2)
|
|||
|
}
|
|||
|
Anot.fn['outer' + name] = function(includeMargin) {
|
|||
|
return cssHooks[method + ':get'](
|
|||
|
this[0],
|
|||
|
void 0,
|
|||
|
includeMargin === true ? 2 : 0
|
|||
|
)
|
|||
|
}
|
|||
|
})
|
|||
|
|
|||
|
Anot.fn.offset = function() {
|
|||
|
//取得距离页面左右角的坐标
|
|||
|
var node = this[0]
|
|||
|
try {
|
|||
|
var rect = node.getBoundingClientRect()
|
|||
|
// Make sure element is not hidden (display: none) or disconnected
|
|||
|
// https://github.com/jquery/jquery/pull/2043/files#r23981494
|
|||
|
if (rect.width || rect.height || node.getClientRects().length) {
|
|||
|
var doc = node.ownerDocument
|
|||
|
var root = doc.documentElement
|
|||
|
var win = doc.defaultView
|
|||
|
return {
|
|||
|
top: rect.top + win.pageYOffset - root.clientTop,
|
|||
|
left: rect.left + win.pageXOffset - root.clientLeft
|
|||
|
}
|
|||
|
}
|
|||
|
} catch (e) {
|
|||
|
return {
|
|||
|
left: 0,
|
|||
|
top: 0
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//=============================val相关=======================
|
|||
|
|
|||
|
function getValType(elem) {
|
|||
|
var ret = elem.tagName.toLowerCase()
|
|||
|
return ret === 'input' && /checkbox|radio/.test(elem.type) ? 'checked' : ret
|
|||
|
}
|
|||
|
|
|||
|
var valHooks = {
|
|||
|
'select:get': function(node, value) {
|
|||
|
var option,
|
|||
|
options = node.options,
|
|||
|
index = node.selectedIndex,
|
|||
|
one = node.type === 'select-one' || index < 0,
|
|||
|
values = one ? null : [],
|
|||
|
max = one ? index + 1 : options.length,
|
|||
|
i = index < 0 ? max : one ? index : 0
|
|||
|
for (; i < max; i++) {
|
|||
|
option = options[i]
|
|||
|
//旧式IE在reset后不会改变selected,需要改用i === index判定
|
|||
|
//我们过滤所有disabled的option元素,但在safari5下,如果设置select为disable,那么其所有孩子都disable
|
|||
|
//因此当一个元素为disable,需要检测其是否显式设置了disable及其父节点的disable情况
|
|||
|
if ((option.selected || i === index) && !option.disabled) {
|
|||
|
value = option.value
|
|||
|
if (one) {
|
|||
|
return value
|
|||
|
}
|
|||
|
//收集所有selected值组成数组返回
|
|||
|
values.push(value)
|
|||
|
}
|
|||
|
}
|
|||
|
return values
|
|||
|
},
|
|||
|
'select:set': function(node, values, optionSet) {
|
|||
|
values = [].concat(values) //强制转换为数组
|
|||
|
for (var i = 0, el; (el = node.options[i++]); ) {
|
|||
|
if ((el.selected = values.indexOf(el.value) > -1)) {
|
|||
|
optionSet = true
|
|||
|
}
|
|||
|
}
|
|||
|
if (!optionSet) {
|
|||
|
node.selectedIndex = -1
|
|||
|
}
|
|||
|
}
|
|||
|
}
|