Skip to content

Commit

Permalink
add eagerShowing option
Browse files Browse the repository at this point in the history
  • Loading branch information
MopTym committed Nov 23, 2017
1 parent 0f8c846 commit 1edbe1e
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 28 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,9 @@ new JuejinLazyload(Element || ElementList || selector, {
// 是否自动监听 window 的 scroll 和 resize 事件
reactive: true,

// true - 图片头部加载完成后立即显示 | false - 全图加载完成后才显示
eagerShowing: false,

// 初始化及 addOrUpdateElement 时调用
infoGetter: (Element) => ({
url: String, // 图片地址,用以设置 IMG 元素的 src 或其它元素的 background-image
Expand Down
4 changes: 2 additions & 2 deletions dist/juejin-lazyload.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "juejin-lazyload",
"version": "0.1.4",
"version": "0.1.5",
"description": "juejin lazyload",
"main": "dist/juejin-lazyload.min.js",
"scripts": {
Expand Down
80 changes: 59 additions & 21 deletions src/juejin-lazyload.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,14 @@ const DEFAULT_OPTIONS = {
interval: 200,
debounce: false,
reactive: true,
eagerShowing: false,
infoGetter: null,
visibleAreaGetter: null,
onStateChange: null
}

const INFO_PROP_NAME = '__JUEJIN_LAZYLOAD'
const META_CHECK_INTERVAL = 300

export default class JuejinLazyload {

Expand Down Expand Up @@ -81,18 +83,26 @@ export default class JuejinLazyload {
}

initElement (element) {
this.attachInfo(element)
this.setPlaceholder(element)
this.updateElementClassByState('inited', element)
this.invokeStateHook('inited', element)
}

attachInfo (element) {
const imgInfo = this.options.infoGetter && this.options.infoGetter(element)
const info = Object.assign({}, imgInfo, {
isImg: element.nodeName === 'IMG',
loading: false
})
info.hasPlaceholder = info.isImg && info.width && info.height
if (info.hasPlaceholder) {
element[INFO_PROP_NAME] = info
}

setPlaceholder (element) {
const info = element[INFO_PROP_NAME]
const isImg = element.nodeName === 'IMG'
if (isImg && info.width && info.height) {
element.src = getPlaceholderDataUrl(info.width, info.height)
}
element[INFO_PROP_NAME] = info
this.updateElementClassByState('inited', element)
this.invokeStateHook('inited', info.url, element)
}

removeInfo (element) {
Expand Down Expand Up @@ -142,23 +152,30 @@ export default class JuejinLazyload {

loadIamge (element) {
const info = element[INFO_PROP_NAME]
const { url, isImg } = info
const { url } = info
info.loading = true
this.updateElementClassByState('loading', element)
this.invokeStateHook('loading', url, element)
loadIamge(url, () => {
if (isImg) {
element.src = url
} else {
element.style.backgroundImage = `url(${url})`
this.invokeStateHook('loading', element)
loadIamge(url, {
onStart: (url, image) => {
if (this.options.eagerShowing) {
this.onMetaLoaded(image, () => {
element.removeAttribute('src') // necessary
element.setAttribute('src', url)
})
}
},
onLoaded: () => {
this.setElementWithImageUrl(url, element)
this.updateElementClassByState('loaded', element)
this.invokeStateHook('loaded', element)
this.removeElement(element)
},
onError: () => {
this.updateElementClassByState('error', element)
this.invokeStateHook('error', element)
this.removeElement(element)
}
this.removeElement(element)
this.updateElementClassByState('loaded', element)
this.invokeStateHook('loaded', url, element)
}, () => {
this.removeElement(element)
this.updateElementClassByState('error', element)
this.invokeStateHook('error', url, element)
})
}

Expand Down Expand Up @@ -186,12 +203,33 @@ export default class JuejinLazyload {
}
}

invokeStateHook (state, url, element) {
invokeStateHook (state, element) {
if (this.options.onStateChange) {
const { url } = element[INFO_PROP_NAME]
this.options.onStateChange(state, url, element, this)
}
}

setElementWithImageUrl (url, element) {
if (element.nodeName === 'IMG') {
element.src = url
} else {
element.style.backgroundImage = `url(${url})`
}
}

onMetaLoaded (image, callback) {
const token = setInterval(() => {
if (image.naturalWidth) {
stop()
callback()
}
}, META_CHECK_INTERVAL)
const stop = () => clearInterval(token)
on(image, 'load', stop)
on(image, 'error', stop)
}

destroy () {
this.removeEventListener()
this.clean()
Expand Down
8 changes: 4 additions & 4 deletions src/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ export function getViewportSize () {
}
}

export function loadIamge (url, onLoaded, onError) {
if (!url) { return }
export function loadIamge (url, { onStart, onLoaded, onError }) {
const image = new Image()
image.onload = function () { onLoaded && onLoaded(url) }
image.onerror = function () { onError && onError(url) }
image.onload = function () { onLoaded && onLoaded(url, image) }
image.onerror = function () { onError && onError(url, image) }
image.src = url
onStart && onStart(url, image)
}

export function throttle (fn, interval) {
Expand Down

0 comments on commit 1edbe1e

Please sign in to comment.