如何自定制audio音频播放器的风格。
这里列举一个简单的测试:对比 PNG 原图、PNG 无损压缩、PNG 转 WebP(无损)、PNG 转 WebP(有损)的压缩效果。更多测试查看这里
webp的最大优势是使图片的体积小,同时具备了有损和无损的压缩模式,支持透明度和动画等特性。
webp在兼容性方面 兼容性查看
目前在pc端,在chrome和firefox浏览器没啥问题。移动端的问题较大,在安卓4.0原生系统以上支持,在ios系统目前不适用。
<figure class="img js-img u-img-placeholder" data-echo="${imgsrc}"></figure>
const lazyLoader = () => {
const CLIENT_HEIGHT = document.documentElement.clientHeight
let imgs
function init() {
document.removeEventListener('scroll', load, false)
document.addEventListener('scroll', load, {
passive: true
})
const currentTop = document.body.scrollTop
imgs = [].slice.call(document.querySelectorAll('[data-echo]:not(.img-error):not(.img-loading)')).map((item) => {
return {
el: item,
top: item.getBoundingClientRect().top + currentTop
}
}).sort((a, b) => a.top - b.top)
load()
}
function load() {
const currentTop = document.body.scrollTop
let index = 0
for (let i = 0; i < imgs.length; i++) {
const el = imgs[i].el
if (imgs[i].top >= currentTop + (CLIENT_HEIGHT * 0.9)) {
index = i
break
} else if (el.dataset.echo) {
insertImg(el)
}
}
imgs = imgs.slice(index)
if (imgs.length === 0) {
document.removeEventListener('scroll', load, false)
}
}
function cssSupports(property) {
if (!window.CSS || !window.CSS.supports) {
return false
}
return CSS.supports(property)
}
function createImg({ src, alt }, onload = () => {}, onerror = () => {}) {
const img = new Image()
img.style.opacity = 0
const prop = cssSupports('transition') ? 'transition' : 'webkitTransition'
img.style[prop] = 'opacity .2s ease-in-out'
img.src = src
img.alt = alt || ''
img.onload = () => {
// setTimeout(onload, 0)
onload()
img.style.opacity = 1
setTimeout(() => {
img.style.cssText = ''
}, 200)
}
img.onerror = () => {
onerror && onerror(img)
}
return img
}
function insertImg(el, onload = () => {}, onerror = () => {}) {
/* eslint-disable no-param-reassign */
const dataset = el.dataset
const img = createImg({ src: dataset.echo, alt: dataset.alt }, () => {
el.classList.add('img-loaded')
el.classList.remove('u-img-placeholder')
el.classList.remove('img-error')
el.classList.remove('img-loading')
el.dataset.echo = ''
onload()
}, (img) => {
el.classList.add('img-error')
el.classList.remove('img-loading')
el.removeChild(img)
if (el.dataset.retry) {
el.dataset.text = '点击加载'
el.addEventListener('click', retryHandler, false)
}
onerror()
})
if (!el.classList.contains('img-loading')) {
el.classList.add('img-loading')
el.insertBefore(img, el.firstChild)
}
/* eslint-enable no-param-reassign */
}
function retryHandler(event) {
event.preventDefault()
event.stopImmediatePropagation()
const target = event.target
target.dataset.text = '加载中'
insertImg(target, () => {
target.dataset.text = ''
target.dataset.retry = ''
}, () => {
target.dataset.text = '点击加载'
})
target.removeEventListener('click', retryHandler, false)
}
function refresh() {
init()
}
return {
init,
refresh
}
}
export default lazyLoader()
nodejs使用了一个事件驱动,非阻塞I/O模式,使其轻量又高效。
浏览器窗口有一个history对象,用来保存浏览历史。
最常用的属性:length
history.length;
history是不可遍历的.