美文网首页
[react]22、router

[react]22、router

作者: 史记_d5da | 来源:发表于2021-11-27 10:46 被阅读0次

1、概念

路由(routing)就是通过互联的网络把信息从源地址传输到目的地址的活动.
路由的概念出现最早是在后端路由中实现的,原因是web的发展主要经历了这样一些阶段:

1.1、后端路由阶段;

早期的网站开发整个HTML页面是由服务器来渲染的.
服务器直接生产渲染好对应的HTML页面, 返回给客户端进行展示.

1.1.1、服务器处理多个页面的步骤:

1、一个页面有自己对应的网址, 也就是URL.
2、URL会发送到服务器, 服务器会通过正则对该URL进行匹配, 并且最后交给一个Controller进行处理.
3、Controller进行各种处理, 最终生成HTML或者数据, 返回给前端.
4、这就完成了一个IO操作.

1.1.2、上面的这种操作, 就是后端路由.

1、当我们页面中需要请求不同的路径内容时, 交给服务器来进行处理, 服务器渲染好整个页面, 并且将页面返回给客户顿.
2、这种情况下渲染好的页面, 不需要单独加载任何的js和css, 可以直接交给浏览器展示, 这样也有利于SEO的优化.

1.1.3、后端路由的缺点:

1、一种情况是整个页面的模块由后端人员来编写和维护的.
2、另一种情况是前端开发人员如果要开发页面, 需要通过PHP和Java等语言来编写页面代码.
3、而且通常情况下HTML代码和数据以及对应的逻辑会混在一起, 编写和维护都是非常糟糕的事情.

1.2、前后端分离阶段

分析:
1、每次请求涉及到的静态资源都会从静态资源服务器获取, 这些资源包括HTML+CSS+JS,然后在前端对这些请求回来的资源进行渲染;
2、客户端的每一次请求,都会从静态资源服务器请求文件;
3、 同时可以看到,和之前的后端路由不同,这时后端只是负责提供API了;
总结前后端分离思想:
1、随着Ajax的出现, 有了前后端分离的开发模式,
2、后端只提供API来返回数据,前端通过Ajax获取数据,并且可以通过JavaScript将数据渲染到页面中

1.3、单页面富应用(SPA)

单页面富应用的英文是single-page application,简称SPA,整个Web应用只有实际上只有一个页面,当URL发生改变时,并不会从服务器请求新的静态资源,而是通过JavaScript监听URL的改变,并且根据URL的不同去渲染新的页面。
前端路由实现:
1、前端路由维护着URL和渲染页面的映射关系
2、路由可以根据不同的URL,最终让我们的框架(比如Vue、React、Angular)去渲染不同的组件
3、最终我们在页面上看到的实际就是渲染的一个个组件页面;

2、前端路由的实现

2.1、前端路由的原理

1、监听URL的改变
1)、 通过URL的hash改变URL
2)、可以通过直接赋值location.hash来改变href, 但是页面不发生刷新
URL的hash也就是锚点(#), 本质上是改变window.location的href属性
注意点:
hash的优势就是兼容性更好,在老版IE中都可以运行、但是缺陷是有一个#,显得不像一个真实的路径;

<body>
    <div id="app">
        <a href="#/home">首页</a>
        <a href="#/about">关于</a>
        <div class="router-view"></div>
    </div>
    <script>
        // 获取routerview docm
        const routerViewEl = document.getElementsByClassName("router-view")[0];
        // 监听url改变
        window.addEventListener("hashchange", () => {
            console.log(routerViewEl);
            switch(location.hash) {
                case "#/home":
                routerViewEl.innerHTML = "首页";
                break;
                case "#/about":
                routerViewEl.innerHTML = "关于";
                break;
                default:
                routerViewEl.innerHTML = "";
                break;
            }
        })
    </script>
</body>
</html>

2)、通过HTML5中的history模式修改URL,它有l六种模式改变URL而不刷新页面

<body>
    <div id="app">
        <a href="/home">首页</a>
        <a href="/about">关于</a>
        <div class="router-view"></div>
    </div>
    <script>
        const routerViewEl = document.getElementsByClassName("router-view")[0];
        // 监听url改变
        const aEls = document.getElementsByTagName("a");
        for (let el of aEls) {
            el.addEventListener("click", e => {
                e.preventDefault();
                const href = el.getAttribute("href");
                history.pushState({}, "", href);
                urlChange()
                // history.go()
                // history.forward()
            })
        }
        window.addEventListener("popstate", urlChange);
        // window.addEventListener("go", urlChange);
        function urlChange() {
            switch (location.pathname) {
                case "/home":
                console.log("首页")
                    routerViewEl.innerHTML = "首页";
                    break;
                case "/about":
                console.log("关于")
                    routerViewEl.innerHTML = "关于";
                    break;
                default:
                console.log("default")
                routerViewEl.innerHTML = "";
            }
        }
    </script>
