上节课我们用Switch
组件来解决了路由按顺序持续匹配问题,这样可以提高匹配效率。这节课我们来介绍一下如何解决样式丢失问题。
回顾
在开始这节课内容之前,我们来对上节课来做一个简单的回顾
- 正常情况下一个路径只对应一个组件
- 当有多个路由时可以通过
Switch
来使路由匹配到路径之后就终止继续往下匹配 Switch
可以提高路由匹配效率。
以上便是上节课的主要要点,接下来我们来介绍如何解决样式丢失问题。
需求
就我们目前的状态来看,其实我们的功能都没有问题,而且也没有出现所谓的样式丢失问题。那么我们来做这么样一个事儿。我们让我们的路径都能有一个前缀。比如原来的/about
路径,现在我们要改成/lynchow/about
,那么没有什么难的,直接在to
属性前面加上前缀就行了,那么相应的,匹配的时候也要加上前缀。
export default class App extends Component { render() { return ( <div> ... <div className="list-group"> <MyNavLink to="/lynchow/about">About</MyNavLink> <MyNavLink to="/lynchow/home">Home</MyNavLink> </div> ... <div className="panel-body"> <Switch> <Route path="/lynchow/about" component={About} /> <Route path="/lynchow/home" component={Home} /> </Switch> </div> ... </div> ); } }
那么我们来看一下这样的话会是什么效果:
仿佛也没有什么问题啊,样式都在啊那么我们来点击一下刷新。
这一下出问题了,样式丢了啊,这是为什么呢?这样,我们先把前缀去掉,我们从头捋。
分析
我们来看我们这个时候bootstrap
是不是正常加载的?我们看一下这个请求链接是什么?是不是我们public
文件夹中的css
文件夹里的bootstrap.css
文件?那么我们并没有配这个路由啊,为什么这个链接不会报 404 呢?
我们之前是不是说过public
文件夹是我们这个脚手架服务的静态资源根目录。所以说当我们我们请求链接的时候,服务都会检查自身有没有这项资源,没有的话再去匹配路由。那么如果我们路由也没匹配到,自身也没有这项资源会怎么样呢?那我们在浏览器中测一下呗:
我们来看,我们的脚手架是不是根本就没有/a/b/c/test.html
这个文件?而且我们也没有做这个路由匹配。那么为什么会这样呢?我们拿到的又是什么呢?我们来看一下这个个内容,这是不是index.html
啊?这就是react
脚手架设计的,如果说出现了网络请求的类似这种的一些错误,我们不报错,但是会把public
中的index.html
给返回回来。
那么我们这个时候是没有问题的,因为我才刚打开页面,而且成功加载了bootstrap
,然后点击了About
,那么这个时候我点击刷新的话,我们来看网络请求。
我们来看,这个时候请求的是不是还是localhost:3000/css/bootstrap.css
,所以我们没有加前缀的时候点击刷新是没有问题的。
那么接下来我们把路由的路径加上前缀再过一遍这个流程
这次我们可是把前缀也加上了,然后我们点击了About
,来看,我们请求的链接是不是没有问题?而且页面的样式也是正常的,那么我们来刷新一下页面:
诶,样式丢了,请求的链接好像有问题啊,他怎么请求了localhost:3000/lynchow/css/bootstrap.css
?我们脚手架的public
中有lynchow
这个目录吗?没有啊,那能匹配到/lynchow/css
的路径的路由吗?也匹配不到啊,那这个时候来兜底的人来了,就是public
中的index.html
,他被展示出来了,但是因为没有成功加载bootstrap
所以样式丢了。
结论
那么经过上面的举例,我们能得出结论了吧,我来问大家,什么时候样式会丢失?是不是我们的路由路径是多级的时候,然后一刷新就会丢失。并不是只要路由路径是多级就会丢失,得当我们刷新了才会丢失。而丢失的原因就是浏览器认为我们多级路径中的前缀也是属于host
的一部分。
解决
那么问题出来了,原因也分析出来了,那么怎么解决这个问题呢?我们有三种解决方法
第一,我们来看public
中的index.html
的代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <meta name="description" content="Web site created using create-react-app"/> <title>React Router</title> <link rel="stylesheet" href="./css/bootstrap.css"> </head> <body> <div id="root"></div> </body> </html>
我们是怎么引入的bootstrap
?是不是用相对路径引入的?我们现在呢不用相对路径了,我们用之前说过的%PUBLIC_URL%
来引入
这次我们再刷新,没有问题,请求的链接也是正常的,因为之前说过%PUBLIC_URL%
是脚手架中定义好的一个关键字,就好比是环境变量一般,这样的话刷新请求的永远都是这个绝对路径下的bootstrap
第二种方法和第一种类似我们直接这样:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <meta name="description" content="Web site created using create-react-app"/> <title>React Router</title> <link rel="stylesheet" href="/css/bootstrap.css"> </head> <body> <div id="root"></div> </body> </html>
这是什么意思?是不是直接从根目录下的css
目录来引入?根目录是谁?是不是public
?所以说这样也不会导致路径出错。
第三种方法可能有人说,我就想在index.html
中写./css
我就是要用相对路径引入,那么这么办呢?也没问题,我们来改index.js
import { HashRouter } from 'react-router-dom' import App from './App'; ReactDOM.render(<HashRouter><App /></HashRouter>, document.getElementById('root'));
我们用HashRouter
,我们都知道HashRouter
和BrowserRouter
最直观的一个差别就是一个有#
另一个没有,我们是不是说过#
后面的东西懂不带给服务器,所以说当我们点击About
,路径是不是/lynchow/about
?但是这一串是不是都在#
后面,所以在刷新的时候直接就从#
截断了,根本不可能会出现路径上的问题。
总结
- 多级路由路径在刷新时会丢失样式
- 样式丢失是由导入样式的相对路径导致的
- 解决样式丢失有三种办法
%PUBLIC_URL%
引入样式- 根目录引入样式
HashRouter
解决
Copyright statement:The articles of this site are all original if there is no special explanation, indicate the source please when you reprint.
Link of this article:https://work.lynchow.com/article/solve_lose_style/