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
|
||
}
|
||
}
|
||
}
|