Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support Vue3 #447

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
"rollup-plugin-node-resolve": "^3.2.0",
"rollup-plugin-replace": "^2.0.0",
"rollup-plugin-uglify": "^1.0.1",
"vue": "^2.5.16"
"vue": "^2.5.16",
"vue3": "npm:vue@^3.0.0"
}
}
12 changes: 12 additions & 0 deletions src/components/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import Vue3LazyComponent from './vue3/vue3-lazy-component'
import Vue3LazyImage from './vue3/vue3-lazy-image'
import LazyComponent from './lazy-component'
import LazyImage from './lazy-image'

export function getLazyImage (tag, lazy) {
return 'isVue3' === tag ? Vue3LazyComponent(lazy) : LazyImage(lazy)
}

export function getLazyComponent(tag, lazy) {
return 'isVue3' === tag ? Vue3LazyComponent(lazy) : LazyComponent(lazy)
}
2 changes: 1 addition & 1 deletion src/lazy-component.js → src/components/lazy-component.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { inBrowser } from './util'
import { inBrowser } from '../util'

export default (lazy) => {
return {
Expand Down
2 changes: 1 addition & 1 deletion src/lazy-image.js → src/components/lazy-image.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {
inBrowser,
loadImageAsync,
noop
} from './util'
} from '../util'

export default (lazyManager) => {
return {
Expand Down
59 changes: 59 additions & 0 deletions src/components/vue3/vue3-lazy-component.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { inBrowser } from '../../util'
import {
h,
ref,
getCurrentInstance,
onMounted,
onBeforeUnmount
} from 'vue3'

export default (lazy) => {
return {
props: {
tag: {
type: String,
default: 'div'
}
},
setup(props, { slots, emit }) {
const show = ref(false)
const state = { loaded: false }
const rect = {}
const dom = getCurrentInstance()

const that = {
el: null,
state: state,
rect: rect,
show: show,
getRect () {
this.rect = dom.refs.root.getBoundingClientRect()
},
checkInView () {
this.getRect()
return inBrowser &&
(this.rect.top < window.innerHeight * lazy.options.preLoad && this.rect.bottom > 0) &&
(this.rect.left < window.innerWidth * lazy.options.preLoad && this.rect.right > 0)
},
load () {
this.show.value = true
this.state.loaded = true
emit('show', this)
}
}

onMounted(() => {
that.el = getCurrentInstance().refs.root
lazy.addLazyBox(that)
lazy.lazyLoadHandler()
})

onBeforeUnmount(() => {
lazy.removeComponent(that)
})

return () =>
h(props.tag, { ref: 'root' }, show ? slots.default() : null)
}
}
}
112 changes: 112 additions & 0 deletions src/components/vue3/vue3-lazy-image.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import {
inBrowser,
loadImageAsync,
noop
} from '../../util'
import {
h,
ref,
getCurrentInstance,
watch,
onMounted,
onBeforeUnmount
} from 'vue3'

export default (lazyManager) => {
return {
props: {
src: [String, Object],
tag: {
type: String,
default: 'img'
}
},
setup(props, { slots }) {
const renderSrc = ref('')
const options = {
src: '',
error: '',
loading: '',
attempt: lazyManager.options.attempt
}
const state = {
loaded: false,
error: false,
attempt: 0
}
const rect = {}
const dom = getCurrentInstance()

const that = {
state: state,
options: options,
rect: rect,
renderSrc: renderSrc,
getRect () {
this.rect = dom.refs.root.getBoundingClientRect()
},
checkInView () {
this.getRect()
return inBrowser &&
(this.rect.top < window.innerHeight * lazyManager.options.preLoad && this.rect.bottom > 0) &&
(this.rect.left < window.innerWidth * lazyManager.options.preLoad && this.rect.right > 0)
},
load (onFinish = noop) {
if ((this.state.attempt > this.options.attempt - 1) && this.state.error) {
if (!lazyManager.options.silent) console.log(`VueLazyload log: ${this.options.src} tried too more than ${this.options.attempt} times`)
onFinish()
return
}
const src = this.options.src
loadImageAsync({ src }, ({ src }) => {
this.renderSrc.value = src
this.state.loaded = true
}, e => {
this.state.attempt++
this.renderSrc.value = this.options.error
this.state.error = true
})
},
$destroy() {}
}

vueImage.lazyManager = lazyManager
vueImage.init(state, options, renderSrc)

watch(() => props,src, () => {
vueImage.init(state, options, renderSrc)
lazyManager.addLazyBox(that)
lazyManager.lazyLoadHandler()
})

onMounted(() => {
that.el = getCurrentInstance().refs.root
lazyManager.addLazyBox(that)
lazyManager.lazyLoadHandler()
})

onBeforeUnmount(() => {
lazyManager.removeComponent(that)
})

return () =>
h(props.tag,{
ref: 'root',
attrs: {
src: renderSrc
}
}, slots.default())
}
}
}

const vueImage = {
init(state, options, renderSrc) {
const opt = this.lazyManage._valueFormatter(src)
state.loaded = false
options.src = opt.src
options.error = opt.error
options.loading = opt.loading
renderSrc.value = options.loading
}
}
159 changes: 103 additions & 56 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,78 +1,125 @@
import Lazy from './lazy'
import LazyComponent from './lazy-component'
import LazyContainer from './lazy-container'
import LazyImage from './lazy-image'
import { getLazyImage, getLazyComponent } from './components'
import { assign } from './util'
import { nextTick } from 'vue3'

const pluginScheam = {
isVue3: (app, lazy, lazyContainer) => {
app.provide('lazyload', lazy)
app.directive('lazy', {
beforeMount(el, binding, vnode) {
lazy.add.call(lazy, el, binding, vnode)
},
beforeUpdate(el, binding, vnode) {
lazy.update.call(lazy, el, binding, vnode)
},
updated() {
lazy.lazyLoadHandler.call(lazy)
},
unmounted(el) {
lazy.remove.call(lazy, el)
}
})
app.directive('lazy-container', {
beforeMount(el, binding, vnode) {
lazyContainer.bind.call(lazyContainer, el, binding, vnode)
},
updated(el, binding, vnode) {
lazyContainer.update.call(lazyContainer, el, binding, vnode)
},
unmounted(el) {
lazyContainer.unbind.call(lazyContainer, el)
}
})
},
isVue2: (Vue, lazy, lazyContainer) => {
Vue.prototype.$Lazyload = lazy
Vue.directive('lazy', {
bind: lazy.add.bind(lazy),
update: lazy.update.bind(lazy),
componentUpdated: lazy.lazyLoadHandler.bind(lazy),
unbind: lazy.remove.bind(lazy)
})
Vue.directive('lazy-container', {
bind: lazyContainer.bind.bind(lazyContainer),
componentUpdated: lazyContainer.update.bind(lazyContainer),
unbind: lazyContainer.unbind.bind(lazyContainer)
})
},
isVue1: (Vue, lazy, lazyContainer) => {
Vue.prototype.$Lazyload = lazy
Vue.directive('lazy', {
bind: lazy.lazyLoadHandler.bind(lazy),
update (newValue, oldValue) {
assign(this.vm.$refs, this.vm.$els)
lazy.add(this.el, {
modifiers: this.modifiers || {},
arg: this.arg,
value: newValue,
oldValue: oldValue
}, {
context: this.vm
})
},
unbind () {
lazy.remove(this.el)
}
})

Vue.directive('lazy-container', {
update (newValue, oldValue) {
lazyContainer.update(this.el, {
modifiers: this.modifiers || {},
arg: this.arg,
value: newValue,
oldValue: oldValue
}, {
context: this.vm
})
},
unbind () {
lazyContainer.unbind(this.el)
}
})
}
}

export default {
/*
* install function
* @param {Vue} Vue
* @param {object} options lazyload options
*/
install (Vue, options = {}) {
install (_Vue, options = {}) {
let vueVer = 'isVue2'
const Vue = Object.create(_Vue)

switch (Vue.version.split('.')[0]) {
case '3':
Vue.nextTick = nextTick
vueVer = 'isVue3'
break
case '2':
vueVer = 'isVue2'
break
default:
vueVer = 'isVue1'
break
}

const LazyClass = Lazy(Vue)
const lazy = new LazyClass(options)
const lazyContainer = new LazyContainer({ lazy })

const isVue2 = Vue.version.split('.')[0] === '2'

Vue.prototype.$Lazyload = lazy

if (options.lazyComponent) {
Vue.component('lazy-component', LazyComponent(lazy))
Vue.component('lazy-component', getLazyComponent(vueVer, lazy))
}

if (options.lazyImage) {
Vue.component('lazy-image', LazyImage(lazy))
Vue.component('lazy-image', getLazyImage(vueVer, lazy))
}

if (isVue2) {
Vue.directive('lazy', {
bind: lazy.add.bind(lazy),
update: lazy.update.bind(lazy),
componentUpdated: lazy.lazyLoadHandler.bind(lazy),
unbind: lazy.remove.bind(lazy)
})
Vue.directive('lazy-container', {
bind: lazyContainer.bind.bind(lazyContainer),
componentUpdated: lazyContainer.update.bind(lazyContainer),
unbind: lazyContainer.unbind.bind(lazyContainer)
})
} else {
Vue.directive('lazy', {
bind: lazy.lazyLoadHandler.bind(lazy),
update (newValue, oldValue) {
assign(this.vm.$refs, this.vm.$els)
lazy.add(this.el, {
modifiers: this.modifiers || {},
arg: this.arg,
value: newValue,
oldValue: oldValue
}, {
context: this.vm
})
},
unbind () {
lazy.remove(this.el)
}
})

Vue.directive('lazy-container', {
update (newValue, oldValue) {
lazyContainer.update(this.el, {
modifiers: this.modifiers || {},
arg: this.arg,
value: newValue,
oldValue: oldValue
}, {
context: this.vm
})
},
unbind () {
lazyContainer.unbind(this.el)
}
})
}
pluginScheam[vueVer](Vue, lazy, lazyContainer)
}
}