jQuery常用功能:
- 在 DOM 树中进行查询
- 修改 DOM 树及 DOM 相关操作
- 事件处理
- Ajax
- Deferred 和 Promise
- 对象和数组处理
- 跨浏览器兼容
原生JS
查詢和取得 DOM [querySelector querySelectorAll]
// 查询单个
const oneElement = document.querySelector('#foo > div.bar')
// 查询所有
const allElements = document.querySelectorAll('.bar')
// 在指定元素下查询
const button = allElements.querySelector('button[type="submit"]')
操作类Class
增加/移除类
// JS
el.classList.add(className);
el.classList.remove(className);
// jQuery
$el.addClass(className);
$el.removeClass(className);
是否有Class
// JS
el.classList.contains(className);
// jQuery
$el.hasClass(className);
切换类
// JS
el.classList.toggle(className);
// jQuery
$el.toggleClass(className);
CSS & Style
1. 获取Style
// JS
const win = el.ownerDocument.defaultView;
win.getComputedStyle(el, null).color;
// jQuery
$el.css('color')
2. 设置Style
// JS
el.style.color = '#fff'
// jQuery
$el.css('color','#fff')
修改DOM
// 建立新的 DOM
const newElement = document.createElement('div')
const newTextNode = document.createTextNode('hello world')
// 复制 DOM
const newElement = oneElement.cloneNode()
element1.appendChild(newElement)
// 移除 DOM,需要參照到親元素
parentElement.removeChild(element1)
// 自己移除自己
element1.parentNode.removeChild(element1)
// 在 element1 后插入一个 element2
element1.appendChild(element2)
// 在 element1 里 的 element3 之前插入一個 element2
element1.insertBefore(element2, element3)
// 在 element1 里的 element3 「之后」插入一個 element2
element1.insertBefore(element2, element3.nextSibling)
要修改元素的內容,傳統的做法可以用 innerHTML:
oneElement.innerHTML = '<div>
<h1>hello world</h1>
</div>'
更好的做法是使用 DocumentFragment:
const text = document.createTextNode('continue reading...')
const hr = document.createElement('hr')
const fragment = document.createDocumentFragment()
fragment.appendChild(text)
fragment.appendChild(hr)
oneElement.appendChild(fragment)
事件
JavaScript 最重要的就是监听(listen)各種事件触发代码。
我们使用 addEventListener 來监听事件处理。
oneElement.addEventListener('click', function (event) {
// do something...
})
同時监听许多元素时候,通过 event.target 來取得是哪個元素触发的。
Array.from(allElements).forEach(element => {
element.addEventListener('change', function (event) {
console.log(event.target.value)
})
})
只想让事件触发一次(jQuery 的 once):
oneElement.addEventListener('change', function listener(event) {
console.log(event.type + ' got triggered on ' + this)
this.removeEventListener('change', listener)
})
动画
以前习惯用 window.setTimeout() 來做动画,
現在我们有更好更快的 window.requestAnimationFrame() 了。
const start = window.performance.now()
const duration = 2000
window.requestAnimationFrame(function fadeIn (now) {
const progress = now - start
oneElement.style.opacity = progress / duration
if (progress < duration) {
window.requestAnimationFrame(fadeIn)
}
}
Ajax
Fetch API 是用于替换 XMLHttpRequest 处理 ajax 的新标准,Chrome 和 Firefox 均支持,旧浏览器可以使用 polyfills 提供支持。
IE9+ 请使用 github/fetch,IE8+ 请使用 fetch-ie8,JSONP 请使用 fetch-jsonp。
从服务器读取数据并替换匹配元素的内容。
// jQuery
$(selector).load(url, completeCallback)
// Native
fetch(url).then(data => data.text()).then(data => {
document.querySelector(selector).innerHTML = data
}).then(completeCallback)
封装
我们可以把这些方式全部包在一個 function 里。
就像 jQuery 链式调用一样(chainable)
(例如: $('foo').css({color: 'red'}).on('click', () => {}) )
const $ = function $(selector, context = document) {
const elements = Array.from(context.querySelectorAll(selector))
return {
elements,
html (newHtml) {
this.elements.forEach(element => {
element.innerHTML = newHtml
})
return this
},
css (newCss) {
this.elements.forEach(element => {
Object.assign(element.style, newCss)
})
return this
},
on (event, handler, options) {
this.elements.forEach(element => {
element.addEventListener(event, handler, options)
})
return this
}
// etc.
}
}
或者用 ES6 的 Class 來包裝:
class DOM {
constructor(selector) {
const elements = document.querySelectorAll(selector)
this.length = elements.length
Object.assign(this, elements)
}
each(callback) {
for (let el of Array.from(this)) {
callback.call(el)
}
return this
}
addClass(className) {
return this.each(function () {
this.classList.add(className)
})
}
removeClass(className) {
return this.each(function () {
this.classList.remove(className)
})
}
hasClass(className) {
return this[0].classList.contains(className)
}
on(event, callback) {
return this.each(function () {
this.addEventListener(event, callback, false)
})
}
// etc.
}
参考
- oui-dom-utils 来做选择器和样式相关
- oui-dom-events 来做 Event,支持命名空间和事件代理