/********************************************************************* * 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) { case 2: dataset[name] = value return this case 1: var val = dataset[name] return parseData(val) case 0: var ret = createMap() for (var i in dataset) { ret[i] = parseData(dataset[i]) } 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 } 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 } } }