前端入门之(vue图片加载框架一)
前言: 之前做android的時候,會接觸各種圖片加載框架,也自己封裝過,封裝網絡框架目的無非就是為了提高圖片的復用性、減少內存消耗、監聽圖片的加載過程等等.換成web前端其實是一樣的操作,好啦! 說了那么多我們來簡單的實現一個圖片加載框架,小伙伴跟緊了哦!!!
因為一直在做vue,所以我就以vue為基礎來開發我們的圖片加載框架了,我們新見一個vue項目,然后運行(我就以之前的vuex的demo為例子了,感興趣的童鞋可以看看我之前寫的vuex的幾篇文章).
<template><div class="opt-container"><img :src="images[0]"></div> </template><script>export default {name: 'Lazy',data() {return {images: ['https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1533137283186&di=c136f7387cfe2b79161f2f93bff6cb96&imgtype=0&src=http%3A%2F%2Fpic1.cxtuku.com%2F00%2F09%2F65%2Fb3468db29cb1.jpg','https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1533137283186&di=de941561df3b6fd53b2df9bfd6c0b187&imgtype=0&src=http%3A%2F%2Fpic43.photophoto.cn%2F20170413%2F0008118236659168_b.jpg','https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1533137283185&di=aff7e8aa60813f6e36ebc6f6a961255c&imgtype=0&src=http%3A%2F%2Fimg.zcool.cn%2Fcommunity%2F01d60f57e8a07d0000018c1bfa2564.JPG%403000w_1l_2o_100sh.jpg',]}}} </script><!-- Add "scoped" attribute to limit CSS to this component only --> <style scoped>.opt-container {font-size: 0px;} </style>可以看到,很簡單! 我們就是放了一個img標簽.然后加載了一張圖片:
現在有一個這樣的需求,因為我們的圖片比較大,所以當圖片正在加載的時候,我們顯示loading圖片,然后當我們圖片加載失敗的時候,我們顯示一個失敗的默認圖,當我們圖片正在加載成功的時候,我們再顯示.
我們來試一下哈~~
我們定義一個方法,叫loadImageAsync:
loadImageAsync(item, resolve, reject) {let image = new Image();image.src = item.src;image.onload = function () {resolve({naturalHeight: image.naturalHeight,naturalWidth: image.naturalWidth,src: image.src});};image.onerror = function (e) {reject(e)};}}代碼很簡單,我就不解釋了~~ ,接下來是在我們的created的時候調用此方法:
created() {let item = {src: this.images[0]};this.loadImageAsync(item,(response)=>{console.log('圖片加載成功');console.log('圖片的寬度為:'+response.naturalWidth);console.log('圖片的高度為:'+response.naturalHeight);},(error)=>{console.log('圖片加載失敗');});}我們重寫運行代碼看log:
[HMR] Waiting for update signal from WDS... Lazy.vue?2392:40 圖片加載成功 Lazy.vue?2392:41 圖片的寬度為:600 Lazy.vue?2392:42 圖片的高度為:398我們可以看到,log里面打印出來了日志,然后把圖片的寬高都打印出來了,我們試著把圖片鏈接寫錯試一下:
created() {//我們把鏈接寫錯let item = {src: 11111+this.images[0]};this.loadImageAsync(item,(response)=>{console.log('圖片加載成功');console.log('圖片的寬度為:'+response.naturalWidth);console.log('圖片的高度為:'+response.naturalHeight);},(error)=>{console.log('圖片加載失敗');});}重新運行代碼:
[HMR] Waiting for update signal from WDS... Lazy.vue?2392:44 圖片加載失敗可以看到,圖片加載失敗了~~
好啦,有了圖片的監聽,我們就可以操作了,我們首先準備兩張圖片,一張為loading(加載中圖片),一張為erro(加載失敗的圖片).
然后我們動態的給img標簽設置上src:
<template><div class="opt-container"><img :src="currSrc"></div> </template><script>const errorImg = require('./error.png');const loadingImg = require('./loading.png');export default {name: 'Lazy',data() {return {images: ['https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1533137283186&di=c136f7387cfe2b79161f2f93bff6cb96&imgtype=0&src=http%3A%2F%2Fpic1.cxtuku.com%2F00%2F09%2F65%2Fb3468db29cb1.jpg','https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1533137283186&di=de941561df3b6fd53b2df9bfd6c0b187&imgtype=0&src=http%3A%2F%2Fpic43.photophoto.cn%2F20170413%2F0008118236659168_b.jpg','https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1533137283185&di=aff7e8aa60813f6e36ebc6f6a961255c&imgtype=0&src=http%3A%2F%2Fimg.zcool.cn%2Fcommunity%2F01d60f57e8a07d0000018c1bfa2564.JPG%403000w_1l_2o_100sh.jpg',],currSrc: loadingImg //默認為加載中狀態}},methods: {loadImageAsync(item, resolve, reject) {let image = new Image();image.src = item.src;image.onload = function () {resolve({naturalHeight: image.naturalHeight,naturalWidth: image.naturalWidth,src: image.src});};image.onerror = function (e) {reject(e)};}},created() {let item = {src: this.images[0]};this.loadImageAsync(item, (response) => {console.log('圖片加載成功');console.log('圖片的寬度為:' + response.naturalWidth);console.log('圖片的高度為:' + response.naturalHeight);//當圖片加載成功的時候,把圖片的src換成目標地址this.currSrc = response.src;}, (error) => {console.log('圖片加載失敗');//當圖片加載失敗的時候,把圖片的src換成失敗的圖片this.currSrc = errorImg;});}} </script><!-- Add "scoped" attribute to limit CSS to this component only --> <style scoped>.opt-container {font-size: 0px;} </style>代碼都有注釋,小伙伴應該看得懂哈~~我們運行一下:
太快了,錄屏看不出loading的效果,我們把圖片鏈接改錯試試:
let item = {src: 1111+this.images[0]};可以看到,我們的圖片加載失敗就顯示了一張失敗的默認圖,好啦! 到這里我們的簡單的需求算是實現了,這時,有小伙伴就要說了,你這也太麻煩了,我只有一張圖片還好,既然是框架,那就得是針對整個工程, 是的!! 我們就封裝一下我們的代碼,最后實現的時候,我們只需要這樣寫就好了:
<template><div class="opt-container"><img v-lazy="{src:images[0]}"></div> </template>我們通過指令的形式來加載我們的圖片,然后在指令中去切換圖片狀態,沒看過指令的童鞋自己去看官網哈https://cn.vuejs.org/v2/guide/custom-directive.html
好啦,我們開動啦~~~
第一步:
我們創建一個叫lazy的文件夾,然后返回一個帶install方法的對象:
然后我們在項目的main.js用一下我們的這個插件:
// The Vue build version to load with the `import` command // (runtime-only or standalone) has been set in webpack.base.conf with an alias. import Vue from 'vue' import App from './App' import router from './router' import store from './store'import LazyImage from './lazy'Vue.config.productionTip = false Vue.use(LazyImage) /* eslint-disable no-new */ new Vue({el: '#app',router,store,components: {App},template: '<App/>' })我們運行代碼:
[HMR] Waiting for update signal from WDS... index.js?bd6a:9 install be called!!可以看到,我們的install方法被調用了~~
第二步:
定義lazy指令
我們運行代碼:
[HMR] Waiting for update signal from WDS... index.js?bd6a:20 bind name: "lazy" value: {"src":"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1533137283186&di=c136f7387cfe2b79161f2f93bff6cb96&imgtype=0&src=http%3A%2F%2Fpic1.cxtuku.com%2F00%2F09%2F65%2Fb3468db29cb1.jpg"} expression: "{src:images[0]}" argument: undefined modifiers: {} vnode keys: tag, data, children, text, elm, ns, context, fnContext, fnOptions, fnScopeId, key, componentOptions, componentInstance, parent, raw, isStatic, isRootInsert, isComment, isCloned, isOnce, asyncFactory, asyncMeta, isAsyncPlaceholder Lazy.vue?2392:50 圖片加載失敗log有點多哈,不過結合我們的指令:
<img v-lazy="{src:images[0]}">我們可以發現,我們可以從value中獲取我們的src~~
好啦,定義好指令后,我們繼續創建一個叫lazy的類,把一些基本的操作放在這個類中.
第三步:
實現lazy類:
然后把我們的指令的構造函數跟我們的lazy類的方法綁定起來:
/*** @author YASIN* @version [React-Native Ocj V01, 2018/8/1]* @date 17/2/23* @description index*/ import lazyDelegate from './LazyDelegate';export default {install(Vue, options = {}) {let LazyClass = lazyDelegate(Vue);let lazy = new LazyClass(options);Vue.directive('lazy', {bind: lazy.add.bind(lazy),update: lazy.update.bind(lazy),componentUpdated: function () {console.log('componentUpdated');},unbind: lazy.remove.bind(lazy),})} }我們找到lazy的add方法:
/*** 只調用一次,指令第一次綁定到元素時調用。在這里可以進行一次性的初始化設置。* @param el 指令所綁定的元素,可以用來直接操作 DOM 。* @param binding* @param vnode*/add(el, binding, vnode) {console.log('add');}我們首先獲取我們指令中的src,然后獲取我們定義的error跟loading:
_valueFormatter(value) {let src = value;let loading = this.options.loading;let error = this.options.error;// 如果value是一個object類型的時候if (value !== null && typeof value === 'object') {src = value.src;loading = value.loading || loading;error = value.error || error;}return {src,loading,error}}因為我們的框架只有一個,但是我們的標簽有很多個,所以我們針對每一個標簽創建一個LazyListener加載工具類.然后在lazy中用一個數組統一的保存起來.
我們創建一個叫LazyListener的類:
然后在我們的lazy的add方法中創建一個listerner:
add(el, binding, vnode) {let {src, loading, error} = this._valueFormatter(binding.value)Vue.nextTick(()=>{const newListener = new ReactiveListener({el,loading,error,src,elRenderer: this._elRenderer.bind(this),})})}然后把創建的listerner保存在lazy的數組中:
return class Lazy {constructor({error, throttleWait, loading, attempt}) {//存放每一個元素的Listener加載類this.ListenerQueue = []......} /*** 只調用一次,指令第一次綁定到元素時調用。在這里可以進行一次性的初始化設置。* @param el 指令所綁定的元素,可以用來直接操作 DOM 。* @param binding* @param vnode*/add(el, binding, vnode) {...Vue.nextTick(() => {const newListener = new ReactiveListener({el,loading,error,src,elRenderer: this._elRenderer.bind(this),})//將加載代理類加入到lazy的代理數組中this.ListenerQueue.push(newListener)})}好啦,我們的全局lazy(經理)類創建好了,然后我們的經紀人(listener)也創建好了,我們接下來就是讓經理通知經紀人干活了, 經理是一個人,經紀人有很多,所以我們把消息發到群里就可以了,我們創建一個群對話方法叫_lazyLoadHandler:
/*** 通知所有的listener該干活了* @private*/_lazyLoadHandler () {//找出哪些是已經完成工作了的const freeList = []this.ListenerQueue.forEach((listener, index) => {//狀態是非錯誤的并且是已完成的叫完成工作的人if (!listener.state.error && listener.state.loaded) {return freeList.push(listener)}//通知未完成工作的人干活了listener.load()})//把完成工作的listener剔除freeList.forEach(vm => remove(this.ListenerQueue, vm))}然后我們去listener中定義一個叫load的方法:
/*** 加載圖片的方法* @param onFinish 完成回調*/load(onFinish) {console.log('load------>');}因為我們的_lazyLoadHandler函數可能會被頻繁的調用,這樣就會阻塞js線程,體驗不太好,所以我們給_lazyLoadHandler方法封裝一下,加一個截流函數:
return class Lazy {constructor({error, throttleWait, loading, attempt}) {//存放每一個元素的Listener加載類this.ListenerQueue = []this.options = {throttleWait: throttleWait || 200,//截流時間...}this.lazyLoadHandler = throttle(this._lazyLoadHandler.bind(this), this.options.throttleWait)} function throttle (action, delay) {let timeout = nulllet lastRun = 0return function () {if (timeout) {return}let elapsed = Date.now() - lastRunlet context = thislet args = argumentslet runCallback = function () {lastRun = Date.now()timeout = falseaction.apply(context, args)}if (elapsed >= delay) {runCallback()} else {timeout = setTimeout(runCallback, delay)}} }好啦,當我們一切準備就緒的時候,我們在我們的add方法中調用我們的lazyLoadHandler方法通知listener去加載圖片:
/*** 只調用一次,指令第一次綁定到元素時調用。在這里可以進行一次性的初始化設置。* @param el 指令所綁定的元素,可以用來直接操作 DOM 。* @param binding* @param vnode*/add(el, binding, vnode) {let {src, loading, error} = this._valueFormatter(binding.value)Vue.nextTick(() => {const newListener = new ReactiveListener({el,loading,error,src,// elRenderer: this._elRenderer.bind(this),})this.ListenerQueue.push(newListener)//通知listener去加載圖片this.lazyLoadHandler()//通知listener去加載圖片Vue.nextTick(() => this.lazyLoadHandler())})}我們代理類的全部代碼:
/*** @author YASIN* @version [React-Native Ocj V01, 2018/8/1]* @date 17/2/23* @description LazyDelegate*/ import LazyListener from './listener'; const DEFAULT_ERRO_URL = require('../components/error.png'); const DEFAULT_LOADING_URL = require('../components/loading.png'); export default function (Vue) {return class Lazy {constructor({error, throttleWait, loading, attempt}) {//存放每一個元素的Listener加載類this.ListenerQueue = []this.options = {throttleWait: throttleWait || 200,//截流時間error: error || DEFAULT_ERRO_URL,//默認失敗圖片loading: loading || DEFAULT_LOADING_URL,//默認成功圖片attempt: attempt || 3 //重試次數}this.lazyLoadHandler = throttle(this._lazyLoadHandler.bind(this), this.options.throttleWait)}/*** 只調用一次,指令第一次綁定到元素時調用。在這里可以進行一次性的初始化設置。* @param el 指令所綁定的元素,可以用來直接操作 DOM 。* @param binding* @param vnode*/add(el, binding, vnode) {let {src, loading, error} = this._valueFormatter(binding.value)Vue.nextTick(() => {const newListener = new LazyListener({el,loading,error,src,// elRenderer: this._elRenderer.bind(this),})this.ListenerQueue.push(newListener)Vue.nextTick(() => this.lazyLoadHandler())})}update(el, binding) {console.log('update');}remove(el) {console.log('remove');}/*** 通知所有的listener該干活了* @private*/_lazyLoadHandler () {//找出哪些是已經完成工作了的const freeList = []this.ListenerQueue.forEach((listener, index) => {if (!listener.state.error && listener.state.loaded) {return freeList.push(listener)}listener.load()})//把完成工作的listener剔除freeList.forEach(vm => remove(this.ListenerQueue, vm))}_valueFormatter(value) {let src = value;let loading = this.options.loading;let error = this.options.error;// 如果value是一個object類型的時候if (value !== null && typeof value === 'object') {src = value.src;loading = value.loading || loading;error = value.error || error;}return {src,loading,error}}} } function throttle (action, delay) {let timeout = nulllet lastRun = 0return function () {if (timeout) {return}let elapsed = Date.now() - lastRunlet context = thislet args = argumentslet runCallback = function () {lastRun = Date.now()timeout = falseaction.apply(context, args)}if (elapsed >= delay) {runCallback()} else {timeout = setTimeout(runCallback, delay)}} }我們listener的全部代碼:
/*** @author YASIN* @version [React-Native Ocj V01, 2018/8/1]* @date 17/2/23* @description listener*/ export default class LazyListener {constructor({el, src, error, loading, options, elRenderer}) {this.el = elthis.src = srcthis.error = errorthis.loading = loadingthis.naturalHeight = 0this.naturalWidth = 0this.options = options//組件狀態渲染方法this.elRenderer = elRenderer//初始化組件狀態this.initState()}/*** 初始化組件狀態*/initState() {this.state = {error: false,loaded: false,rendered: false}}/*** 加載圖片的方法* @param onFinish 完成回調*/load(onFinish) {console.log('load------>');} }當我運行代碼:
[HMR] Waiting for update signal from WDS... listener.js?4bef:40 load------>可以看到,我們的listener(經紀人)的load方法執行了~~
然后我們把我們一開始寫的loadImageAsync方法搬進我們的listener中:
const loadImageAsync = (item, resolve, reject) => {let image = new Image()image.src = item.srcimage.onload = function () {resolve({naturalHeight: image.naturalHeight,naturalWidth: image.naturalWidth,src: image.src})}image.onerror = function (e) {reject(e)} }然后我們首先是渲染我們的loading:
/*** 加載圖片的方法* @param onFinish 完成回調*/load(onFinish) {//如果重試的次數>我們設置的次數并且失敗的時候我們直接不加載了if ((this.attempt > this.options.attempt - 1) && this.state.error) {onFinish && onFinish()return}//如果該組件已經加載完畢了直接結束if (this.state.loaded) {this.state.loaded = trueonFinish && onFinish()//渲染srcreturn this.render('loaded')}this.renderLoading(() => {this.attempt++loadImageAsync({src: this.src}, data => {this.naturalHeight = data.naturalHeightthis.naturalWidth = data.naturalWidththis.state.loaded = truethis.state.error = falsethis.render('loaded')onFinish && onFinish()}, err => {this.state.error = truethis.state.loaded = falsethis.render('error')})})} /*** 渲染loading* @param cb 回調*/renderLoading(cb) {loadImageAsync({src: this.loading}, data => {this.render('loading')cb()}, () => {cb()})}然后加載完了統一執行render方法:
/*** 根據狀態渲染src* @param state*/render(state) {this.elRenderer(this, state)} constructor({el, src, error, loading, options, elRenderer}) {..this.elRenderer = elRenderer//初始化組件狀態this.initState()}其中listener的elRenderer方法其實是經理(lazy)傳過去的,所以我們在lazy類中統一定義一個elRenderer方法:
/*** 根據狀態渲染src* @param listener 經紀人* @param state 狀態* @private*/_elRenderer(listener, state) {if (!listener.el) returnconst {el} = listenerlet srcswitch (state) {case 'loading':src = listener.loadingbreakcase 'error':src = listener.errorbreakdefault:src = listener.srcbreak}//通過js方法給el設置上src屬性if (el.getAttribute('src') !== src) {el.setAttribute('src', src)}el.setAttribute('lazy', state)}然后在創建listener的時候傳給listener(經紀人):
add(el, binding, vnode) {let {src, loading, error} = this._valueFormatter(binding.value)Vue.nextTick(() => {const newListener = new LazyListener({el,loading,error,src,options: this.options,elRenderer: this._elRenderer.bind(this),})this.ListenerQueue.push(newListener)Vue.nextTick(() => this.lazyLoadHandler())})}好啦,我們經理lazy的全部代碼:
/*** @author YASIN* @version [React-Native Ocj V01, 2018/8/1]* @date 17/2/23* @description LazyDelegate*/ import LazyListener from './listener';const DEFAULT_ERRO_URL = require('../components/error.png'); const DEFAULT_LOADING_URL = require('../components/loading.png'); export default function (Vue) {return class Lazy {constructor({error, throttleWait, loading, attempt}) {//存放每一個元素的Listener加載類this.ListenerQueue = []this.options = {throttleWait: throttleWait || 200,//截流時間error: error || DEFAULT_ERRO_URL,//默認失敗圖片loading: loading || DEFAULT_LOADING_URL,//默認成功圖片attempt: attempt || 3 //重試次數}this.lazyLoadHandler = throttle(this._lazyLoadHandler.bind(this), this.options.throttleWait)}/*** 只調用一次,指令第一次綁定到元素時調用。在這里可以進行一次性的初始化設置。* @param el 指令所綁定的元素,可以用來直接操作 DOM 。* @param binding* @param vnode*/add(el, binding, vnode) {let {src, loading, error} = this._valueFormatter(binding.value)Vue.nextTick(() => {const newListener = new LazyListener({el,loading,error,src,options: this.options,elRenderer: this._elRenderer.bind(this),})this.ListenerQueue.push(newListener)Vue.nextTick(() => this.lazyLoadHandler())})}update(el, binding) {console.log('update');}remove(el) {console.log('remove');}/*** 通知所有的listener該干活了* @private*/_lazyLoadHandler() {//找出哪些是已經完成工作了的const freeList = []this.ListenerQueue.forEach((listener, index) => {if (!listener.state.error && listener.state.loaded) {return freeList.push(listener)}listener.load()})//把完成工作的listener剔除freeList.forEach(vm => remove(this.ListenerQueue, vm))}/*** 根據狀態渲染src* @param listener 經紀人* @param state 狀態* @private*/_elRenderer(listener, state) {if (!listener.el) returnconst {el} = listenerlet srcswitch (state) {case 'loading':src = listener.loadingbreakcase 'error':src = listener.errorbreakdefault:src = listener.srcbreak}//通過js方法給el設置上src屬性if (el.getAttribute('src') !== src) {el.setAttribute('src', src)}el.setAttribute('lazy', state)}_valueFormatter(value) {let src = value;let loading = this.options.loading;let error = this.options.error;// 如果value是一個object類型的時候if (value !== null && typeof value === 'object') {src = value.src;loading = value.loading || loading;error = value.error || error;}return {src,loading,error}}} }function throttle(action, delay) {let timeout = nulllet lastRun = 0return function () {if (timeout) {return}let elapsed = Date.now() - lastRunlet context = thislet args = argumentslet runCallback = function () {lastRun = Date.now()timeout = falseaction.apply(context, args)}if (elapsed >= delay) {runCallback()} else {timeout = setTimeout(runCallback, delay)}} }我們經紀人(listener)的全部代碼:
/*** @author YASIN* @version [React-Native Ocj V01, 2018/8/1]* @date 17/2/23* @description listener*/ export default class LazyListener {constructor({el, src, error, loading, options, elRenderer}) {this.el = elthis.src = srcthis.error = errorthis.loading = loadingthis.attempt = 0 //重試次數this.naturalHeight = 0this.naturalWidth = 0this.options = options//組件狀態渲染方法this.elRenderer = elRenderer//初始化組件狀態this.initState()}/*** 初始化組件狀態*/initState() {this.state = {error: false,loaded: false,rendered: false}}/*** 加載圖片的方法* @param onFinish 完成回調*/load(onFinish) {//如果重試的次數>我們設置的次數并且失敗的時候我們直接不加載了if ((this.attempt > this.options.attempt - 1) && this.state.error) {onFinish && onFinish()return}//如果該組件已經加載完畢了直接結束if (this.state.loaded) {this.state.loaded = trueonFinish && onFinish()//渲染srcreturn this.render('loaded')}this.renderLoading(() => {this.attempt++loadImageAsync({src: this.src}, data => {this.naturalHeight = data.naturalHeightthis.naturalWidth = data.naturalWidththis.state.loaded = truethis.state.error = falsethis.render('loaded')onFinish && onFinish()}, err => {this.state.error = truethis.state.loaded = falsethis.render('error')})})}/*** 渲染loading* @param cb 回調*/renderLoading(cb) {loadImageAsync({src: this.loading}, data => {this.render('loading')cb()}, () => {cb()})}/*** 根據狀態渲染src* @param state*/render(state) {this.elRenderer(this, state)} } const loadImageAsync = (item, resolve, reject) => {let image = new Image()image.src = item.srcimage.onload = function () {resolve({naturalHeight: image.naturalHeight,naturalWidth: image.naturalWidth,src: image.src})}image.onerror = function (e) {reject(e)} }然后我們的測試類中的全部代碼:
<template><div class="opt-container"><img v-lazy="{src:images[1]}"></div> </template><script>export default {name: 'Lazy',data() {return {images: ['https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1533137283186&di=c136f7387cfe2b79161f2f93bff6cb96&imgtype=0&src=http%3A%2F%2Fpic1.cxtuku.com%2F00%2F09%2F65%2Fb3468db29cb1.jpg','https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1533137283186&di=de941561df3b6fd53b2df9bfd6c0b187&imgtype=0&src=http%3A%2F%2Fpic43.photophoto.cn%2F20170413%2F0008118236659168_b.jpg','https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1533137283185&di=aff7e8aa60813f6e36ebc6f6a961255c&imgtype=0&src=http%3A%2F%2Fimg.zcool.cn%2Fcommunity%2F01d60f57e8a07d0000018c1bfa2564.JPG%403000w_1l_2o_100sh.jpg',]}}} </script><!-- Add "scoped" attribute to limit CSS to this component only --> <style scoped>.opt-container {font-size: 0px;} </style>運行代碼:
我們寫一個錯誤的圖片鏈接試試:
<template><div class="opt-container"><img v-lazy="{src:111+images[1]}"></div> </template>好啦~~ 已經基本實現了我們的效果了~~篇幅有點長了,寫得我都睡著了,細心的小伙伴可能會發現,代碼長得好像一個叫vue-lazyload的框架,是的!! 我就是一點一點在解析它的源碼,哈哈哈!!! 小伙伴不要失望哈,學習別人的東西不一定就是很丟丑的一件事情,別人牛逼干嘛不去學習呢??
好啦~ 先附上vue-lazyload框架的地址:
https://github.com/hilongjw/vue-lazyload
當然!! 我這個只是一個demo,小伙伴千萬不要直接丟到項目中哦,要用的話直接去拖vue-lazyload的代碼就好了.
這一節先結束了,下一節我將帶大家一起實現(懶加載、緩存、監聽等)未實現的功能,睡覺噠!!!!!! 歡迎入群,歡迎交流~~~~
總結
以上是生活随笔為你收集整理的前端入门之(vue图片加载框架一)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 最方便的在线Oracle SQL学习环境
- 下一篇: lazyload.css,图片加载优化及