目录javascript
这是一篇关于在前端开发中 与图片相关的一些常见问题,回想一下,咱们在平常的开发过程当中前端与图片打交道的次数能够说是比全部开发职位都要多吧。特别是在 nodeJs 盛行之后。 从咱们最开始学习前端的那一天,咱们是否是认识了 一个叫 <img /> 的 标签,这个标签的 src 属性能够引用对应路径的图片,而后手动刷新页面,咱们的图片就显示在了页面上了, 哇~ 大学的教师里你们都不约而同的发出了哇的声音,回想起来仍是历历在目啊~ 那么 从业前端 这个岗位也这么多年了,总结一下在前端中与图片打交道的一些经验或者总结吧
jpg、png、gif、base6四、字体图标。貌似平常开发中,咱们经常会用到的就说这些了。 那咱们来纵向的来统计一下图片的类型 和 这些类型的图片在不一样场景下有哪些优缺点。 ( 由于自己对于图片的理解度仍是不够的,因此询问了公司的 UI设计师的小姐姐们来帮忙答疑解惑 )
先上和UI部门的小姐姐的聊天~
其实我以为 小姐姐的回答 能够说是很是容易懂了
矢量图:
通常来讲矢量图表示的是几何图形,文件相对较小,而且放大缩小不会失真。css
用途:SVG,图标字体font-awesome
位 图:
位图又叫像素图或栅格图,它是经过记录图像中每个点的颜色、深度、透明度等信息来存储和显示图像。 放大会失真(变模糊)html
用途:png,gif,jpg,canvas
有损压缩
是对图像数据进行处理,去掉那些图像上会被人眼忽略的细节,而后使用附件的颜色经过渐变或其余形式进行填充。适用于
: JPG。 从字面意义上理解就是 对图片会有必定的损伤。像素的损伤,从而压缩了 图片的体积。前端
无损压缩
是先判断图像上哪些区域的颜色是相同的,哪些是不一样的,而后把这些相同的数据信息进行压缩记录,而把不一样的数据另外保存。适用于
: PNG。对于图片的压缩也会形成必定的损伤,可是相对有限。看完上面的 对比,仿佛发现了上帝是公平的
开了一扇门,也关上了一扇窗。vue
索引透明java
即布尔透明,相似于GIF,某一个像素只有全透和全不透明二者效果,不能对透明度进行设置。node
Alpha透明react
半透明,能够设置 0~100 的透明度。git
出自于谷歌,是一种支持有损压缩和无损压缩的图片文件格式,派生自图像编码格式VP8。github
具备更优的图像数据压缩算法,能带来更小的图片体积,并且拥有肉眼识别无差别的图像质量。
具有了无损和有损的压缩模式
支持Alpha透明以及动画的特性
在JPEG和PNG的转化效果都很是优秀,稳定和统一。
如何生成 Base64 格式的图片
var reader = new FileReader(),htmlImage; reader.onload = function(e){ //e.target.result 就是base64编码 htmlImage = '<img src="' + e.target.result + '"/>'; } reader.readAsDataURL(file);
优缺点:
优势
减小HTTP请求
没有图片更新要从新上传,清理缓存的问
缺点
增长了CSS文件的尺寸
编码成本
3.一、原理
经过CSS或者JavaScript,先请求图片到本地,再利用浏览器的缓存机制,当要使用图片时(图片路径一致),浏览器直接从本地缓存获取到图片,加快图片的加载速度。
3.二、场景
背景,幻灯片,相册等,将要展现的前一张和后一张优先下载
3.三、优缺点
若是都在首页进行预加载确定会加长首页加载时间,首屏加载变慢,影响体验。 可是在 http2 来临的时候这个问题,应该能够颇有效的进行一个解决。
3.四、实现方法
CSS
#preload{ backgroud: url(./01.png) no-repeat -9999px -9999px;}
使用这个方法加载图片会同页面的其余内容一块儿加载,增长了页面的总体加载时间
JS
let img = document.createElement('img') img.src = './02.png'
let img = new Image() img.src = './01.png' // 可是这种方法是没法添加的 DOM 树中去的。
4.一、原理
当要使用到图片时,再加载图片,而不是一会儿加载完全部的图片的方式,来提升页面其余图片的加载速度。
4.二、场景
当前页面的图片数量过多,且页面长度很长。
4.三、JS 实现
思路很简单,通常都是在页面上添加一个滚动条事件,判断图片位置与浏览器顶部的距离是否小于(可视高度+滚动距离),若是小于则优先加载。 下面咱们就基于 react 来进行懒加载的实现。 或者能够查看 github 地址:
代码以下:
componentDidMount() { const lazyload = (options) => { // 获取图片外部dom let doc = options.id ? document.getElementById(options.id) : document if (doc === null) return // 获取当前dom 内,全部的图片标签 let tmp = doc.getElementsByTagName('img') let tmplen = tmp.length let imgobj = [] // 判断当前 元素是否到了应该显示的 位置 const isLoad = (ele) => { let scrollTop = document.documentElement.scrollTop || window.pageYOffset || document.body.scrollTop if (typeof ele === 'undefined') return false let edit = ~~ele.getAttribute('data-range') || options.lazyRange let clientHeight = scrollTop + document.documentElement.clientHeight + edit let offsetTop = 0 while (ele.tagName.toUpperCase() !== 'BODY') { offsetTop += ele.offsetTop ele = ele.offsetParent } return (clientHeight > offsetTop) } // 给已经到了能够显示图片位置的 img 标签添加 src 值 const setimg = (ele) => { ele.src = ele.getAttribute('data-src') } // 遍历当前 dom 内全部要显示的 img 标签 for (let i = 0; i < tmplen; i++) { var _tmpobj = tmp[i] if (_tmpobj.getAttribute('data-src') !== null) { if (isLoad(_tmpobj)) { setimg(_tmpobj) } else { imgobj.push(_tmpobj) } } } // 滚动的时候动态 判断当前 元素的是否 能够赋值 let len = imgobj.length const handler = () => { for (let i = 0, end = len; i < end; i++) { let obj = imgobj[i] if (isLoad(obj)) { _setimg(obj) imgobj.splice(i, 1) len-- if (len === 0) { loadstop() } } } } // 根据上下文要求动态低进行 图片 src 赋值 const _setimg = (ele) => { if (options.lazyTime) { setTimeout(function () { setimg(ele) }, options.lazyTime + ~~ele.getAttribute('data-time')) } else { setimg(ele) } } // 去除 滚动事件监听 const loadstop = () => { window.removeEventListener ? window.removeEventListener('scroll', handler, false) : window.detachEvent('onscroll', handler) } loadstop() // 添加滚动事件监听 window.addEventListener ? window.addEventListener('scroll', handler, false) : window.attachEvent('onscroll', handler) } lazyload({ id: 'imgs', lazyTime: 200, lazyRange: 100 }) }
在以上的基础上,其实能够进行很好的 组件化
的操做。 是一个 很好的面向对象的一个 JS 代码的实现的例子。后面的文章当中。咱们也会加大 JS 中 OOP 相关文章的篇幅,敬请期待~
今天终于要讲到咱们的主角了, 骨架屏
。 终于不是首页进去就是加载一个 菊花
了,让你成为 菊外人
了,而是一个 科技感满满的的 骨架屏
,好了,话很少说,开始今天的讨论吧!
5.一、原理
在 H5 中,骨架屏已经不是什么新奇的概念了,在咱们经常使用的不少网站中都有关于这方面的介绍,并且咱们在实际的应用中也能查找到一些案例,好比说: 饿了么、小米、掘金等 他们的 H5 端都有作骨架屏,让咱们的体验不会显得那么的单薄,而是满满都科技感。 至于实现的原理的话,其实也很简单,就是在页面还未加载渲染出来以前,在页面的空白处先展现出来一个简单的相似页面原型的html。(小程序除外,后面也会介绍到小程序的骨架屏)
5.二、场景
先上图:
图片来源网络,侵删
在对前端技术比较依赖的大小厂当中,都已经使用骨架屏来改善自家的首屏加载、模块加载,那咱们是否是也应该折腾的搞起来!
5.三、JS实现
目前前端大的框架、模式大体能够分为三类: Vue、 React、 小程序。(为何没有 Angular ? 你能够去问大漠穷秋撒~😄)
那么咱们今天就来说讲这三个方向的 骨架屏
优化!
5.3.1 React
<div id="root"> <div class="skeleton page"> <div class="skeleton-nav"></div> <div class="skeleton-swiper"></div> <ul class="skeleton-tabs"> <li class="skeleton-tabs-item"><span></span></li> <li class="skeleton-tabs-item"><span></span></li> <li class="skeleton-tabs-item"><span></span></li> <li class="skeleton-tabs-item"><span></span></li> <li class="skeleton-tabs-item"><span></span></li> <li class="skeleton-tabs-item"><span></span></li> <li class="skeleton-tabs-item"><span></span></li> <li class="skeleton-tabs-item"><span></span></li> </ul> <div class="skeleton-banner"></div> <div class="skeleton-productions"></div> <div class="skeleton-productions"></div> <div class="skeleton-productions"></div> <div class="skeleton-productions"></div> <div class="skeleton-productions"></div> <div class="skeleton-productions"></div> </div> </div>
<style> .skeleton { position: relative; height: 100%; overflow: hidden; padding: 15px; box-sizing: border-box; background: #fff; } .skeleton-nav { height: 45px; background: #eee; margin-bottom: 15px; } .skeleton-swiper { height: 160px; background: #eee; margin-bottom: 15px; } .skeleton-tabs { list-style: none; padding: 0; margin: 0 -15px; display: flex; flex-wrap: wrap; } .skeleton-tabs-item { width: 25%; height: 55px; box-sizing: border-box; text-align: center; margin-bottom: 15px; } .skeleton-tabs-item span { display: inline-block; width: 55px; height: 55px; border-radius: 55px; background: #eee; } .skeleton-banner { height: 60px; background: #eee; margin-bottom: 15px; } .skeleton-productions { height: 20px; margin-bottom: 15px; background: #eee; } </style>
在咱们 最初建立的html文件中的 id = #root Dom
内,写入咱们的骨架屏的 html 和 css 的代码。
在 id = #root Dom
的 VD 还未被渲染出来以前, 就会先渲染出写死在骨架屏中的html代码。
这个就是 骨架屏 最原始的原理。
可是!!! 这么写前端的代码是否是特别LOW呐?前端早已过了刀耕火种的年代了,再这么不科学的写代码就
会被作 code review 的同窗砍死的吧。
那么咱们就来写一些高级一点,且适合维护的前端代码。就是下面介绍到的第二种实现的方式。
上面已经介绍到了,骨架屏实际最为真实的原理,那么咱们如今就须要让 这个真实的原理穿上盔甲,变得强硬起来。
5.3.2 Vue
Vue 实现骨架屏的第一种方式也是上面那样。
可是第二种纯粹的代码实现就 相对于 react 的要困难一些,须要用到 node服务去作 服务端渲染,而后在输出index.html 的时候 先显示 骨架屏组件的内容,等到 app.js 中的内容加载完毕之后便自动替换了html 中的文件。
可是!
vue 有一点优势就是 任何组件均可以来进行骨架屏的优化。
具体以下:
const AsyncComponent = () => ({ // 须要加载的组件 (应该是一个 `Promise` 对象) component: import('./MyComponent.vue'), // 异步组件加载时使用的组件 loading: LoadingComponent, // 加载失败时使用的组件 error: ErrorComponent, // 展现加载时组件的延时时间。默认值是 200 (毫秒) delay: 200, // 若是提供了超时时间且组件加载也超时了, // 则使用加载失败时使用的组件。默认值是:`Infinity` timeout: 3000 })
经过异步组件加载的机制,来变相的实现 骨架屏也是一种不错的思路。时间有限,你们能够本身下去思考下。
5.3.2 小程序
这里的原理能够同 上面 H5的方法同样,文章中也是简单介绍2中方法。
先写一个 skeleton 的组件。 放在首页的第一渲染的位置。经过 wx-if 来控制 skeleton 组件的显示和 小程序 index 渲染。
方法二: 其实也是经过方法一来一样实现的。可是小程序首页加载的问题,并非经过 骨架屏就能来解决的。 其实 首页分包 + 骨架屏 同时来使用,首页加载的问题应该能够获得相应的解决。
5.四、尾声
写到最会,其实骨架屏没有多大的难度,若是有效的来管理这些骨架屏才是难点之一。
文章后面写到的 骨架屏并未作过多的阐述,后面有机会的话再来拿实际的项目数据来解释这个不难的技术。
Github传送门,欢迎 Star - -