• 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('
    ').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('
    '); //按行进行处理
                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('
    ');
            }
            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
  • 相关阅读:
    [Codeforces 1245D] Shichikuji and Power Grid (最小生成树)
    [BZOJ 1535] [Luogu 3426]SZA-Template (KMP+fail树+双向链表)
    [BZOJ1009] [HNOI2008] GT考试(KMP+dp+矩阵快速幂)
    [Codeforces 1246B] Power Products (STL+分解质因数)
    [BZOJ 3992] [SDOI 2015] 序列统计(DP+原根+NTT)
    [BZOJ5306] [HAOI2018]染色(容斥原理+NTT)
    [Codeforces 1239D]Catowise City(2-SAT)
    [BZOJ 3527] [ZJOI2014]力(FFT)
    [BZOJ 3456]城市规划(cdq分治+FFT)
    【2-SAT(最小字典序/暴力染色)】HDU1814-Peaceful Commission
  • 原文地址:https://www.cnblogs.com/XHappyness/p/9390404.html
Copyright © 2020-2023  润新知