电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

您的位置:首頁技術文章
文章詳情頁

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

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

github項目地址: github.com/murongg/vue…

求star 與 issues

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

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

安裝:

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

需求分析

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

<img src='http://www.hdgsjgj.cn/bcjs/...' lazy='loading'><img src='http://www.hdgsjgj.cn/bcjs/...' lazy='loaded'><img src='http://www.hdgsjgj.cn/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 ,當為 string 時,默認為需要加載的 url,當為 object 時,可傳入

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

目錄結構

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

編寫懶加載類

懶加載主要通過 IntersectionObserver對象實現(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 類基礎框架代碼,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 文件內,此文章不在贅述此方法代碼,可在后文 github 倉庫內查看此代碼 * 此方法主要功能是合并兩個對象 * * @param {*} [options={}] * @memberof Lazy */ public config(options = {}): void { assign(this.options, options) } public mount(el: HTMLElement, binding: DirectiveBinding<string | ValueFormatterObject>): void {} // 對應 directive mount hook public update() {} // 對應 directive update hook public unmount() {} // 對應 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 // 選項api,可以通過this.$Lazyload獲取到Lazy類的實例,組合api我還不知道怎么獲取 // 所以通過 provide 來實現(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實現(xiàn)圖片懶加載插件的詳細內容,更多關于vue3 圖片懶加載的資料請關注好吧啦網(wǎng)其它相關文章!

標簽: Vue
相關文章:
主站蜘蛛池模板: 成都顶呱呱信息技术有限公司-贷款_个人贷款_银行贷款在线申请 - 成都贷款公司 | 三价铬_环保铬_环保电镀_东莞共盈新材料贸易有限公司 | 一级建造师培训_一建培训机构_中建云筑建造师培训网校 | 根系分析仪,大米外观品质检测仪,考种仪,藻类鉴定计数仪,叶面积仪,菌落计数仪,抑菌圈测量仪,抗生素效价测定仪,植物表型仪,冠层分析仪-杭州万深检测仪器网 | crm客户关系管理系统,销售管理系统,crm系统,在线crm,移动crm系统 - 爱客crm | 超细粉碎机|超微气流磨|气流分级机|粉体改性设备|超微粉碎设备-山东埃尔派粉碎机厂家 | 护栏打桩机-打桩机厂家-恒新重工 | 雨燕360体育免费直播_雨燕360免费NBA直播_NBA篮球高清直播无插件-雨燕360体育直播 | 深圳展厅设计_企业展馆设计_展厅设计公司_数字展厅设计_深圳百艺堂 | 液压升降货梯_导轨式升降货梯厂家_升降货梯厂家-河南东圣升降设备有限公司 | 扒渣机,铁水扒渣机,钢水扒渣机,铁水捞渣机,钢水捞渣机-烟台盛利达工程技术有限公司 | 臭氧实验装置_实验室臭氧发生器-北京同林臭氧装置网 | 阳光1号桔柚_无核沃柑_柑橘新品种枝条苗木批发 - 苧金网 | 潍坊青州古城旅游景点攻略_青州酒店美食推荐-青州旅游网 | 大通天成企业资质代办_承装修试电力设施许可证_增值电信业务经营许可证_无人机运营合格证_广播电视节目制作许可证 | 定做大型恒温循环水浴槽-工业用不锈钢恒温水箱-大容量低温恒温水槽-常州精达仪器 | 工业车间焊接-整体|集中除尘设备-激光|等离子切割机配套除尘-粉尘烟尘净化治理厂家-山东美蓝环保科技有限公司 | 智成电子深圳tdk一级代理-提供TDK电容电感贴片蜂鸣器磁芯lambda电源代理经销,TDK代理商有哪些TDK一级代理商排名查询。-深圳tdk一级代理 | 洁净实验室工程-成都手术室净化-无尘车间装修-四川华锐净化公司-洁净室专业厂家 | 电主轴-高速精密电主轴-高速电机厂家-瑞德沃斯品牌有限公司 | 科威信洗净科技,碳氢清洗机,超声波清洗机,真空碳氢清洗机 | 二手电脑回收_二手打印机回收_二手复印机回_硒鼓墨盒回收-广州益美二手电脑回收公司 | 活性炭-蜂窝-椰壳-柱状-粉状活性炭-河南唐达净水材料有限公司 | 水性绝缘漆_凡立水_绝缘漆树脂_环保绝缘漆-深圳维特利环保材料有限公司 | 千斤顶,液压千斤顶-力良企业,专业的液压千斤顶制造商,shliliang.com | 带式过滤机厂家_价格_型号规格参数-江西核威环保科技有限公司 | 石牌坊价格石牌坊雕刻制作_石雕牌坊牌楼石栏杆厂家_山东嘉祥石雕有限公司 | 阳光1号桔柚_无核沃柑_柑橘新品种枝条苗木批发 - 苧金网 | 超声波乳化机-超声波分散机|仪-超声波萃取仪-超声波均质机-精浩机械|首页 | 洛阳防爆合格证办理-洛阳防爆认证机构-洛阳申请国家防爆合格证-洛阳本安防爆认证代办-洛阳沪南抚防爆电气技术服务有限公司 | 亚洲工业智能制造领域专业门户网站 - 亚洲自动化与机器人网 | 玉米加工设备,玉米深加工机械,玉米糁加工设备.玉米脱皮制糁机 华豫万通粮机 | 今日娱乐圈——影视剧集_八卦娱乐_明星八卦_最新娱乐八卦新闻 | 碎石机设备-欧版反击破-欧版颚式破碎机(站)厂家_山东奥凯诺机械 高低温试验箱-模拟高低温试验箱订制-北京普桑达仪器科技有限公司【官网】 | 品牌策划-品牌设计-济南之式传媒广告有限公司官网-提供品牌整合丨影视创意丨公关活动丨数字营销丨自媒体运营丨数字营销 | 厦门ISO认证|厦门ISO9001认证|厦门ISO14001认证|厦门ISO45001认证-艾索咨询专注ISO认证行业 | 济南画室培训-美术高考培训-山东艺霖艺术培训画室 | 振动筛,震动筛,圆形振动筛,振动筛价格,振动筛厂家-新乡巨宝机电 蒸汽热收缩机_蒸汽发生器_塑封机_包膜机_封切收缩机_热收缩包装机_真空机_全自动打包机_捆扎机_封箱机-东莞市中堡智能科技有限公司 | 螺杆泵_中成泵业| 锂电混合机-新能源混合机-正极材料混料机-高镍,三元材料混料机-负极,包覆混合机-贝尔专业混合混料搅拌机械系统设备厂家 | 浙江富广阀门有限公司|