Demo link github address
Basic Function Description
Through input, Textarea can be highlighted input box, mainly used to deal with the text field, text box keyword highlighting
Implementation approach
Div overlaps with Textarea and input in exactly the same style and position, while Textarea text is transparent to the background, Textarea is responsible for input, and div is responsible for highlighting
Points to note:
- Input and Textarea need to make text and background transparent.
- The div, which is responsible for the display, passes
pointer-events: none;
Set the mouse event to invalid
The green background is div
The effect
Gao Liang text: team, organization
Component design
Usage
// highlightKey: [' team ', HighlightKey ="highlightKey"> < highlightKey="highlightKey" SRC ="highlightKey" SRC ="highlightKey" SRC ="highlightKey"> </highlight-textarea>Copy the code
props
The name of the | type | The default value | Whether will pass | describe |
---|---|---|---|---|
placeholder | String | Please enter the | no | Prompt message when value is empty |
type | String | ‘textarea’ | is | Type textarea/input |
text | String | ‘ ‘ | no | Text information |
highlightKey | Array | [] | no | Highlighted keywords [‘ team ‘, ‘organization ‘] |
maxHeight | Number | 220 | no | Height of the text field |
Methods
The name of the | describe |
---|---|
syncScrollTop | Synchronize the height of textarea with div and the value of scrollTop |
scrollMousewheel | Scroll wheel level event handling when scroll bar appears in text field |
highlightHtml | Text highlighting |
escapeString | Handles characters in a string that might affect the re |
The complete code
<template> <div class="highlight-box"> <template v-if="type === 'textarea'"> <div v-if="value" class="textarea-outer" ref="textareaOuter" :style="{'height': `${maxHeight}px`}"> <div ref="outerInner" class="outer-inner" v-html="highlightHtml(value)"> </div> </div> <textarea ref="textareaBox" :style="{'height': `${maxHeight}px`}" :placeholder="placeholder" @keyup.enter="syncScrollTop" v-model.trim="value"> </textarea> </template> <template v-if="type === 'input'"> <div v-if="value" class="input-outer" v-html="highlightHtml(value)"> </div> <input type="text" :placeholder="placeholder" v-model.trim="value" /> </template> </div> </template> <script> export default { name: 'HighlightTextarea', data() { return { value: '' }; }, props: {placeholder: {type: String, required: false, default: 'Please input'}, text: {type: String, required: false, default: '' }, highlightKey: { type: Array, require: false, default: () => [] }, type: { type: String, required: true, default: 'textarea' }, maxHeight: { type: Number, required: false, default: 220 } }, created() { this.value = this.text.replace(/(^\s*)|(\s*$)/g, '').replace(/<br \/>|<br\/>|<br>/g, '\n'); }, mounted() { this.scrollMousewheel(); }, methods: { highlightHtml(str) { if ((! str || ! this.highlightKey || this.highlightKey.length === 0) && this.type ! == 'textarea') { return str; } let rebuild = str; if (this.highlightKey.filter(item => ~str.indexOf(item)).length) { let regStr = ''; let regExp = null; this.highlightKey.forEach(list => { regStr = this.escapeString(list); regExp = new RegExp(regStr, 'g'); rebuild = rebuild.replace(regExp, `<span>${list}</span>`); }); } if (this.type === 'textarea') { rebuild = rebuild.replace(/\n/g, '<br/>').replace(/\s/g, ' '); <br/> const wrap = this.$refs.textareabox; if (wrap && wrap.scrollHeight > this.maxHeight) { rebuild = rebuild + '<br/>'; } } return rebuild; }, syncScrollTop() { const wrap = this.$refs.textareaBox; const outerWrap = this.$refs.textareaOuter; const outerInner = this.$refs.outerInner; if (wrap.scrollHeight > this.maxHeight && outerInner.scrollHeight ! == wrap.scrollHeight) { outerInner.style.height = `${wrap.scrollHeight}px`; } if (wrap.scrollTop ! == outerWrap.scrollTop) { outerWrap.scrollTop = wrap.scrollTop; } }, scrollMousewheel() { if (this.type === 'input') { return; } this.$nextTick(() => { this.eventHandler('add'); }); }, / / processing may have an impact on the regular characters in a string escapeString (value) {const characterss = [' (', ') ', '(',') ', '{','} ', '^', '$',' | ', '? ', '*', '+', '. ']; let str = value.replace(new RegExp('\\\\', 'g'), '\\\\'); characterss.forEach(function (characters) { let r = new RegExp('\\' + characters, 'g'); str = str.replace(r, '\\' + characters); }); return str; }, eventHandler(type) { const wrap = this.$refs.textareaBox; if (wrap) { let mousewheelevt = (/Firefox/i.test(navigator.userAgent)) ? 'DOMMouseScroll' : 'mousewheel'; wrap[`${type}EventListener`](mousewheelevt, this.syncScrollTop); wrap[`${type}EventListener`]('scroll', this.syncScrollTop); } } }, destroyed() { this.eventHandler('remove'); }}; </script> <style lang="less"> @width: 500px; .highlight-box { position: relative; font-size: 12px; width: @width; position: relative; color: #333333; background: #ffffff; border-radius: 5px; overflow: hidden; .textarea-outer, .input-outer { width: @width; position: absolute; top: 0; left: 0; right: 0; border: 1px solid transparent; border-top: 0; Ie6-10 does not support pointer-events: None; cursor: text; span { color: #F27C49; } &:hover { border-color: #4C84FF; } } .textarea-outer { overflow-y: auto; line-height: 20px; word-break: break-word; .outer-inner { padding: 4px 8px; width: 100%; } } textarea { width: @width; line-height: 20px; resize: none; } .input-outer, input { width: @width; height: 28px; line-height: 28px; } .input-outer { bottom: 0; padding: 0 8px; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; } textarea, input { // position: relative; // z-index: 2; // Cursor color: #333333; // Text-shadow: 0 0 0 rgba(0, 0, 0, 0); -webkit-text-fill-color: transparent; background: transparent; border-radius: 5px; border: 1px solid #E0E0E0; padding: 4px 8px; &::placeholder { -webkit-text-fill-color: #999999; } &:hover { border-color: #4C84FF; } &:focus { border-color: #4C84FF; box-shadow: 0 0 0 2px #DBE4FF; outline: none; } } } </style>Copy the code