成人在线亚洲_国产日韩视频一区二区三区_久久久国产精品_99国内精品久久久久久久

您的位置:首頁技術(shù)文章
文章詳情頁

vue3+typescript實(shí)現(xiàn)圖片懶加載插件

瀏覽:18日期:2022-11-12 08:42:42

github項(xiàng)目地址: github.com/murongg/vue…

求star 與 issues

我文采不好,可能寫的文章不咋樣,有什么問題可以在留言區(qū)評論,我會盡力解答

本項(xiàng)目已經(jīng)發(fā)布到npm

安裝:

$ npm i vue3-lazyload# or$ yarn add vue3-lazyload

需求分析

支持自定義 loading 圖片,圖片加載狀態(tài)時使用此圖片 支持自定義 error 圖片,圖片加載失敗后使用此圖片 支持 lifecycle hooks,類似于 vue 的生命周期,并同時在 img 標(biāo)簽綁定 lazy 屬性,類似于

<img src='http://www.piao2010.com/bcjs/...' lazy='loading'><img src='http://www.piao2010.com/bcjs/...' lazy='loaded'><img src='http://www.piao2010.com/bcjs/...' lazy='error'>

并支持:

img[lazy=loading] { /*your style here*/ } img[lazy=error] { /*your style here*/ } img[lazy=loaded] { /*your style here*/ }

支持使用 v-lazy 自定義指令,指定可傳入 string/object ,當(dāng)為 string 時,默認(rèn)為需要加載的 url,當(dāng)為 object 時,可傳入

src: 當(dāng)前需要加載的圖片 url loading: 加載狀態(tài)時所用到的圖片 error: 加載失敗時所用到的圖片 lifecycle: 本次 lazy 的生命周期,替換掉全局生命周期

目錄結(jié)構(gòu)

- src---- index.ts 入口文件,主要用來注冊插件---- lazy.ts 懶加載主要功能---- types.ts 類型文件,包括 interface/type/enum 等等---- util.ts 共享工具文件

編寫懶加載類

懶加載主要通過 IntersectionObserver對象實(shí)現(xiàn),可能有些瀏覽器不支持,暫未做兼容。

確定注冊插件時傳入的參數(shù)

