给标签添加contenteditable属性可以实现富文本编辑框,随意定义内容的样式
1 <div contenteditable ="true" > </div >
监听输入,获取内容 1 2 3 4 5 <div ref ="editorCon" contenteditable ="true" @input ="handleInput" > </div >
1 2 3 4 5 6 handleInput (e) { const html = this .$refs .editorCon .innerHTML .toString ().replace (/<br>/g , '' ) this .$emit('input' , html) }
获取光标,插入内容 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 pasteHtmlAtCaret ($html) { let sel, range if (window .getSelection ) { sel = window .getSelection () if (sel && sel.rangeCount ) range = sel.getRangeAt (0 ) if (['' , null , undefined ].includes (range)) { range = this .keepCursorEnd (true ).getRangeAt (0 ) } else { const contentRange = document .createRange () contentRange.selectNode (this .$refs .editorCon ) const compareStart = range.compareBoundaryPoints ( Range .START_TO_START , contentRange ) const compareEnd = range.compareBoundaryPoints ( Range .END_TO_END , contentRange ) const compare = compareStart !== -1 && compareEnd !== 1 if (!compare) range = this .keepCursorEnd (true ).getRangeAt (0 ) } let input = range.createContextualFragment ($html) let lastNode = input.lastChild range.insertNode (input) if (lastNode) { range = range.cloneRange () range.setStartAfter (lastNode) range.collapse (true ) sel.removeAllRanges () sel.addRange (range) } } else if ( document ['selection' ] && document ['selection' ].type !== 'Control' ) { document ['selection' ].createRange ().pasteHTML ($html) } const html = this .$refs .editorCon .innerHTML .toString ().replace (/<br>/g , '' ) this .$emit('input' , html) }, keepCursorEnd ($isReturn) { if (window .getSelection ) { this .$refs .editorCon .focus () let sel = window .getSelection () sel.selectAllChildren (this .$refs .editorCon ) sel.collapseToEnd () if ($isReturn) return sel } else if (document ['selection' ]) { let sel = document ['selection' ].createRange () sel.moveToElementText (this .$refs .editorCon ) sel.collapse (false ) sel.select () if ($isReturn) return sel } }
粘贴时会有原本样式,不要保留的话需要消除样式 1 2 3 4 <div contenteditable ="true" @paste ="HandlePaste" > </div >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 HandlePaste (e) { e.stopPropagation () e.preventDefault () let text = '' const event = e.originalEvent || e if (event.clipboardData && event.clipboardData .getData ) { text = event.clipboardData .getData ('text/plain' ) } else if (window ['clipboardData' ] && window ['clipboardData' ].getData ) { text = window ['clipboardData' ].getData ('Text' ) } text = text.replace (/\[\d+\]|\n|\r/ig , '' ) if (document .queryCommandSupported ('insertText' )) { document .execCommand ('insertText' , false , text) } else { document .execCommand ('paste' , false , text) } }
常见问题 ios下点击软键盘弹出但是无光标显示 出现的原因是:生成了默认样式: -webkit-user-select:none;
(无法选中,导致出现问题)。需在该元素上添加以下css:
1 2 -webkit-user-select: text; user-select: text;
聚焦难,ios机型需要双击或者长按才会获取到焦点 由于项目中使用了Fastclick插件导致无法聚焦。 fastclick在ios条件下ontouchend方法中若needsClick(button、select、textarea、input、label、iframe、video 或类名包含needsclick)为不可点击防止了事件冒泡(preventDefault),所以出现无法点击情况。
1.给该元素添加类needsclick,不阻止事件冒泡 1 2 3 4 <div class ="needsclick" contenteditable ="true" > </div >
2.重写FastClick main.js 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import fastclick from 'fastclick' fastclick.attach (document .body ) var deviceIsWindowsPhone = navigator.userAgent .indexOf ('Windows Phone' ) >= 0 var deviceIsIOS = /iP(ad|home|od)/ .test (navigator.userAgent ) && !deviceIsWindowsPhonefastclick.prototype .focus = function (targetElement ) { var length if (deviceIsIOS && targetElement.setSelectionRange && targetElement.type .indexOf ('date' ) !== 0 && targetElement.type !== 'time' && targetElement.type !== 'month' ) { length = targetElement.value .length targetElement.setSelectionRange (length, length) } else { targetElement.focus () } targetElement.focus () }
添加换行(contenteditable本身换行会插入div标签) 1 2 3 4 5 <div class ="needsclick" contenteditable ="true" @keydown ="handleKeyDown" > </div >
1 2 3 4 5 6 handleKeyDown (e) { if (e.keyCode === 13 ) { document .execCommand ('insertHTML' , false , '\n‌' ) e.preventDefault () } }
1 2 3 .ss-editor { white-space : pre-wrap; }
添加placeholder 1 2 3 4 5 <div class ="ss-editor needsclick" placeholder ="请输入内容" contenteditable ="true" > </div >
1 2 3 4 5 6 .ss-editor { & :empty ::before { content : attr (placeholder); color : #cccccc ; } }