第
react编写可编辑标题示例详解
目录需求初始需求方案设计方案一span+contentEditable思路代码如下在这个方案中遇到的问题存在的问题方案二直接用input处理展示和编辑踩到的坑
需求
因为自己换工作到了新公司,上周入职,以前没有使用过react框架,虽然前面有学习过react,但是并没有实践经验
这个需求最终的效果是和石墨标题修改实现一样的效果
初始需求
文案支持可编辑用户点击位置即光标定位处超过50字读的时候,超出部分进行截断当用户把所有内容删除时,失去焦点时文案设置为无文案三个字编辑区域随着编辑内容的宽度而变化,最大宽度1000px500px失去焦点时保存文案内容
方案设计
在看到第一眼需求的时候,想到的时候用span和input进行切换,但是这个肯定是满足不了需求中第2点,所以首先这个需求肯定不会是两个标签切换,只能一个标签承担展示和编辑的功能,第一反应是用html属性contentEditable,就有了我的第一个套方案,后因为需求的第三点实现上存在问题,所以被迫换了方案二(使用input标签),下面我们详细说说为啥弃用方案1选用方案二以及在这过程中遇到的问题。
方案一span+contentEditable
思路
利用h5提供contentEditble,可实现需求点的1/2/5监听focus事件和input时间,可以实现需求点4监听blur事件,可以实现需求点3
但是需求点中的3点,因为是用字数做的截断,在这个方案中是实现不了的,所以我给出的建议方案是编辑的时候不做截断,非编辑的时候做截断段(是否失去焦点可用作判断是否为编辑态的依据)
代码如下
演示demo:
importReact,{useState,useRef,useEffect}fromreact;
importReactDomfromreact-dom;
interfaceEditTextProps{
text:string;
//告知父组件文案已被修改
changeText:(text:string)=void;
constEditText=function(props:EditTextProps){
useEffect(()={
setShowText(props.text);
},[props.text]);
const[showText,setShowText]=useState();
const[isBlank,setIsBlank]=useState(false);
const[isFocus,setIsFocus]=useState(false);
consttextRef=useRefHTMLDivElement(null);
constonFocus=()={
setIsFocus(true)
constonInput=()={
//避免失去焦点的时候,标题区域明显的闪动
setIsBlank(!textRef.current.innerHTML);
constonBlur=()={
constnewTitle=textRef.current.innerHTML||无标题;
constoldTitle=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个字符
constgetCharsByLength=(title:string,length:number)={
consttitleLength=title.length;
//假设都是非中文字符,一个中文字符的宽度可以显示两个非