我不完全理解它,但显然it isn't recommended to use findDOMNode()。
我尝试创建拖放组件,但我不确定如何从组件变量访问refs。这是我目前拥有的一个例子:
const cardTarget = {
hover(props, monitor, component) {
...
// Determine rectangle on screen
const hoverBoundingRect = findDOMNode(component).getBoundingClientRect();
...
}
}
修改
这可能是由于我的组件既是拖放源又是目标,因为我可以在this example中使用它而不是this one。
答案 0 :(得分:20)
假设您正在使用es6类语法和最新版本的React(15,在撰写本文时),您可以在您共享的链接上附加一个回调参考,就像Dan在他的示例中所做的那样。来自the docs:
当在HTML元素上使用ref属性时,ref回调接收底层DOM元素作为其参数。例如,此代码使用ref回调来存储对DOM节点的引用:
<h3
className="widget"
onMouseOver={ this.handleHover.bind( this ) }
ref={node => this.node = node}
>
然后您就可以像我们以前与我们的老朋友findDOMNode()
或getDOMNode()
一样访问该节点:
handleHover() {
const rect = this.node.getBoundingClientRect(); // Your DOM node
this.setState({ rect });
}
行动中: https://jsfiddle.net/ftub8ro6/
因为React DND在幕后做了一些魔术,我们必须使用他们的API来获取装饰组件。它们提供getDecoratedComponentInstance()
,因此您可以获得基础组件。使用后,您可以按预期获得component.node
:
hover(props, monitor, component) {
const dragIndex = monitor.getItem().index;
const hoverIndex = props.index;
const rawComponent = component.getDecoratedComponentInstance();
console.log( rawComponent.node.getBoundingClientRect() );
...
这是在行动:
答案 1 :(得分:2)
更好的解决方案是使用div
包装可拖动组件,在其上定义一个引用并将其传递给可拖动组件,即
<div key={key} ref={node => { this.node = node; }}>
<MyComponent
node={this.node}
/>
</div>
和MyComponent
包含在DragSource
中。现在你可以使用
hover(props, monitor, component) {
...
props.node && props.node.getBoundingClientRect();
...
}
(仅添加props.node &&
以避免在未定义的对象上调用getBoundingClientRect
)
findDOMNode
如果您不想添加换行div
,则可以执行以下操作。
@imjared和the suggested solution here的回复不起作用(至少在react-dnd@2.3.0
和react@15.3.1
中)。
findDOMNode(component).getBoundingClientRect();
唯一不使用findDOMNode
的替代方法是:
hover(props, monitor, component) {
...
component.decoratedComponentInstance._reactInternalInstance._renderedComponent._hostNode.getBoundingClientRect();
...
}
这不是很漂亮且危险,因为react
可能会在以后的版本中更改此内部路径!
使用monitor.getDifferenceFromInitialOffset();
,它不会为您提供精确的值,但如果您有一个小的 dragSource ,它可能已经足够了。然后,根据 dragSource 的大小,返回的值非常容易预测,误差范围很小。
答案 2 :(得分:0)
React-DnD
的API非常灵活 - 我们可以(ab)使用它。
例如,React-DnD允许我们确定将哪些连接器传递给底层组件。这意味着我们也可以包装它们。 :)
例如,让我们覆盖目标连接器以将节点存储在监视器上。我们将使用Symbol
,因此我们不会将这个小黑客泄露给外界。
const NODE = Symbol('Node')
function targetCollector(connect, monitor) {
const connectDropTarget = connect.dropTarget()
return {
// Consumer does not have to know what we're doing ;)
connectDropTarget: node => {
monitor[NODE] = node
connectDropTarget(node)
}
}
}
现在,在hover
方法中,您可以使用
const node = monitor[NODE]
const hoverBoundingRect = node.getBoundingClientRect()
这种方法依赖于React-DnD的流程,并使用Symbol
来屏蔽外部世界。
无论您是使用此方法还是基于类的this.node = node
ref方法,您都依赖于底层的React节点。我更喜欢这个,因为消费者不必记住手动使用除了React-DnD已经要求的ref
之外的import tkinter as tk
from tkinter import ttk
from PIL import Image, ImageTk
# Custom Label Class
class ResizingLabel(tk.Label): #inherit from Label Class
def __init__(self, parent, imagepath, *args, **kwargs): # specific for this Subclass: give me an image-path and resize image to label-size
tk.Label.__init__(self, parent, *args, **kwargs) # I can do everything what tk.Label can do
# Default configure settings (Label has no border)
self.configure(bd=0)
self.parent=parent
self.parent.bind('<Configure>', self._resize_image)
self.imagepath = imagepath
self.image = Image.open(self.imagepath)
self.img_copy= self.image.copy()
self.background_image = ImageTk.PhotoImage(self.image)
self.background = tk.Label(self, image=self.background_image,bd=0)
self.background.grid(row=0,column=0,sticky="NSEW")
self.background.grid_rowconfigure(0,weight=1)
self.background.grid_columnconfigure(0,weight=1)
self.background.bind('<Configure>', self._resize_image)
def _resize_image(self,event):
new_width = self.parent.winfo_width()
new_height = self.parent.winfo_height()
self.image = self.img_copy.resize((new_width, new_height))
self.background_image = ImageTk.PhotoImage(self.image)
self.background.configure(image = self.background_image)
# For the follwing code: See SentDex-Tutorial
LARGE_FONT= ("Verdana", 12)
class SeaOfBTC(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
tk.Tk.wm_title(self,"Sea of BTC")
container = tk.Frame()
container.pack(side="top", fill="both", expand = True)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
self.frames = {}
for F in (StartPage, PageOne):
frame = F(container,self)
self.frames[F] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame(StartPage)
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self,parent)
# Create string object with path
path = "banner.png"
# Create custom label with reference to path
label = ResizingLabel(self, path)
label.grid()
# Create example button on top of custom label
button = tk.Button(label,text="Example Button")
button.grid(column=0,row=0)
class PageOne(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
# This frame contains nothing (only exists so that for-loop (see above) can iterate)
app = SeaOfBTC()
app.mainloop()
,消费者也不必是类组件。