textarea怎么解析html代碼,從而實現一個可高亮的輸入框


效果:

 

思路: 讓一個div浮動在textarea上,樣式和位置保持完全一致,textarea負責輸入,div負責高亮顯示

代碼:

.vue

<template>
    <div class="highlight-contain">
        <!-- 本組件是帶高亮的textarea,需要接受高亮關鍵詞數組來進行高亮 -->
        <div id="highlight-area" class="input-font el-textarea" >
            <div id="fake-textarea" class="el-textarea__inner" v-html="highlightHtml"></div>
        </div>
        <div id="input-area">
            <el-input 
                class="input-font"
                id="input-textarea"
                type="textarea" 
                :placeholder="placeholder" 
                :autosize="autosize" 
                v-model="strValue"
                @input="getHighlightHtml"
                @mousemove.native="setHighlightArea('height',true)"
            ></el-input>
        </div>
    </div>
</template>

<style lang="postcss">
/* 這里是為了讓textarea中的文字隱藏,同時這只光標和placeholder顏色 */
#input-area .el-textarea .el-textarea__inner {
  color: #606266; /* 光標的顏色*/
  text-shadow: 0px 0px 0px rgba(0, 0, 0, 0); /* 文本顏色 */
  -webkit-text-fill-color: transparent;
  &::-webkit-input-placeholder {
    color: #dcdfe6; /* 改變placeholder文本顏色 */
    text-shadow: none;
    -webkit-text-fill-color: initial;
  }
}

.highlight-contain {
  position: relative;
  & #highlight-area {
    /* 自定義樣式 */
    position: absolute;
    left: 0px;
    top: 0px;
    pointer-events: none;
    & #fake-textarea {
      /* color: #ec140d; */
      pointer-events: none;
      border: none;
      resize: none;
      background-color: rgba(0, 0, 0, 0);
      line-height: 1.5 !important;
      max-height: 590px;
      overflow-y: auto;
      /* 和html中的類一樣,都是為了設定和textarea一模一樣的樣式,防止文字對接不上(這里是復制的瀏覽器中textarea元素屬性) */
      -webkit-appearance: textarea;
      -webkit-rtl-ordering: logical;
      -webkit-writing-mode: horizontal-tb !important;
      flex-direction: column;
      white-space: pre-wrap;
      word-wrap: break-word;
      text-rendering: auto;
      letter-spacing: normal;
      word-spacing: normal;
      text-transform: none;
      text-indent: 0px;
      text-shadow: none;
      text-align: start;
      margin: 0em;
      font: 400 14px Arial;
    }
  }
}

/* 高亮色 */
.highlight-11 {
  color: #fb4546;
}
.highlight-10 {
  color: #0fed40;
}
.highlight-9 {
  color: #feb71d;
}
.highlight-8 {
  color: #39afea;
}
.highlight-7 {
  color: #e512bf;
}
.highlight-6 {
  color: #0f29ed;
}
.highlight-5 {
  color: #f088c1;
}
.highlight-4 {
  color: #acbb09;
}
.highlight-3 {
  color: #7a152e;
}
.highlight-2 {
  color: #7ca51c;
}
.highlight-1 {
  color: #5e36aa;
}
.highlight-bracket {
  color: #000000;
}
</style>

<script lang="ts" src="./highlightTextarea.ts"></script>
View Code

.ts

import { Vue, Component, Prop } from "vue-property-decorator"
import $ from 'jquery'
@Component({})

export default class HighlightTextarea extends Vue {
    /* ---- 從父元素接受參數 ---- */
    @Prop()
    value: string
    @Prop()
    placeholder: string
    @Prop()
    autosize: { minRows: number, maxRows: number }
    @Prop()
    highlightKey: string[] //要高亮的詞

    /* ---- 變量 ---- */
    get strValue() {
        return this.value ? this.value : ''
    }
    set strValue(val) {
        this.$emit('input', val)
    }
    highlightHtml: string = '';

