I love coding!
Talk is cheap. Show me the code.
今天我们来用原生js实现一个骨架屏的效果,效果如下:
首先思考如何实现
骨架屏的原理是在数据没加载出来的时候,使用滚动的背景颜色去替代,等到加载完毕后则显示对应内容
那么我们的核心就是实现一个.skeleton
的样式,当这个样式出现的时候,就通过animation
去开启一个背景色无限滚动的动画,数据加载完毕后则将这个类名去除即可
思路还是比较简单的,我们先搭建一个整体结构,将数据都写死看看效果单的,我们先搭建一个整体结构,将数据都写死看看效果e单的,我们先搭建一个整体结构,将数据都写死看看效果单的,我们先搭建一个整体结构,将数据都写死看看效果e先
<I love coding!
Talk is cheap. Show me the code.
再写一些基础样式
img {height: 100%;width: 100%;object-fit: cover;
}
.card {width: 350px;border-radius: 10px;background-color: white;overflow: hidden;box-shadow: 5px 5px 10px 10px rgba(255, 255, 255, 0.2);
}
.card header {height: 200px;
}
.card main {padding: 30px;
}
.card main h3 {margin: 0;
}
.card main p {color: gray;
}
.author {display: flex;align-items: center;gap: 10px;
}
.author .author-avatar {height: 40px;width: 40px;border-radius: 50%;overflow: hidden;
}
.author .author-info {display: flex;flex-direction: column;gap: 5px;width: 100px;
}
.author .author-info small {color: gray;
}
现在的效果如下:
现在就可以尝试添加骨架屏特效了,骨架屏特效本身就只是一个背景色向右流动的效果,所以我们需要一个渐变色背景,然后设置一个动画让背景色的background-position
不断向右移动,就可以实现骨架屏的效果
对应的css
代码如下:
.skeleton {background: linear-gradient(to right,#f6f7f8 0%,#edeef1 10%,#f6f7f8 20%,#f6f7f8 100%);background-size: 200% 100%;animation: flow 1s linear infinite;
}
@keyframes flow {0% {background-position: 50% 0;}100% {background-position: -150% 0;}
}
那么有了这个骨架屏特效的代码,我们还需要看看其效果是否真的和我们预期中一样呢?
可以先把html
中的内容注释掉,只保留框架部分,模拟一下数据还没加载时候的效果,然后再在需要应用骨架屏特效的地方加上.skeleton
类名
我们要应用骨架屏特效的地方有背景图片、卡片标题、卡片内容、作者头像、作者姓名、留言日期,所以在这些地方加上.skeleton
类名
< -->
再来看看效果:
咦?生效是生效了,但是只有头部背景图和作者头像有效果,而文字部分全都没效果了,这是为啥呢?
这是因为文本元素中没有文本的时候,它没有自己的宽高,那设置background
属性自然也是不会生效的,所以我们需要给它添加一个用于占位的元素,只要有一个字符,就能够充满当前行了,这里我们就填充一个
空格占位符吧
< -->
现在的效果如下:
可以看到这样就行了,那么接下来我们就通过js
去模拟数据加载,加载完成后,将数据插入到对应元素中,并将.skeleton
样式去除
为了方便js
获取对应元素,我们给应用了骨架屏特效的元素起一个语义化的id
< -->
现在就可以用js
去模拟数据加载效果啦
(() => {const skeletonEls = {oHeaderImgContainer: document.getElementById("header-img-container"),oCardTitle: document.getElementById("card-title"),oCardContent: document.getElementById("card-content"),oCardAuthorAvatarContainer: document.getElementById("card-author-avatar-container"),oCardAuthorName: document.getElementById("card-author-name"),oCardAuthorDate: document.getElementById("card-author-date"),};const init = () => {const fetchData = () => {setTimeout(() => {const data = {headerImg: ` `,cardTitle: "I love coding`,cardAuthorName: "Plasticine",cardAuthorDate: "Aug 13, 2022",};// 插入加载到的数据skeletonEls.oHeaderImgContainer.innerHTML = data.headerImg.trim();skeletonEls.oCardTitle.innerHTML = data.cardTitle;skeletonEls.oCardContent.innerHTML = data.oCardContent;skeletonEls.oCardAuthorAvatarContainer.innerHTML =data.cardAuthorAvatar.trim();skeletonEls.oCardAuthorName.innerHTML = data.cardAuthorName;skeletonEls.oCardAuthorDate.innerHTML = data.cardAuthorDate;// 移除 `.skeleton` 类名从而 移除骨架屏特效for (const el of Object.values(skeletonEls)) {el.classList.remove("skeleton");}}, 3000);};fetchData();};init()" style="margin: auto" />
})();
最终效果就像开头中的那样,大功告成!
整理了75个JS高频面试题,并给出了答案和解析,基本上可以保证你能应付面试官关于JS的提问。
有需要的小伙伴,可以点击下方卡片领取,无偿分享