</body>

2、当监听到URL发生变化时,我们可以通过自己判断当前的URL,决定到底渲染什么样的内容。

3、react-router

3.1、react-router介绍

1、目前前端流行的三大框架, 都有自己的路由实现:
Angular的ngRouter、React的react-router、Vue的vue-router
2、react-router的代码组成

  • react-router是router的核心部分代码
  • react-router-dom是用于浏览器的
  • react-router-native 是用于原生应用的

3、安装react-router:
安装react-router-dom会自动帮助我们安装react-router的依赖;
安装命令yarn add react-router-dom

3.2、react-router基本使用

react-router最主要的API是给我们提供的一些组件:
1、BrowserRouter或HashRouter

  • Router中包含了对路径改变的监听,并且会将相应的路径传递给子组件
  • BrowserRouter使用history模式
  • HashRouter使用hash模式
import React, { PureComponent } from 'react'
import { BrowserRouter, Link, Route, NavLink, Switch, withRouter } from 'react-router-dom'
import About from './pages/about'
import Home from './pages/home'
import Profile from './pages/profile'
class App extends PureComponent {
    static propTypes = {}
    constructor(props) {
        super(props)
    }

    render() {
        return (
            <BrowserRouter>
                <Link to="/">首页</Link>
                <Link to="/about">关于</Link>
                <Link to="/profile">我的</Link>
                <Route exact={true} path="/" component={Home}></Route>
                <Route path="/profile" component={Profile}></Route>
                <Route path="/about" component={About}></Route>
            </BrowserRouter>
        )
    }
}

2、Link和NavLink:

  • 通常路径的跳转是使用Link组件,最终会被渲染成a元素
  • NavLink是在Link基础之上增加了一些样式属性(后续学习)
  • to属性:Link中最重要的属性,用于设置跳转到的路径

3、Route

  • Route用于路径的匹配
  • path属性:用于设置匹配到的路径
  • component属性:设置匹配到路径后,渲染的组件
  • exact:精准匹配,只有精准匹配到完全一致的路径,才会渲染对应的组件

3.3、NavLink的使用

NavLink可以改变选中时对应的a元素变为红色
NavLink的三个属性:
1、activeStyle:活跃时(匹配时)的样式、
2、activeClassName:活跃时添加的class;(在默认匹配成功时,NavLink就会添加上一个动态的active class)
3、exact:是否精准匹配;

<NavLink exact to="/" activeClassName={"link-active"}>首页</NavLink>
<NavLink to="/about" >关于</NavLink>
<NavLink to="/profile" >我的</NavLink>

对应的.css

a.active {
    color: red;
    font-size: 30px;
    margin: 10px;
    text-decoration: line-through;
}

3.4、Switch使用

当匹配到某一个路径时,会发现有一些问题,比如/about路径匹配到的同时,/:userid也被匹配到了,并且最后的一个NoMatch组件总是被匹配到
原因是默认情况下,react-router中只要是路径被匹配到的Route对应的组件都会被渲染;
如果希望只匹配到了第一个,后面的就不继续匹配了,可以使用Switch

<Switch>
       <Route exact={true} path="/" component={Home}></Route>
       <Route path="/profile" component={Profile}></Route>
       <Route path="/about" component={About}></Route>
       <Route path="/user" component={User}></Route>
       <Route path="/login" component={Login}></Route>
       <Route path="/product" component={Product}></Route>
       <Route path="/detail/:id" component={Detail}></Route>
       <Route path="/detail2" component={Detail2}></Route>
       <Route path="/detail3" component={Detail3}></Route>
       <Route component={NoMatch}></Route>  
</Switch>
3.5、Redirect

Redirect用于路由的重定向,当这个组件出现时,就会执行跳转到对应的to路径中

import React, { PureComponent } from 'react'
import PropTypes from 'prop-types'
import { Redirect } from 'react-router-dom'
class User extends PureComponent {
    static propTypes = {}
    constructor(props) {
        super(props)
        this.state = {
            isLogin: false
        }
    }
    render() {
        return (
            this.state.isLogin ? (<div>
                <h2>Login</h2>
                <h2>coder why</h2>
            </div>) : (<Redirect to="/login"/>)
        )
    }
}
export default User
3.6、手动路由跳转

