css3
首先擺上那個(gè)灰色的圈
然后蓋上一個(gè)藍(lán)色的半圈(由一半的藍(lán)色和一半的透明border組成)
讓它轉(zhuǎn)起來
這就像進(jìn)度為百分之五十的時(shí)候的樣子
把右邊給他遮住,這樣他還沒到百分之五十的時(shí)候喇喉,右邊不會(huì)出現(xiàn)這個(gè)半圓的一個(gè)部分
動(dòng)起來是這樣的
左邊.gif
然后右邊我們?nèi)绶ㄅ谥埔粋€(gè)祖今,這樣整個(gè)圓就實(shí)現(xiàn)了
完整效果
<template>
<div class="processCircle">
<div class="grayCircle center">
<p>{{ percent }}%</p>
</div>
<section class="half left">
<div class="blueCircle"></div>
</section>
<section class="half right">
<div class="blueCircle"></div>
</section>
</div>
</template>
<script>
export default {
name: 'processCircle',
data() {
return {
percent: 1,
timeLimit: 5000
};
},
created() {
let gap = this.timeLimit / 100;
let clock = setInterval(() => {
if (this.percent < 99) {
let res = Math.floor(this.percent + 4);
this.percent = res >= 99 ? 99 : res;
if (this.percent > 40) {
gap = 0.5;
}
} else {
clearInterval(clock);
}
}, 100);
}
};
</script>
<style lang="scss">
.processCircle {
$maxl: 110px;
position: relative;
width: $maxl;
height: $maxl;
display: flex;
align-items: flex-end;
.half {
width: 51%;
height: 100%;
overflow: hidden;
position: absolute;
top: 0;
}
.center {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
display: flex;
p {
text-align: center;
margin: auto;
color: #384369;
font-size: 18px;
font-family: fzlt_bold;
}
}
@mixin circle($w) {
width: $w;
height: $w;
$wh: $w / 2;
border-radius: $wh;
}
.grayCircle {
@include circle(106px);
border: 0;
border: 6px solid #f4f4f4;
}
.blueCircle {
// border-image: linear-gradient(to right, #90b2ff, #6d91ff) 1 10;
@include circle($maxl);
border: 10px solid transparent;
}
.left {
left: 0;
.blueCircle {
border-top: 10px solid #6d91ff;
border-left: 10px solid #6d91ff;
transform: rotate(135deg);
animation: load_left 2s ease-in;
animation-fill-mode: forwards;
}
}
.right {
right: 0;
.blueCircle {
transform: rotate(135deg);
position: relative;
left: -$maxl / 2;
animation: load_right 3s ease-in;
animation-fill-mode: forwards;
}
}
@-webkit-keyframes load_left {
0% {
border-top: 10px solid #6d91ff;
border-left: 10px solid #6d91ff;
transform: rotate(150deg);
}
50% {
border-top: 10px solid #6d91ff;
border-left: 10px solid #6d91ff;
transform: rotate(315deg);
}
100% {
border-top: 10px solid #6d91ff;
border-left: 10px solid #6d91ff;
transform: rotate(315deg);
}
}
@-webkit-keyframes load_right {
0% {
transform: rotate(135deg);
}
50% {
border-bottom: 10px solid #90b2ff;
border-right: 10px solid #90b2ff;
transform: rotate(135deg);
}
100% {
border-bottom: 10px solid #6d91ff;
border-right: 10px solid #6d91ff;
transform: rotate(312deg);
}
}
.success {
width: 90px;
height: 90px;
position: relative;
margin: 0 auto;
img {
width: 100%;
height: auto;
}
}
}
</style>
最終
!!
但是這個(gè)效果和最終設(shè)想的差別有比較大的距離。如果使用這個(gè)方案是做不出漸變色和圓角的效果的拣技。
svg
只要去學(xué)習(xí)一下svg的圓和漸變千诬,就能很容易地做出來這個(gè)效果。
所以在這里簡單說一下動(dòng)畫的原理膏斤。
在
circle
標(biāo)簽上支持兩個(gè)屬性大渤,stroke-dashoffset
和stroke-dasharray
。
stroke-dashoffset
屬性指定了dash模式到路徑開始的距離
如果使用了一個(gè) <百分比> 值掸绞, 那么這個(gè)值就代表了當(dāng)前viewport的一個(gè)百分比泵三。
屬性stroke-dasharray
可控制用來描邊的點(diǎn)劃線的圖案范式。
作為一個(gè)外觀屬性衔掸,它也可以直接用作一個(gè)CSS樣式表內(nèi)部的屬性烫幕。
噫,老實(shí)說沒看懂這兩個(gè)參數(shù)到底是干啥的敞映。動(dòng)手試一下這兩個(gè)屬性较曼。
控制變量法:
- 我的圓周長大約為314。
此時(shí)設(shè)置
stroke-dashoffset: 0;
stroke-dasharray: 314;
則圓為這樣
- 設(shè)置
stroke-dashoffset: 0;
stroke-dasharray: 298;
合理地猜測振愿,stroke-dasharray的改變可以變更軌跡的樣子捷犹。
其實(shí)如果把這個(gè)值變小弛饭,這個(gè)外圍就是虛線,所以僅僅靠變更這個(gè)值去實(shí)現(xiàn)連續(xù)的藍(lán)色弧線是行不通的萍歉。
- 變更stroke-dashoffset
stroke-dashoffset: 314;
stroke-dasharray: 314;
如果這兩值相等侣颂,則藍(lán)色的部分就消失了。
stroke-dashoffset: 100;
stroke-dasharray: 314;
終上所述枪孩,設(shè)置
stroke-dasharray
為圓周長憔晒,讓stroke-dashoffset
從大到小變化,則動(dòng)畫就會(huì)從缺到完整那么去動(dòng)蔑舞。
我這里設(shè)置了最終為有缺口的99%狀態(tài)拒担,效果及源碼如下:
最終效果
完整代碼如下
// progressBar.vue
<template>
<div class="loadingContainer">
<svg
:width="progressBarParams.boxWidth"
:height="progressBarParams.boxHeight"
:VIEWBOX="
'0 0 ' +
progressBarParams.boxWidth +
' ' +
progressBarParams.boxHeight
"
id="svg"
>
<defs>
<linearGradient id="cirGradient">
<stop
offset="0%"
:stop-color="progressBarParams.frontColor"
/>
<stop
offset="100%"
:stop-color="progressBarParams.endColor"
/>
</linearGradient>
</defs>
<circle
:cx="progressBarParams.boxWidth / 2"
:cy="progressBarParams.boxHeight / 2"
:r="progressBarParams.raduis"
:stroke="progressBarParams.innerClcColor"
:stroke-width="progressBarParams.innerClcWidth"
fill="none"
stroke-linecap="round"
/>
<circle
id="clc"
class="loadingProcess"
:cx="progressBarParams.boxWidth / 2"
:cy="progressBarParams.boxHeight / 2"
:r="progressBarParams.raduis"
stroke="url(#cirGradient)"
:stroke-width="progressBarParams.outerClcWidth"
fill="none"
stroke-linecap="round"
/>
</svg>
<div id="loadingPercent">
<span>{{ percent }}</span
><span style="font-size:14px;">%</span>
</div>
</div>
</template>
<script>
export default {
props: {
progressBarParams: Object
},
data() {
return {
offset: 0,
percent: 0,
strokeDasharray: 0
};
},
created() {
let gap = 3;
let clock = setInterval(() => {
if (this.percent < 99) {
let res = Math.floor(this.percent + gap);
this.percent = res >= 99 ? 99 : res;
if (this.percent > 50) {
gap = 2;
}
if (this.percent > 80) {
gap = 1.5;
}
} else {
clearInterval(clock);
}
}, 100);
},
methods: {}
};
</script>
<style lang="scss" scoped>
.loadingContainer {
position: relative;
width: 100%;
height: 110px;
font-size: 12px;
display: flex;
}
.loadingContainer span {
font-size: 18px;
font-weight: bold;
}
.loadingContainer > svg {
margin: 0 auto;
}
#loadingPercent {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
font-family: fzlt_bold;
font-size: 18px;
color: #384369;
margin-left: 3px;
margin-top: 1px;
}
$perimter: 314;
$percent: 1;
.loadingProcess {
transform-origin: center;
animation: task 5s ease-in;
animation-fill-mode: forwards;
// stroke-dashoffset: ((100 - $percent) / 100) * $perimter;
// stroke-dasharray: $perimter;
transform: rotate(95deg);
}
@-webkit-keyframes task {
0% {
$percent: 2;
stroke-dashoffset: ((100 - $percent) / 100) * $perimter;
stroke-dasharray: $perimter;
}
20% {
$percent: 30;
stroke-dashoffset: ((100 - $percent) / 100) * $perimter;
stroke-dasharray: $perimter;
}
50% {
$percent: 60;
stroke-dashoffset: ((100 - $percent) / 100) * $perimter;
stroke-dasharray: $perimter;
}
90% {
$percent: 80;
stroke-dashoffset: ((100 - $percent) / 100) * $perimter;
stroke-dasharray: $perimter;
}
100% {
// $percent: 93;
stroke-dashoffset: 32;
stroke-dasharray: 329;
}
}
</style>
// 使用
<progress-bar
v-if="status === 'loading'"
v-bind:progressBarParams="progressBarParams"
></progress-bar>
<script>
import progressBar from './progressBar';
export default {
name: 'processCircle',
components: {
progressBar
},
props: {
status: {
type: String,
default: 'loading'
}
},
data() {
return {
percent: 1,
timeLimit: 5000,
progressBarParams: {
boxWidth: '110',
boxHeight: '110',
raduis: '50',
innerClcWidth: '6',
outerClcWidth: '10',
frontColor: '#90B2FF',
endColor: '#6D91FF',
innerClcColor: '#F4F4F4',
fastDurTime: 100,
slowDurTime: 1000
}
};
},
}
</script>