首页>>前端>>JavaScript->前端实现程序日志的自动滚动显示

前端实现程序日志的自动滚动显示

时间:2023-11-29 本站 点击:2

一、需求

当某个程序在后端运行的时候,前端经常要显示一个动态的进度条,或者 loading 的动画,或者百分比的数字

当然,更好的效果是给当前的用户展示出程序运行的具体细节,比如运行中记录的日志,或者实时的进程环节

比如:

[12:01:59]正在启动应用进程[12:02:00]进程启动成功,正在获取网络资源...[12:02:01]成功启动下载任务[12:02:02]下载中....[12:02:03]下载成功,开始解析网络资源[12:02:04]正在安装相关程序[12:02:05]安装成功,应用进程结束

当然,这是我瞎写的,只是为了展示我们想要实现的日志的样子,当这样的日志内容或者进程内容很多的时候,最好的办法是随着内容的增加,让页面自动向下滚动,方便用户查看最新的消息

二、分析

在这个过程中,一方面要不断的调用接口来获取最新的数据,一方面还要把数据渲染到页面中,同时让页面发生滚动

注意这里要让页面产生滚动的动画,有三个条件

不能每次接口都返回全量数据直接替换页面数据,这样会导致页面没有滚动的动画

页面的 css 样式要正确设置,确保内容只在父元素的可视区域内发生滚动而不是整个页面滚动

使用正确的 API 来完成滚动的效果

三、实现方法

第一个条件是很好的做的,我们可以使用 setInterval

vartimer=setInertval(()=>{getLogList().then(res=>{randerView(res.data)})},2000)

不过这样做有个弊端,就是当用户网络不那么畅通,或者服务器比较拥挤的时候,已经调用的接口一直处于 pendding 的状态,后面的接口还在持续不断的调用,会让本就拥堵的服务雪上加霜

所以我更喜欢使用 setTimeout

asyncfunctiongetLogData(){constlogData=awaitgetLogList()randerView(logData.data)setTimeout(getLogData,2000)}getLogData()

第二个样式问题,只需要正确的给父元素添加固定的高度和overflow-y: scroll就可以了。

下面来说说第三个问题,如何让内容自动的向下滚动,因为这部分是比较重点的内容,我就单独放一个小节里来说

页面自动滚动的方案探讨

一般来说,如何让内容自动的向下滚动有两种方法来实现。

scrollIntoView

scrollIntoView 方法会滚动元素的父容器,使调用 scrollIntoView 的元素在父元素中可见。

语法如下:

element.scrollIntoView(); // 等同于element.scrollIntoView(true) element.scrollIntoView(alignToTop); // Boolean型参数 element.scrollIntoView(scrollIntoViewOptions); // Object型参数

参数说明:

参数类型默认值备注alignToTopbooleantrue该元素的顶端是否和其所在滚动区的可视区域的顶端对齐scrollIntoViewOptionsobject{behavior: "auto", block: "start", inline: "nearest"}behavior:定义滚动动画过度,可选autosmooth;block:定义垂直方向的对齐,可选start, center, end, 或 nearest;inline:定义水平方向的对齐,可选 start, center, end, 或 nearest

使用方法:

<template><div><strong>进程日志</strong><divstyle="max-height:120px;position:relative"><divv-if="logs.length"><pv-for="(item,index)inlogs":key="index":id="(logs.length===index+1)?'scollLog':''">{{item}}</p></div><pv-else>暂无数据</p></div></div></template><script>import{Component,Vue,Watch,Prop}from'vue-property-decorator'import{formatTime}from'@/utils'@ComponentexportdefaultclassextendsVue{@Prop()privateLOGS:Array<object>;privatename:string='processLog';privatelogs:Array<string>=[];//getData将父组件传递过来的日志转成`[12:01:59]正在启动应用进程`这种格式privategetData(){this.logs=this.LOGS?this.LOGS.map((item:object):string=>'['+formatTime(item.updatedTime)+']'+item.content+'\n'):[]}@Watch('LOGS')scrollLogs(newValue){this.getData()//在日志渲染之后,将最底下的日志滚动到其父元素可视区域内this.$nextTick(()=>{if(newValue.length!==0){(document.getElementById('scollLog')asHTMLElement).scrollIntoView({behavior:'smooth',block:'nearest'})}})}mounted(){this.getData()}}</script><stylescoped>.logList-item{padding:8px0;margin:0;}</style>

总结

scrollIntoView 这个方法的对 ios safari 和 IE 不是很友好,其他的浏览器没有什么问题

另外,这个方法对布局也没有什么要求,简单方便又易于理解,只需要针对最后一条渲染的日志调用即可

scrollTo

这个方法是老生常谈了,这个方法可把内容滚动到指定的坐标。

语法如下:

scrollTo(xpos,ypos)

参数说明:

参数类型默认值备注xposnumber-必需。要在窗口文档显示区左上角显示的文档的 x 坐标yposnumber-必需。要在窗口文档显示区左上角显示的文档的 y 坐标

使用方法:

<template><div><divref="consoleWindow"><divid="console_output"ref="consoleOutput"><--这里写日志信息,注意,一定要在父元素外再套一层--></div></div></div></template><script>import{Component,Vue,Watch,Prop}from'vue-property-decorator'import{post}from'@/utils/http'@ComponentexportdefaultclassextendsVue{asyncgetData(){constres=awaitpost(`/api/get/log`,{read:true})this.formatData(res.data)}formatData(data){try{if(data.length){data.forEach(item=>{this.printLine('['+item.updateTime+']'+item.value)})}else{this.printLine('暂无数据','input_line')}}catch(e){console.log('error')}}printLine(s,type){if((s=String(s))){letn=document.createElement('pre')if(!type)type='output_line'if(n.innerText!==undefined){//IEhastouseinnerTextn.innerText=s}else{//FirefoxusescreateTextNoden.appendChild(document.createTextNode(s))}n.className=typethis.$refs.consoleOutput.appendChild(n)//添加完日志后,让父元素滚动到其自身的距离this.$refs.consoleWindow.scrollTop=this.$refs.consoleWindow.scrollHeight}}mounted(){this.getData()}}</script><stylescoped>.console-wraper{display:flex;flex-direction:column;height:100%;}.console_window{flex:1;background:#333;overflow:auto;.console_output{white-space:pre-wrap;word-wrap:break-word;padding:12px;font-weight:bold;}/deep/pre.input_line{font-size:14px;color:yellow;opacity:0.8;padding:020px;}/deep/pre.output_line{color:#fff;font-size:13px;white-space:pre-wrap;word-wrap:break-word;padding-left:40px;opacity:0.7;}}</style>

本文的内容到此就结束了,案例代码未经完整测试,有任何问题可以在评论区留言哦 :)

作者:晴天同学


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:/JavaScript/683.html