突然感觉自己是天生的牛马了,今天同事接到个需求,要写一个关于气象的插件,其他的功能还好说,但是这个时间轴的功能,网上的插件貌似比较少,自己手搓呢,他又不想这么麻烦。然后我看到这个功能感觉觉得挺考验技术的,顿时心里就特别痒痒。哈哈,看我贱不贱。
随后我利用周末的时间就手搓了一个时间轴。本来想用canvas来绘制来着,后来想到用canvas绘制的图形性能方面也许会好很多,但是想修改样式缺很不容易。并且我拿给同事去用的话,里面有些计算的地方一时半会也不容易捋清楚,所有我就用JavaScript+Dom的形式来渲染时间轴。样式修改起来会相对容易很多!!!
好了,话不多说,直接上正题
当前的时间轴就是利用dom,来进行展示,本来想使用canvas来绘制的,但是后来想到canvas绘制出来后样式不容易修改,就没有使用了,使用dom修改样式特别方便。
我们实现时可以首先用除法计算出每一个时间段所需要的宽度,称为tx,然后给时间线添加一个鼠标按下事件,通过事件的回调参数获取当前鼠标在时间线上点击的偏移量,称为offsetx。通过相除得出rx,公式为rx=offsetx/tx。让rx+1就是当前鼠标点击的通过的时间段。然后我们计算更精确的时间,就是把每个时间段分为多个小段,如一个时间段是一个小时,那么一个小时是60分钟,分60小段。称为_tx,让使用如下公式即可得出更_rx = (offsetx%tx) / tx * _tx;此时就能计算出当前鼠标的具体为几点了;
但是当一个时间段表示一月时,计算的方式就不一样了,我们需要首先计算出当前时间段是哪个月份,然后根据当前的月份来计算出本月有多少天,称为month,计算更详细的时间步骤就变成了_rx = (offsetx%tx) / tx * this.getDaysByMonth(month);
判断每个月有多少天的代码如下:
/**
* 通过月份来返回本月的时间
* @param month 月份
* @returns 本月的时间
*/
getDaysByMonth(month: number) {
let a = [1, 3, 5, 7, 8, 10, 12];
let b = [2]
if (a.includes(month)) {
return 31
} else if (b.includes(month)) {
return 28
} else {
return 30
}
}
1、本实例中可以展示的时间轴分为4级,分别可以显示小时,周,年等。
此实例显示的数据都是在界面渲染前将要显示的数据保存在相应的数组中,等渲染时之间根据下标查找数据即可。
/**
* 要显示的宏观文本数组--就是时间轴中最高级的显示单位
*/
MacroTextArray: string[] = []
/**
* 要显示的微观数组
*/
DateTextArray: number[] = []
展示层级为0级时要展示的信息内容
/**
* 设置显示的时间文本数组
* 0级
*/
setDateTextArrayZore() {
let date = new Date();
// 月份
let month = date.getMonth() + 1;
// 小时
let hours = date.getHours();
this.MacroTextArray = []
this.DateTextArray = []
for (let i = 0; i < this.ReviewNum; i++) {
this.MacroTextArray.push(month + '')
this.DateTextArray.push(hours)
hours += 1;
if (hours == 24) {
month++
hours = 0;
}
}
}
展示层级为1级时要展示的信息内容
/**
* 设置显示的时间文本数组
* 1级
*/
setDateTextArrayOne() {
let date = new Date();
// 周几
let week = date.getDay();
// 几号 ,因为下面会+1 因此这里要 -1
let day = date.getDate() - 1;
// 月份
let month = date.getMonth() + 1;
// 本月的天数
let monthDay = this.getDaysByMonth(month);
let _monthDay = 0;
this.MacroTextArray = []
this.DateTextArray = []
for (let i = 0; i < this.ReviewNum; i++) {
this.MacroTextArray.push(((week + i) % 7) + '')
_monthDay++;
// 避免月份出错
if (_monthDay > monthDay) {
month++
monthDay = this.getDaysByMonth(month);
_monthDay = 0;
}
this.DateTextArray.push(((day + i) % (monthDay)) + 1)
}
}
/**
* 通过月份来返回本月的时间
* @param month 月份
* @returns 本月的时间
*/
getDaysByMonth(month: number) {
let a = [1, 3, 5, 7, 8, 10, 12];
let b = [2]
if (a.includes(month)) {
return 31
} else if (b.includes(month)) {
return 28
} else {
return 30
}
}
展示层级为2级时要展示的信息内容
/**
* 设置显示的时间文本数组
* 2级
*/
setDateTextArrayTwo() {
let date = new Date();
// 月份
let month = date.getMonth() + 1;
// 年份
let year = date.getFullYear();
this.MacroTextArray = []
this.DateTextArray = []
for (let i = 0; i < this.ReviewNum; i++) {
this.MacroTextArray.push(year + '')
this.DateTextArray.push(month)
month += 1
if (month == 13) {
year++
month = 1
}
}
}
展示层级为3级时要展示的信息内容
/**
* 设置显示的时间文本数组
* 3级
*/
setDateTextArrayThree() {
let date = new Date();
// 年份
let year = date.getFullYear();
this.MacroTextArray = []
this.DateTextArray = []
for (let i = 0; i < this.ReviewNum; i++) {
this.MacroTextArray.push(year + '')
this.DateTextArray.push(0)
year++
}
}
2、下面是比较重要的方法,将相应的长度传给此方法,自动将长度转换为我们自己想要的数据
需要注意:长度的起点是相对时间线的,不是屏幕哦
/**
* @description 将长度转换为时间
* @description 本长度的起点是指时间线0点距离,不是屏幕的0点
*/
getDateByOffsetX(len: number) {
// 跨越的时间段
let timeSolt = Math.floor(len / this.TimeSlotWidth);
// 剩余的时间段距离
let _timeSolt = Math.floor(len % this.TimeSlotWidth);
let macro = this.MacroTextArray[Math.floor(timeSolt)];
let day = this.DateTextArray[timeSolt] + 1;
// 记录下当前走到哪里了
this.CurrentDay = day;
// 具体时间
let date = Math.floor(_timeSolt / this.TimeSlotIntervalWidth);
// 如果时间轴的层级是2,则因为月份会有不同,因此要使用另一种计算方法
if (this.TimeLevel == 2) {
// getDaysByMonth方法上面有讲到
let a = this.getDaysByMonth(this.DateTextArray[Math.floor(timeSolt)])
let b = a / this.TimeSlotWidth;
date = (Math.ceil(_timeSolt * b) % a) + 1;
}
return {
macro,
day,
date
}
}
3、在实例中我们需要定义useTimeShowTextByLevel方法,在使用时需要更换显示层级时,可以调用useTimeShowTextByLevel方法,但是此方法只会更改时间线的显示层级,所以调用完后需要调用下init()的初始化方法。
/**
* 按照显示级别来给时间轴设置显示文本
*/
useTimeShowTextByLevel(level?: number) {
let l = level ? level : this.TimeLevel;
switch (l) {
case 0:
this.setDateTextArrayZore()
// 一个小时有60分钟
this.TimeSlotInterval = 60;
break;
case 1:
this.setDateTextArrayOne()
// 一天有24小时
this.TimeSlotInterval = 24;
break;
case 2:
this.setDateTextArrayTwo()
// 一月有30天,但是每个月有特殊性
this.TimeSlotInterval = 30;
break;
case 3:
this.setDateTextArrayThree()
// 一月有30天,但是每个月有特殊性
this.TimeSlotInterval = 12;
break;
default:
throw new Error("当前显示设置级别不合理")
break;
}
}
4、此时大致的内容已经讲完了,下面是销毁事件,当我们在使用中不需要时间轴时,我们可以调用销毁方法来接触绑定的事件
这里说一下,在绑定事件时,因为使用addEventListener使绑定事件,所以我们需要使bind来改变下this的指向。
/**
* 销毁时间线中实例和绑定的事件
*/
DestoryTimeLine(){
let time_progressbar = this.getByClass("time_progressbar")
if(!time_progressbar || time_progressbar?.length == 0) return false;
time_progressbar[0].removeEventListener("mousedown",this.Time_MouseDown)
window.removeEventListener("mousemove",this.WindowMouseMove_time)
window.removeEventListener("mouseup",this.WindowMouseUp_time)
// 清空父元素
this.ParentNode && (this.ParentNode.innerHTML = "");
}
1、css样式
因为我们的时间轴使用的是dom来渲染的,为的是容易修改它的样式,这里我写了点初始的样式,下面是具体的内容
.timeLine{
width: 100%;
height: 100%;
display: flex;
justify-content: flex-start;
align-items: center;
}
.time_switch{
width: 35px;
height: 35px;
background-color: #fcfcfc;
display: flex;
justify-content: center;
align-items: center;
box-shadow: 0px 0px 5px 3px #8f8b8b;
border-radius: 50%;
}
.time_content{
width: calc(100% - 60px);
height: 100%;
margin-left: 10px;
display: flex;
flex-direction: column;
justify-content: flex-end;
}
.time_progressbar_tooltip{
position: absolute;
left: 0;
top: 0;
padding: 10px 20px;
border-radius: 4px;
background-color: #e3ecec;
z-index: -1;
opacity: 0;
}
.time_progressbar{
width: 100%;
height: 10px;
background-color: #464749;
cursor: pointer;
position: relative;
border-radius: 10px;
}
.t_progressbar{
width: 0;
height: 100%;
position: absolute;
left: 0;
top: 0;
border-top-left-radius: 10px;
border-bottom-left-radius: 10px;
background-color: #fff;
}
.time_progressbar_remind{
width: 100%;
height: 20px;
display: flex;
justify-content: flex-start;
align-items: center;
}
.time_progressbar_remind span{
color: #fff;
font-size: 12px;
border-right: 2px solid #626262;
align-items: flex-end;
display: flex;
height: 100%;
text-indent: 1em;
}
.time_progressbar_remind span:last-child{
border: none !important;
}
2、TypeScript/JavaScript代码
创建一个TimeLine.ts文件
export class useTimeLine {
/**
* 时间数组
*/
DateArray: string[] = ["周日", "周一", "周二", "周三", "周四", "周五", "周六"]
/**
* 记录单位的数组 ["号","周","月","年"]
*/
UnitArray: string[] = ["号", "周", "年", "年"]
/**
* 记录是否是初次加载 默认:是
*/
isInitLoad:boolean = true;
/**
* 当前显示时间轴的级别,默认:1
*/
TimeLevel: number = 1;
/**
* 最外层的元素元素
*/
ParentNode: HTMLElement | null;
/**
* 需要显示未来几天的数据
*/
ReviewNum: number = 10;
/**
* 每个时间段需要的长度
*/
TimeSlotWidth: number = 0
/**
* 每个时间段又分出多少间隔,默认:24
*/
TimeSlotInterval: number = 60;
/**
* 时间段中每个间隔的长度
*/
TimeSlotIntervalWidth: number = 0;
/**
* 保存当前时间进度
*/
CurrentTimeProgress: number = 0;
/**
* 时间轴移动的速度
*/
TimeMoveSpeed: number = 200;
/**
* 保存当前的移动进度
*/
CurrentDay: number = 0;
/**
* 要显示的宏观文本数组--就是时间轴中最高级的显示单位
*/
MacroTextArray: string[] = []
/**
* 要显示的微观数组
*/
DateTextArray: number[] = []
/**
* 时间轴与鼠标交互时的元素
*/
time_progressbar_tooltip: Element | null = null;
/**
* 覆盖在时间轴元素上方
*/
t_progressbar: Element | null = null;
/**
* 自动播放按钮的点击状态回调
* @param {*} flag 点击状态 播放:true 停止:false
* @param {*} target 当前的元素
*/
autoPlayClickStatus: Function | null = null;
/**
* @description tooltip更换显示dom
* @description tip:请返回string形式的dom
* @param {object} e macro:最宏观的显示单位 day:中等显示单位 date:最小显示单位
*
*/
setTooltipElementFn: Function | null = null;
/**
* 自定义时间轴底部的显示内容
* @param {object} macro 当前的宏远显示单位
* @param {object} secondary 当前二级显示单位
*/
CustomReMindLabelfn: Function | null = null;
/**
* 生成时间轴
* @param eleId 最外层的id
* @param reviewNum 要显示的天数
* @param level 可选参数- 显示的层级
* @returns
*/
constructor(eleId: string, param:any) {
this.ParentNode = this.getById(eleId);
if(!this.ParentNode) return this;
this.ReviewNum = param.reviewNum ? param.reviewNum : 0;
(param.CustomReMindLabelfn instanceof Function ) && (this.CustomReMindLabelfn = param.CustomReMindLabelfn);
(param.level != void 0) && (this.TimeLevel = param.level);
// 根据层级编辑展示信息数组
this.useTimeShowTextByLevel()
this.init();
return this;
}
init() {
// 如果不是第一次加载--先销毁先前添加的事件
!this.isInitLoad && this.DestoryTimeLine()
// 往父元素中添加内容
this.ParentNode?.appendChild(this.createElement())
// 添加时间轴底部的信息展示框
this.MakeReMindElement()
// 添加鼠标事件
this.addEventMouse()
// 开关添加点击事件
this.SwitchAddClick();
this.ParentNode && this.ElementAddProxy(this.ParentNode)
// 改变是否初次加载的值,变为false
this.isInitLoad = false;
}
/**
* 按照显示级别来给时间轴设置显示文本
*/
useTimeShowTextByLevel(level?: number) {
let l = level ? level : this.TimeLevel;
switch (l) {
case 0:
this.setDateTextArrayZore()
// 一个小时有60分钟
this.TimeSlotInterval = 60;
break;
case 1:
this.setDateTextArrayOne()
// 一天有24小时
this.TimeSlotInterval = 24;
break;
case 2:
this.setDateTextArrayTwo()
// 一月有30天,但是每个月有特殊性
this.TimeSlotInterval = 30;
break;
case 3:
this.setDateTextArrayThree()
// 一月有30天,但是每个月有特殊性
this.TimeSlotInterval = 12;
break;
default:
throw new Error("当前显示设置级别不合理")
break;
}
}
ElementAddProxy(target: HTMLElement) {
if (!target) return false;
let self = this;
// let observer = new MutationObserver((mutationList) => {
// observer.disconnect()
// console.log("html元素尺寸发生变化:", mutationList)
// self.init()
// })
// observer.observe(target, { attributes: true, subtree:true,characterData:true, attributeFilter: ['style'], attributeOldValue: true })
// // 观察目标节点的变化
const observer = new MutationObserver(mutations => {
mutations.forEach(mutation => {
if (mutation.attributeName === 'style') {
observer.disconnect()
self.init()
}
});
});
const config = {
attributes: true, //监听元素的属性有没有变化
attributeFilter: ['style'],
characterData: true,
};
observer.observe(target, config);
}
/**
* @description 鼠标是否可以拖动时间轴的条件
* @description true:允许
* @description false:禁止
*/
TimeMouseDownFlag:boolean=false;
// 为时间轴添加鼠标相应的事件
addEventMouse() {
let time_progressbar = this.getByClass("time_progressbar")
if(!time_progressbar) return false;
// 因为使用addEventListener来绑定事件,所以使用bind来更改this的指向
time_progressbar[0].addEventListener("mousedown",this.Time_MouseDown.bind(this))
window.addEventListener("mousemove",this.WindowMouseMove_time.bind(this))
window.addEventListener("mouseup",this.WindowMouseUp_time.bind(this))
return true;
}
/**
* window上的鼠标移动事件
*/
WindowMouseMove_time(e:any){
let self = this;
if (!self.TimeMouseDownFlag) return false;
self.updataElementStatus(e.offsetX)
}
/**
* window上的鼠标松开事件
*/
WindowMouseUp_time(e:any){
this.TimeMouseDownFlag = false;
}
/**
* 时间轴上的鼠标按下事件
*/
Time_MouseDown(e:any){
let self = this;
self.TimeMouseDownFlag = true;
self.updataElementStatus(e.offsetX)
}
/**
* 销毁时间线中实例和绑定的事件
*/
DestoryTimeLine(){
let time_progressbar = this.getByClass("time_progressbar")
if(!time_progressbar || time_progressbar?.length == 0) return false;
time_progressbar[0].removeEventListener("mousedown",this.Time_MouseDown)
window.removeEventListener("mousemove",this.WindowMouseMove_time)
window.removeEventListener("mouseup",this.WindowMouseUp_time)
// 清空父元素
this.ParentNode && (this.ParentNode.innerHTML = "");
}
// 给时间轴的开关添加点击事件
SwitchAddClick() {
let self = this;
let time_switch = this.getByClass("time_switch")[0];
if (!time_switch) {
setTimeout(() => {
self.SwitchAddClick()
}, 1000)
return false;
}
if (time_switch == null) return false;
let autoClickStatus = true
time_switch.onclick = function () {
self.autoUpdateTimeStatus(autoClickStatus);
self.autoPlayClickStatus instanceof Function && self.autoPlayClickStatus(autoClickStatus, time_switch)
autoClickStatus = !autoClickStatus;
}
return true;
}
// 自动播放的定时器id,方便清除定时器
_setInterval: any;
/**
* 自动修改时间轴状态
* @param flag
*/
autoUpdateTimeStatus(flag: boolean) {
let self = this;
if (flag) {
// 某个时间段内的进一步的值
let IntervalWidth = this.TimeSlotIntervalWidth;
if (this.TimeLevel == 2) {
let curr_monthDay = this.getDaysByMonth(this.CurrentDay);
IntervalWidth = curr_monthDay / this.TimeSlotWidth;
}
let len = self.CurrentTimeProgress + self.TimeSlotIntervalWidth;
let totalLen = self.TimeSlotWidth * self.ReviewNum;
if (len >= totalLen) len = 0;
self.updataElementStatus(len)
self._setInterval && clearInterval(self._setInterval);
self._setInterval = setInterval(() => {
self.autoUpdateTimeStatus(flag);
}, self.TimeMoveSpeed)
} else {
clearInterval(self._setInterval)
}
}
/**
* 修改时间轴的位置-进度
* @param PosiX
* @returns
*/
updataElementStatus(PosiX: number) {
if (this.t_progressbar == null || this.time_progressbar_tooltip == null) return false;
let offsetX = PosiX;
this.CurrentTimeProgress = offsetX;
this.t_progressbar.style.cssText = `width:${offsetX}px;`
this.updataShowTooltip(PosiX)
}
/**
* 定时器的id,
* 控制tip元素的消失
*/
_setTimeoutId: any;
/**
* 更改tip元素样式
* @param PosiX
* @returns
*/
updataShowTooltip(PosiX: number) {
let self = this;
let offsetX = PosiX;
if (this.time_progressbar_tooltip == null) return false;
let rect = self.getDateByOffsetX(offsetX);
this.time_progressbar_tooltip.innerHTML = (self.setTooltipElementFn instanceof Function && self.setTooltipElementFn(rect)) || `
周:${rect.week}
日期:${rect.day}
时间:${rect.date}
`
let tooltip_rect = this.getElementRectById("time_progressbar_tooltip");
this.time_progressbar_tooltip.style.cssText = `z-index:999;opacity:1;left:${offsetX}px;top:-${(tooltip_rect.height) - 10}px`
if (this._setTimeoutId != 0) clearTimeout(self._setTimeoutId);
this._setTimeoutId = setTimeout(() => {
clearTimeout(self._setTimeoutId)
if (self.time_progressbar_tooltip == null) return false;
self.time_progressbar_tooltip.style.cssText = "opacity:0,z-index:-1;"
}, 2000)
}
/**
* @description 将长度转换为时间
* @description 本长度的起点是指时间线0点距离,不是屏幕的0点
*/
getDateByOffsetX(len: number) {
// 跨越的时间段
let timeSolt = Math.floor(len / this.TimeSlotWidth);
// 剩余的时间段距离
let _timeSolt = Math.floor(len % this.TimeSlotWidth);
let macro = this.MacroTextArray[Math.floor(timeSolt)];
let day = this.DateTextArray[timeSolt] + 1;
// 记录下当前走到哪里了
this.CurrentDay = day;
// 具体时间
let date = Math.floor(_timeSolt / this.TimeSlotIntervalWidth);
// 如果时间轴的层级是2,则因为月份会有不同,因此要使用另一种计算方法
if (this.TimeLevel == 2) {
let a = this.getDaysByMonth(this.DateTextArray[Math.floor(timeSolt)])
let b = a / this.TimeSlotWidth;
date = (Math.ceil(_timeSolt * b) % a) + 1;
}
return {
macro,
day,
date
}
}
/**
* 添加时间提示dom
* @returns
*/
MakeReMindElement() {
let rect = this.getElementRectById("time_content");
if (rect == null) return false;
this.TimeSlotWidth = Math.floor(rect?.width / this.ReviewNum);
this.TimeSlotIntervalWidth = Number((this.TimeSlotWidth / this.TimeSlotInterval).toFixed(2))
let time_progressbar_remind = this.getByClass("time_progressbar_remind")[0];
for (let i = 0; i < this.ReviewNum; i++) {
let span = document.createElement("span");
span.innerText = (this.CustomReMindLabelfn instanceof Function) ?
this.CustomReMindLabelfn(this.MacroTextArray[i], this.DateTextArray[i]) :
this.MacroTextArray[i] + this.UnitArray[this.TimeLevel] + (this.DateTextArray[i] ? this.DateTextArray[i] : '')
span.style.cssText = `width:${this.TimeSlotWidth}px;`
time_progressbar_remind?.appendChild(span)
}
return true
}
/**
* 设置显示的时间文本数组
* 0级
*/
setDateTextArrayZore() {
let date = new Date();
// 月份
let month = date.getMonth() + 1;
// 小时
let hours = date.getHours();
this.MacroTextArray = []
this.DateTextArray = []
for (let i = 0; i < this.ReviewNum; i++) {
this.MacroTextArray.push(month + '')
this.DateTextArray.push(hours)
hours += 1;
if (hours == 24) {
month++
hours = 0;
}
}
}
/**
* 设置显示的时间文本数组
* 1级
*/
setDateTextArrayOne() {
let date = new Date();
// 周几
let week = date.getDay();
// 几号 ,因为下面会+1 因此这里要 -1
let day = date.getDate() - 1;
// 月份
let month = date.getMonth() + 1;
// 本月的天数
let monthDay = this.getDaysByMonth(month);
let _monthDay = 0;
this.MacroTextArray = []
this.DateTextArray = []
for (let i = 0; i < this.ReviewNum; i++) {
this.MacroTextArray.push(((week + i) % 7) + '')
_monthDay++;
// 避免月份出错
if (_monthDay > monthDay) {
month++
monthDay = this.getDaysByMonth(month);
_monthDay = 0;
}
this.DateTextArray.push(((day + i) % (monthDay)) + 1)
}
}
/**
* 设置显示的时间文本数组
* 2级
*/
setDateTextArrayTwo() {
let date = new Date();
// 月份
let month = date.getMonth() + 1;
// 年份
let year = date.getFullYear();
this.MacroTextArray = []
this.DateTextArray = []
for (let i = 0; i < this.ReviewNum; i++) {
this.MacroTextArray.push(year + '')
this.DateTextArray.push(month)
month += 1
if (month == 13) {
year++
month = 1
}
}
}
/**
* 设置显示的时间文本数组
* 3级
*/
setDateTextArrayThree() {
let date = new Date();
// 年份
let year = date.getFullYear();
this.MacroTextArray = []
this.DateTextArray = []
for (let i = 0; i < this.ReviewNum; i++) {
this.MacroTextArray.push(year + '')
this.DateTextArray.push(0)
year++
}
}
/**
* 通过月份来返回本月的时间
* @param month 月份
* @returns 本月的时间
*/
getDaysByMonth(month: number) {
let a = [1, 3, 5, 7, 8, 10, 12];
let b = [2]
if (a.includes(month)) {
return 31
} else if (b.includes(month)) {
return 28
} else {
return 30
}
}
// 创建指定的元素
createElement() {
// 最外层的元素
let timeLine = document.createElement("div");
timeLine.classList.add('timeLine')
// 控制时间轴的开关
let time_switch = document.createElement("div");
time_switch.classList.add('time_switch')
// 时间轴线的外层元素
let time_content = document.createElement("div");
time_content.classList.add('time_content')
// 最下面的问题提示元素--周一--周二
let time_progressbar_remind = document.createElement("div");
time_progressbar_remind.classList.add('time_progressbar_remind')
// 时间轴与鼠标交互时的元素
this.time_progressbar_tooltip = document.createElement("div");
this.time_progressbar_tooltip.classList.add('time_progressbar_tooltip')
// 时间轴线
let time_progressbar = document.createElement("div");
time_progressbar.classList.add('time_progressbar')
// 覆盖在时间轴元素上方
this.t_progressbar = document.createElement("div");
this.t_progressbar.classList.add('t_progressbar')
timeLine.appendChild(time_switch)
timeLine.appendChild(time_content)
time_content.appendChild(this.time_progressbar_tooltip)
time_content.appendChild(time_progressbar)
time_content.appendChild(time_progressbar_remind)
time_progressbar.appendChild(this.t_progressbar)
return timeLine;
}
/**
* 通过id查找元素
* @param id
* @param flag 是否往时间轴最外层元素中找元素
* @returns
*/
getById(id: string,flag=true) {
let n = flag ? document : this.ParentNode;
return n && n.getElementById(id);
}
/**
* 通过class查找元素
* @param className
* @returns
*/
getByClass(className: string) {
if(this.ParentNode==null) return null;
return this.ParentNode.getElementsByClassName(className);
}
/**
* 通过id获取元素的具体信息
* @param id
* @returns
*/
getElementRectById(id: string) {
let e = this.getByClass(id);
return e && e[0].getBoundingClientRect();
}
}
3、调用方式
使用import来引入相应的ts方法,创建一个最外层的盒子,定义好相应的样式,具体使用方式如下:
#wtimeLine{
width: 80%;
height: 50px;
position: absolute;
left: 10%;
bottom: 50px;
}
let timeLine:useTimeLine;
onMounted(async () => {
timeLine = new useTimeLine("wtimeLine",{
reviewNum:10,
CustomReMindLabelfn:(macro:any,secondary:any)=>{
// 自定义展示标签
return "周"+(Number(macro)+1)+'--'+secondary+"号"
}
})
// 设置跟随元素的样式和显示内容
timeLine.setTooltipElementFn = (e:any)=>{
return `
${e.date}--${e.macro}--${e.day-1}
`
}
})
该实例在使用和业务构思时可能存在不足,在功能上可能也会存在缺陷,但目前还未发现,我会持续改进,也非常欢迎有建议的伙伴们来提出有意义的建议,我们共同进步。