react-router4 - 實現Link組件進行點擊跳轉

原生Link組件用法

 <Router>
   <Link to='/'>Home</Link>
   <Link to='/about'>About</Link>
   <Link to='/mine'>Mine</Link>
   <div>
     <Route component={Home} path='/' exact></Route>
     <Route component={About} path='/about'></Route>
     <Route component={Mine} path='/mine'></Route>
   </div>
 </Router>

  1. 導出Link 組件, 該組件 接收一個 to 屬性,爲要跳轉的路徑, 標籤裏邊可以寫文本等內容

實現自己的Link 組件

  1. 入口文件先導出這個組件
import Route from './Route';
import HashRouter from './HashRouter';
import Link from './Link';
export { HashRouter, Route, Link };
  1. 創建Link.js
import React from 'react';
class Link extends React.Component {
  render() {
    // 拿到傳入的 to屬性對應的值, 拿到內部的子節點或文本
    const { to, children } = this.props;
    // 轉化成 a 標籤
    return <a href={`#` + to}>{children}</a>;
  }
}
export default Link;

改進Link 組件

  • 現在使用的是 a 標籤的 默認錨點行爲進行跳轉的,把它改成 方法跳轉的
import React, { Component } from 'react';
import Context from './Context';

class Link extends Component {
  static contextType = Context;
  // 阻止默認行爲,進行事件跳轉
  hashPush = (e, to) => {
    e.preventDefault();
    this.context.history.push(to);
  };
  render() {
    const { to, children } = this.props;
    return (
      <a href={`#` + to} onClick={(e) => this.hashPush(e, to)}>
        {children}
      </a>
    );
  }
}
export default Link;

在 HashRouter文件上添加 跳轉方法

同時這裏處理一個問題, 就是初始化默認hash值的問題,讓它默認爲 #/, 不再去掉了,而是在 Route文件中處理

import React, { Component } from 'react';
import Context from './Context';
class HashRouter extends Component {
  state = {
    location: {
      pathname: '#/', // 默認hash 值路徑
    },
    history: {
      push(path) {
        // 路徑跳轉方法
        window.location.hash = '#' + path;
      },
    },
  };
  UNSAFE_componentWillMount() {
    // 監聽hash 值的變化
    window.addEventListener('hashchange', () => {
      this.setState((state) => ({
        ...state,
        location: {
          pathname: window.location.hash || '#/',
        },
      }));
    });
  }
  render() {
    return (
      <Context.Provider value={this.state}>
        {this.props.children}
      </Context.Provider>
    );
  }
}
export default HashRouter;

Route.js

這裏把 正則匹配的那個單獨抽出來了, 因爲 下邊還有組件要用到

import React, { Component } from 'react';
import Context from './Context';
import { isMatch } from './utils';
class Route extends Component {
  static contextType = Context;
  render() {
    // // 拿到  <Route component={Home} path='/' exact></Route> 這上邊的屬性
    let { component: Component } = this.props;
    if (isMatch(this.context, this.props)) {
      return <Component />;
    }
    return null;
  }
}
export default Route;

utils.js

在這裏統一處理 # 符號問題

import { pathToRegexp } from 'path-to-regexp';

/**
 * @returns 匹配的結果 true | false
 * @param {*} context 上下文
 * @param {*} component props
 */
export function isMatch(context, props) {
  const { path, exact = false, to } = props;
  // 拿到上下文中的 hash 值
  let { pathname } = context.location;
  // 截取掉 # 號
  pathname = pathname.slice(1);
  // 轉成正則
  // path || to 如果是Route 組件上都是path, 但Redirect 上是 to 屬性,這裏需要處理
  let regexp = pathToRegexp(path || to, [], { end: exact });
  return pathname.match(regexp);
}

代碼及效果演示

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章