【问题标题】:D3.js v4: Access current DOM element in ES6 arrow function event listenerD3.js v4:在 ES6 箭头函数事件监听器中访问当前 DOM 元素
【发布时间】:2017-05-22 19:20:46
【问题描述】:

在 D3.js v4 中,通过传统回调函数注册事件监听器时,this 引用当前 DOM 元素:

d3.select("div").on('mouseenter', function() {
  d3.select(this).text("Yay");
});

ES6 提供了箭头函数,恕我直言,这使得 D3.js 代码更具可读性,因为它们非常简洁。但是,传统的回调不能一味的用箭头函数代替:

d3.select("div").on('mouseenter', () => {
  d3.select(this); // undefined
});

文章“On D3 and Arrow Functions”很好地解释了为什么this没有按预期绑定。文章建议对需要访问当前 DOM 元素的代码使用传统的回调。

是否可以通过箭头函数访问当前的 DOM 元素?

【问题讨论】:

    标签: d3.js ecmascript-6 arrow-functions


    【解决方案1】:

    在 D3 中有一种惯用的方法:只需使用不太知名的第三个​​参数

    selection.on("mouseenter", (d, i, nodes) => {
        d3.select(nodes[i]);
    });
    

    这也是:

    selection.on("mouseenter", function() {
        d3.select(this);
    });
    

    我在这里写了一个例子:d3 v4 retrieve drag DOM target from drag callback when `this` is not available

    这是一个演示:

    d3.selectAll("circle").on("mouseover", (d, i, p) => {
            d3.select(p[i]).attr("fill", "maroon")
        })
        .on("mouseout", (d, i, p) => {
            d3.select(p[i]).attr("fill", "seagreen")
        });
    <script src="https://d3js.org/d3.v4.min.js"></script>
    <svg>
    	<circle cx="50" cy="50" r="20" fill="seagreen"></circle>
    	<circle cx="125" cy="50" r="20" fill="seagreen"></circle>
    	<circle cx="200" cy="50" r="20" fill="seagreen"></circle>
    </svg>

    实际上,如果您查看链接的文章的末尾,他给出了相同的解决方案。

    您的proposed solutiond3.event.target 尽管为事件侦听器工作,但在某些情况下不起作用。例如:

    d3.selectAll("circle").each(()=&gt;d3.select(d3.event.target).attr("fill", "red"))
    <script src="https://d3js.org/d3.v4.min.js"></script>
    <svg>
    	<circle cx="50" cy="50" r="20" fill="seagreen"></circle>
    	<circle cx="125" cy="50" r="20" fill="seagreen"></circle>
    	<circle cx="200" cy="50" r="20" fill="seagreen"></circle>
    </svg>

    但同样的代码使用第三个参数起作用:

    d3.selectAll("circle").each((d,i,p)=&gt;d3.select(p[i]).attr("fill", "red"))
    <script src="https://d3js.org/d3.v4.min.js"></script>
    <svg>
    	<circle cx="50" cy="50" r="20" fill="seagreen"></circle>
    	<circle cx="125" cy="50" r="20" fill="seagreen"></circle>
    	<circle cx="200" cy="50" r="20" fill="seagreen"></circle>
    </svg>

    【讨论】:

    • 谢谢,我知道这个解决方案。虽然它可能是“惯用的”方式,但恕我直言 d3.select(d3.event.target)d3.select(nodes[i]) 更具可读性。但最好有多种方法,以便人们可以选择!
    • 我不知道d3.event.target 是否“更具可读性”,这是基于意见的。但我知道这一点:它 notthis 相同,更重要的是,它仅适用于特定情况(我知道您问题标题中的“事件侦听器”)。查看我的编辑。
    • 是的,我同意,我对可读性的评论是特定于事件侦听器示例的。
    【解决方案2】:

    可以使用 ES6 箭头函数并通过 d3.event.target 访问当前 DOM 元素:

    d3.select("div").on('mouseenter', () => {
      d3.select(d3.event.target).text("Yay, this works!");
    });
    

    【讨论】:

    • 您的意思是devent 参数吗?
    • 不,我的意思是d3.eventd 并没有实际使用,为了清楚起见我将其删除...
    • 是的,有可能,但有什么意义呢?它当然不比普通函数更具可读性。箭头函数的目的是提供词法this。对于没有考虑到这个问题的旧库来说,情况并非如此。
    • 对于像.attr("x", d =&gt; xScale(d)) 这样简单的东西,它们当然更具可读性。就个人而言,我宁愿始终如一地使用它们,即不与传统语法混合使用。但这只是我的两分钱(来自 Scala / FP)。
    • 当然,不客气。即使是熟悉的事物在不同的语言中也可能具有不同的语义。顺便说一句,当 SO cmets 中有超过 1 名受访者时,应直接使用@netzwerg 联系用户。我看到你最后的评论纯属偶然。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-02-18
    • 1970-01-01
    • 1970-01-01
    • 2020-03-17
    • 2014-05-11
    • 2016-02-27
    • 2013-10-06
    相关资源
    最近更新 更多