<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
因為自己換工作到了新公司,上週入職,以前沒有使用過react框架,雖然前面有學習過react,但是並沒有實踐經驗
這個需求最終的效果是和石墨標題修改實現一樣的效果
在看到第一眼需求的時候,想到的時候用span和input進行切換,但是這個肯定是滿足不了需求中第2點,所以首先這個需求肯定不會是兩個 標籤切換,只能一個標籤承擔展示和編輯的功能,第一反應是用html屬性contentEditable,就有了我的第一個套方案,後因為需求的第三點實現上存在問題,所以被迫換了方案二(使用input標籤),下面我們詳細說說為啥棄用方案1選用方案二以及在這過程中遇到的問題。
但是 需求點中的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的更新,針對這個問題我找到了兩個解決方式
嘗試了一下這個方案,從使用角度來說並不會特別明顯的閃動。不過個人覺得這個方案程式碼看著很怪異
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) } }
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> ); }
input自頻寬度,無法實現寬度隨著文案的改變而改變。
在方案一做出來後,就和UI進行了溝通在【編輯的時候用字數做截斷實現不了】,給出了一個建議的方案【編輯的時候不做截斷】,但是設計同學覺得不截斷的方案過醜,,,,,然後她就說能實現 【石墨標題編輯】時,類似的效果互動嗎???於是我就開啟了研究石墨的效果的征途中。
只發現 石墨用了一個input實現了不錯的效果,input後面放了一個span標籤,我體驗的時候,一直在想為什麼會有一個span標籤呢??(小朋友,是不是滿臉疑問)
直到我發現input自頻寬度,無法隨著內容的寬度的改變而改變。此時才恍然大悟span標籤的作用。
我也採用了利用span標籤的寬度的方式來控input輸入內容的寬度。
開玩笑,咋可能這麼順利,我遇到了第二個問題
用useEffect 來監控 witdthRef.current.offsetWidth
時,拿到的是上次文案的寬度 經過查閱資料,我發現了useLayoutEffect
這個hook,真香
以上就是react編寫可編輯標題範例詳解的詳細內容,更多關於react編寫可編輯標題的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45