Automatischer Scrolleffekt des Front-End-Protokolls

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

おすすめ

転載: blog.csdn.net/zhai_865327/article/details/113527424