Vue時(shí)間軸 vue-light-timeline的用法說明
輕量的vue時(shí)間軸組件
install
npm install vue-light-timeline
如果你使用的是yarn
yarn add vue-light-timeline
usage
import LightTimeline from 'vue-light-timeline';
Vue.use(LightTimeline);
<template>
<light-timeline :items='items'></light-timeline>
</template>
export default {
data () {
return {
items: [
{
tag: '2019-02-12',
content: '測試內(nèi)容'
},
{
tag: '2019-02-13',
type: 'circle',
content: '練習(xí)內(nèi)容'
}
]
}
}
}
或者你還可以為時(shí)間軸的每個(gè)部分傳遞插槽:
<template>
<light-timeline :items='items'>
<template slot='tag' slot-scope='{ item }'>
{{item.date}}
</template>
<template slot='content' slot-scope='{ item }'>
{{item.msg}}
</template>
</light-timeline>
</template>
<script>
export default {
data () {
return {
items: [
{
date: '2019-02-12',
msg: '測試內(nèi)容'
},
{
date '2019-02-13',
msg: '練習(xí)內(nèi)容'
}
]
}
}
}

自己寫個(gè)好看點(diǎn)的樣式就行了
補(bǔ)充知識:Vue可移動水平時(shí)間軸
里程碑時(shí)間軸具體實(shí)現(xiàn)
效果圖

編輯里程碑效果圖

