react-router 环境使用锚点的方法

锚点是通过在界面中增加一些特征(比如 id),然后在 URL 地址后面加上 #id 就可以访问到指定页面的指定位置,这样可以让我们快速跳转到页面的某个位置,但是在 react-router 中这种方法遇到了问题,因为 react-router 会把 # 当做是 hash 来处理。导致即使跳转到指定页面后,# 后面的锚点也不生效。针对这个问题,在 react-router 的一个 issue 中大家也展开了激烈的讨论。以下是我看过以后整理的几种解决办法。

只有某些页面需要

当只有某些页面需要使用锚点的时候,可以在访问到该页面后使用 react 生命周期中 componentDidMount 阶段来判断 # 后面的字符串,然后使用 dom 操作取到这个字符串所属的 dom,然后滚动到该位置。具体代码如下:

componentDidMount() {
  // Decode entities in the URL
  // Sometimes a URL like #/foo#bar will be encoded as #/foo%23bar
  window.location.hash = window.decodeURIComponent(window.location.hash);
  const scrollToAnchor = () => {
    const hashParts = window.location.hash.split('#');
    if (hashParts.length > 2) {
      const hash = hashParts.slice(-1)[0];
      document.querySelector(`#${hash}`).scrollIntoView();
    }
  };
  scrollToAnchor();
  window.onhashchange = scrollToAnchor;
}

说不准哪些页面会使用

以上方法适用于具有生命周期的 react component,而且是在组件的生命周期中实现这个功能,若需要所有页面都实现这个功能,明显我们不可能在所有 component 中都增加这个方法。这就产生另外一个方案,就是在 Router 的 onUpdate 函数中实现该功能。onUpdate 函数在路由跳转后会被调用一次,如下所示:

import React from 'react';
import { render } from 'react-dom';
import { Router, Route, browserHistory } from 'react-router';

const routes = (
  // your routes
);

function hashLinkScroll() {
  const { hash } = window.location;
  if (hash !== '') {
    // Push onto callback queue so it runs after the DOM is updated,
    // this is required when navigating from a different page so that
    // the element is rendered on the page before trying to getElementById.
    setTimeout(() => {
      const id = hash.replace('#', '');
      const element = document.getElementById(id);
      if (element) element.scrollIntoView();
    }, 0);
  }
}

render(
  <Router
    history={browserHistory}
    routes={routes}
    onUpdate={hashLinkScroll}
  />,
  document.getElementById('root')
)

当地址改变后,hashLinkScroll 会被调用,函数内部实现原理与上面的原理是一样的,拿到 # 后面的 id 并找到指定 dom,然后滚动到该 dom 的位置。

总结

两种方案各有优劣,可以根据自己的情况来选择使用。

Post Views: 1,128

相关

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏phodal

如何在 React Native 实现类微信小程序平台:WebView 调用原生组件

在《我们是如何将 Cordova 应用嵌入到 React Native 中》 一文中,我们简单地介绍了『React Native 重写 Cordova 插件:复...

36510
来自专栏xingoo, 一个梦想做发明家的程序员

DoModal 函数的用法

使用有模式对话框时在对话框弹出后调用函数不会立即返回,而是等到对话框销毁后才会返回(请注意在对话框弹出后其他窗口的消息依然会被传递)。所以在使用对话框时其他窗口...

3159
来自专栏Windows Community

Extensions in UWP Community Toolkit - Mouse Cursor

概述 UWP Community Toolkit Extensions 中有一个为 Mouse 提供的扩展 - Mouse Cursor Extensions,...

3568
来自专栏柠檬先生

VUE 入门基础(7)

八,事件处理器 监听事件   可以用v-on 指令监听DOM 事件来触发一些javaScript     <div id="example-1">   ...

2239
来自专栏james大数据架构

使用脚本操作UpdatePanel中控件的问题

假设有一个脚本(用js或者jQuery等类似手段编写),为UpdatePanel中的一个普通的TextBox赋值。如果你以为这样写: <head runat="...

20310
来自专栏Google Dart

AngularDart4.0 指南- 模板语法二 顶

Class绑定语法类似于属性(property)绑定。 以前缀类开始,可选地跟一个点(.)和一个CSS类的名字替代括号内的元素属性:[class.class-n...

542
来自专栏刘望舒

Android解析WMS之Window删除过程

前言 在本系列文章中,我提到过:Window的操作分为两大部分,一部分是WindowManager处理部分,另一部分是WMS处理部分,Window的删除过程也不...

3847
来自专栏技术之路

wcf http 返回图片

做项目时候用wcf 返回图片,从官网上找了找一次只能返回一张图片,但是一直查不到返回多个图片的方法,ios 可以异步加载看速度也可以 ,先记录一下等以后用解决了...

1856
来自专栏向治洪

用xml来编写动画

我们可以使用代码来编写所有的动画功能,这也是最常用的一种做法。不过,过去的补间动画除了使用代码编写之外也是可以使用XML编写的,因此属性动画也提供了这一功能,...

1795
来自专栏狮乐园

codereview-s8

之后再efficiencyView方法中调用stopPropagation方法阻止事件冒泡

593

扫码关注云+社区