共计 3416 个字符,预计需要花费 9 分钟才能阅读完成。
第六集: 从零开始实现(loading 组件)
本集定位 :
loading 组件我相信只要与后端存在交互的项目都是需要它的, 组件虽然简单, 但他的作用十分重要:
- 让用户有一个良好的体验, 也就是反馈给用户一个信号, ‘ 我正在做, 再等等 …’.
- 遮挡住用户的操作, 也就是此期间 (有可能) 不让用户再去触发其他事件.
- 不让用户看到白屏, 看到白屏的体验差到爆炸啊.
- 各种炫酷的效果, 也是吸睛的一种手段.
一: loading 需求分析
- 出现之时, 要遮挡用户的操作.
- 不依赖 dom, 要通过 js 就能控制它的出现与隐藏, 比如配置 axios.
- 充满父级, 而不是充满 body, 因为是 pc 端, 所以不是小黑块的形式.
屏幕上方进度条的讨论
我去年的工程里面用的进度条, 体验太差了, 不够显眼, 屏幕上不能点击让人懵圈, 所以本次不用.
骨架屏的讨论
下一章会做(简易版骨架屏).
很多技术方向, 是为了完美展示 dom 结构的阴影, 1:1 的还原还未加载出的 dom 的样子, 其实我感觉不用这样把 …. 只是个过渡阶段有个大致的样子就可以了, 更多的精力与能力放在业务上, 据我观察了很多 app, 真的 100% 还原的真的不多, 而且我问过很多朋友是否注意到骨架屏与真实的 dom 结构存在偏差, 全都说没注意到, 所以骨架屏这方面本套组件只做最基本的功能.
二: 基础结构的搭建
模板
<template>
// 老规矩:
<div class="cc-loading">
// 黑色的遮罩层
<div class="cc-loading__curtain"/>
// icon 与内容显示区
<section class="cc-loading__icon">
// icon 组件
<ccIcon :name='iconName'
:color='iconColor' />
// 显示的提示文字
<span>{{title}}</span>
</section>
</template>
js
props: {
title: {
type: String,
default: "加载中 . . ."
},
iconName: { // 加载图标的样子肯定是用户自定义的
type: String,
default: "cc-load1" // 默认就是普通的菊花
},
iconColor: { // 图标的颜色也是用户自己定的, 万一有特殊需求
type: String,
default: "#3F8BDB"
}
}
css 部分, 针对居中与定位都有封装.
@import './common/var.scss';
@import './common/extend.scss';
@import './common/mixin.scss';
@include b(loading) {@include position();
&__curtain{@include position();
}
&__icon{
position: absolute;
color: $--color-nomal;
z-index: 10;
@include flexCenter;
@include position();
:nth-child(1){ // 文字与图标分的开一些
margin-bottom:6px;
}
}
}
src/style/common/mixin.scss
@mixin position($position: absolute) {
margin: auto;
position: $position;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
@mixin flexCenter {
display: flex;
align-items: center;
flex-direction: column;
justify-content: center;
}
使用显示
// 需要显示的时候, 让这个 dom 显示即可, 因为默认是对浏览器定位的.
<cc-loading v-if='show' />
三: 针对父级定位, 而不是全局的 loading
其实很简单, 也就是属性的差别, 把 fixed 定位换掉即可, 都可以换上吸附属性浪一浪
让我来加很多友好的属性
<template>
<div class="cc-loading"
:style="{'zIndex':boxZIndex, // 层级'position': position // 定位方式}">
<div class="cc-loading__curtain"
:style="{'opacity':opacity, // 这个层的透明度也会友好的让用户填写'background-color':curtainColor // 颜色也是用户选}" />
<section class="cc-loading__icon"
:style="{'fontSize':iconSize+'px' // 图标的大小}">
<ccIcon :name='iconName'
:color='iconColor' />
<span :style="{'fontSize':textFontSize+'px', // 文字的大小'color':textColor // 文字的颜色}">{{title}}</span>
</section>
</div>
</template>
js, 这里面的默认值都是本套工程的共用值;
props: {
position: {
type: String,
default: "fixed"
},
title: {
type: String,
default: "加载中 . . ."
},
textColor: {
type: String,
default: "#3F8BDB"
},
opacity: {
type: Number,
default: 0.8
},
iconName: {
type: String,
default: "cc-load1"
},
iconColor: {
type: String,
default: "#3F8BDB"
},
curtainColor: {
type: String,
default: "black"
},
boxZIndex: {
type: Number,
default: 100
},
textFontSize: {
type: Number,
default: 17
},
iconSize: {
type: Number,
default: 25
}
},
效果展示
四: 添加事件与 js 编程式调用
其实就算是蒙层状态, 也要给个点击事件, 比如用户点了很多下, 可以给用户弹出一个 ’ 马上好, 再点受不了了 …’, 用户可以自己通过 native 修饰符去做, 但是那样太不工程化了.
<div class="cc-loading"
@click.stop="onClickLoading">
onClickLoading() {this.$emit("click");
}
别忘了加 stop 修饰符, 不然点击穿透可就坏事了.
我们更多时候是要从 js 的方式控制加载状态的
vue-cc-ui/src/components/loading/main/loading.js
// 引入写好的组件
import Loading from './loading.vue';
Loading.install = function(Vue) {
// 注册一下才能使用
Vue.component(Loading.name, Loading);
// 在原型上挂在一波
Vue.prototype.$ccShowLoading = function(options) {
// extend 也就是实例化这个组件
let Constructor = Vue.extend(Loading);
let node = new Constructor({propsData: options // 所有的配置也都如数传进去});
// 执行到他的钩子
node.vm = node.$mount();
// 插入 body, 因为这个就没必要插入固定的父级了, 用户自己传也可以
document.body.appendChild(node.$el);
};
// 有出现就要有消失
Vue.prototype.$ccHiddenLoading = function() {
// 从 body 上面找到 class 为这个的元素就干掉.
document.body.childNodes.forEach(item => {if (item.className === 'cc-loading') {document.body.removeChild(item);
}
});
};
};
export default Loading;
下一章: 简易版骨架屏
欢迎大家一起进步!
github: 链接描述
个人网站: 链接描述