<template>
<div class="state_grade">
<!-- <mile-stone :projectId="projectData.proId" :projectName="projectData.proName" :proNum="projectData.proNum"></mile-stone>-->
<div class="timeLine" style="overflow: hidden;">
<div style="width: 10%; display: inline-block; margin-left: 5px;">
<el-button @click="mileStoUpdateVisible = true" type="primary">編輯里程碑</el-button>
</div>
<div style="width: 70%;display: inline-block" align="center">
<div style="width: 20%;display: inline-block; font-size: 14px;">里程碑狀態(tài):</div>
<div style="width: 100px;display: inline-block; font-size: 14px; ">開始 <img class="node_picture" src="../../assets/images/timeLineA.png"></div>
<div style="width: 100px;display: inline-block; font-size: 14px;">超期 <img class="node_picture" src="../../assets/images/timeLineB.png"> </div>
<div style="width: 100px;display: inline-block; font-size: 14px;">關(guān)閉 <img class="node_picture" src="../../assets/images/timeLineC.png"> </div>
</div>
<div class="my_timeline_prev" @click="moveLeft">
<img src="../../assets/arrow_left_blue.png" class="my_timeline_node"/>
<!-- <div class="my_timeline_item_line" style="margin-top: -18px;"></div>-->
<!-- <div class="my_timeline_item_content" style="color: rgba(0,0,0,0);">上</div>-->
</div>
<div v-if="destroyIncomeStatistics" class="ul_box">
<ul class="my_timeline" ref="mytimeline" style="margin-left: 10px;">
<li class="my_timeline_item" v-for="(item,index) in timeLineList" :key="index">
<el-tooltip placement="top" effect="light">
<div slot="content" class="tooltip">
<el-row>
<el-col :span="24">{{'階段名稱:'+item.stageName}}</el-col>
</el-row>
<el-row>
<el-col :span="24">{{'階段目標(biāo):'+item.stageTarget}}</el-col>
</el-row>
<el-row>
<el-col :span="24">{{'開始時(shí)間:'+item.startTime}}</el-col>
</el-row>
<el-row>
<el-col :span="24">{{'結(jié)束時(shí)間:'+item.endTime}}</el-col>
</el-row>
<el-row>
<el-col :span="24">{{'驗(yàn)收標(biāo)準(zhǔn):'+item.acceptStar}}</el-col>
</el-row>
<el-row>
<el-col :span="24">
<span v-if="item.milepostState==='1'">里程碑狀態(tài):打開</span>
<span v-if="item.milepostState==='2'">里程碑狀態(tài):超期</span>
<span v-if="item.milepostState==='3'">里程碑狀態(tài):關(guān)閉</span>
</el-col>
</el-row>
</div>
<!--圈圈節(jié)點(diǎn)-->
<!-- <div class="my_timeline_node" style="backgroundColor: #999; width: 28px;height: 28px;" @click="changeActive(index)" :class="{active: index == timeIndex}"></div>-->
<div class="my_timeline_node">
<div style="background-color: #FCFCFC">
<img class="my_timeline_picture" v-if="item.milepostState==='1'"
src="../../assets/images/timeLineA.png">
<img class="my_timeline_picture" v-if="item.milepostState==='2'"
src="../../assets/images/timeLineB.png">
<img class="my_timeline_picture" v-if="item.milepostState==='3'"
src="../../assets/images/timeLineC.png">
</div>
</div>
</el-tooltip>
<!--線-->
<div
:class="[timeLineList.length==index+1?my_timeline_item_line_last:my_timeline_item_line_not_last]"></div>
<!--標(biāo)注-->
<div class="my_timeline_item_content">
<div>{{item.endTime}}</div>
<el-tooltip placement="top" effect="light">
<div slot="content">{{item.endTime}}<br/>{{item.stageName}}</div>
<div class="detail_info">{{item.stageName}}</div>
</el-tooltip>
</div>
</li>
</ul>
</div>
<div class="my_timeline_next" @click="moveRight">
<img src="../../assets/arrow_right_blue.png" class="my_timeline_node"/>
<div class="my_timeline_item_content" style="color: rgba(0,0,0,0);">下</div>
</div>
</div>
<el-dialog :title="titleMessage" center :visible="mileStoUpdateVisible" width="50%"
@open="onMileStoUpdateVisibleOpen()" @close="closeMileStone()">
<stone-detail :projectId="this.projectId" :proNum="this.projectData.proNum" @closeMileStone="closeMileStone()" ref="stone-detail"
@refreshMileStoneData="searchMileStone()"></stone-detail>
</el-dialog>
</div>
</div>
</template>
<script>
import API from '../../api/api_project';
import StoneDetail from "../../components/project-info/stonedetail"
import MemberDetail from "../../components/project-info/memberdetail.vue"
export default {
name: 'project-detail',
components:{
MemberDetail,
StoneDetail,
},
data() {
return {
destroyIncomeStatistics:true,
loading: false,
titleMessage: '',
mileStoUpdateVisible: false,
my_timeline_item_line_last: "my_timeline_item_line_last",
my_timeline_item_line_not_last: "my_timeline_item_line_not_last",
menuTree:[],
timeLineList: [],
page:{
total:0,
pageNum: 0,
pageSize: 10,
},
model: {
select: "",
searchConent: "",
projectId: "",
proName:"",
},
projectData:{
proId: '',
proNum: '',
proName: '',
hwDept: '',
hwPo: '',
busineMode: '1',
buildProDate: '',
startDate: '',
expEndDate: '',
hwPoDate: '',
hwPoEndDate:'',
realEndDate: '',
proManageId:'',
proQa:'',
hwPm:'',
proEstNum: '0',
proState:'1'
},
proPeoId:'',
projectId:'',
proPeoUpdateVisible:false,
projectMember: [],
}
},
mounted(){
this.projectId=this.$route.params.projectId
this.searchMileStone()
this.sortDataArray(this.timeLineList)
//到數(shù)據(jù)庫獲取projectId對應(yīng)的信息列表存入projectData
API.getProjectInfo(this.projectId).then((data)=>{
this.projectData=data.data;
this.projectData.busineMode = this.projectData.busineMode.toString();
this.projectData.proState = this.projectData.proState.toString();
})
this.search();
},
methods: {
searchMileStone() {
console.log('項(xiàng)目id:'+this.projectId)
let params={
proId:this.projectId,
};
API.getMileStoneList(params).then(data => {
let result = data.data
if (result && result.list) {
if(this.timeLineList.length>0){
this.timeLineList.splice(0,this.timeLineList.length);
}
for(var i=0;i<result.list.length;i++){
this.timeLineList.splice(i, 1, result.list[i])
}
this.sortDataArray(this.timeLineList)
}
},({msg})=>{
this.$message.error(msg);
});
console.log('刷新里程碑列表')
console.log(this.timeLineList)
},
closeMileStone() {
this.mileStoUpdateVisible = false;
// this.projectId = '';
},
onMileStoUpdateVisibleOpen() {
this.titleMessage = this.projectData.proNum + '項(xiàng)目里程碑';
this.$nextTick(() => {
let form = this.$refs["stone-detail"];
form.initPage();
});
},
changeActive(index) {
this.timeIndex = index;
},
moveLeft() {
let marginLeft = parseInt(this.$refs.mytimeline.style.marginLeft);
let listNum = 0;
if (Math.abs(marginLeft) > 10) {
this.$refs.mytimeline.style.marginLeft = marginLeft + 120 + 'px';
}
},
moveRight() {
let marginLeft = parseInt(this.$refs.mytimeline.style.marginLeft);
if (marginLeft <= 10 && (marginLeft >= -(this.timeLineList.length * 120))) {
this.$refs.mytimeline.style.marginLeft = marginLeft - 120 + 'px';
}
},
//對數(shù)組根據(jù)日期進(jìn)行排序
sortDataArray(dataArray) {
return dataArray.sort(function (a, b) {
return Date.parse(a.endTime.replace(/-/g, "/")) - Date.parse(b.endTime.replace(/-/g, "/"));
})
},
sortByKey(array,key){
return array.sort(function(a,b){
var y = a[key];
var x = b[key];
return((x<y)?-1:((x>y)?1:0));
})
},
handleCurrentChange(val) {
this.page.pageNum = val ;
this.search();
},
handleSizeChange(val) {
this.page.pageSize = val;
this.search();
},
handleSearch(){
this.page.pageNum= 0;
this.search();
},
}
</script>
.content {
height: 100px;
}
.my_timeline_next {
float: left;
display: inline-block;
background-color: #FCFCFC;
cursor: pointer;
}
.my_timeline_prev {
width: 50px;
float: left;
margin-top: 110px;
}
.my_timeline_next {
width: 34px;
margin-top: 80px;
}
.el-col-24 {
margin-left: 10px;
padding-bottom: 5px;
}
.el-col-12 {
margin-left: 10px;
}
.tooltip {
}
.ul_box {
width: 80%;
height: 120px;
display: inline-block;
float: left;
margin-top: 50px;
overflow: hidden;
}
.my_timeline_item {
display: inline-block;
width: 150px;
}
.my_timeline_node {
background-color: #FCFCFC;
box-sizing: border-box;
border-radius: 50%;
cursor: pointer;
width: 40px;
height: 40px;
}
.node_picture {
//margin-top: 20px;
height: 25px;
width: 25px;
margin-left: 5px;
margin-bottom: -7px;
}
.my_timeline_picture {
margin-top: 13px;
height: 25px;
width: 25px;
}
.my_timeline_node.active {
background-color: #fff !important;
border: 6px solid #f68720;
}
.my_timeline_item_line_last {
width: 100%;
height: 10px;
margin: -14px 0 0 28px;
border-left: none;
}
.my_timeline_item_line_not_last {
width: 100%;
height: 10px;
margin: -14px 0 0 25px;
border-top: 2px solid #E4E7ED;
border-left: none;
}
.my_timeline_item_content {
margin: 10px 0 0 -10px;
width: 90%; /*根據(jù)自己項(xiàng)目進(jìn)行定義寬度*/
font-size: 14px;
}
.detail_info {
width: 80%;
height: 250px;
padding-bottom: 50px;
overflow: hidden; /*設(shè)置超出的部分進(jìn)行影藏*/
text-overflow: ellipsis; /*設(shè)置超出部分使用省略號*/
white-space: nowrap; /*設(shè)置為單行*/
font-size: 14px;
}
.state_grade.process_wrap{
border-color: #e4ebf0;
margin-top: 150px;
border-radius: 2px;
padding-bottom: 10px;
}
.fall-back {
float:right;
margin-right: 20px;
margin-bottom:50px;
}
.state_grade{
border: 1px solid #e6e6e6;
background: #FCFCFC;
padding: 10px;
//position: relative;
/*height: 90px;*/
height: 250px;
margin-bottom: 15px;
/*margin-top: 15px;*/
}
.title_top{
height: 33px;
}
.obj_tit_wrap{
border-bottom: 1px solid #e6e6e6;
padding-bottom: 3px;
font-size: 14px;
}
.obj_tit_mile{
width: 150px;
height: 35px;
}
.tit_deco{
color: #9a9a9a;
font-size: 14px;
}
.add_contain{
display:inline-block;
padding-bottom: 10px;
padding-top: 20px;
}
.project_content_warp{
background: #fdfdfd;
margin-bottom: 15px;
}
.project_job_add{
padding-left: 30px;
background: #FCFCFC;
border-bottom: 1px solid #E5E5E5;
line-height: 10px;
margin-bottom: 15px;
font-size: 14px;
}
.project_info_span{
display:inline-block;
padding-left: 10px;
}
.el-col-8{
height: 50px;
}
</style>
編輯里程碑
stonedetail.vue
<template>
<div>
<el-row>
<el-col :span="23">
<div style="margin-top: 10px">
<el-tag effect="dark" style="font-size: 16px;width: 110px;text-align: center">里程碑</el-tag>
</div>
</el-col>
<el-col :span="1">
<img src="../../assets/images/add.png" style="width: 30px;height: 30px;margin-top: 10px" @click="addItems()"/>
</el-col>
</el-row>
<hr/>
<el-row style="text-align: center">
<el-col :span="3">
<el-tag style="width: 100%;font-size: 14px">序 號</el-tag>
</el-col>
<el-col :span="8">
<el-tag style="width: 100%;font-size: 14px">階段名稱</el-tag>
</el-col>
<el-col :span="7">
<el-tag style="width: 100%;font-size: 14px">起始時(shí)間</el-tag>
</el-col>
<el-col :span="5">
<el-tag style="width: 100%;font-size: 14px">結(jié)束時(shí)間</el-tag>
</el-col>
</el-row>
<el-form label-width="100px" align="left" ref="form" style="text-align: left;" :model="model">
<div v-for="(item, index) in model.timeLineList" :key="index">
<el-row>
<el-col :span="3">
<input style="text-align: center" class="el-input__inner" type="text" v-model="index" disabled="true">
</el-col>
<el-col :span="8">
<input placeholder="請輸入階段名稱" style="text-align: center" class="el-input__inner" type="text"
v-model="item.stageName">
</el-col>
<el-col :span="6">
<el-date-picker
style="width: 100%"
type="date"
:editable="false"
v-model="item.startTime"
placeholder="請選擇起始時(shí)間"
format="yyyy-MM-dd"
value-format="yyyy-MM-dd"
>
</el-date-picker>
</el-col>
<el-col :span="6">
<el-date-picker
style="width: 100%"
type="date"
:editable="false"
v-model="item.endTime"
placeholder="請選擇結(jié)束時(shí)間"
format="yyyy-MM-dd"
value-format="yyyy-MM-dd"
>
</el-date-picker>
</el-col>
</el-row>
<el-row>
<el-col :span="3">
<input placeholder="階段目標(biāo)" style="text-align: center;" class="el-input__inner" type="text" disabled="true">
</el-col>
<el-col :span="20">
<el-input v-model="item.stageTarget" placeholder="請輸入階段目標(biāo)"></el-input>
<!-- <textarea placeholder="請輸入階段目標(biāo)" v-model="item.stageTarget" style="height: 30px;" class="el-input__inner" type="text"></textarea>-->
</el-col>
</el-row>
<el-row>
<el-col :span="3">
<input placeholder="驗(yàn)收標(biāo)準(zhǔn)" style="text-align: center;" class="el-input__inner" type="text" disabled="true">
</el-col>
<el-col :span="20">
<el-input v-model="item.acceptStar" placeholder="請輸入驗(yàn)收標(biāo)準(zhǔn)"></el-input>
</el-col>
</el-row>
<el-row>
<el-col :span="3">
<input placeholder="里程碑狀態(tài)" style="text-align: center;" class="el-input__inner" type="text" disabled="true">
</el-col>
<el-col :span="20">
<template>
<el-select v-model="item.milepostState" placeholder="請選擇">
<el-option
v-for="item in milepostStateList"
:key="item.ref_id"
:label="item.ref_value"
:value="item.ref_id">
</el-option>
</el-select>
</template>
</el-col>
<el-col :span="1">
<img src="../../assets/images/delete.png" style="width: 30px;height: 30px" @click="deleteItems(index)"/>
</el-col>
</el-row>
</div>
</el-form>
<div style="text-align: center;margin-top: 30px">
<el-button type="primary" @click="submit()">確認(rèn)修改</el-button>
</div>
</div>
</template>
<script>
import API from '../../api/api_project';
export default {
name: "stoneDetail",
props: ['projectId', 'proNum'],
watch: {
'proId': {
// projectId,所以每次都能監(jiān)聽到變化
immediate: true,
handler: function (val) {
if (!val) return;
this.onProjectIdChange(val);
}
}
},
data() {
return {
proId:'',
milepostStateList: [{
ref_id: "1",
ref_value: '打開',
ref_key: '1'
}, {
ref_id: "2",
ref_value: '超期',
ref_key: '2'
}, {
ref_id: "3",
ref_value: '關(guān)閉',
ref_key: '3'
}],
deleteList: [],
model: {
timeLineList: [],
},
}
},
methods: {
/**
* 提交修改的信息
*/
submit: function () {
this.$refs.form.validate((valid) => {
if (!valid) {
this.$message.error('請?zhí)顚懻_信息');
return;
}
console.log('編輯里程碑結(jié)果:')
console.log(this.model.timeLineList)
let proMileposts = this.model.timeLineList
API.updatetMileStone(proMileposts).then(data => {
if (data.code == 200) {
this.$message.success("修改成功");
this.refreshMileStoneData();
this.close();
} else {
this.$message.error(data.msg);
// this.close();
}
})
});
},
close() {
this.$emit("closeMileStone");
this.proId=''
this.model.timeLineList.splice(0,this.model.timeLineList.length)
},
refreshMileStoneData() {
this.$emit("refreshMileStoneData");
},
addItems() {
this.model.timeLineList.push({
milepostId:'',
proId: this.proId,
stageName: '',
startTime: this.addDate(),
endTime: this.addDate(),
stageTarget: '',
acceptStar: '',
deliverableName: '',
milepostState: '1',
});
},
addDate() {
var date = new Date();
var seperator1 = "-";
var year = date.getFullYear();
var month = date.getMonth() + 1;
var strDate = date.getDate();
if (month >= 1 && month <= 9) {
month = "0" + month;
}
if (strDate >= 0 && strDate <= 9) {
strDate = "0" + strDate;
}
var currentdate = year + seperator1 + month + seperator1 + strDate;
return currentdate;
},
deleteItems(index) {
this.$confirm('確認(rèn)刪除該記錄嗎?', '提示', {
confirmButtonClass: 'el-button--warning'
}).then(() => {
if(this.model.timeLineList[index].milepostId)
{
API.deleteMileStone(this.model.timeLineList[index].milepostId).then(data=>{
if(data.code===200)
{
this.$message.success("刪除成功");
this.model.timeLineList.splice(index, 1);
this.refreshMileStoneData();
}else {
this.$message.error(data.msg);
}
})
}
else{
this.model.timeLineList.splice(index, 1);
}
}).catch(() => {});
},
onProjectIdChange(id) {
this.model.timeLineList.splice(0,this.model.timeLineList.length)
// if (id) {
let params={
proId:id,
};
API.getMileStoneList(params).then(data => {
let result = data.data
if (result && result.list) {
for(var i=0;i<result.list.length;i++){
this.model.timeLineList.splice(i, 1, result.list[i])
}
}
}, ({msg}) => {
this.$message.error(msg);
});
// }
console.log('dailog打開里程碑列表')
console.log(this.model.timeLineList)
},
initPage() {
this.proId=this.projectId;
if (this.proId) {
this.onProjectIdChange(this.proId);
}
}
},
}
</script>
<style scoped>
</style>
以上這篇Vue時(shí)間軸 vue-light-timeline的用法說明就是小編分享給大家的全部內(nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
如何隱藏element-ui中tree懶加載葉子節(jié)點(diǎn)checkbox(分頁懶加載效果)
這篇文章主要介紹了如何隱藏element-ui中tree懶加載葉子節(jié)點(diǎn)checkbox(分頁懶加載效果),具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-07-07
100行代碼實(shí)現(xiàn)一個(gè)vue分頁組功能
今天用vue來實(shí)現(xiàn)一個(gè)分頁組件,總體來說,vue實(shí)現(xiàn)比較簡單,樣式部分模仿了elementUI。接下來本文通過實(shí)例代碼給大家介紹100行代碼實(shí)現(xiàn)一個(gè)vue分頁組功能,感興趣的朋友跟隨小編一起看看吧2018-11-11
vue v-for直接循環(huán)數(shù)字實(shí)例
今天小編就為大家分享一篇vue v-for直接循環(huán)數(shù)字實(shí)例,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-11-11
關(guān)于this.$refs獲取不到dom的可能原因及解決方法
這篇文章主要介紹了關(guān)于this.$refs獲取不到dom的可能原因及解決方法,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-11-11
vue3?中的toRef函數(shù)和toRefs函數(shù)的基本使用
這篇文章主要介紹了vue3?toRef函數(shù)和toRefs函數(shù),文中介紹了ref和toRef的區(qū)別,ref本質(zhì)是拷貝,修改響應(yīng)式數(shù)據(jù)不會影響原始數(shù)據(jù),toRef的本質(zhì)是引用關(guān)系,修改響應(yīng)式數(shù)據(jù)會影響原始數(shù)據(jù),需要的朋友可以參考下2022-11-11
vue + element-ui實(shí)現(xiàn)簡潔的導(dǎo)入導(dǎo)出功能
Element-UI是餓了么前端團(tuán)隊(duì)推出的一款基于Vue.js 2.0 的桌面端UI框架,手機(jī)端有對應(yīng)框架是 Mint UI,下面這篇文章主要給大家介紹了關(guān)于利用vue + element-ui如何實(shí)現(xiàn)簡潔的導(dǎo)入導(dǎo)出功能的相關(guān)資料,需要的朋友可以參考下。2017-12-12