通过JavaScript代码进行跳转有一个前提:必须获取到history对象,如果该组件是通过路由直接跳转过来的,那么可以直接获取history、location、match对象
index.js文件

ReactDOM.render(
  <BrowserRouter>
    <App />
  </BrowserRouter>,
  document.getElementById('root')
);

App.js文件

class App extends PureComponent {
    static propTypes = {}
    constructor(props) {
        super(props)

        this.state = {
            links: [
                {to: "/", title: "首页"},
                {to: "/about", title: "关于"},
                {to: "/profile", title: "我的"}
            ]
        }
    }

    render() {
        const id = "abc"

        const info = {name: "codey", age: 18};
        return (
            <div>
                    {/* {
                        this.props.links.map((item, index) => {
                            return (
                                <div key={item.title} className={classNames({"active": index === this.state.currentIndex})}>
                                    <Link to={item.to}>{item.title}</Link>
                                </div>
                            )
                        })
                    } */}
                    <NavLink exact to="/" activeClassName={"link-active"}>首页</NavLink>
                    <NavLink to="/about" >关于</NavLink>
                    <NavLink to="/profile" >我的</NavLink>
                    <NavLink to="/abc" >abc</NavLink>
                    <NavLink to="/user" >user</NavLink>
                    <NavLink to="/login" >login</NavLink>
                    <NavLink to={`/detail/${id}`} activeClassName={"link-active"}>详情</NavLink>
                    <NavLink to={`/detail2?name=cody&age=10`} activeClassName={"link-active"}>详情2</NavLink>
                    <NavLink to={{
                        pathname: "/detail3",
                        search: "?names=abc",
                        state: info
                    }} activeClassName={"link-active"}>详情3</NavLink>
                    <button onClick={e => this.jumpProduct()}>商品列表</button>

{/*switch的作用*/}
                   <Switch>
                        <Route exact={true} path="/" component={Home}></Route>
                        <Route path="/profile" component={Profile}></Route>
                        <Route path="/about" component={About}></Route>
                        <Route path="/user" component={User}></Route>
                        <Route path="/login" component={Login}></Route>
                        <Route path="/product" component={Product}></Route>
                        <Route path="/detail/:id" component={Detail}></Route>
                        <Route path="/detail2" component={Detail2}></Route>
                        <Route path="/detail3" component={Detail3}></Route>
                        <Route component={NoMatch}></Route>  
                    </Switch> 
                    { (routes)}
            </div>
        )
    }

    // 跳转商品列表
    jumpProduct() {
        this.props.history.push("/product")
    }
}

export default withRouter(App)
3.7、参数传递

参数传递方式:1、search传递参数,2、Link中to可以直接传入一个对象

<NavLink to={`/detail2?name=cody&age=10`} activeClassName={"link-active"}>详情2</NavLink>
<NavLink to={{
                        pathname: "/detail3",
                        search: "?names=abc",
                        state: info
                    }} activeClassName={"link-active"}>详情3</NavLink>

参数接收

<h2>Detail2 : {this.props.location.search}</h2>

4、react-router-config

安装react-router-configyarn add react-router-config
配置路由映射的关系数组

const routes = [
    {
        path: "/",
        exact: true,
        component: Home
    },
    {
        path: "/about",
        component: About,
        routes: [
            {
                path: "/about",
                exact: true,
                component: AboutHistory
            }
        ]
    },
    {
        path: "/profile",
        component: Profile
    },
    {
        path: "/",
        component: User
    }
]
export default routes;

renderRoutes源码分析

function renderRoutes(routes, extraProps, switchProps) {
  if (extraProps === void 0) {
    extraProps = {};
  }

  if (switchProps === void 0) {
    switchProps = {};
  }

  return routes ? React.createElement(reactRouter.Switch, switchProps, routes.map(function (route, i) {
    return React.createElement(reactRouter.Route, {
      key: route.key || i,
      path: route.path,
      exact: route.exact,
      strict: route.strict,
      render: function render(props) {
        return route.render ? route.render(_extends({}, props, {}, extraProps, {
          route: route
        })) : React.createElement(route.component, _extends({}, props, extraProps, {
          route: route
        }));
      }
    });
  })) : null;
}

相关文章

网友评论

      本文标题:[react]22、router

      本文链接:https://www.haomeiwen.com/subject/ajsitrtx.html