我如何在 React 组件内定位 DOM 元素,或者我应该避免同时定位 DOM 元素?

tim*_*imo 9 dom reactjs

我创建了一个脚本,该脚本在父容器上的鼠标悬停时激活,并且应该将其子元素从鼠标移开。我目前已经让它工作了,但代码的某些部分似乎与 REACT 代码的外观相矛盾。特别是两部分。

  1. 我在渲染函数中使用了一个计数器,以便每个跨度都能获得正确的自定义属性,state.customProperties该自定义属性是一个数组,该数组在父元素鼠标悬停时更新自定义属性。

    render() {
        let counter = 0;
        const returnCustomProp = function(that) {
            counter++;
            let x = 0;
            if (that.state.customProperties[counter - 1]) {
                x = that.state.customProperties[counter - 1].x;
            }
            let y = 0;
            if (that.state.customProperties[counter - 1]) {
                y = that.state.customProperties[counter - 1].y;
            }
            return "customProperty(" + x + " " + y + ")";
        }
        return (
            <div onMouseMove={this._testFunction} id="ParentContainer">
                    <section custom={returnCustomProp(this)}>
                        <b>Custom content for part 1</b>
                        <i>Could be way different from all the other elements</i>
                    </section>
                    <section custom={returnCustomProp(this)}>
                        2
                    </section>
                    <section custom={returnCustomProp(this)}>
                        <div>
                            All content can differ internally so I'm unable to create a generic element and loop trough that
                        </div>
                    </section>
                    <section custom={returnCustomProp(this)}>
                        4
                    </section>
                    <section custom={returnCustomProp(this)}>
                        5
                    </section>
                    <section custom={returnCustomProp(this)}>
                        <div>
                            <b>
                                This is just test data, the actualy data has no divs nested inside secions
                            </b>
                            <h1>
                                6
                            </h1>
                        </div>
                    </section>
                    <section custom={returnCustomProp(this)}>
                        7
                    </section>
                    <section custom={returnCustomProp(this)}>
                        8
                    </section>
                </div>
        );
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 在 mousemove 函数中,我使用document.getElementByIdquerySelectorAll获取所有截面元素并将鼠标的鼠标坐标与截面元素坐标进行比较。

    var mouseX = e.pageX;
    var mouseY = e.pageY;
    var spans = document.getElementById('ParentContainer').querySelectorAll('section');
    var theRangeSquared = 10 * 10;
    var maxOffset = 5;
    var newCustomProperties = [];
    for (var i = 0; i < spans.length; i++) {
        var position = spans[i].getBoundingClientRect();
        var widthMod = position.width / 2;
        var heightMod = position.height / 2;
        var coordX = position.x + widthMod;
        var coordY = position.y + heightMod + window.scrollY;
        // Distance from mouse
        var dx = coordX - mouseX;
        var dy = coordY - mouseY;
        var distanceSquared = (dx * dx + dy * dy);
        var tx = 0,
            ty = 0;
        if (distanceSquared < theRangeSquared && distanceSquared !== 0) {
            // Calculate shift scale (inverse of distance)
            var shift = maxOffset * (theRangeSquared - distanceSquared) / theRangeSquared;
            var distance = Math.sqrt(distanceSquared);
            tx = shift * dx / distance;
            ty = shift * dy / distance;
        }
        newCustomProperties.push({
            x: tx,
            y: ty
        });
    }
    
    Run Code Online (Sandbox Code Playgroud)

我有一种感觉,我将这一切都错了。我不确定如何在保留通用returnCustomProp函数以返回所述元素的属性的同时避免使用计数器(在实时代码中,我有大约 200 个这些元素,因此手动为它们设置数组项编号效率不高) .

第二部分通过实际组件内的 ID 定位元素感觉很糟糕。我觉得我应该能够在不遍历 DOM 的情况下定位它。引用 section 元素可能是一个解决方案,但我相信引用应该保持在最低限度,正如所述,实际代码由数百个这样的部分组成。

JSFIDDLE

代码不会比更新custom="customProperty(0 0)"属性做更多的 atm 。您可以通过鼠标悬停时的元素检查器看到这种情况。

我可以让这个功能工作而不必计算<section>渲染函数中的元素而不必使用document.querySelectorAll吗?

joy*_*joy 8

如何在 React 组件中定位 DOM 元素?

根据 React 的官方文档,您可以使用 refs 访问 dom 元素。您必须使用React.createRef()调用创建一个引用。

我应该完全避免针对 DOM 元素吗?

遍历 dom 以获取特定的 dom 元素对于 React 来说不是一个好习惯,因为它会导致性能问题。但是,react 允许通过使用createRef().

我可以在不必计算渲染函数内的元素并且不必使用 document.querySelectorAll 的情况下使此功能工作吗?

是的,请考虑以下步骤来实现这一点:

在构造函数中,为 parentContainer 创建一个 ref,如下所示:

  this.ParentContainer=React.createRef();
Run Code Online (Sandbox Code Playgroud)

然后在渲染中使用 parentContainer ref:

    <div onMouseMove={this._testFunction} id="ParentContainer" 
      ref={this.ParentContainer} >
Run Code Online (Sandbox Code Playgroud)

在测试组件中,使用 this.parentContainer 作为:

//replace this 
//var spans = document.getElementById('ParentContainer').querySelectorAll('section');
//with this
  var spans = this.parentContainer.current.childNodes;
Run Code Online (Sandbox Code Playgroud)

你可以在这里查看

编辑

关于如何解决不得不在渲染函数中使用 let 计数器的任何想法

您可以returnCustomProp像这样定义外部渲染:(在这里您需要传递每个部分的索引而不是this引用)

    returnCustomProp = (index)=> {
      let x = 0;
      if(this.state.customProperties[index]) {
          x = this.state.customProperties[index].x;
      }
      let y = 0;
      if(this.state.customProperties[index]) {
          y = this.state.customProperties[index].y;
      }
      return "customProperty("+x+" "+y+")";
    }
Run Code Online (Sandbox Code Playgroud)

并将其与这样的部分一起使用:

   <section custom={returnCustomProp(0)}>
            <b>Custom content for part 1</b>
            <i>Could be way different from all the other elements</i>
        </section>
        <section custom={returnCustomProp(1)}>
            2
        </section>
        <section custom={returnCustomProp(2)}>
            <div>
                All content can differ internally so I'm unable to create a generic element and loop trough that
            </div>
        </section>
        <section custom={returnCustomProp(3)}>
            4
        </section>
        <section custom={returnCustomProp(4)}>
            5
        </section>
        <section custom={returnCustomProp(5)}>
            <div>
                <b>
                    This is just test data, the actual data has no divs nested inside sections
                </b>
                <h1>
                    6
                </h1>
            </div>
        </section>
        <section custom={returnCustomProp(6)}>
            7
        </section>
        <section custom={returnCustomProp(7)}>
            8
        </section>
Run Code Online (Sandbox Code Playgroud)