好久都没有写博客了,一是因为最近工作也比较繁杂,二是在学习路由的时候卡了一下壳,三是工作找不到很是郁闷。经过一段时间的尝试,终于在学习的过程中迈出了一小步,实现了自己当初订的一个小需求。由于还在学习过程中,就只是先拿出一点实际的效果和中间遇到的一些困难。(用react-router实现导航)
github:https://github.com/liuzaijiang/React-Router-Demo(这个是我们自己参考网上的Demo然后自己实现的一个路由导航实例)
参考的Demo:https://github.com/reactjs/react-router-tutorial/tree/master/lessons/08-index-routes
路由的基础知识:http://www.ruanyifeng.com/blog/2016/05/react_router.html?utm_source=tool.lu(阮一峰的入门博客)
我眼中的路由:
我目前接触到的路由一般都是用来做导航栏,选项卡之类的功能;我就类比一下用jq的方法去实现这样一个功能的:大体思路就是先把所有的导航和导航对应的显示内容写好,然后全部隐藏,最后根据点击的那个导航,来相应的显示那一块内容(导航和内容一一对应)
把这个思路用到react 中去也是可以的,相应的内容就是我们的组件,我们可以根据点击某个导航来选择渲染哪一个组件;这
里其实就可以看到react的优势,不显示的内容不存在于DOM节点中,而用传统的方法的话,不显示的内容只是display:none而
已,这样来说当你切换导航的时候就免去了不必要的重绘和重排;
当然,reacr-router也是解决这个的方法之一,我说一下我个人第一次用完后觉得它好的地方:
******************************************************************************************************************************
1.首先它不用去判断渲染哪个组件,它只需要为每个组件定义好一个path属性,为每个导航栏定义好to属性,指向我们需要显
示的组件的path属性,点击相应的导航栏即显示相应组件(其实就是<a>标签的效果,不过react-router是用<Link>这个标签代替
了<a>标签的作用),这样我们不用去为每个导航栏去绑定事件。
2.然后<Link>本身有一个activeClassName这个属性,这个属性的好处就是为我们当前点击的导航栏增加样式,这个真的是真
心棒的,如果要我们自己动手去实现这个你或许还需要为获取当前是哪个导航栏被点击花一点功夫去写代码,这里我们直接拿来用
就好了。
3.最后,如果我们访问点击了一个页面的一个导航内容,刷新之后页面还是会显示之前的导航内容,如果是不用路由的方法页
面是会显示默认的导航内容的;这个是因为使用路由后,页面显示的相应内容会在url中有具体的体现,比如我要看a内容,则是
http://www.this-is-a-spa.com/a,b内容则是http://www.this-is-a-spa.com/b,如果是传统的导航显示的话,整个页面就只有一
个 url http://www.this-is-a-spa.com/
(我相信它的功能应该远远不至于此,只是我目前才疏学浅,还没学到它更深的内容)
******************************************************************************************************************************
在网上查找了一些别人的看法:
1.什么是前端路由?
2.什么时候使用前端路由?
3.前端路由有什么优点和缺点?
-
优点
-
缺点
-
使用浏览器的前进,后退键的时候会重新发送请求,没有合理地利用缓存
-
单页面无法记住之前滚动的位置,无法在前进,后退的时候记住滚动的位置
-
________________________________________________________________________________________________________________________________
具体的实践:(代码为前面的参考Demo)
首先来个最简单的,效果就是一个页面中有2个“导航”,点击则显示相应的内容;
下面是关键代码:
index.js
import React from 'react' import { render } from 'react-dom' import { Router,Route,hashHistory} from 'react-router' import App from './modules/App' import About from './modules/About' import Repos from './modules/Repos' import Repo from './modules/Repo' render(( <Router history={hashHistory}> <Route path="/" component={App}> <Route path="/repos" component={Repos}/> <Route path="/about" component={About}/> </Route> </Router> ),document.getElementById('app'))
App.js
import React from 'react' import NavLink from './NavLink' export default React.createClass({ render() { return ( <div> <h1>React Router Tutorial</h1> <ul role="nav"> <li><NavLink to="/about">About</NavLink></li> <li><NavLink to="/repos">Repos</NavLink></li> </ul> {this.props.children} </div> ) } })
这里初学者要注意{this.props.children}这句话,是用来显示我们路由对应的子组件的;(App里面包含了Repos和About这2个组件)
当前上面这个还存在一个小问题:如果我页面一进去想默认先显示第一个导航怎么办?
我们这里只需要利用IndexRoute这个标签,写好我们的默认路由即可:(记得在import中先定义好)
import React from 'react' import { render } from 'react-dom' import { Router,hashHistory,IndexRoute} from 'react-router' import App from './modules/App' import About from './modules/About' import Repos from './modules/Repos' import Repo from './modules/Repo' render(( <Router history={hashHistory}> <Route path="/" component={App}> <IndexRoute path="/repos" component={Repos}/> <Route path="/repos" component={Repos}/> <Route path="/about" component={About}/> </Route> </Router> ),document.getElementById('app'))
因为需求中导航中还有子导航,所以我们的就需要用到路由嵌套;
其实这个的难点在于:如何将我们的需求和路由的结构理清楚,对于初学者来说是一个比较费时的地方。
========================================================================
(我自己列的一个导航路由和组件的关系图,对比代码看会清晰不少)
/repos/reactjs/react-router(Repo组件)
/repos(Repos组件){
/(App组件) { /repos/facebook/react(Repo组件)
/about(About组件)
========================================================================
先把这个关系列好~每层之间的路由关系其实也就是我们的导航与内容,导航与子导航之间的关系;
A.最开始页面进入根路径/,url就是http://localhost:8080/#/?_k=8a84lu 根路由是App组件
B.点击页面中的About导航后渲染About组件,然后url会变成http://localhost:8080/#/about?_k=rf9brt
C.点击Repos导航的时候渲染Repos组件,url变成http://localhost:8080/#/repos?_k=a9umbj
D.再点击Repos下面的子导航React Router的时候,渲染Repo组件,url变成http://localhost:8080/#/repos/reactjs/react-router?_k=giihrr....这个就是我们能观察到的现象
然后就是我们路由的代码书写:
<Router history={hashHistory}> <Route path="/" component={App}> <Route path="/repos" component={Repos}> <Route path="/repos/:userName/:repoName" component={Repo}/> </Route> <Route path="/about" component={About}/> </Route> </Router>一层层嵌套的关系,可以用这个代码和我前面列出来的那个关系表对比看一下,就很清楚了。
Repo.js
import React from 'react' export default React.createClass({ render() { return ( <div> <h2>{this.props.params.repoName}</h2> </div> ) } })
Repos.js
import React from 'react' import NavLink from './NavLink' export default React.createClass({ render() { return ( <div> <h2>Repos</h2> <ul> <li><NavLink to="/repos/reactjs/react-router">React Router</NavLink></li> <li><NavLink to="/repos/facebook/react">React</NavLink></li> </ul> {this.props.children} </div> ) } })
这里提一下:
path="/repos/:userName/:repoName"
这个用到了路由的通配符,其实我们通过观察,我们可以发现path属性中的 :userName 和 :repoName就相当于我们的to属性中的react.js 和react-router,个人认为就是函数中的形参和实参的关系,我们可以通过this.props.params.xxx来获取相应的值。
最后我自己总结一下:
1.路由是可以用来局部刷新页面的一种方式,主要是通过url的改变来渲染不同的组件,url中定义的路径就是每个组件的“位置",定义在我们的<Route>标签中的path属性中,然后我们通过<Link>标签的to属性来找到我们想要的路由,进而来渲染我们想要的组件;
2.我们是通过{ this.props.childern }来渲染我们的路由所对应的组件 (对于初学者如果遇到路由都对的情况下,还是不能渲染组件的时候,可以看看是不是掉了这句话)
3.我们可以把<Link>标签类比我们的<a>标签,而且它还具有activeClassName属性,可以定义我们当前导航的样式class,或者直接把样式写在activeStyle里面也行。
4.使用<IndexRoute>标签来定义我们的默认路由,即为我们的默认”导航“
5.在进行路由嵌套的时候画一下关系对比图,让自己的大脑更加清晰,书写代码的时候会更加流畅
(目前对于路由的研究是浅尝辄止,继续学习ing!)