This repository has been archived on 2023-08-29. You can view files and clone it, but cannot push or open issues/pull-requests.
yutent
/
anot.js
Archived
1
0
Fork 0
anot.js/src/11-dom.instance.js

448 lines
12 KiB
JavaScript
Raw Normal View History

2018-08-04 16:26:50 +08:00
/*********************************************************************
* 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({
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) {
var len = arguments.length
var dataset = this[0].dataset
name = hyphen(name || '')
if (!name) {
len = 0
}
switch (len) {
2018-08-04 16:26:50 +08:00
case 2:
dataset[name] = value
2018-08-04 16:26:50 +08:00
return this
case 1:
var val = dataset[name]
2018-08-04 16:26:50 +08:00
return parseData(val)
case 0:
var ret = createMap()
for (var i in dataset) {
ret[i] = parseData(dataset[i])
}
2018-08-04 16:26:50 +08:00
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
}
})
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
2018-08-04 16:26:50 +08:00
} 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
2018-08-04 16:26:50 +08:00
}
//=============================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
}
}
}