发布网友 发布时间:2024-09-30 17:57
共1个回答
热心网友 时间:2024-12-14 23:19
一、需求当某个程序在后端运行的时候,前端经常要显示一个动态的进度条,或者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就可以了。
下面来说说第三个问题,如何让内容自动的向下滚动,因为这部分是比较重点的内容,我就单独放一个小节里来说
页面自动滚动的方案探讨
一般来说,如何让内容自动的向下滚动有两种方法来实现。
scrollIntoViewscrollIntoView方法会滚动元素的父容器,使调用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使用方法:<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这个方法的对iossafari和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>本文的内容到此就结束了,案例代码未经完整测试,有任何问题可以在评论区留言哦:)
作者:晴天同学