前端模拟终端(三):文本显示与自动换行

  前面都在说 IOTerm 中使用 div 显示文本,但其实一开始选用的是 pre 元素,因为它可以原模原样的显示,而不会少了空格。  pre 默认使用等宽字体,这也正好符合终端的需要。但是 pre 默认是不会自动换行的,文本会超出元素范围,也就是 white-space 为 pre。可以将 white-space 改成 pre-wrap,这样就可以既保留空格又能正常换行了。但是因为默认的 w...
摘要由CSDN通过智能技术生成

目录

前端模拟终端(一):如果我的这款 IOTerm 不是你想要的
前端模拟终端(二):部分可输入而部分不可修改的多行文本域
前端模拟终端(三):文本显示与自动换行
前端模拟终端(四):显示、输入与光标
前端模拟终端(五):看谁用了 rm -rf / 之历史记录
前端模拟终端(六):快捷输入的好助手、终端的灵魂之补全和提示

文本显示与自动换行

  前面都在说 IOTerm 中使用 div 显示文本,但其实一开始选用的是 pre 元素,因为它可以原模原样的显示,而不会少了空格。

  pre 默认使用等宽字体,这也正好符合终端的需要。但是 pre 默认是不会自动换行的,文本会超出元素范围,也就是 white-spacepre。可以将 white-space 改成 pre-wrap,这样就可以既保留空格又能正常换行了。但是因为默认的 world-break 是在单词之间换行,而不会破开整个单词,这就造成在最后一列凹凸不平,不和终端一样。把 world-break 换成 break-all,就可以在单词中断开了。但是效果依然不佳,在都是英文字母,且字体为等宽字体时,还是会出现最后一列不齐的情况。也就是当本应换行处的字母的后面是标签符号时,最后一个字符会被拉到下一行,即标签符号不会出现在一行开头(除了左括号、引号)。有什么好的办法呢?是的,最初,我选择自己写自动换行。不断地测量以确定插入换行符的位置。

  首先需要一个辅助的元素,它的样式要和显示文本的 prediv 一模一样,至少字体、字号等要一样。然后开始不断地尝试与测量吧。最容易想到的当然就是顺序取字符,测量字符串长度。取第一个字符赋值给辅助元素,获取辅助元素的宽度,短了就继续取,长了就插入换行符。取第二个字符与第一个字符组成字符串赋值为辅助元素,获取辅助元素的宽度,进行比较……这样就是一个 O(n)。慢,是肯定的。

  所以,我用了二分法。一行的最大宽度是已知的,记为 maxWidth。设当前测量的字符串为 subText,其宽度为 subTextWidth。当使用的是等宽字体时,就英文来说,每个字符的宽度是一样的,而终端中输入的最多的就是英文了。那么可以通过以下方式估算插入换行符的位置:

endIndex = Math.floor(subText.length * maxWidth / subTextWidth);

  当字符串中有中文等其他文字时,这种估算也只能获取大概的位置,还需要评估其左右。若其宽度 subTextWidth 小于 maxWidth,则往其右再取一个字符,比较宽度,若长了,则 endIndex 为精确的换行位置。若 subTextWidth 大于 maxWidth,则往其左再取一个字符,比较长度,若短了,则 endIndex - 1 为精确的换行位置。

  考虑到实际处理的字符串和显示出来的字符串是可能不一样的,比如存在高亮时,HTML 标签是占长度但不显示的,以及 <、>、& 等转义字符,在代码实现中,将确定插入换行符位置和处理 HTML 标签以及转义字符分为两个步骤。具体代码如下:

private getLineFeedsIndices(text: string) {
   
    // Find the indices where to insert line feeds into the string `text`.
    //
    // This function returns a object containing `indices`, `numRows` and
    // 'colOffset'. The `indices` is an array recording the indices where to
    // insert line feeds in the string `text`. The `numRows` is the number
    // of rows after the `text` is inserted with line feeds <br>.
    // The 'colOffset' is the width in pixel of the last line after the
    // `text` is inserted with line feeds <br>.

    // The `startIndex` is the starting index of the string `subText` in the
    // string `text`.
    let startIndex = 0;
    let maxWidth = this.main.panel.offsetWidth;
    let indices: number[] = [];

    let subText: string;
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值