在浏览器中打开URL时反应滚动以定位

时间:2019-07-12 07:53:23

标签: javascript html reactjs

可以说我有组件“ Post”,其中包含多个组件“ Comment”。当我输入如下网址时,我想使该应用程序向下滚动到具有该锚点的注释:

private static void getEmployees()
{
   final String uri = "http://localhost:8080/springrestexample/employees.xml";

   RestTemplate restTemplate = new RestTemplate();
   String result = restTemplate.getForObject(uri, String.class);

   System.out.println(result);
}

我已经在使用postId路由/post/:postId/#commentId

我试图用react-hash-link npm包实现它,但是它没有按预期工作。

每个注释都具有在组件上设置的自己的ID,如下所示:

/post/:postId

例如,如果我打开如下网址:

<div class="post">
   <div class="post-header">
      <div class="post-header-avatar">
        SOME TEXT
      </div>
      <div class="post-header-info">
        SOME TEXT
      </div>
   </div>
   <div class="post-content">
      <span>POST CONTENT</span>
   </div>
   <div class="post-likers-container">
      <div class="post-likers-header label">People who like this post</div>
      <div class="post-likers">
          SOME TEXT
      </div>
   </div>
   <div class="post-comments">
      <div class="comments ">
         <div class="comments-all label">Comments</div>
         <div class="comments">
            <div class="comment" id="5d27759edd51be1858f6b6f2">
               <div class="comment-content">
               COMMENT 1 TEXT
               </div>
            </div>
            <div class="comment" id="5d2775b2dd51be1858f6b720">
               <div class="comment-content">
               COMMENT 2 TEXT
               </div>
            </div>
            <div class="comment" id="5d2775ecdd51be1858f6b753">
               <div class="comment-content">
                COMMENT 3 TEXT
               </div>
            </div>
         </div>
      </div>
   </div>
</div>

我想打开帖子页面,并使用#锚点向下滚动到评论。

有什么办法可以实现这一目标?

4 个答案:

答案 0 :(得分:1)

我真的很喜欢您的解决方案@SaltyTeemooo。受到它的启发,我发现了没有任何回调的更简单的方法。

我的设置非常相似,所以可以说我正在处理帖子和评论。

Post中,我像这样创建Comment(简化)并传递anchorId:

<Comments anchorId={window.location.href.slice(window.location.href.indexOf("#") + 1)} props... />

Comments中,将锚点ID传递到Comment.js

<Comment anchorId={props.anchorId} props.../>

然后在Comment中,将当前元素滚动到视图中(如果它是链接的元素)

import React, { useRef, useEffect } from 'react';

function Comment () {

    const comment = useRef(null); //to be able to access the current one

    useEffect(() => {
        if(props.anchorId === props.commentData.id)
        {
            comment.current.scrollIntoView({ behavior: "smooth" });
        }
    }, []) //same as ComponentDidMount

    
    return(
       <div id={props.commentData.id} ref={comment}> //here is where the ref gets set
           ...
       </div>
    )
}

答案 1 :(得分:0)

保证...

import React, { useEffect } from 'react';

const MainApp = () => {

    const MyRef = React.createRef();

    useEffect(() => { // Same like ComponentDidMount().
        scrollTo();
    })

    const scrollTo = () => {
        window.scrollTo({
            top:myRef.offsetTop, 
            behavior: "smooth" // smooth scroll.
        });   
    }

        return (
            <div ref={MyRef}>My DIV to scroll to.</div>
        )
}

答案 2 :(得分:0)

花相当多的时间,但是请尝试以下沙箱:https://codesandbox.io/s/scrollintoview-with-refs-and-redux-b881s

这将为您提供大量有关如何使用URL参数滚动到元素的见识。

import React from "react";
import { connect } from "react-redux";
import { getPost } from "./postActions";

class Post extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      activeComment: null
    };

    this._nodes = new Map();
  }

  componentDidMount() {
    this.props.getPost(this.props.match.params.id);
    const path = window.location.href;
    const commentId = path.slice(path.indexOf("#") + 1);
    if (commentId) {
      this.setState({
        activeComment: commentId
      });
    }
  }

  componentDidUpdate(prevProps, prevState) {
    if (this.state.activeComment !== prevState.activeComment) {
      this.scrollToComment();
    }
  }

  scrollToComment = () => {
    const { activeComment } = this.state;
    const { comments } = this.props.posts.post;
    const nodes = [];
    //Array.from creates a new shallow-copy of an array from an array-like or iterable object
    Array.from(this._nodes.values()) //this._nodes.values() returns an iterable-object populated with the Map object values
      .filter(node => node != null)
      .forEach(node => {
        nodes.push(node);
      });

    const commentIndex = comments.findIndex(
      comment => comment.id == activeComment
    );

    if (nodes[commentIndex]) {
      window.scrollTo({
        behavior: "smooth",
        top: nodes[commentIndex].offsetTop
      });
    }
  };

  createCommentList = () => {
    const { post } = this.props.posts;
    const { activeComment } = this.state;

    if (post) {
      return post.comments.map((comment, index) => {
        return (
          <div
            key={comment.id}
            className={
              "comment " + (activeComment == comment.id ? "activeComment" : "")
            }
            ref={c => this._nodes.set(comment.id, c)}
          >
            {comment.text}
          </div>
        );
      });
    }
  };

  displayPost = () => {
    const { post } = this.props.posts;

    if (post) {
      return (
        <div className="post">
          <h4>{post.title}</h4>
          <p>{post.text}</p>
        </div>
      );
    }
  };

  render() {
    return (
      <div>
        <div>{this.displayPost()}</div>
        <div>{this.createCommentList()}</div>
      </div>
    );
  }
}

const mapStateToProps = state => {
  return {
    posts: state.posts
  };
};

const mapDispatchToProps = dispatch => {
  return {
    getPost: postId => {
      dispatch(getPost(postId));
    }
  };
};

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(Post);

答案 3 :(得分:0)

我设法为我的用例找到了简单的解决方案,而没有为引用创建引用,也没有传递引用等。由于我的组件层次结构是这样的:

  1. Post->渲染组件Comments
  2. Comments->渲染     从Comment传递道具数据的多个组件Post

Post组件中,我创建了函数:

scrollToComment= () => {
    let currentLocation = window.location.href;
    const hasCommentAnchor = currentLocation.includes("/#");
    if (hasCommentAnchor) {
      const anchorCommentId = `${currentLocation.substring(currentLocation.indexOf("#") + 1)}`;
      const anchorComment = document.getElementById(anchorCommentId);
      if(anchorComment){
          anchorComment.scrollIntoView({ behavior: "smooth" });
      }
    }
  }

然后我像这样渲染Comments

<Comments limit={limit} post={post} scrollToComment={this.scrollToComment} />

Comments中,我经过如下排序后生成评论:

{sortedComments.map((comment, i) => <Comment key={i} {...comment} scrollToComment={this.props.scrollToComment}/> )}

最后在Comment组件中,我在scrollToComment中执行ComponentDidMount()

if(this.props.scrollToComment)
    this.props.scrollToComment(this.props._id);

之后,当我转到某个URL时,可以平滑滚动到URL哈希部分中指定的注释。

我尝试了@Christopher解决方案,但对我没有用。