效果
最近遇到了个需求,需要按后端传过来的刻度显示进度条,并且刻度个数不定,进度总额不定,要求进度会一直趋近于结尾但永远不会到达结尾。
实现
我的做法是只限于前90%显示后端传来的数据,后10%用来作趋近无穷的变化。
src/views/processLine.vue
<template>
<div class="container">
<div class="progressline">
<div class="progress" v-for="(item, index) in list" :key="index" :style="progressDistance(item.perNode)"></div>
<i class="line" :style="{ 'width': percent + '%'}"></i>
</div>
<div class="info">
<p class="text2">{{title}}</p>
<div class="node" v-for="(item, index) in list" :key="index" :style="nodeDistance(item.perNode)">{{item.node}}</div>
</div>
</div>
</template>
<script>
import { mapGetters } from 'vuex'
export default {
name: 'progressLine',
computed: {
...mapGetters('task', ['myPercent', 'myList']),
percent () {
let len = this.myList.length
return (90 / len) * this.myPercent
}
},
data () {
return {
}
},
mounted () {
},
methods: {
progressDistance (perNode) {
let count = perNode + '%'
return {left: `${count}`}
},
nodeDistance (perNode) {
let count = perNode + '%'
return {left: `calc(${count} - 60px)`}
}
}
}
</script>
<style lang="scss" scoped>
.text2 {
font-size: 14px;
line-height: 24px;
}
.node {
color: rgba($color: #1C1F23, $alpha: 0.8);
}
.container {
color: #1C1F23;
.progressline {
margin-top: 16px;
position: relative;
width: 100%;
height: 8px;
line-height: 8px;
background-color: #FFF3D9;
border-radius: 4px;
overflow: hidden;
text-align: center;
.progress {
position: absolute;
width: 1px;
background: rgba(89, 89, 89, 0.3);
height: 8px;
z-index: 9;
}
i {
position: absolute;
left: 0;
top: 0;
height: 100%;
border-radius: 4px;
}
.line {
background-image: linear-gradient(to right, #FFF026, #FFB200);
}
}
.info {
margin-top: 4px;
position: relative;
.node {
position: absolute;
width: 60px;
font-size: 14px;
text-align: right;
top: 4px;
}
}
}
</style>
src/store/vuex.js
import Vue from 'vue'
import Vuex from 'vuex'
import task from './modules/task'
Vue.use(Vuex)
const locatVuexOption = {
modules: {
task
}
}
export default new Vuex.Store(locatVuexOption)
src/store/task.js
import { getTaskInfo } from '@/api/task'
import { formatNum, formatThousand } from '@/common/utils'
const task = {
namespaced: true,
state: () => ({
// 目前总数
myCur: 0,
// 任务阶梯列表
myList: []
// myList: [
// {
// class: 1,
// lowerNode: 1,
// reward: 2000 // 奖励/元
// },
// {
// class: 2,
// lowerNode: 4,
// reward: 12000 // 奖励/元
// },
// {
// class: 3,
// lowerNode: 8,
// reward: 30000 // 奖励/元
// },
// {
// class: 4,
// lowerNode: 16,
// reward: 80000 // 奖励/元
// },
// {
// class: 5,
// lowerNode: 25,
// reward: 120000 // 奖励/元
// }
// ]
}),
getters: {
// 任务进度
myPercent: state => {
const list = state.myList
const cur = state.myCur
const len = list.length
let pastNum = 0
let stage = 0
let progress = 0
for(let i = 0; i < len; i++) {
if (cur >= list[i].lowerNode) {
pastNum = list[i].lowerNode
stage += 1
if (i === len - 1) {
if (cur == list[i].lowerNode) {
return stage
} else {
// 不断重置上限
let top = pastNum * (Math.ceil(cur/pastNum) + 1)
progress = stage + ((cur - pastNum) / (top - pastNum))
}
}
continue
} else if (cur < list[i].lowerNode) {
if (i === 0) {
progress = stage + (cur / (list[i].lowerNode- pastNum))
} else {
progress = stage + ((cur - pastNum) / (list[i].lowerNode- pastNum))
}
break
} else {
break
}
}
return progress
},
myList: state => {
let res = []
state.myList.forEach((item) => {
let count = (90 / state.myList.length) * item.class
let obj = {
class: item.class,
node: formatThousand(item.lowerNode),
reward: formatNum(item.reward),
perNode: count
}
res.push(obj)
})
return res
}
},
mutations: {
// 获取任务信息
getMyTask (state, payload) {
let data = JSON.parse(JSON.stringify(payload))
state.myCur = data.cur
},
// 获取列表
getMyList (state, payload) {
state.myList = payload
}
},
actions: {
// 获取任务信息
async getTaskInfoData ({ commit }, params) {
const res = await getTaskInfo(params)
if (res.data.status === 0) {
commit('getMyTask', res.data.data.myTask)
commit('getMyList', res.data.data.myList)
} else {
this._vm.$message.error(res.data.msg || '获取信息失败!')
}
}
}
}
export default task
src/common/utils.js
//格式化数字(1,000,000.00)
export const formatNum = function (str) {
let newStr = "";
let count = 0;
str += "";
if (str.indexOf(".") == -1) {
for (let i = str.length - 1; i >= 0; i--) {
if (count % 3 == 0 && count != 0) {
newStr = str.charAt(i) + "," + newStr;
} else {
newStr = str.charAt(i) + newStr;
}
count++;
}
str = newStr;
return str;
} else {
for (let i = str.indexOf(".") - 1; i >= 0; i--) {
if (count % 3 == 0 && count != 0) {
newStr = str.charAt(i) + "," + newStr;
} else {
newStr = str.charAt(i) + newStr;
}
count++;
}
str = newStr + (str + "00").substr((str + "00").indexOf("."), 3);
return str;
}
}
// 格式化数字(10w)
export const formatThousand = function (str) {
let num = Number(str)
if(num < 10000) {
return num.toString()
} else {
return Math.round(num / 10000).toString() + 'w'
}
}