export interface LazyOptions { error?: string; // 加載失敗時的圖片 loading?: string; // 加載中的圖片 observerOptions?: IntersectionObserverInit; // IntersectionObserver 對象傳入的第二個參數(shù) log?: boolean; // 是否需要打印日志 lifecycle?: Lifecycle; // 生命周期 hooks}export interface ValueFormatterObject { src: string, error?: string, loading?: string, lifecycle?: Lifecycle;}export enum LifecycleEnum { LOADING = ’loading’, LOADED = ’loaded’, ERROR = ’error’}export type Lifecycle = { [x in LifecycleEnum]?: () => void;};

確定類的框架

vue3 的 Custom Directives,支持以下 Hook Functions:beforeMount 、mounted、beforeUpdate、updated、beforeUnmount、unmounted,具體釋義可以去 vue3 文檔查看,目前僅需要用到mounted、updated、unmounted,這三個 Hook。

Lazy 類基礎(chǔ)框架代碼,lazy.ts:

export default class Lazy { public options: LazyOptions = { loading: DEFAULT_LOADING, error: DEFAULT_ERROR, observerOptions: DEFAULT_OBSERVER_OPTIONS, log: true, lifecycle: {} }; constructor(options?: LazyOptions) { this.config(options) } /** * merge config * assgin 方法在 util.ts 文件內(nèi),此文章不在贅述此方法代碼,可在后文 github 倉庫內(nèi)查看此代碼 * 此方法主要功能是合并兩個對象 * * @param {*} [options={}] * @memberof Lazy */ public config(options = {}): void { assign(this.options, options) } public mount(el: HTMLElement, binding: DirectiveBinding<string | ValueFormatterObject>): void {} // 對應(yīng) directive mount hook public update() {} // 對應(yīng) directive update hook public unmount() {} // 對應(yīng) directive unmount hook}

編寫懶加載功能

/** * mount * * @param {HTMLElement} el * @param {DirectiveBinding<string>} binding * @memberof Lazy */ public mount(el: HTMLElement, binding: DirectiveBinding<string | ValueFormatterObject>): void { this._image = el const { src, loading, error, lifecycle } = this._valueFormatter(binding.value) this._lifecycle(LifecycleEnum.LOADING, lifecycle) this._image.setAttribute(’src’, loading || DEFAULT_LOADING) if (!hasIntersectionObserver) { this.loadImages(el, src, error, lifecycle) this._log(() => { throw new Error(’Not support IntersectionObserver!’) }) } this._initIntersectionObserver(el, src, error, lifecycle) } /** * force loading * * @param {HTMLElement} el * @param {string} src * @memberof Lazy */ public loadImages(el: HTMLElement, src: string, error?: string, lifecycle?: Lifecycle): void { this._setImageSrc(el, src, error, lifecycle) } /** * set img tag src * * @private * @param {HTMLElement} el * @param {string} src * @memberof Lazy */ private _setImageSrc(el: HTMLElement, src: string, error?: string, lifecycle?: Lifecycle): void { const srcset = el.getAttribute(’srcset’) if (’img’ === el.tagName.toLowerCase()) { if (src) el.setAttribute(’src’, src) if (srcset) el.setAttribute(’srcset’, srcset) this._listenImageStatus(el as HTMLImageElement, () => { this._log(() => { console.log(’Image loaded successfully!’) }) this._lifecycle(LifecycleEnum.LOADED, lifecycle) }, () => { // Fix onload trigger twice, clear onload event // Reload on update el.onload = null this._lifecycle(LifecycleEnum.ERROR, lifecycle) this._observer.disconnect() if (error) el.setAttribute(’src’, error) this._log(() => { throw new Error(’Image failed to load!’) }) }) } else { el.style.backgroundImage = ’url(’’ + src + ’’)’ } } /** * init IntersectionObserver * * @private * @param {HTMLElement} el * @param {string} src * @memberof Lazy */ private _initIntersectionObserver(el: HTMLElement, src: string, error?: string, lifecycle?: Lifecycle): void { const observerOptions = this.options.observerOptions this._observer = new IntersectionObserver((entries) => { Array.prototype.forEach.call(entries, (entry) => { if (entry.isIntersecting) { this._observer.unobserve(entry.target) this._setImageSrc(el, src, error, lifecycle) } }) }, observerOptions) this._observer.observe(this._image) } /** * only listen to image status * * @private * @param {string} src * @param {(string | null)} cors * @param {() => void} success * @param {() => void} error * @memberof Lazy */ private _listenImageStatus(image: HTMLImageElement, success: ((this: GlobalEventHandlers, ev: Event) => any) | null, error: OnErrorEventHandler) { image.onload = success image.onerror = error } /** * to do it differently for object and string * * @public * @param {(ValueFormatterObject | string)} value * @returns {*} * @memberof Lazy */ public _valueFormatter(value: ValueFormatterObject | string): ValueFormatterObject { let src = value as string let loading = this.options.loading let error = this.options.error let lifecycle = this.options.lifecycle if (isObject(value)) { src = (value as ValueFormatterObject).src loading = (value as ValueFormatterObject).loading || this.options.loading error = (value as ValueFormatterObject).error || this.options.error lifecycle = ((value as ValueFormatterObject).lifecycle || this.options.lifecycle) } return { src, loading, error, lifecycle } } /** * log * * @param {() => void} callback * @memberof Lazy */ public _log(callback: () => void): void { if (!this.options.log) { callback() } } /** * lifecycle easy * * @private * @param {LifecycleEnum} life * @param {Lifecycle} [lifecycle] * @memberof Lazy */ private _lifecycle(life: LifecycleEnum, lifecycle?: Lifecycle): void {switch (life) { case LifecycleEnum.LOADING: this._image.setAttribute(’lazy’, LifecycleEnum.LOADING) if (lifecycle?.loading) { lifecycle.loading() } break case LifecycleEnum.LOADED: this._image.setAttribute(’lazy’, LifecycleEnum.LOADED) if (lifecycle?.loaded) { lifecycle.loaded() } break case LifecycleEnum.ERROR: this._image.setAttribute(’lazy’, LifecycleEnum.ERROR) if (lifecycle?.error) { lifecycle.error() } break default: break } }

編寫 update hook

/** * update * * @param {HTMLElement} el * @memberof Lazy */ public update(el: HTMLElement, binding: DirectiveBinding<string | ValueFormatterObject>): void { this._observer.unobserve(el) const { src, error, lifecycle } = this._valueFormatter(binding.value) this._initIntersectionObserver(el, src, error, lifecycle) }

編寫 unmount hook

/** * unmount * * @param {HTMLElement} el * @memberof Lazy */ public unmount(el: HTMLElement): void { this._observer.unobserve(el) }

在 index.ts 編寫注冊插件需要用到的 install 方法

import Lazy from ’./lazy’import { App } from ’vue’import { LazyOptions } from ’./types’export default { /** * install plugin * * @param {App} Vue * @param {LazyOptions} options */ install (Vue: App, options: LazyOptions): void { const lazy = new Lazy(options) Vue.config.globalProperties.$Lazyload = lazy // 留著備用,為了兼容$Lazyload // 選項(xiàng)api,可以通過this.$Lazyload獲取到Lazy類的實(shí)例,組合api我還不知道怎么獲取 // 所以通過 provide 來實(shí)現(xiàn)此需求 // 使用方式 const useLazylaod = inject(’Lazyload’) Vue.provide(’Lazyload’, lazy) Vue.directive(’lazy’, { mounted: lazy.mount.bind(lazy), updated: lazy.update.bind(lazy), unmounted: lazy.unmount.bind(lazy) }) }}

使用插件

import { createApp } from ’vue’import App from ’./App.vue’import VueLazyLoad from ’../src/index’const app = createApp(App)app.use(VueLazyLoad, { log: true, lifecycle: { loading: () => { console.log(’loading’) }, error: () => { console.log(’error’) }, loaded: () => { console.log(’loaded’) } }})app.mount(’#app’)

App.vue:

<template> <div /> <img v-lazy='’/example/assets/logo.png’' alt='Vue logo' width='100'> <img v-lazy='{src: errorlazy.src, lifecycle: errorlazy.lifecycle}' alt='Vue logo' width='100'> <button @click='change'> change </button></template><script>import { reactive } from ’vue’export default { name: ’App’, setup() { const errorlazy = reactive({ src: ’/example/assets/log1o.png’, lifecycle: { loading: () => { console.log(’image loading’) }, error: () => { console.log(’image error’) }, loaded: () => { console.log(’image loaded’) } } }) const change = () => { errorlazy.src = ’http://t8.baidu.com/it/u=3571592872,3353494284&fm=79&app=86&size=h300&n=0&g=4n&f=jpeg?sec=1603764281&t=bedd2d52d62e141cbb08c462183601c7’ } return { errorlazy, change } }}</script><style>.margin { margin-top: 1000px;}.image[lazy=loading] { background: goldenrod;}.image[lazy=error] { background: red;}.image[lazy=loaded] { background: green;}</style>

以上就是vue3+typescript實(shí)現(xiàn)圖片懶加載插件的詳細(xì)內(nèi)容,更多關(guān)于vue3 圖片懶加載的資料請關(guān)注好吧啦網(wǎng)其它相關(guān)文章!

標(biāo)簽: Vue
相關(guān)文章:
成人在线亚洲_国产日韩视频一区二区三区_久久久国产精品_99国内精品久久久久久久
亚洲视频导航| 欧美激情1区| aaa亚洲精品| 色域天天综合网| 亚洲蜜臀av乱码久久精品蜜桃| 国产成人av一区二区三区在线| 亚洲欧美久久久久一区二区三区| 欧美极品美女视频| 成人午夜电影小说| 欧美日韩mp4| 日韩成人一区二区| 国产一区二区免费在线| 久久精品一区二区国产| 亚洲女与黑人做爰| 成人sese在线| 欧美女孩性生活视频| 三级不卡在线观看| 亚洲狼人精品一区二区三区| 久久久精品综合| 粉嫩久久99精品久久久久久夜 | 日韩欧美成人午夜| 久国产精品韩国三级视频| 久久久久久一区| 一区二区高清在线| 在线视频日韩| 亚洲日本在线观看| 91看片淫黄大片一级| 精品国产乱码久久久久久影片| 国产麻豆视频一区二区| 欧美日韩黄色影视| 麻豆高清免费国产一区| 日本韩国一区二区三区| 日韩精品色哟哟| 久久一综合视频| 日日欢夜夜爽一区| 在线一区免费观看| 亚洲人成网站色在线观看| 欧美日韩亚洲一区在线观看| 久久先锋影音av鲁色资源| 成人av在线看| 日韩欧美国产不卡| 国产一区二区中文字幕| 精品视频全国免费看| 麻豆精品新av中文字幕| 欧美偷拍一区二区| 黑人巨大精品欧美一区| 欧美猛男gaygay网站| 国内精品写真在线观看| 欧美一区二区日韩一区二区| 国产盗摄一区二区| 日韩一级免费观看| 成人网在线播放| 久久亚洲免费视频| 欧美日韩亚洲在线| 亚洲欧美日韩国产中文在线| 99香蕉国产精品偷在线观看| 亚洲欧美福利一区二区| 国产精品裸体一区二区三区| 亚洲国产精品久久久男人的天堂| 国产精品女主播一区二区三区| 亚洲综合丝袜美腿| 亚洲免费中文| 麻豆成人在线观看| 欧美成人r级一区二区三区| 欧美不卡三区| 18欧美乱大交hd1984| 不卡的av电影在线观看| 久久精品视频免费| 亚洲一二三区在线| 亚洲福利视频三区| 欧美日韩一区不卡| 国产精品乡下勾搭老头1| 日韩亚洲欧美在线观看| 99精品黄色片免费大全| 国产精品久久久久永久免费观看| 亚洲精品激情| 人禽交欧美网站| 91精品免费在线| 欧美在线高清| 亚洲综合在线第一页| 色欧美片视频在线观看| 国产精品资源网| 国产亚洲一区二区三区| 国产精品v亚洲精品v日韩精品| 亚洲欧美日韩中文播放| 91久久一区二区| 韩国av一区二区三区在线观看| 日韩午夜小视频| 韩日成人在线| 国产精品青草久久| 久久午夜精品一区二区| 高清日韩电视剧大全免费| 国产精品区一区二区三区| 久久蜜桃精品| 成人晚上爱看视频| 亚洲婷婷综合久久一本伊一区| 久久午夜影视| 成人av影视在线观看| 亚洲欧美激情一区二区| 欧美偷拍一区二区| 色综合久久综合| 午夜精品久久一牛影视| 777久久久精品| 一区在线电影| 日本aⅴ精品一区二区三区| 精品国产一区二区在线观看| 亚洲人成免费| 久久国产精品色| 国产精品视频麻豆| 在线免费观看视频一区| 91亚洲精华国产精华精华液| 亚洲资源在线观看| 在线播放一区二区三区| 亚洲午夜一区| 国产在线精品不卡| 亚洲日本丝袜连裤袜办公室| 欧美日韩精品三区| 色综合夜色一区| 天堂久久久久va久久久久| 亚洲精品一区二区三区99| 在线亚洲一区| 成人动漫一区二区在线| 亚洲成人www| 久久日韩精品一区二区五区| 久久国产精品高清| 91一区一区三区| 奇米777欧美一区二区| 国产欧美日韩另类一区| 在线一区二区三区四区| 欧美日韩三级| 黑人巨大精品欧美一区| 亚洲精品精品亚洲| 777a∨成人精品桃花网| 99国产精品| 99免费精品视频| 精品一区中文字幕| 亚洲嫩草精品久久| 日韩欧美一级片| 久色成人在线| 国产精品sss| 国产精品一级片在线观看| 夜夜嗨av一区二区三区四季av | 久久久蜜桃一区二区人| 91美女在线视频| 激情久久久久久久久久久久久久久久| 亚洲欧洲国产日本综合| 精品国产一二三区| 久久黄色影院| 精品电影一区| 99国产精品久久久久久久久久久 | 性久久久久久久久久久久| 国产欧美精品一区二区三区四区| 欧美剧在线免费观看网站| 亚洲综合国产| 国产精品v欧美精品v日韩精品| 国产九九视频一区二区三区| 一区二区不卡在线播放| 欧美激情综合在线| 欧美一区二区精美| 91久久国产综合久久| 亚洲激情欧美| 欧美日韩国产精品一卡| 成人app在线| 国产精品主播直播| 久久不见久久见免费视频1| 日韩高清一区二区| 日韩国产在线一| 亚洲成人av电影在线| 一区二区不卡在线播放| 亚洲天堂久久久久久久| 国产精品美女一区二区在线观看| 26uuu国产一区二区三区| 精品国产91九色蝌蚪| 日韩精品一区在线| 在线综合视频播放| 欧美精品1区2区3区| 欧美精品在线视频| 日韩一区二区精品葵司在线| 91精品国产美女浴室洗澡无遮挡| 欧美日韩国产精品成人| 欧美日韩一级视频| 69堂精品视频| 精品少妇一区二区三区视频免付费 | 美女国产一区二区三区| 婷婷夜色潮精品综合在线| 一区二区三国产精华液| 国产精品女主播av| 国产欧美一区二区三区在线老狼| 欧美一区二区在线免费观看| 在线观看视频一区二区欧美日韩 | 欧美大白屁股肥臀xxxxxx| 欧美日韩一区二区三区四区五区| 久久国产精品久久w女人spa| 色哟哟精品一区| 六月丁香综合| 国产一区二区三区久久| 亚洲片区在线| 在线观看成人av| 国产精品激情| 国产精品草草|