轻量的vue时间轴组件
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: '测试内容'
},
{
tag: '2019-02-13',
type: 'circle',
content: '练习内容'
}
]
}
}
}
或者你还可以为时间轴的每个部分传递插槽:
<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: '测试内容'
},
{
date '2019-02-13',
msg: '练习内容'
}
]
}
}
}
自己写个好看点的样式就行了
补充知识:Vue可移动水平时间轴
里程碑时间轴具体实现
效果图
编辑里程碑效果图
<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;">里程碑状态:</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;">关闭 <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">{{'阶段目标:'+item.stageTarget}}</el-col>
</el-row>
<el-row>
<el-col :span="24">{{'开始时间:'+item.startTime}}</el-col>
</el-row>
<el-row>
<el-col :span="24">{{'结束时间:'+item.endTime}}</el-col>
</el-row>
<el-row>
<el-col :span="24">{{'验收标准:'+item.acceptStar}}</el-col>
</el-row>
<el-row>
<el-col :span="24">
<span v-if="item.milepostState==='1'">里程碑状态:打开</span>
<span v-if="item.milepostState==='2'">里程碑状态:超期</span>
<span v-if="item.milepostState==='3'">里程碑状态:关闭</span>
</el-col>
</el-row>
</div>
<!--圈圈节点-->
<!-- <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>
<!--标注-->
<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)
//到数据库获取projectId对应的信息列表存入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('项目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 + '项目里程碑';
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';
}
},
//对数组根据日期进行排序
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%; /*根据自己项目进行定义宽度*/
font-size: 14px;
}
.detail_info {
width: 80%;
height: 250px;
padding-bottom: 50px;
overflow: hidden; /*设置超出的部分进行影藏*/
text-overflow: ellipsis; /*设置超出部分使用省略号*/
white-space: nowrap; /*设置为单行*/
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">起始时间</el-tag>
</el-col>
<el-col :span="5">
<el-tag style="width: 100%;font-size: 14px">结束时间</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="请选择起始时间"
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="请选择结束时间"
format="yyyy-MM-dd"
value-format="yyyy-MM-dd"
>
</el-date-picker>
</el-col>
</el-row>
<el-row>
<el-col :span="3">
<input placeholder="阶段目标" 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="请输入阶段目标"></el-input>
<!-- <textarea placeholder="请输入阶段目标" 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="验收标准" 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="请输入验收标准"></el-input>
</el-col>
</el-row>
<el-row>
<el-col :span="3">
<input placeholder="里程碑状态" 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()">确认修改</el-button>
</div>
</div>
</template>
<script>
import API from '../../api/api_project';
export default {
name: "stoneDetail",
props: ['projectId', 'proNum'],
watch: {
'proId': {
// projectId,所以每次都能监听到变化
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: '关闭',
ref_key: '3'
}],
deleteList: [],
model: {
timeLineList: [],
},
}
},
methods: {
/**
* 提交修改的信息
*/
submit: function () {
this.$refs.form.validate((valid) => {
if (!valid) {
this.$message.error('请填写正确信息');
return;
}
console.log('编辑里程碑结果:')
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('确认删除该记录吗?', '提示', {
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时间轴 vue-light-timeline的用法说明就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持小牛知识库。
基础时间轴 时间轴可让你将多个动画同步在一起。 默认情况下,添加到时间轴的每个动画都会在上一个动画结束时开始。 创建时间轴: var myTimeline = anime.timeline(parameters); Argument Type Info Required parameters Object The default parameters of the timeline inherit
TimeLine 时间轴 平台差异说明 App H5 微信小程序 支付宝小程序 百度小程序 头条小程序 QQ小程序 √ √ √ √ √ √ √ 基本使用 该组件左边图标默认为显示一个点,如需自定义,请通过name为node的slot传入内容 组件右边内容为了更强的自定义,需要请通过name为content的slot传入 以下为基本示例,完整示例请见演示部分 <template> <u-time-
本文向大家介绍Vue实现可移动水平时间轴,包括了Vue实现可移动水平时间轴的使用技巧和注意事项,需要的朋友参考一下 本文实例为大家分享了Vue实现可移动水平时间轴的具体代码,供大家参考,具体内容如下 里程碑时间轴具体实现 效果图 编辑里程碑效果图 编辑里程碑 stonedetail.vue 关于vue.js组件的教程,请大家点击专题vue.js组件学习教程进行学习。 以上就是本文的全部内容,希望对
本文向大家介绍vue中destroyed方法的使用说明,包括了vue中destroyed方法的使用说明的使用技巧和注意事项,需要的朋友参考一下 我们从destroyed的字面意思可知,中文意为是“销毁”的意思,当我们离开这个页面的时候,便会调用这个函数(具体可以看看vue的的生命周期),我们常用来销毁一些监听事件及定时函数,例如: 从上函数可知,当用户离开页面的时候便会销毁监听事件。 补充知识:v
本文向大家介绍有使用过vue吗?说说你对vue的理解相关面试题,主要包含被问及有使用过vue吗?说说你对vue的理解时的应答技巧和注意事项,需要的朋友参考一下 Vue是一个构建数据驱动的渐进性框架,它的目标是通过API实现响应数据绑定和视图更新
本文向大家介绍vue使用laydate时间插件的方法,包括了vue使用laydate时间插件的方法的使用技巧和注意事项,需要的朋友参考一下 之前在做vue项目时使用iviewUI库中的DatePicker组件,发现DatePicker使用起来比较麻烦,尤其是对时间精确度上的限制不尽人意,操作起来也比较繁琐,总之在处理一系列时间组件相互联动上存在一大堆问题,比如 DatePicker时间组件 时间精