反应用输入替换event.target

时间:2018-08-14 15:53:52

标签: javascript reactjs

更新 这是一些演示

contentEditable demo-需要双击才能使H1变为可编辑状态

replace with input demo-采用event.target样式,但在渲染时使UI“抽搐”


所以我有一些功能组件,比如:

component1.js

import React from 'react';
const component1 = props => (
<div>
 <h1>Title</h1>
</div>
);
export { component1 };

它们是可变的。 event.target可以是任何带有文本的内容,因此,段落,标题都可以。我试图让用户通过单击内容来内联编辑内容,因此我将一个函数editMode传递给这些功能组件,这将通过编辑信息来更新父状态,就像这样:

<h1 onClick={event => {editMode(event, props.name, props.title, 'title')}}>title</h1>

这会将父本地状态更改为具有所有必要信息,以便从redux获取值,定义目标等。在此示例中,props.name是组件的名称,props.title是值,而'title'是redux中的对象键。

因此,我将添加一些内容到 component1.js 中,并使它看起来像这样:

import React from 'react';
const component1 = props => (
    <div>
        {props.editState === 'true' &&
            <EditLayout
                name={props.name}
                target={props.target}
                value={props.value}
                onChange={event => someFunc(event)}
            />
        }
        <h1>Title</h1>
    </div>
    );
export { component1 };

现在这可以正常工作,只是无法缩放。在这种情况下,EditLayout将仅返回具有正确值的输入。我需要做的是适应单击的内容,获取字体大小,背景,填充,边距,位置。我这样做对吗?我尝试的每种方式都遇到了巨大的问题:

想法1-将EditLayout组件移到功能组件之外

问题:定位

因此,我将把EditLayout移到同时包含component1.jsEditLayout的父组件中。这将使我能够从功能组件内部进行操作,而不必在所有位置都包含它。然后,我将像这样从event.target获取坐标和其他重要信息:

const coords = event.target.getBoundingClientRect();
const offsetX = coords.left;
const offsetY = coords.top;
const childHeight = coords.height;
const childWidth = coords.width;
const childClass = event.target.className;

然后我将包装EditLayout以返回一个包含输入的容器,并将尺寸/坐标应用于绝对定位的容器。这将产生一个输入会被随机像素偏移的问题,具体取决于event.target的大小/位置。

想法2-将相关的计算样式传递给EditLayout

问题:在渲染时抽搐,我必须为每个可能的EditLayout添加event.target,并对其渲染条件进行限制

所以我将抓住所有重要的计算样式,如下所示:

const computedTarget = window.getComputedStyle(event.target);
const childMargins = computedTarget.marginBottom;
const childPaddings = computedTarget.padding;
const childFontSize = computedTarget.fontSize;
const childTextAlign = computedTarget.textAlign;

并将其传递到component1.js,然后将其传递到EditLayout event.target内的component1.js. I'll then condition the组件以隐藏它是否被编辑,如下面这样:

<h1 className={ props.target === 'title' ? 'd-none' : ''}>Title</h1>

并设置EditLayout仅在需要时显示:

{props.target === 'title' && <EditLayout />}

在此示例中,单击h1将显示输入,但是布局本身在渲染时带有抽搐。输入将具有与h1或event.target完全相同的页边距和字体大小,但它会显得更大并扩展布局。演示:

enter image description here

想法3-使用条件内容可编辑

问题:需要双击才能启用,在safari中不起作用,不允许我预先选择值

这是所有人中最奇怪的。我认为这很简单,可以在功能组件render中执行以下操作:

<h1 contentEditable={props.target === 'title'} onClick={event => props.setTarget(event)}>Title</h1>

但是,我必须双击以启用它。我不知道为什么,如果每次触发onClick时都附加一个控制台日志,我将获得正确的输出,我也将获得正确的目标值。我已经尝试了多种方法,但是只需要双击即可。甚至尝试在功能组件内部处理此问题,因为大多数内容都是由父组件处理的,没有任何区别。

我简化了示例,因此可以安全地假设/理解以下内容:

  • 我正在以正确的方式传递道具,它们不是不确定的
  • 我正在使用引导程序
  • 我正在使用样式化的组件,而EditLayout是样式化的组件 它接受道具并将其变成CSS,例如:font-size: ${props => props.fontSize};
  • 值应该是正确的,我没有处理从getComputedStyle()getBoundingClientRect()返回的任何内容
  • 我热衷于保持功能组件的功能性,并且易于使用 加。在这种情况下,功能组件是简单的HTML结构, 并且我想让它们尽可能简单

1 个答案:

答案 0 :(得分:0)

因此,有一个巧妙的解决方案,contentEditable需要两次单击而不是单击,而不是绑定onClick并传递以启用contentEditable,只需保持contentEditable为真并处理即可随你喜欢而改变。这是一个有效的h1,与演示中的点击不同,无需点击两次即可启用contentEditable

<h1
    className="display-4 text-center"
    contentEditable
    suppressContentEditableWarning
    onBlur={event =>  updateValues(event)}
>
    Title 
</h1>

触发器更新的可用方法可以是onBluronInput