We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
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
网页在获取图片资源的时候,经常会由于 资源路径无效、网络环境不理想、服务器过载 等原因导致资源加载超时或失败。为了保证良好的用户体验,我们需要对图片加载做容错处理。
最简单的方式就是通过绑定 img 元素的 error 事件,在图片加载失败时显示备用图片 error.jpg。
img
error
error.jpg
若采用此方式,需要在 error 事件触发时取消事件的绑定,避免当 error.jpg 也加载失败时死循环拉取资源。
<img src="image-path.jpg" onerror="this.onerror=null;this.src='error.jpg'">
如果需要对 背景图片(background-image) 实施容错处理呢?
background-image
如果需要在图片加载过程中加 loading 效果呢?
这个时候就需要 “替身” 发挥作用了 ——
我们可以利用一个对用户不可见的 img 元素,来验证图片资源的合法性。
额外创建一个不插入 DOM 节点树的 img 元素 “替身”,src 属性值为目标资源的 url。若 “替身” 能成功获取目标资源(load 事件触发),即让目标节点加载该资源,否则(error 事件触发)加载备用资源。
src
load
注意,重复加载同一个资源时并不会产生额外的网络消耗,浏览器会从本地缓存获取该资源。
在 jQuery 环境下,建议以插件的形式扩展,维持链式调用的特性:
$.fn.img = function(opts) { const $img = document.createElement('img'); // 未加载完成时,显示 loading this.css('background-image', `url('${opts.loading}')`); $img.onload = () => { this.css('background-image', `url('${opts.src}')`); }; $img.onerror = () => { this.css('background-image', `url('${opts.error}')`); }; $img.src = opts.src; return this; } $('.image').img({ src: 'success.jpg', error: 'error.jpg', loading: 'loading.gif', });
预览地址:https://codepen.io/JunreyCen/pen/WBapBw
如果使用了模板引擎(譬如 lodash 的 _.template 函数)的渲染方式,且希望维持 数据驱动视图 的模式时,可以参考下面的处理:
lodash
_.template
<div id="app"></div> <template id="tpl"> <div class="image" style="background-image: url('<%= loading %>')"></div> <img style="display: none" src="<%= src %>" onload="$(this).siblings('.image').css('background-image', 'url(<%= src %>)')" onerror="$(this).siblings('.image').css('background-image', 'url(<%= error %>)')"> </template> <script> $(function() { $('#app').append(_.template($('#tpl').html())({ src: 'success.jpg', error: 'error.jpg', loading: 'loading.gif', })); }); </script>
题外话,推荐把 demo 中的处理封装成模板组件,配合 CSS 命名空间 就可以实现组件化了。鉴于 jQuery + 模板引擎 这类技术栈流行度已经没那么高了,这里不再单独提供例程。
我们通过绑定 vue 指令 来实现图片的容错处理。其好处在于,每当图片资源的 src 被初始化或更新时,vue 指令都可以捕捉到变化,并容错处理后再响应式地作用于目标节点。
vue 官方文档 中对于 自定义指令 有详细的教程,这里就不多说了,直接贴代码。
<div id="app"></div> <template id="tpl"> <div class="image" v-img="{ src: 'success.jpg', error: 'error.jpg', loading: 'loading.gif', }"></div> </template> <script> function imgHandler($el, binding) { const opts = binding.value; const $img = document.createElement('img'); $el.style.backgroundImage = `url('${opts.loading}')`; $img.onload = () => { $el.style.backgroundImage = `url('${opts.src}')`; }; $img.onerror = () => { $el.style.backgroundImage = `url('${opts.error}')`; }; $img.src = opts.src; } Vue.directive('img', { inserted: imgHandler, update: imgHandler, }); new Vue({ el: '#app', template: '#tpl', }); </script>
基于上面提供的 vue demo,我们来模拟一个场景:
path-to-image-A.jpg
path-to-image-B.jpg
此时,万一资源 A 的加载速度比资源 B 还要慢,就会出现历史资源(A)把最新资源(B)覆盖掉的问题。我们稍微修改下 demo 来实现这个场景:
A
B
<div class="image" v-img="{ // ... src, delay, }"></div> <script> function imgHandler($el, binding) { // ... if (opts.delay) { // 模拟图片加载延迟 setTimeout(() => { $img.src = opts.src; }, opts.delay); } else { $img.src = opts.src; } } new Vue({ data() { return { src: '', delay: 0, }; }, mounted() { this.delay = 200; this.src = 'success.jpg'; this.$nextTick(() => { this.delay = 0; this.src = 'success_2.jpg'; }); }, }); </script>
或者直接看 demo 效果:https://codepen.io/JunreyCen/pen/JqmNQP
解决方案也很简单,我们只需要把所有 “替身” 都记录下来,在更新时把上一次创建的 “替身” 清理掉。即使出现历史资源的捕获时机比最新资源的还要靠后的情况,由于历史资源的 onload 和 onerror 方法已经被重置,不会产生影响。
onload
onerror
最终方案例程:https://github.com/JunreyCen/blog-demo/blob/master/image-handler/vue.2.html
PS: 文章首发于 简书 ,欢迎大家关注。
The text was updated successfully, but these errors were encountered:
No branches or pull requests
网页在获取图片资源的时候,经常会由于 资源路径无效、网络环境不理想、服务器过载 等原因导致资源加载超时或失败。为了保证良好的用户体验,我们需要对图片加载做容错处理。
最简单的方式就是通过绑定
img
元素的error
事件,在图片加载失败时显示备用图片error.jpg
。如果需要对 背景图片(
background-image
) 实施容错处理呢?如果需要在图片加载过程中加 loading 效果呢?
这个时候就需要 “替身” 发挥作用了 ——
我们可以利用一个对用户不可见的
img
元素,来验证图片资源的合法性。jQuery 环境
额外创建一个不插入 DOM 节点树的
img
元素 “替身”,src
属性值为目标资源的 url。若 “替身” 能成功获取目标资源(load
事件触发),即让目标节点加载该资源,否则(error
事件触发)加载备用资源。在 jQuery 环境下,建议以插件的形式扩展,维持链式调用的特性:
预览地址:https://codepen.io/JunreyCen/pen/WBapBw
jQuery + 模板引擎
如果使用了模板引擎(譬如
lodash
的_.template
函数)的渲染方式,且希望维持 数据驱动视图 的模式时,可以参考下面的处理:题外话,推荐把 demo 中的处理封装成模板组件,配合 CSS 命名空间 就可以实现组件化了。鉴于 jQuery + 模板引擎 这类技术栈流行度已经没那么高了,这里不再单独提供例程。
Vue 环境
我们通过绑定 vue 指令 来实现图片的容错处理。其好处在于,每当图片资源的
src
被初始化或更新时,vue 指令都可以捕捉到变化,并容错处理后再响应式地作用于目标节点。vue 官方文档 中对于 自定义指令 有详细的教程,这里就不多说了,直接贴代码。
踩坑点
基于上面提供的 vue demo,我们来模拟一个场景:
src
被更新;譬如,
src
先被赋值为path-to-image-A.jpg
,再更新为path-to-image-B.jpg
。此时,万一资源
A
的加载速度比资源B
还要慢,就会出现历史资源(A
)把最新资源(B
)覆盖掉的问题。我们稍微修改下 demo 来实现这个场景:或者直接看 demo 效果:https://codepen.io/JunreyCen/pen/JqmNQP
优化方案
解决方案也很简单,我们只需要把所有 “替身” 都记录下来,在更新时把上一次创建的 “替身” 清理掉。即使出现历史资源的捕获时机比最新资源的还要靠后的情况,由于历史资源的
onload
和onerror
方法已经被重置,不会产生影响。最终方案例程:https://github.com/JunreyCen/blog-demo/blob/master/image-handler/vue.2.html
PS: 文章首发于 简书 ,欢迎大家关注。
The text was updated successfully, but these errors were encountered: