本文是笔者写组件设计的第八篇文章, 今天带你们用5分钟实现一个极具创意的加载(loading)组件.涉及的核心知识点主要是css3相关特性, 若是你们很是熟悉,可直接跳过介绍直接看正文.javascript
时刻问本身:是否具有创造力?css
因此咱们在设计组件系统的时候能够参考如上分类去设计,该分类也是antd, element, zend等主流UI库的分类方式.html
若是对于react/vue组件设计原理不熟悉的,能够参考个人以前写的组件设计系列文章:前端
笔者已经将组件库发布到npm上了, 你们能够经过npm安装的方式体验组件.vue
在开始组件设计以前但愿你们对css3和js有必定的基础,并了解基本的react/vue语法.咱们先看看实现后的组件效果: java
按照以前笔者总结的组件设计原则,咱们第一步是要确认需求. 首先咱们设计的不是后台管理系统专用的加载动画,而是做为一个C端产品的功用型加载动画.咱们都知道加载动画的做用是:在用户等待网页时能看到有用的信息,好比网站介绍,引导, 公司信息等,缓解用户焦虑. 做为一名产品经理或者用户体验师, 这种个性化的加载体验效果每每是更好的.node
而加载动画通常会分为策略型加载动画和通用加载动画,通用加载动画我就不说了,你们平时作的系统大部分应该都是通用型加载动画. 我这里介绍一下策略型加载动画: 策略型加载动画每每用在C端产品或者系统中,用来为用户提供更多的引导信息, 当用户首次访问系统或者网站时, 因为某种主动型引导(网站在加载时或者切换页面时故意给用户看到的加载信息)或者环境缘由(网络,带宽限制致使的加载过慢,此时出现加载动画), 这些加载信息每每带有某种用途,好比对于我的博客网站, 这个加载动画能够是博主的介绍,博主的宣传信息,github地址等, 对于企业来讲,多是某个新功能的介绍, 网站服务信息的介绍,联系方式等.react
在了解完以上背景后, 咱们来看看组件设计的线框图: webpack
经过以上需求分析, 其实一个加载动画很是简单, 不会涉及到太多功能, 主要在于css3动画的使用. 具体属性有:css3
接下来咱们就来看看具体实现.
由于该组件不会涉及到太多的js代码,主要是html和css,因此咱们直接先构建组件的结构:
/** * 骨架屏组件(SEO) * @param {isLoading} bool 加载状态 * @param {loadingText} string 加载时的加载文本 */
export default function Skeleton(props) {
let { isLoading = true, loadingText = '正在为您疯狂加载...' } = props
return isLoading ? <div className={styles.skeletonWrap}> <div className={styles.skeletonContent} data-loadingText={loadingText}> 自定义的引导内容 </div> </div> : null
}
复制代码
自定义的引导内容这里我就不介绍了, 主要根据不一样的网站性质灵活配置.我主要介绍加载动画部分, 其实原理也很简单, 咱们在skeletonContent元素上使用一个::after伪对象来实现窗帘动画便可.
在实现动画前你们最好对关键帧动画有所了解,我相信你们都比较了解. 这种关窗帘动画一种实现方式就是经过控制元素宽度, 从0到100%, 而后添加适当的要是优化便可. 动画的代码以下:
@keyframes spread {
0% {
width: 0;
}
100% {
width: 100%;
}
}
复制代码
咱们只须要在::after里直接这样使用就行了:
&::after {
animation: spread 18s 3s infinite;
}
复制代码
这样动画已经作完了, 可是为了让动画更完整,咱们还要考虑一个事实, 若是窗帘宽度从0慢慢变化的过程当中, 加载动画的文字一直保持一个颜色会很生硬, 以下图:
&::after {
color: rgba(255, 255, 255, 0);
animation: spread 18s infinite;
}
@keyframes spread {
0% {
width: 0;
color: rgba(255, 255, 255, 0);
}
100% {
width: 100%;
color: rgba(255, 255, 255, 1);
}
}
复制代码
效果以下:
最后咱们来实现loadingText. 这块也涉及到一个知识点, 由于加载文本其实主要是用来修饰元素的,并无太多的语义化场景, 因此咱们会放在::after伪对象的content里, 可是通常content是在css里写的,那么如何实现动态文本呢? 咱们这里就要采用css的属性内容这个api. content不只仅能够接收一个字符串,还能够接收attr这个关键字,关键字里面的内容是元素的自定义属性, 好比:
<div data-tip="loading"></div>
复制代码
那么咱们在css里能够经过这种方式直接使用data-tip属性的值:
div::after{
content: attr(data-tip)
}
复制代码
经过以上的方式咱们能够在::after里直接拿到data-tip的内容了, content其实还有更多的功能,好比用纯css实现一个计数器,你们能够研究学习一下.
这样,咱们的Loading组件就完成了, 还有一个问题是我代码里的组件命名,为何叫骨架屏呢?其实咱们只要改变内容结构, 它立马就能够变成一个骨架屏,因此命名这块能够按照实际需求来肯定.
import PropTypes from 'prop-types'
// ...
Skeleton.propTypes = {
isLoading: PropTypes.bool,
loadingText: PropTypes.string
}
复制代码
组件完整css代码以下:
.skeletonWrap {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
background-color: rgba(0,0,0, .6);
.skeletonContent {
position: relative;
margin: 200px auto 0;
padding: 20px;
width: 800px;
display: flex;
align-items: center;
border-radius: 8px;
overflow: hidden;
background-color: #fff;
&::after {
content: '正在为您疯狂加载...';
position: absolute;
top: 0;
left: 0;
display: flex;
align-items: center;
justify-content: center;
width: 0;
height: 100%;
border-right: 2px solid #ccc;
box-shadow: 0 0 8px #000;
background: #096;
color: rgba(255, 255, 255, 0);
font-size: 24px;
white-space: nowrap;
animation: spread 18s 3s infinite;
}
@keyframes spread {
0% {
width: 0;
color: rgba(255, 255, 255, 0);
}
100% {
width: 100%;
color: rgba(255, 255, 255, 1);
}
}
.imgBox {
margin-right: 20px;
width: 400px;
.img {
width: 100%;
height: 200px;
background-color: #ccc;
}
img {
width: 100%;
}
}
.rightBox {
flex: 1;
.tit {
margin-top: 8px;
margin-bottom: 8px;
font-size: 22px;
}
.labelWrap {
span {
margin: 3px;
display: inline-block;
font-size: 12px;
padding: 2px 6px;
border-radius: 3px;
color: #fff;
background-color: #58bd6b;
}
}
.desc {
color: rgb(44, 44, 44);
font-size: 14px;
}
}
}
}
复制代码
关于代码中的css module和classnames的使用你们能够本身去官网学习,很是简单.若是不懂的能够在评论区提问,笔者看到后会第一时间解答.
咱们能够经过以下方式使用它:
<Skeleton loadingText="玩命加载中..." />
复制代码
笔者已经将实现过的组件发布到npm上了,你们若是感兴趣能够直接用npm安装后使用,方式以下:
npm i @alex_xu/xui
// 导入xui
import {
Button,
Skeleton,
Empty,
Progress,
Tag,
Switch,
Drawer,
Badge,
Alert
} from '@alex_xu/xui'
复制代码
该组件库支持按需导入,咱们只须要在项目里配置babel-plugin-import便可,具体配置以下:
// .babelrc
"plugins": [
["import", { "libraryName": "@alex_xu/xui", "style": true }]
]
复制代码
npm库截图以下:
后续笔者将会继续实现
等组件, 来复盘笔者多年的组件化之旅.
若是想获取组件设计系列完整源码, 或者想学习更多H5游戏, webpack,node,gulp,css3,javascript,nodeJS,canvas数据可视化等前端知识和实战,欢迎在公号《趣谈前端》加入咱们的技术群一块儿学习讨论,共同探索前端的边界。