getElements ByClass Nameとclassis List互換性があります(ie 8及び以上)
7161 ワード
知乎文章の住所:https://zhuanlan.zhihu.com/p/52423430
前の面接では、これまでのクラスを添削しましたが、クラスListを使って原型と互換性があるという先輩がいて、とても満足しています.ただし、現在はie 8にしか対応していません.以下は具体的な方案です.
GtElements ByClass Name対応:
また、配列のindexOf方法はie 8及び以下のブラウザに対応していません.
最後に、私達のgithub住所を共有します.
yaodebian/Browser-Commpatible githb.com
前の面接では、これまでのクラスを添削しましたが、クラスListを使って原型と互換性があるという先輩がいて、とても満足しています.ただし、現在はie 8にしか対応していません.以下は具体的な方案です.
GtElements ByClass Name対応:
// getElementsByClassName
if (!('getElementsByClassName' in document)) {
function getElementsByClassName (classList) {
if (typeof classList !== 'string') throw TypeError('the type of classList is error')
//
var parent = this
//
var child = parent.getElementsByTagName('*')
var nodeList = []
// classList
var classAttr = classList.replace(/^\s+|\s+$/g, '').split(/\s+/)
for (var j = 0, len = child.length; j < len; j++) {
var element = child[j]
for (var i = 0, claLen = classAttr.length; i < claLen; i++) {
var className = classAttr[i]
if (element.className.search(new RegExp('(\\s+)?'+className+'(\\s+)?')) === -1) break
}
if (i === claLen) nodeList.push(element)
}
return nodeList
}
// ie5 document getElementsByClassName
document.getElementsByClassName = getElementsByClassName
// ie8 getElementsByClassName
window.Element.prototype.getElementsByClassName = getElementsByClassName
}
互換性クラスリスト:// classList
// classList
function ClassList (obj) {
this.obj = obj
}
// add、remove contains
function op (self, valArr, tag) {
var className = self.obj.className
if (tag === 2) {
if (valArr.length === 0) throw TypeError("Failed to execute 'contains' on 'DOMTokenList': 1 argument required, but only 0 present.")
if (typeof valArr[0] !== 'string' || !!~valArr[0].search(/\s+/g)) return false
return !!~className.search(new RegExp(valArr[0]))
}
for (var i in valArr) {
if(typeof valArr[i] !== 'string' || !!~valArr[i].search(/\s+/g)) throw TypeError('the type of value is error')
var temp = valArr[i]
var flag = !!~className.search(new RegExp('(\\s+)?'+temp+'(\\s+)?'))
if (tag === 1) {
!flag ? className += ' ' + temp : ''
} else if (tag === 3) {
flag ? className = className.replace(new RegExp('(\\s+)?'+temp),'') : ''
}
}
self.obj.className = className
}
ClassList.prototype.add = function () {
var self = this
op(self, arguments, 1)
}
ClassList.prototype.contains = function () {
var self = this
return op(self, arguments, 2)
}
ClassList.prototype.item = function (index) {
typeof index === 'string' ? index = parseInt(index) : ''
if (arguments.length === 0 || typeof index !== 'number') throw TypeError("Failed to execute 'toggle' on 'DOMTokenList': 1 argument required, but only 0 present.")
var claArr = this.obj.className.replace(/^\s+|\s+$/, '').split(/\s+/)
var len = claArr.length
if (index < 0 || index >= len) return null
return claArr[index]
}
ClassList.prototype.remove = function () {
var self = this
op(self, arguments, 3)
}
ClassList.prototype.toggle = function (value) {
if(typeof value !== 'string' || arguments.length === 0) throw TypeError("Failed to execute 'toggle' on 'DOMTokenList': 1 argument(string) required, but only 0 present.")
if (arguments.length === 1) {
this.contains(value) ? this.remove(value) : this.add(value)
return
}
!arguments[1] ? this.remove(value) : this.add(value)
}
var div = document.createElement("div")
if (undefined === div.classList) {
console.log(111)
// ie8 classList, ie8
window.Element.prototype.classList = function () {
return new ClassList(this)
}
}
// classList( , , )
function getClassList (el) {
if (!el) throw TypeError("Failed to execute 'getClassList': 1 argumen required, but only 0 present.")
if (typeof el.classList === 'function') {
return el.classList()
}
return el.classList
}
上のような方法はちょっと煩わしいです.普通はclassis List属性だけにアクセスすればいいです.ですから、以下の方法を採用して、ie 8まで対応できます.if (!("classList" in document.documentElement)) {
Object.defineProperty(window.Element.prototype, 'classList', {
get: function () {
var self = this
function update(fn) {
return function () {
var className = self.className.replace(/^\s+|\s+$/g, ''),
valArr = arguments
return fn(className, valArr)
}
}
function add_rmv (className, valArr, tag) {
for (var i in valArr) {
if(typeof valArr[i] !== 'string' || !!~valArr[i].search(/\s+/g)) throw TypeError('the type of value is error')
var temp = valArr[i]
var flag = !!~className.search(new RegExp('(\\s+)?'+temp+'(\\s+)?'))
if (tag === 1) {
!flag ? className += ' ' + temp : ''
} else if (tag === 2) {
flag ? className = className.replace(new RegExp('(\\s+)?'+temp),'') : ''
}
}
self.className = className
return tag
}
return {
add: update(function (className, valArr) {
add_rmv(className, valArr, 1)
}),
remove: update(function (className, valArr) {
add_rmv(className, valArr, 2)
}),
toggle: function (value) {
if(typeof value !== 'string' || arguments.length === 0) throw TypeError("Failed to execute 'toggle' on 'DOMTokenList': 1 argument(string) required, but only 0 present.")
if (arguments.length === 1) {
this.contains(value) ? this.remove(value) : this.add(value)
return
}
!arguments[1] ? this.remove(value) : this.add(value)
},
contains: update(function (className, valArr) {
if (valArr.length === 0) throw TypeError("Failed to execute 'contains' on 'DOMTokenList': 1 argument required, but only 0 present.")
if (typeof valArr[0] !== 'string' || !!~valArr[0].search(/\s+/g)) return false
return !!~className.search(new RegExp(valArr[0]))
}),
item: function (index) {
typeof index === 'string' ? index = parseInt(index) : ''
if (arguments.length === 0 || typeof index !== 'number') throw TypeError("Failed to execute 'toggle' on 'DOMTokenList': 1 argument required, but only 0 present.")
var claArr = self.className.replace(/^\s+|\s+$/, '').split(/\s+/)
var len = claArr.length
if (index < 0 || index >= len) return null
return claArr[index]
}
}
}
})
}
注目すべきは、ie 10、11はクラスListをサポートしているが、ここでは、add及びremove方法は複数のクラスを削除することをサポートしていない.また、toggale方法については、2番目のブールタイプのパラメータは無効である.また、配列のindexOf方法はie 8及び以下のブラウザに対応していません.
最後に、私達のgithub住所を共有します.
yaodebian/Browser-Commpatible githb.com