中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

怎么使用react編寫可編輯標題

發布時間:2022-08-24 10:50:07 來源:億速云 閱讀:112 作者:iii 欄目:開發技術

這篇文章主要介紹“怎么使用react編寫可編輯標題”,在日常操作中,相信很多人在怎么使用react編寫可編輯標題問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”怎么使用react編寫可編輯標題”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!

    需求

    初始需求

    • 文案支持可編輯

    • 用戶點擊位置即光標定位處

    • 超過50字讀的時候,超出部分進行截斷

    • 當用戶把所有內容刪除時,失去焦點時文案設置為 “無文案”三個字

    • 編輯區域隨著編輯內容的寬度而變化,最大寬度1000px 500px

    • 失去焦點時保存文案內容

    方案設計

    在看到第一眼需求的時候,想到的時候用span和input進行切換,但是這個肯定是滿足不了需求中第2點,所以首先這個需求肯定不會是兩個 標簽切換,只能一個標簽承擔展示和編輯的功能,第一反應是用html屬性contentEditable,就有了我的第一個套方案,后因為需求的第三點實現上存在問題,所以被迫換了方案二(使用input標簽),下面我們詳細說說為啥棄用方案1選用方案二以及在這過程中遇到的問題。

    方案一 span + contentEditable

    思路
    • 利用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框樣式的方法,讓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編寫可編輯標題”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    AI

    崇礼县| 海淀区| 无为县| 肥东县| 延长县| 伊吾县| 大理市| 荆州市| 竹山县| 土默特右旗| 利川市| 登封市| 镇安县| 缙云县| 马关县| 霍州市| 福安市| 平阴县| 怀集县| 九龙城区| 五河县| 安仁县| 比如县| 渭源县| 元阳县| 屯昌县| 拉萨市| 潮安县| 庐江县| 大化| 宁明县| 磐安县| 神木县| 通化县| 泸定县| 中方县| 嵊泗县| 甘肃省| 张家界市| 乐东| 吴江市|