點燈坊

失くすものさえない今が強くなるチャンスよ

使用 FitAddon 讓 Xterm.js 也能 RWD

Sam Xiao's Avatar 2021-04-29

實務上會遇到很長的 Log 必須在 Xterm.js 顯示,且由於 Browser 的 RWD 特性,要如何讓 Xterm.js 能根據各種寬度改變是很大挑戰。

Version

Vue 3.0.11
Xterm.js 4.11.0

Add FitAddon

$ yarn add xterm-addon-fit

使用 Yarn 安裝 xterm-addont-fit。

Composition API

fit000

儘管 String 很長,會自動填滿 Xterm.js 所佔據寬度。

fit001

就算 resize browser,String 也會自動換行。

<template lang='pug'>
  div(ref='xterm')
</template>

<script setup>
import { onMounted, onUnmounted } from 'vue'
import { Terminal } from 'xterm'
import { FitAddon } from 'xterm-addon-fit'
import 'xterm/css/xterm.css'
import 'xterm/lib/xterm.js'

ref: xterm = null
let terminal = new Terminal
let fitAddon = new FitAddon

let xtermFit = () => fitAddon.fit()

let mount = () => {
  addEventListener('resize', xtermFit)

  terminal.loadAddon(fitAddon)
  terminal.open(xterm)
  fitAddon.fit()

  terminal.writeln('Lorem ipsum dolor sit amet, consectetur adipisicing elit. Dolorem ea eligendi labore officia voluptatibus! Aliquam aut culpa ea nam natus porro praesentium quaerat quia quibusdam reiciendis, sapiente suscipit tempore ut?')
}

let unmount = () => removeEventListener('resize', xtermFit)

onMounted(mount)
onUnmounted(unmount)
</script>

21 行

terminal.loadAddon(fitAddon)
terminal.open(xterm)
fitAddon.fit()
  • 使用 terminal.loadAddon() 載入 FitAddon
  • terminal.open() 之後執行 fitAddon.fit(),會第一次根據目前 Xterm.js 寬度動態調整

25 行

terminal.writeln('Lorem ipsum dolor sit amet, consectetur adipisicing elit. Dolorem ea eligendi labore officia voluptatibus! Aliquam aut culpa ea nam natus porro praesentium quaerat quia quibusdam reiciendis, sapiente suscipit tempore ut?')

使用 terminal.writeln() 顯示很長的 String。

terminal.write() 將無法 RWD,只能使用 terminal.writeln()

20 行

addEventListener('resize', xtermFit)

另外一個要解決問題是 resize browser 時,該如何動態改變很長 String 顯示。

使用 addEventListener()xternFit() 註冊到 resize event。

16 行

let xtermFit = () => fitAddon.fit()

執行 fitAddon.fit() 根據目前 Xterm.js 寬度重新調整顯示。

28 行

let unmount = () => removeEventListener('resize', xtermFit)

由於在 onMounted hook 註冊了 resize event,別必須在 onUnmounted hook 取消註冊 resize event。

30 行

onMounted(mount)
onUnmounted(unmount)
  • onMounted():註冊 onMounted hook
  • onUnmounted():註冊 onUnmounted hook

Point-free

fit000

結果不變,但使用 Point-free 改寫。

<template lang='pug'>
  div(ref='xterm')
</template>

<script setup>
import { onMounted, onUnmounted } from 'vue'
import { pipe, always } from 'ramda'
import { Terminal } from 'xterm'
import { FitAddon } from 'xterm-addon-fit'
import 'xterm/css/xterm.css'
import 'xterm/lib/xterm.js'

ref: xterm = null
let terminal = new Terminal
let fitAddon = new FitAddon

let xtermFit = () => fitAddon.fit()

let mount = () => {
  addEventListener('resize', xtermFit)

  terminal.loadAddon(fitAddon)
  terminal.open(xterm)
  fitAddon.fit()

  terminal.writeln('Lorem ipsum dolor sit amet, consectetur adipisicing elit. Dolorem ea eligendi labore officia voluptatibus! Aliquam aut culpa ea nam natus porro praesentium quaerat quia quibusdam reiciendis, sapiente suscipit tempore ut?')
}

let unmount = () => removeEventListener('resize', xtermFit)

pipe(
  always(mount),
  onMounted,
  always(unmount),
  onUnmounted
)()
</script>

31 行

pipe(
  always(mount),
  onMounted,
  always(unmount),
  onUnmounted
)()

使用 pipe() 組合 IIFE:

  • always(mount):準備 mount() 傳入 onMounted()
  • onMounted:註冊 onMounted hook
  • always(unmount):準備 unmount() 傳入到 onUnmounted()
  • onUnmounted:註冊 onUnmounted hook

Conclusion

  • FitAddon 只能解決一開始寬度問題,必須在結合 resize event 再次執行 FitAddon 才能完美解決 RWD
  • 只能使用 terminal.writeln(),不能使用 terminal.write()

Reference

Xterm.js, xterm-addon-fit