    /* ---- 函數 ---- */
    setHighlightArea(type: string, right?: boolean) {
        if (type === 'height') {
            if (right) {
                let height = document.getElementById('input-textarea').style.height;
                document.getElementById('fake-textarea').style.height = height;
            } else {
                window.setTimeout(() => {
                    let height = document.getElementById('input-textarea').style.height;
                    document.getElementById('fake-textarea').style.height = height;
                }, 100);
            }
        } else if (type === 'scrollTop') {
            if (right) {
                let scroll = document.getElementById('input-textarea').scrollTop
                document.getElementById('fake-textarea').scrollTop = scroll;
            } else {
                window.setTimeout(() => {
                    let scroll = document.getElementById('input-textarea').scrollTop
                    document.getElementById('fake-textarea').scrollTop = scroll;
                }, 100);
            }
        }
    }

    getHighlightHtml(val) {
        if (val.split('\n').length > this.autosize.maxRows) {  //超過最大行textarea有滾動時,為解決div底部不能和textarea重合,故加一個<br/>,並延時設置scrolltop
            this.highlightHtml = this.highlightStr(val, this.highlightKey) + '<br/>';
            this.setHighlightArea('scrollTop', false);
        } else {
            this.highlightHtml = this.highlightStr(val, this.highlightKey)
        }
        // 高亮區和輸入區高度保持一致
        this.setHighlightArea('height');
    }
    /**
     * 高亮方法:
     * 1.將oriStr中的高亮關鍵字使用“{{{關鍵字}}}”替換,這里防止關鍵詞數組中有包含關系,所有用空格區分oriStr
     * 2. 然后再循環highlightKey用<span class="..."></span>替換文中的{{{和}}}
     * @param oriStr 要高亮的字符串
     * @param highlightKey 高亮關鍵詞
     */
    highlightStr(oriStr: string, highlightKey: string[]): string {
        if (!oriStr || !highlightKey || highlightKey.length === 0)
            return oriStr;
        let strConvert = (s: string, key: string): string => {
            let rowArr = s.split('\n'); //按行進行處理
            for (let i = 0; i < rowArr.length; i++) {
                let strArr = rowArr[i].split(' ').filter(item => item !== '');
                strArr = strArr.map(item => {
                    if (item === key) {
                        item = `{{{${item}}}}`
                    }
                    return item;
                })
                rowArr[i] = strArr.join(' ')
            }
            return rowArr.join('\n');
        }
        let rebuild = highlightKey.reduce(strConvert, oriStr);
        let regExp;
        let regStr;
        for (let i = 0; i < highlightKey.length; i++) {
            regStr = '\\{\\{\\{' + this.escapeString(highlightKey[i]);
            regExp = new RegExp(regStr, 'g');
            if (highlightKey[i] === '(' || highlightKey[i] === ')') { //小括號顏色
                rebuild = rebuild.replace(regExp, `<span class="highlight-bracket">${highlightKey[i]}</span>`)
            } else {
                rebuild = rebuild.replace(regExp, `<span class="highlight-${i + 1}">${highlightKey[i]}`)
            }
        }
        rebuild = rebuild.replace(/\}\}\}/g, '</span>');
        return rebuild;
    }
    //處理字符串中可能對正則有影響的字符串
    escapeString(value: string): string {
        var str = value.replace(new RegExp('\\\\', 'g'), '\\\\');
        var characterss = ['(', ')', '[', ']', '{', '}', '^', '$', '|', '?', '*', '+', '.'];
        characterss.forEach(function (characters) {
            var r = new RegExp('\\' + characters, 'g')
            str = str.replace(r, '\\' + characters)
        })
        return str;
    }

    /* ---- 生命周期 ---- */
    mounted() {
        this.highlightKey.sort((a, b) => b.length - a.length);// 為了使高亮正常,關鍵詞長的排在前面
        $('#input-textarea').scroll((e) => {
            this.setHighlightArea('scrollTop', true);
        });
    }
}
View Code

 

使用:import HighlightTextarea from "..."引入后, 

  <highlight-textarea 
    :highlightKey="['=', '<', '>', '!=', '<=', '>=', 'like', '(', ')']" 
    placeholder="請輸入監測" 
    :autosize="{minRows: 4, maxRows: 10}"
    v-model="str">
</highlight-textarea>
View Code

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM