Javascript 在 React 中获取 div 的 offsetTop 位置
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/32667847/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Get div's offsetTop positions in React
提问by JavaScripter
I am trying to implement a List view in React.
What I am trying to achieve is that to store the list headers informations and register the components and register the scroll event.
every time when user scroll the window, I'd like to take out the stored div and re-calculate the offsetTop
data.
我正在尝试在 React 中实现一个列表视图。我想要实现的是存储列表标题信息并注册组件并注册滚动事件。每次当用户滚动窗口时,我想取出存储的 div 并重新计算offsetTop
数据。
The problem now is that, I found the console just print out the initial value (the value is fixed and never changed) offsetTop
data never change in onscroll
function.
现在的问题是,我发现控制台只是打印出初始值(该值是固定的,永远不会改变)offsetTop
数据在onscroll
功能上永远不会改变。
Anyone suggest how to get latest offsetTop
from the _instances
object?
有人建议如何offsetTop
从_instances
对象中获取最新信息吗?
import React, { Component } from 'react';
import ListHeader from './lib/ListHeader';
import ListItems from './lib/ListItems';
const styles = {
'height': '400px',
'overflowY': 'auto',
'outline': '1px dashed red',
'width': '40%'
};
class HeaderPosInfo {
constructor(headerObj, originalPosition, originalHeight) {
this.headerObj = headerObj;
this.originalPosition = originalPosition;
this.originalHeight = originalHeight;
}
}
export default class ReactListView extends Component {
static defaultProps = {
events: ['scroll', 'mousewheel', 'DOMMouseScroll', 'MozMousePixelScroll', 'resize', 'touchmove', 'touchend'],
_instances:[],
_positionMap: new Set(),
_topPos:'',
_topWrapper:''
}
static propTypes = {
data: React.PropTypes.array.isRequired,
headerAttName: React.PropTypes.string.isRequired,
itemsAttName: React.PropTypes.string.isRequired,
events: React.PropTypes.array,
_instances: React.PropTypes.array,
_positionMap: React.PropTypes.object,
_topPos: React.PropTypes.string,
_topWrapper: React.PropTypes.object
};
state = {
events: this.props.events,
_instances: this.props._instances,
_positionMap: this.props._positionMap,
_topPos: this.props._topPos
}
componentDidMount() {
this.initStickyHeaders();
}
componentWillUnmount() {
}
componentDidUpdate() {
}
refsToArray(ctx, prefix){
let results = [];
for (let i=0;;i++){
let ref = ctx.refs[prefix + '-' + String(i)];
if (ref) results.push(ref);
else return results;
}
}
initHeaderPositions() {
// Retrieve all instance of headers and store position info
this.props._instances.forEach((k)=>{
this.props._positionMap.add(new HeaderPosInfo(
k,
k.refs.header.getDOMNode().offsetTop,
k.refs.header.getDOMNode().offsetHeight
));
});
let it = this.props._positionMap.values();
let first = it.next();
this.props._topPos = first.value.originalPosition;
this.props._topWrapper = first.value.headerObj;
}
initStickyHeaders () {
this.props._instances = this.refsToArray(this, 'ListHeader');
this.initHeaderPositions();
// Register events listeners with the listview div
this.props.events.forEach(type => {
if (window.addEventListener) {
React.findDOMNode(this.refs.listview).addEventListener(type, this.onScroll.bind(this), false);
} else {
React.findDOMNode(this.refs.listview).attachEvent('on' + type, this.onScroll.bind(this), false);
}
});
}
onScroll() {
// update current header positions and apply fixed positions to the top one
console.log(1);
let offsetTop = React.findDOMNode(this.props._instances[0].refs.header).offsetTop;
}
render() {
const { data, headerAttName, itemsAttName } = this.props;
let _refi = 0;
let makeRef = () => {
return 'ListHeader-' + (_refi++);
};
return (
<div ref="listview" style={styles}>
{
Object.keys(data).map(k => {
const header = data[k][headerAttName];
const items = data[k][itemsAttName];
return (
<ul key={k}>
<ListHeader ref={makeRef()} header={header} />
<ListItems items={items} />
</ul>
);
})
}
</div>
);
}
}
The whole source code is on Github, you can clone and compile it from here:
整个源代码都在 Github 上,你可以从这里克隆和编译它:
回答by Eugene Tiurin
You may be encouraged to use the Element.getBoundingClientRect()method to get the top offset of your element. This method provides the full offset values (left, top, right, bottom, width, height) of your element in the viewport.
可能会鼓励您使用Element.getBoundingClientRect()方法来获取元素的顶部偏移量。此方法在视口中提供元素的完整偏移值(左、上、右、下、宽、高)。
Check the John Resig's postdescribing how helpful this method is.
查看描述此方法有多大帮助的John Resig 的帖子。
回答by sonarforte
Eugene's answer uses the correct function to get the data, but for posterity I'd like to spell out exactly how to use it in React v0.14+ (according to this answer):
Eugene 的答案使用正确的函数来获取数据,但为了后代,我想详细说明如何在 React v0.14+ 中使用它(根据这个答案):
import ReactDOM from 'react-dom';
//...
componentDidMount() {
var rect = ReactDOM.findDOMNode(this)
.getBoundingClientRect()
}
Is working for me perfectly, and I'm using the data to scroll to the top of the new component that just mounted.
非常适合我,我正在使用数据滚动到刚刚安装的新组件的顶部。
回答by Pavel Ye
I do realize that the author asks question in relation to a class-based component, however I think it's worth mentioning that as of React 16.8.0 (February 6, 2019)you can take advantage of hooks in function-based components.
我确实意识到作者提出了与基于类的组件相关的问题,但是我认为值得一提的是,从React 16.8.0(2019 年 2 月 6 日)开始,您可以利用基于函数的组件中的钩子。
Example code:
示例代码:
import { useRef } from 'react'
function Component() {
const inputRef = useRef()
return (
<input ref={inputRef} />
<div
onScroll={() => {
const { offsetTop } = inputRef.current
...
}}
>
)
}
回答by Chikwado
A quicker way if you are using React 16.3 and above is by creating a ref in the constructor, then attaching it to the component you wish to use with as shown below.
如果您使用 React 16.3 及更高版本,一个更快的方法是在构造函数中创建一个 ref,然后将其附加到您希望使用的组件,如下所示。
...
constructor(props){
...
//create a ref
this.someRefName = React.createRef();
}
}
onScroll(){
let offsetTop = this.someRefName.current.offsetTop;
}
}
render(){
...
<Component ref={this.someRefName} />
}
}
回答by Pietro
A better solution with ref to avoid findDOMNode that is discouraged.
使用 ref 的更好解决方案可以避免不鼓励的 findDOMNode。
...
onScroll() {
let offsetTop = this.instance.getBoundingClientRect().top;
}
...
render() {
...
<Component ref={(el) => this.instance = el } />
...
回答by rhigdon
import ReactDOM from 'react-dom';
//...
componentDidMount() {
var n = ReactDOM.findDOMNode(this);
console.log(n.offsetTop);
}
You can just grab the offsetTop from the Node.
您可以从节点中获取 offsetTop。