怎么使用react编写可编辑标题

发布时间:2022-08-24 10:50:07 作者:iii
来源:亿速云 阅读:112

这篇文章主要介绍“怎么使用react编写可编辑标题”,在日常操作中,相信很多人在怎么使用react编写可编辑标题问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”怎么使用react编写可编辑标题”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

需求

初始需求

方案设计

在看到第一眼需求的时候,想到的时候用span和input进行切换,但是这个肯定是满足不了需求中第2点,所以首先这个需求肯定不会是两个 标签切换,只能一个标签承担展示和编辑的功能,第一反应是用html属性contentEditable,就有了我的第一个套方案,后因为需求的第三点实现上存在问题,所以被迫换了方案二(使用input标签),下面我们详细说说为啥弃用方案1选用方案二以及在这过程中遇到的问题。

方案一 span + contentEditable

思路

但是 需求点中的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框样式的方法,让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编写可编辑标题”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注亿速云网站,小编会继续努力为大家带来更多实用的文章!

推荐阅读:
  1. 如何使用HTML书写标题
  2. React项目动态设置title标题的方法示例

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

react

上一篇:el-table点击某一行高亮并显示小圆点怎么实现

下一篇:微信小程序全屏滚动字幕如何实现

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》