1. Nachfrage
Wenn ein Programm im Backend läuft, zeigt das Frontend oft einen dynamischen Fortschrittsbalken, eine Ladeanimation oder eine Prozentzahl an
Ein besserer Effekt besteht natürlich darin, die spezifischen Details des Programmbetriebs des Benutzers anzuzeigen, z. B. die während des Betriebs aufgezeichneten Protokolle
Es ist wie die Besetzungsliste, die nach dem Ende der Fernsehsendung abgespielt wird
Zwei, klar
Im Allgemeinen gibt es zwei Möglichkeiten, diese Anforderung zu erfüllen.
1、scrollIntoView()
Die scrollIntoView()-Methode scrollt durch den übergeordneten Container des Elements, sodass das Element, das scrollIntoView aufruft, im übergeordneten Element sichtbar ist.
Die Syntax lautet wie folgt:
element.scrollIntoView(); // Äquivalent zu element.scrollIntoView(true)
element.scrollIntoView(alignToTop); // Boolescher Typparameter
element.scrollIntoView(scrollIntoViewOptions); // Objekttypparameter
Die Parameter sind wie folgt:
Parameter | Typ | Standardeinstellungen | Anmerkung |
---|---|---|---|
alignToTop | Boolescher Wert | WAHR | Ob die Oberseite des Elements an der Oberseite des sichtbaren Bereichs des Bildlaufbereichs ausgerichtet ist, in dem es sich befindet |
scrollIntoViewOptions | Objekt | {Verhalten: „auto“, Block: „start“, inline: „nearest“} | Verhalten: Definieren Sie den Übergang der Scroll-Animation, optional auto , smooth ; Block: Definieren Sie die Ausrichtung in vertikaler Richtung, optional start , center , end , oder nearest ; inline: Definieren Sie die Ausrichtung in horizontaler Richtung, optional start , center , end , odernearest |
Anweisungen:
<template>
<div >
<strong>进程日志</strong>
<div style="max-height:120px; position:relative">
<div v-if="logs.length">
<p
class="logList-item"
v-for="(item, index) in logs"
:key="index"
:id="(logs.length === index+1)?'scollLog':''"
>{
{
item }}</p>
</div>
<p v-else>暂无数据</p>
</div>
</div>
</template>
<script lang='ts'>
import {
Component, Vue, Watch, Prop } from 'vue-property-decorator'
import {
formatTime } from '@/utils'
@Component
export default class extends Vue {
private name: string = 'processLog';
private logs: Array<string> = [];
@Prop() private LOGS: any;
@Prop() private scrollT: any;
// getData 将父组件传递过来的日志转成 `[2021-01-01 12:12:12] 系统正在启动` 这种格式
private getData () {
this.logs = this.LOGS
? this.LOGS.map(
(item: object): string =>
'[' + formatTime(item.updatedTime) + '] ' + item.content + '\n'
)
: []
}
@Watch('LOGS')
scrollLogs (newValue: any) {
this.getData()
// 在日志渲染之后,将最底下的日志滚动到其父元素可视区域内
this.$nextTick(() => {
let top = 160
if (newValue.length !== 0 && this.scrollT < top) {
(document.getElementById('scollLog') as HTMLElement).scrollIntoView({
behavior: 'smooth', block: 'nearest' })
}
})
}
mounted () {
this.getData()
}
}
</script>
<style lang="scss" scoped>
.logList-item {
padding: 8px 0;
margin: 0;
}
</style>
Zusammenfassen
Diese Methode ist für iOS Safari und IE nicht sehr benutzerfreundlich, andere Browser haben kein Problem
Darüber hinaus stellt diese Methode keine Anforderungen an das Layout. Sie ist einfach, bequem und leicht zu verstehen. Unabhängig davon, ob das Backend vollständige Daten oder akkumulierte Daten zurückgibt, muss es nur für das zuletzt gerenderte Protokoll aufgerufen werden.
2、scrollenZu
Diese Methode wird sehr häufig verwendet und die Syntax und die Parameter werden übersprungen. Es ist zu beachten, dass diese Methode Anforderungen an das Layout hat. Wenn das Layout falsch ist, kann diese Methode das Scrollen nicht realisieren.
Anweisungen
<template>
<div class="console-wraper">
<div class="console_window" ref="consoleWindow">
<div id="console_output" ref="consoleOutput">
<-- 这里写日志信息,注意,一定要在父元素外再套一层-->
</div>
</div>
</div>
</template>
<script>
/* eslint-disable camelcase */
import {
postRest } from '@/utils/http'
export default {
data() {
return {
sessionType: '',
sessionId: 0,
command: '',
}
},
methods: {
async getData() {
const res = await postRest(`/sessions/${
sessionId}/shell`, {
read: true, cmd: command })
if (!res) return
this.command = ''
this.cleanData(res)
},
cleanData(res) {
const {
con_prompt, con_update, con_append } = res
this.consolePrompt = unescape(con_prompt)
try {
let conAppend = JSON.parse(con_append)
if (conAppend.length) {
conAppend.forEach(item => {
this.printLine(unescape(item[1]), item[0])
})
} else {
if (con_update.length) {
this.printLine(unescape(con_update), 'output_line')
}
}
} catch (e) {
console.log('error')
}
},
printLine(s, type) {
if ((s = String(s))) {
let n = document.createElement('pre')
if (!type) type = 'output_line'
// IE has to use innerText
if (n.innerText !== undefined) {
n.innerText = s
// Firefox uses createTextNode
} else {
n.appendChild(document.createTextNode(s))
}
n.className = type
this.$refs.consoleOutput.appendChild(n)
// 添加完日志后,让父元素滚动到其自身的距离
this.$refs.consoleWindow.scrollTop = this.$refs.consoleWindow.scrollHeight
}
},
help () {
this.printLine(' Web Console Internal Commands\n')
this.printLine('=========================================\n\n')
this.printLine(' /help Show this text\n')
this.printLine(' /clear Clear the screen\n')
this.printLine('\n')
},
clear () {
this.$refs.consoleOutput.innerHTML = ''
}
},
async mounted() {
this.getData()
}
}
</script>
<style lang=scss scoped>
.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;
}
}
</style>
Wenn es dir gefällt, kannst du es abholen, hahaha