您好,登錄后才能下訂單哦!
這篇文章主要介紹“怎么使用react編寫可編輯標題”,在日常操作中,相信很多人在怎么使用react編寫可編輯標題問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”怎么使用react編寫可編輯標題”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
文案支持可編輯
用戶點擊位置即光標定位處
超過50字讀的時候,超出部分進行截斷
當用戶把所有內容刪除時,失去焦點時文案設置為 “無文案”三個字
編輯區域隨著編輯內容的寬度而變化,最大寬度1000px 500px
失去焦點時保存文案內容
在看到第一眼需求的時候,想到的時候用span和input進行切換,但是這個肯定是滿足不了需求中第2點,所以首先這個需求肯定不會是兩個 標簽切換,只能一個標簽承擔展示和編輯的功能,第一反應是用html屬性contentEditable,就有了我的第一個套方案,后因為需求的第三點實現上存在問題,所以被迫換了方案二(使用input標簽),下面我們詳細說說為啥棄用方案1選用方案二以及在這過程中遇到的問題。
利用h6提供contentEditble,可實現需求點的1/2/5
監聽focus事件和input時間,可以實現需求點4
監聽blur事件,可以實現需求點3
但是 需求點中的3點,因為是用字數做的截斷,在這個方案中是實現不了的,所以我給出的建議方案是編輯的時候不做截斷,非編輯的時候做截斷段(是否失去焦點可用作判斷是否為編輯態的依據)
演示demo:
import React, { useState, useRef, useEffect } from 'react'; import ReactDom from 'react-dom'; interface EditTextProps { text: string; // 告知父組件文案已被修改 changeText?: (text: string) => void; } const EditText = function (props: EditTextProps) { useEffect(() => { setShowText(props.text); }, [props.text]); const [showText, setShowText] = useState(''); const [isBlank, setIsBlank] = useState(false); const [isFocus, setIsFocus] = useState(false); const textRef = useRef<HTMLDivElement>(null); const onFocus = () => { setIsFocus(true) } const onInput = () => { // 避免失去焦點的時候,標題區域明顯的閃動 setIsBlank(!textRef.current?.innerHTML); } const onBlur = () => { const newTitle = textRef.current?.innerHTML || '無標題'; const oldTitle = props.text; setIsFocus(false); setIsBlank(false); // 文案更新 if (newTitle !== oldTitle) { props?.changeText(newTitle); setShowText(getCharsByLength(newTitle, 50)); } else { // 文案不更新 setShowText(getCharsByLength(newTitle, 50)); if(textRef.current) { textRef.current.innerHTML = getCharsByLength(newTitle, 50) } } } // 獲取前length個字符 const getCharsByLength = (title: string, length: number) => { const titleLength = title.length; // 假設都是非中文字符,一個中文字符的寬度可以顯示兩個非中文字符 let maxLength = length * 2; const result = []; for (let i = 0; i < titleLength; i++) { const char = title[i]; // 中文字符寬度2,非中文字符寬度1 maxLength -= /[\u4e00-\u9fa5]/.test(char) ? 2 : 1; result.push(char); if (maxLength <= 0) { break; } } if (result.length < titleLength) { result.push('...'); } return result.join(''); }; return <div className="title"> {isFocus && isBlank ? <span className="title-blank">無標題</span> : ''} <span className="title-text" contentEditable suppressContentEditableWarning ref={textRef} onFocus={onFocus} onInput={onInput} onBlur={onBlur} >{showText}</span> </div>; };
如果在用戶修改之前的文案就是【無標題】,此時用戶刪除了文案所有的內容【將文案置空】,此時失去焦點,根據需求我們應該展示【無標題】,可是在代碼邏輯中 進行了setShowText(getCharsByLength(newTitle, 50));
的處理,在不斷試探中,發現修改前后的showText
一摸一樣,無法觸發dom的更新,針對這個問題我找到了兩個解決方式
方式一 在不需要更新標題,用戶觸發了失去焦點,但是并沒有修改標題時,先把showText設置為空,在setTimeout中設置會以前的標題。
嘗試了一下這個方案,從使用角度來說并不會特別明顯的閃動。不過個人覺得這個方案代碼看著很怪異
const onBlur = () => { const newTitle = textRef.current?.innerHTML || '無標題'; const oldTitle = props.text; setIsFocus(false); setIsBlank(false); // 文案更新 if (newTitle !== oldTitle) { props?.changeText(newTitle); setShowText(getCharsByLength(newTitle, 50)); } else { // 文案不更新 setShowText(''); setTimeout(() => { setShowText(getCharsByLength(newTitle, 50)); }, 0) } }
方式二 利用ref
const onBlur = () => { const newTitle = textRef.current?.innerHTML || '無標題'; const oldTitle = props.text; setIsFocus(false); setIsBlank(false); // 文案更新 if (newTitle !== oldTitle) { props?.changeText(newTitle); setShowText(getCharsByLength(newTitle, 50)); } else { // 文案不更新 setShowText(getCharsByLength(newTitle, 50)); if(textRef.current) { textRef.current.innerHTML = getCharsByLength(newTitle, 50) } } }
無法用字數做限制
如果用寬度做限制,可以出現截斷的效果,但是內容無法滑動
采用修改input框樣式的方法,讓input展示和可編輯文案。整體的效果和文章開頭展示的效果一致。 canEdit
這個參數時我后面加的,用來控制EditText
組件是否可以編輯。遇到的問題見面后面。 演示demo:
import React, { useState, useEffect, useRef, useLayoutEffect } from 'react'; interface EditTextProps { text: string; canEdit?: boolean; changeText?: (text: string) => void; } function EditText(props: EditTextProps) { // 根據span獲取寬度 const witdthRef = useRef<HTMLDivElement>(null); const [showText, setShowText] = useState(''); const [isFocus, setIsFocus] = useState(false); const [inputWith, setInputWith] = useState(100); const minTitleWidth = 70; const maxTitleWidth = 500; useEffect(() => { setShowText(props.text); }, [props.text]); useLayoutEffect(() => { dealInputWidth(); }, [showText]); const dealInputWidth = () => { const offsetWidth = witdthRef?.current?.offsetWidth || minTitleWidth; // +5 防止出現 截斷 const width = offsetWidth < maxTitleWidth ? offsetWidth + 5 : maxTitleWidth; setInputWith(width); }; const titleFocus = () => { setIsFocus(true); }; const titleInput = (e: React.ChangeEvent<HTMLInputElement>) => { const newTitle = e.target.value; setShowText(newTitle); }; const titleBlur = () => { const newTitle = showText || '無標題'; const oldTitle = props.text; setIsFocus(false); if (showText !== oldTitle) { setShowText(newTitle); setIsFocus(false); if (props?.changeText) { props.changeText(newTitle); } } else { setIsFocus(false); setShowText(newTitle); } }; return ( <div className='wrap'> {props.canEdit ? ( <input value={showText} style={{ width: inputWith }} onFocus={titleFocus} onChange={titleInput} onBlur={titleBlur} className='input' placeholder="無標題" /> ) : ( '' )} {/* 為了計算文字的寬度 */} <span ref={witdthRef} className={props.canEdit ? 'width' : 'text'}> {showText} </span> </div> ); }
到此,關于“怎么使用react編寫可編輯標題”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。