時間:2024-02-17 23:10:02 | 來源:網(wǎng)站運營
時間:2024-02-17 23:10:02 來源:網(wǎng)站運營
怎么用HTML開發(fā)一個動態(tài)留言板?:jsx { type: 'string', // 表示Entity的類型; eg:'LINK', 'TOKEN', 'PHOTO', 'IMAGE' mutability: 'MUTABLE' | 'IMMUTABLE' | 'SEGMENTED', // 此屬性表示在編輯器中編輯文本范圍時使用此實體對象注釋的文本范圍的行為。 data: 'object', // Entity的元數(shù)據(jù); 用于存儲你想要存儲在該Entity里的任何信息 }
其中 Mutability 這條屬性三個值的含義分別是:import React from 'react'import { Editor, EditorState } from 'draft-js';import 'draft-js/dist/Draft.css';import './App.css';function MyEditor() { const [editorState, setEditorState] = React.useState( () => EditorState.createEmpty(), ); const handleEditorChange = (newEditorState) => { setEditorState(newEditorState); } return ( <div className='box'> <Editor editorState={editorState} onChange={handleEditorChange} /> <button className='btn'>提交</button> </div> );}export default MyEditor;
可以看到并沒有出現(xiàn)一個帶工具欄的文本框,而是生成一個可編輯區(qū)域,接下來我們將賦予他獨特的功能。handleBeforeInput?: ( chars: string, // 輸入的內(nèi)容 editorState: EditorState, // 編輯器的文本內(nèi)容狀態(tài) eventTimeStamp: number,) => 'handled' | 'not-handled'
當(dāng) handleBeforeInput 返回 handled 的時候輸入的默認(rèn)行為會被阻止,handlePastedText 同理。handlePastedText?: ( text: string, html?: string, editorState: EditorState,) => 'handled' | 'not-handled'
接下來修改我們的代碼:const MAX_LENGTH = 200;function MyEditor() { const [editorState, setEditorState] = React.useState( () => EditorState.createEmpty(), ); const handleEditorChange = (newEditorState) => { setEditorState(newEditorState); } const handleBeforeInput = (_, editorState) => { // 獲取編輯器的文本內(nèi)容狀態(tài) const currentContent = editorState.getCurrentContent(); // 獲取編輯器文本長度,getPlainText返回當(dāng)前編輯器的文本內(nèi)容,字符串類型 const currentContentLength = currentContent.getPlainText('').length; if (currentContentLength > MAX_LENGTH - 1) { // 當(dāng)前文本長度大于最大長度的時候阻止輸入,反之允許輸入 return 'handled'; } return 'not-handled'; } return ( <div className='box'> <Editor editorState={editorState} onChange={handleEditorChange} handleBeforeInput={handleBeforeInput} /> <button className='btn'>提交</button> </div> );}
這里可能有個疑惑:MAX_LENGTH 為什么要減一?const getLengthOfSelectedText = () => { // 獲取編輯器的選擇狀態(tài) const currentSelection = editorState.getSelection(); // 返回選擇狀態(tài),錨點和焦點的偏移量相同(沒有選擇)和錨點和焦點的block_key相同時返回true const isCollapsed = currentSelection.isCollapsed(); let length = 0; if (!isCollapsed) { const currentContent = editorState.getCurrentContent(); // 獲取選擇范圍的起始位置block_key const startKey = currentSelection.getStartKey(); // 獲取選擇范圍的結(jié)束位置block_key const endKey = currentSelection.getEndKey(); if (startKey === endKey) { // 選擇范圍在同一個block,那么選擇長度=終點偏移量-起點偏移量 length += currentSelection.getEndOffset() - currentSelection.getStartOffset(); } else { const startBlockTextLength = currentContent.getBlockForKey(startKey).getLength(); // 起始block的選擇長度 = 起始block的長度-起點偏移量 const startSelectedTextLength = startBlockTextLength - currentSelection.getStartOffset(); // 終點在結(jié)束block中的偏移量 const endSelectedTextLength = currentSelection.getEndOffset(); // getKeyAfter返回指定key的block后面一個block的key const keyAfterEnd = currentContent.getKeyAfter(endKey); let currentKey = startKey; // 累加起始block到結(jié)束block中間的block的選擇長度 while (currentKey && currentKey !== keyAfterEnd) { if (currentKey === startKey) { length += startSelectedTextLength + 1; } else if (currentKey === endKey) { length += endSelectedTextLength; } else { length += currentContent.getBlockForKey(currentKey).getLength() + 1; } currentKey = currentContent.getKeyAfter(currentKey); } } } return length; };
這個方法有些長,又涉及到 draftjs 的幾個 api 和 block 的概念,稍微復(fù)雜點,不過用途很簡單,就是獲取選擇的長度?,F(xiàn)在我們來改造下 handleBeforeInput:const handleBeforeInput = (_, editorState) => { const currentContent = editorState.getCurrentContent(); const currentContentLength = currentContent.getPlainText('').length; // 實際長度 = 當(dāng)前內(nèi)容的長度-選擇的長度(被替換的長度) if (currentContentLength - getLengthOfSelectedText() > MAX_LENGTH - 1) { return 'handled'; } return 'not-handled'; }
依葫蘆畫瓢,現(xiàn)在我們來添加 handlePastedText,如果是粘貼情況下,則多了個 pastedText(被粘貼的文本)參數(shù)。const handlePastedText = (pastedText) => { const currentContent = editorState.getCurrentContent(); const currentContentLength = currentContent.getPlainText('').length; const selectedTextLength = getLengthOfSelectedText(); if (currentContentLength + pastedText.length - selectedTextLength > maxLength - 1) { return 'handled'; } return 'not-handled'; };
為了有更好的使用體驗,可以在編輯器右下角加一個當(dāng)前內(nèi)容長度/最大長度的提示。改造一下 handleEditorChange 方法,把當(dāng)前文本長度用 state 存儲起來。const handleEditorChange = (newEditorState) => { const currentContent = newEditorState.getCurrentContent(); const currentContentLength = currentContent.getPlainText('').length; setLength(currentContentLength); setEditorState(newEditorState); }
調(diào)整一下樣式,看下效果:const HANDLE_REGEX = /@[/w]+/g; const compositeDecorator = new CompositeDecorator([ { strategy: (contentBlock, callback) => { // 編輯器每次change都會觸發(fā)此函數(shù),得到內(nèi)容文本。 const text = contentBlock.getText(); let matchArr, start; while ((matchArr = HANDLE_REGEX.exec(text)) !== null) { // 得到匹配值的起始位置和偏移量,callback之后就會被此decorator的component替換 start = matchArr.index; callback(start, start + matchArr[0].length); } }, component: (props) => { return ( <span className='mention' data-offset-key={props.offsetKey} > {props.children} </span> ); }, }, ]); const [editorState, setEditorState] = React.useState( () => EditorState.createEmpty(compositeDecorator), );
看下效果:const insertEntity = (entityData) => { let contentState = editorState.getCurrentContent(); // 創(chuàng)建實體 contentState = contentState.createEntity('LINK', 'IMMUTABLE', entityData); const entityKey = contentState.getLastCreatedEntityKey(); let selection = editorState.getSelection(); // 判斷是替換還是插入 if (selection.isCollapsed()) { contentState = Modifier.insertText( contentState, selection, entityData.name + ' ', undefined, entityKey, ); } else { contentState = Modifier.replaceText( contentState, selection, entityData.name + ' ', undefined, entityKey, ); } let end; // 獲取實體在編輯器中顯示的范圍,目的是讓光標(biāo)在插入實體后停留在實體尾部 contentState.getFirstBlock().findEntityRanges( (character) => character.getEntity() === entityKey, (_, _end) => { end = _end; }); let newEditorState = EditorState.set(editorState, { currentContent: contentState }); selection = selection.merge({ anchorOffset: end, focusOffset: end, }); newEditorState = EditorState.forceSelection(newEditorState, selection); handleEditorChange(newEditorState); };
看下效果:draftjs:https://draftjs.org/公眾號:全象云低代碼
關(guān)鍵詞:動態(tài),留言
微信公眾號
版權(quán)所有? 億企邦 1997-2025 保留一切法律許可權(quán)利。