前端实现日志的自动滚动

您所在的位置:网站首页 vue版本更新日志 前端实现日志的自动滚动

前端实现日志的自动滚动

2023-09-30 22:04| 来源: 网络整理| 查看: 265

这是我参与8月更文挑战的第5天,活动详情查看:8月更文挑战

一、需求

当某个程序在后端运行的时候,前端经常要显示一个动态的进度条,或者 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 var timer = setInertval(()=>{ getLogList().then(res=>{ randerView(res.data) }) },2000)

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

所以我更喜欢使用 setTimeout

async function getLogData(){ const logData = await getLogList() 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:定义滚动动画过度,可选auto 、smooth;block:定义垂直方向的对齐,可选start, center, end, 或 nearest;inline:定义水平方向的对齐,可选 start, center, end, 或 nearest 使用方法: 进程日志 {{ item }} 暂无数据 import { Component, Vue, Watch, Prop } from 'vue-property-decorator' import { formatTime } from '@/utils' @Component export default class extends Vue { @Prop() private LOGS: Array; private name: string = 'processLog'; private logs: Array = []; // getData 将父组件传递过来的日志转成`[12:01:59] 正在启动应用进程`这种格式 private getData () { 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') as HTMLElement) .scrollIntoView({ behavior: 'smooth', block: 'nearest' }) } }) } mounted () { this.getData() } } .logList-item { padding: 8px 0; margin: 0; } 总结

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

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

scrollTo

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

语法如下:

scrollTo(xpos,ypos)

参数说明: 参数类型默认值备注xposnumber-必需。要在窗口文档显示区左上角显示的文档的 x 坐标yposnumber-必需。要在窗口文档显示区左上角显示的文档的 y 坐标 使用方法: import { Component, Vue, Watch, Prop } from 'vue-property-decorator' import { post } from '@/utils/http' @Component export default class extends Vue { async getData() { const res = await post(`/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))) { let n = document.createElement('pre') if (!type) type = 'output_line' if (n.innerText !== undefined) { // IE has to use innerText n.innerText = s } else { // Firefox uses createTextNode n.appendChild(document.createTextNode(s)) } n.className = type this.$refs.consoleOutput.appendChild(n) // 添加完日志后,让父元素滚动到其自身的距离 this.$refs.consoleWindow.scrollTop = this.$refs.consoleWindow.scrollHeight } } mounted () { this.getData() } } .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: 0 20px; } /deep/ pre.output_line { color: #fff; font-size: 13px; white-space: pre-wrap; word-wrap: break-word; padding-left: 40px; opacity: 0.7; } }

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



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3