果图
今天给大家带来的是一款,超酷模糊背景同步jQuery旋转木马特效源码
大气的外表,十分适合科技、艺术类的网站。
也可以适当的修改成自己喜欢的风格!
文件版源码可在评论区留言
废话不多说上 源码!
@font-face {
font-family: 'icomoon';
src:url('../fonts/icomoon.eot?rretjt');
src:url('../fonts/icomoon.eot?#iefixrretjt') format('embedded-opentype'),
url('../fonts/icomoon.woff?rretjt') format('woff'),
url('../fonts/icomoon.ttf?rretjt') format('truetype'),
url('../fonts/icomoon.svg?rretjt#icomoon') format('svg');
font-weight: normal;
font-style: normal;
}
[class^="icon-"], [class*=" icon-"] {
font-family: 'icomoon';
speak: none;
font-style: normal;
font-weight: normal;
font-variant: normal;
text-transform: none;
line-height: 1;
/* Better Font Rendering =========== */
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
body, html { font-size: 100%; padding: 0; margin: 0;}
/* Reset */
*,
*:after,
*:before {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
/* Clearfix hack by Nicolas Gallagher: http://nicolasgallagher.com/micro-clearfix-hack/ */
.clearfix:before,
.clearfix:after {
content: " ";
display: table;
}
.clearfix:after {
clear: both;
}
body{
background: #494A5F;
color: #D5D6E2;
font-weight: 500;
font-size: 1.05em;
font-family: "Microsoft YaHei","宋体","Segoe UI", "Lucida Grande", Helvetica, Arial,sans-serif, FreeSans, Arimo;
}
a{ color: rgba(255, 255, 255, 0.6);outline: none;text-decoration: none;-webkit-transition: 0.2s;transition: 0.2s;}
a:hover,a:focus{color:#74777b;text-decoration: none;}
.htmleaf-container{
margin: 0 auto;
}
.bgcolor-1 { background: #f0efee; }
.bgcolor-2 { background: #f9f9f9; }
.bgcolor-3 { background: #e8e8e8; }/*light grey*/
.bgcolor-4 { background: #2f3238; color: #fff; }/*Dark grey*/
.bgcolor-5 { background: #df6659; color: #521e18; }/*pink1*/
.bgcolor-6 { background: #2fa8ec; }/*sky blue*/
.bgcolor-7 { background: #d0d6d6; }/*White tea*/
.bgcolor-8 { background: #3d4444; color: #fff; }/*Dark grey2*/
.bgcolor-9 { background: #ef3f52; color: #fff;}/*pink2*/
.bgcolor-10{ background: #64448f; color: #fff;}/*Violet*/
.bgcolor-11{ background: #3755ad; color: #fff;}/*dark blue*/
.bgcolor-12{ background: #3498DB; color: #fff;}/*light blue*/
.bgcolor-20{ background: #494A5F;color: #D5D6E2;}
/* Header */
.htmleaf-header{
padding: 1em 190px 1em;
letter-spacing: -1px;
text-align: center;
background: #66677c;
}
.htmleaf-header h1 {
color: #D5D6E2;
font-weight: 600;
font-size: 2em;
line-height: 1;
margin-bottom: 0;
font-family: "Microsoft YaHei","宋体","Segoe UI", "Lucida Grande", Helvetica, Arial,sans-serif, FreeSans, Arimo;
}
.htmleaf-header h1 span {
font-family: "Microsoft YaHei","宋体","Segoe UI", "Lucida Grande", Helvetica, Arial,sans-serif, FreeSans, Arimo;
display: block;
font-size: 60%;
font-weight: 400;
padding: 0.8em 0 0.5em 0;
color: #c3c8cd;
}
/*nav*/
.htmleaf-demo a{color: #fff;text-decoration: none;}
.htmleaf-demo{width: 100%;padding-bottom: 1.2em;}
.htmleaf-demo a{display: inline-block;margin: 0.5em;padding: 0.6em 1em;border: 3px solid #fff;font-weight: 700;}
.htmleaf-demo a:hover{opacity: 0.6;}
.htmleaf-demo a.current{background:#1d7db1;color: #fff; }
/* Top Navigation Style */
.htmleaf-links {
position: relative;
display: inline-block;
white-space: nowrap;
font-size: 1.5em;
text-align: center;
}
.htmleaf-links::after {
position: absolute;
top: 0;
left: 50%;
margin-left: -1px;
width: 2px;
height: 100%;
background: #dbdbdb;
content: '';
-webkit-transform: rotate3d(0,0,1,22.5deg);
transform: rotate3d(0,0,1,22.5deg);
}
.htmleaf-icon {
display: inline-block;
margin: 0.5em;
padding: 0em 0;
width: 1.5em;
text-decoration: none;
}
.htmleaf-icon span {
display: none;
}
.htmleaf-icon:before {
margin: 0 5px;
text-transform: none;
font-weight: normal;
font-style: normal;
font-variant: normal;
font-family: 'icomoon';
line-height: 1;
speak: none;
-webkit-font-smoothing: antialiased;
}
/* footer */
.htmleaf-footer{width: 100%;padding-top: 10px;}
.htmleaf-small{font-size: 0.8em;}
.center{text-align: center;}
/****/
.related {
color: #fff;
background: #494A5F;
text-align: center;
font-size: 1.25em;
padding: 0.5em 0;
overflow: hidden;
}
.related > a {
vertical-align: top;
width: calc(100% - 20px);
max-width: 340px;
display: inline-block;
text-align: center;
margin: 20px 10px;
padding: 25px;
font-family: "Microsoft YaHei","宋体","Segoe UI", "Lucida Grande", Helvetica, Arial,sans-serif, FreeSans, Arimo;
}
.related a {
display: inline-block;
text-align: left;
margin: 20px auto;
padding: 10px 20px;
opacity: 0.8;
-webkit-transition: opacity 0.3s;
transition: opacity 0.3s;
-webkit-backface-visibility: hidden;
}
.related a:hover,
.related a:active {
opacity: 1;
}
.related a img {
max-width: 100%;
opacity: 0.8;
border-radius: 4px;
}
.related a:hover img,
.related a:active img {
opacity: 1;
}
.related h3{font-family: "Microsoft YaHei", sans-serif;font-size: 1.2em}
.related a h3 {
font-size: 0.85em;
font-weight: 300;
margin-top: 0.15em;
color: #fff;
}
/* icomoon */
.icon-htmleaf-home-outline:before {
content: "\e5000";
}
.icon-htmleaf-arrow-forward-outline:before {
content: "\e5001";
}
@media screen and (max-width: 1024px) {
.htmleaf-header {
padding: 2em 10% 2em;
}
.htmleaf-header h1 {
font-size:1.4em;
}
.htmleaf-links{font-size: 1.4em}
}
@media screen and (max-width: 960px) {
.htmleaf-header {
padding: 2em 10% 2em;
}
.htmleaf-header h1 {
font-size:1.2em;
}
.htmleaf-links{font-size: 1.2em}
.related h3{font-size: 1em;}
.related a h3 {
font-size: 0.8em;
}
}
@media screen and (max-width: 766px) {
.htmleaf-header h1 {
font-size:1.3em;
}
.htmleaf-links{font-size: 1.3em}
}
@media screen and (max-width: 640px) {
.htmleaf-header {
padding: 2em 10% 2em;
}
.htmleaf-header h1 {
font-size:1em;
}
.htmleaf-links{font-size: 1em}
.related h3{font-size: 0.8em;}
.related a h3 {
font-size: 0.6em;
}
}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>超酷模糊背景同步jQuery旋转木马特效| jQuery特效|手机微信网站特效| 网页特效库</title>
<meta name="keywords" content="SVG特效, 手机微信网站特效, css3动画, html5特效, 网页特效" />
<meta name="description" content="扣丁学堂-专注于HTML5、CSS3、js、jQuery、手机移动端等网页特效的手机与分享。特效库始终坚持:无会员、无积分、无限制的“三无原则”。" />
<link rel="stylesheet" type="text/css" href="css/normalize.css" />
<link rel='stylesheet prefetch' href='css/slick.min.css'>
<link rel="stylesheet" type="text/css" href="css/style.css">
</head>
<body>
<div class="section section-project">
<h2>Project Carousel</h2>
<div>
<div>
<div><img src="img/1.jpg" alt=""/></div>
<div><img src="img/2.jpg" alt=""/></div>
<div><img src="img/3.jpg" alt=""/></div>
<div><img src="img/4.jpg" alt=""/></div>
<div><img src="img/5.jpg" alt=""/></div>
<div><img src="img/6.jpg" alt=""/></div>
<div><img src="img/7.jpg" alt=""/></div>
<div><img src="img/8.jpg" alt=""/></div>
<div><img src="img/9.jpg" alt=""/></div>
</div>
<div>
<div>
<div><img src="img/1.jpg" alt=""/></div>
<div><img src="img/2.jpg" alt=""/></div>
<div><img src="img/3.jpg" alt=""/></div>
<div><img src="img/4.jpg" alt=""/></div>
<div><img src="img/5.jpg" alt=""/></div>
<div><img src="img/6.jpg" alt=""/></div>
<div><img src="img/7.jpg" alt=""/></div>
<div><img src="img/8.jpg" alt=""/></div>
<div><img src="img/9.jpg" alt=""/></div>
</div>
<div></div>
</div>
</div>
</div>
<div style="width: 100%; height: auto; line-height: 25px; text-align: center;">
</div>
<script src="js/jquery-1.11.0.min.js" type="text/javascript"></script>
<script src='js/slick.min.js'></script>
<script type="text/javascript">
$(".project-detail").slick({
slidesToShow: 1,
arrows: false,
asNavFor: '.project-strip',
autoplay: true,
autoplaySpeed: 3000
});
$(".project-strip").slick({
slidesToShow: 5,
slidesToScroll: 1,
arrows: false,
asNavFor: '.project-detail',
dots: false,
infinite: true,
centerMode: true,
focusOnSelect: true
});
</script>
</body>
</html>
于前端性能优化方法有很多,包括:图片合并、使用缓存、使用CDN、减少重定向、减少请求、压缩等等。今天就针对减少请求、资源压缩,给大家推荐一个基于.Net开发的资源合并与压缩的开源项目。
在介绍这个项目之前,先问大家一个问题,大家知道一个浏览器同域名请求的最大并发数限制是多少吗?
在早期的浏览器有的是2个、有的是4个,现在市面主流的浏览器一般限制数量是6个,手机一般是4个。虽然每个浏览器限制数量不一样,但我们知道的是,当一个页面同时发起过多的请求,肯定会导致部分请求在等待的。
所以,我们压缩和合并静态资源请求数量,对于我们优化性能肯定有好处的。
这是一个基于.Net Core开发的,实现压缩Css、Javascript、Html资源的压缩、合并功能的组件。通过这个组件我们就可以实现静态资源的捆绑,实现对js、css、less、scss等静态资源的自动打包捆绑处理。
通过将多个文件合并成了一个文件,减少浏览器的请求从而实现提升网站的访问性能的需求。
特点:
1、Js压缩:进行去掉空格,换行,注释等,格式紧凑,内部方法匿名化,节约存储空间。
2、Css压缩:去掉空格,换行,注释等,格式紧凑,节约存储空间。
3、Html压缩:压缩效果可以实现5-10%的压缩,删除助手、折叠空白、删除可选标记(p、li…)、删除引用的属性、删除特定属性、解码HTML实体、压缩内联样式和脚本;支持Html5。
1、平台:基于.Net Core 4.5、Netstandard2.0开发
2、开发工具:Visual Studio 2017
Js文件压缩
var result = Uglify.Js("var x = 5; var y = 6;");
Console.WriteLine(result.Code);
// prints: var x=5,y=6
Css文件压缩
var result = Uglify.Css("div { color: #FFF; }");
Console.WriteLine(result.Code);
// prints: div{color:#fff}
Html文件压缩
var result = Uglify.Html("<div> <p>This is <em> a text </em></p> </div>");
Console.WriteLine(result.Code);
//prints: <div><p>This is <em>a text</em></div>
文本解析Html
var result = Uglify.HtmlToText("<div> <p>This is <em> a text </em></p> </div>");
Console.WriteLine(result.Code);
// prints: This is a text
Js、Css文件合并请求示例
app.UseBundling(bundles =>
{
bundles.LoadFromConfigFile("/bundleconfig.json", _env.ContentRootFileProvider); // 如果你需要对Bundle Minifier的配置也进行处理
bundles.AddCss("/main.css") // 告诉中间件需要将以下的文件最终打包成一个虚拟文件名
.Include("/Content/bootstrap.min.css")
.Include("/fonts/icomoon.min.css")
.Include("/Content/jquery.paging.css")
.Include("/Content/common/reset.css")
.Include("/Content/common/loading.css")
.Include("/Content/common/style.css")
.Include("/Content/common/articlestyle.css")
.Include("/Content/common/leaderboard.css")
.Include("/Content/microtip.min.css")
.Include("/Assets/breadcrumb/style.css")
.Include("/Assets/nav/css/style.css")
.Include("/Assets/tippy/tippy.css");
bundles.AddJs("/main.js") // 告诉中间件需要将以下的文件最终打包成一个虚拟文件名
.Include("/Scripts/bootstrap.min.js")
.Include("/Scripts/bootstrap-suggest.min.js")
.Include("/Scripts/jquery.query.js")
.Include("/Scripts/jquery.paging.js")
.Include("/Scripts/ripplet.js")
.Include("/Scripts/global/scripts.js")
.Include("/Assets/tippy/tippy.js")
.Include("/Assets/newsbox/jquery.bootstrap.newsbox.js")
.Include("/Assets/tagcloud/js/tagcloud.js")
.Include("/Assets/scrolltop/js/scrolltop.js")
.Include("/Assets/nav/js/main.js");
});
最后,对于提升网站性能虽然非常重要,但合并文件如果太大,也是会影响性能的。另外采用合并中间件,对于开发的时候需要编写额外的代码、相对于原生的写法比较不直观,所以在优化性能的同时,我们也要找到一个平衡点,而不是一味的追求性能优化。
私信回复:1070
- End -
推荐阅读
React Router是React的事实上的标准路由库。当您需要在具有多个视图的React应用程序中导航时,将需要一个路由器来管理URL。React Router会做到这一点,使您的应用程序UI和URL保持同步。
本教程向您介绍React Router v5以及您可以使用它进行的许多操作。
React是一个流行的库,用于创建在客户端呈现的单页应用程序(SPA)。SPA可能具有多个视图(又称页面),并且与传统的多页面应用程序不同,在这些视图中导航不应导致整个页面被重新加载。相反,我们希望视图在当前页面中内联呈现。习惯了多页应用程序的最终用户希望SPA中具有以下功能:
路由是保持浏览器URL与页面上呈现的内容同步的过程。React Router使您可以声明式处理路由。声明式路由方法允许您通过说“路由应如下所示”来控制应用程序中的数据流:
<Route path="/about" component={About} />
您可以将<Route>组件放置在要渲染路线的任何位置。由于<Route>,<Link>以及我们将要处理的所有其他React Router API都是组件,因此您可以轻松地习惯于在React中进行路由。
开始之前的注释。人们普遍误以为React Router是Facebook开发的官方路由解决方案。实际上,它是一个第三方库,它以其设计和简单性而广受欢迎。如果您的需求仅限于用于导航的路由器,则可以从头开始实施自定义路由器,而不会带来太多麻烦。但是,了解React Router的基础知识将使您更好地了解路由器应如何工作。
本教程分为不同的部分。首先,我们将使用npm设置React和React Router。然后,我们将直接进入React Router基础知识。您将在实际中找到React Router的不同代码演示。本教程介绍的示例包括:
与构建这些路线有关的所有概念将一路讨论。该项目的完整代码可在此GitHub存储库中找到。进入特定的演示目录后,运行npm install以安装依赖项。要在开发服务器上为应用程序提供服务,请运行npm start并http://localhost:3000/转至观看演示示例。
让我们开始吧!
我假设您已经有一个开发环境正在运行。如果没有,请转到“ React和JSX入门 ”。另外,您可以使用Create React App生成创建基本React项目所需的文件。这是Create React App生成的默认目录结构:
react-router-demo
├── .gitignore
├── package.json
├── public
│ ├── favicon.ico
│ ├── index.html
│ └── manifest.json
├── README.md
├── src
│ ├── App.css
│ ├── App.js
│ ├── App.test.js
│ ├── index.css
│ ├── index.js
│ ├── logo.svg
│ └── registerServiceWorker.js
└── yarn.lock
该阵营路由器库包括三个包:react-router,react-router-dom,和react-router-native。react-router是路由器的核心软件包,而其他两个是特定于环境的。react-router-dom如果您正在构建网站,并且react-router-native正在使用React Native在移动应用程序开发环境中,则应使用。
使用npm进行安装react-router-dom:
npm install --save react-router-dom
这是我们路线的外观示例:
<Router>/* App component */
class App extends React.Component {
render() {
return (
<div>
<nav className="navbar navbar-light">
<ul className="nav navbar-nav">
/* Link components are used for linking to other views */
<li>
<Link to="/">Homes</Link>
</li>
<li>
<Link to="/category">Category</Link>
</li>
<li>
<Link to="/products">Products</Link>
</li>
</ul>
</nav>
/* Route components are rendered if the path prop matches the current URL*/
<Route path="/" component={Home} />
<Route path="/category" component={Category} />
<Route path="/products" component={Products} />
</div>
);
}
}
<Route exact path="/" component={Home} />
<Route path="/category" component={Category} />
<Route path="/login" component={Login} />
<Route path="/products" component={Products} />
</Router>
您需要一个路由器组件和几个路由组件来设置上述基本路由。由于我们正在构建基于浏览器的应用程序,因此可以使用React Router API中的两种类型的路由器:
它们之间的主要区别在于它们创建的URL:
// <BrowserRouter>
http://example.com/about
// <HashRouter>
http://example.com/#/about
该<BrowserRouter>因为它使用了HTML5 API历史来跟踪你的路由器的历史当中是两个更受欢迎。的<HashRouter>,而另一方面,使用URL(的哈希部分window.location.hash)记住的东西。如果您打算支持旧版浏览器,则应坚持使用<HashRouter>。
将<BrowserRouter>组件包装在App组件周围。
/* Import statements */
import React from "react";
import ReactDOM from "react-dom";
/* App is the entry point to the React code.*/
import App from "./App";
/* import BrowserRouter from 'react-router-dom' */
import { BrowserRouter } from "react-router-dom";
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById("root")
);
注意:路由器组件只能有一个子元素。子元素可以是HTML元素(例如div)或react组件。
为了使React Router正常工作,您需要从react-router-dom库中导入相关的API 。在这里,我已将导入BrowserRouter到中index.js。我还App从导入了组件App.js。App.js您可能已经猜到了,这是React组件的入口点。
上面的代码为我们整个App组件创建了一个历史实例。让我正式向您介绍历史。
history是一个JavaScript库,可让您在运行JavaScript的任何地方轻松管理会话历史记录。history提供了一个最小的API,可让您管理历史记录堆栈,导航,确认导航以及在会话之间保持状态。— React Training文档
每个路由器组件都创建一个历史对象,该对象跟踪当前位置(history.location)以及堆栈中的先前位置。当前位置更改时,将重新渲染视图,您会感到导航。当前位置如何变化?历史对象具有诸如history.push()和的方法history.replace()。history.push()单击<Link>组件history.replace()时调用,使用时调用<Redirect>。其他方法(例如history.goBack()和history.goForward())可用于通过后退或前进页面来浏览历史记录堆栈。
继续,我们有链接和路线。
该<Route>组件是React路由器中最重要的组件。如果当前位置与路线的路径匹配,它将呈现一些UI。理想情况下,<Route>组件应具有一个名为的prop path,并且如果路径名与当前位置匹配,则它将被呈现。
<Link>另一方面,该组件用于在页面之间导航。与HTML锚点元素相当。但是,使用锚链接会导致浏览器刷新,这是我们不希望的。因此,我们可以使用<Link>导航到特定的URL,并在不刷新浏览器的情况下重新渲染视图。
我们已经介绍了创建基本路由器所需的所有知识。让我们来建立一个。
/* Import statements */
import React, { Component } from "react";
import { Link, Route, Switch } from "react-router-dom";
/* Home component */
const Home = () => (
<div>
<h2>Home</h2>
</div>
);
/* Category component */
const Category = () => (
<div>
<h2>Category</h2>
</div>
);
/* Products component */
const Products = () => (
<div>
<h2>Products</h2>
</div>
);
export default function App() {
return (
<div>
<nav className="navbar navbar-light">
<ul className="nav navbar-nav">
<li>
<Link to="/">Homes</Link>
</li>
<li>
<Link to="/category">Category</Link>
</li>
<li>
<Link to="/products">Products</Link>
</li>
</ul>
</nav>
/* Route components are rendered if the path prop matches the current URL */
<Route path="/" component={Home} />
<Route path="/category" component={Category} />
<Route path="/products" component={Products} />
</div>
);
}
我们已经在内部声明了Home,Category和Products的组件App.js。尽管现在还可以,但是当组件开始变大时,最好为每个组件创建一个单独的文件。根据经验,如果组件占用的代码超过10行,我通常会为其创建一个新文件。从第二个演示开始,我将为已变得太大而无法容纳在文件中的组件创建一个单独的App.js文件。
在App组件内部,我们编写了路由逻辑。所述<Route>的路径与当前位置匹配,并且组件被渲染。应该渲染的组件作为第二个属性传入。
这里/匹配/和/category。因此,两条路线都匹配并渲染。我们如何避免这种情况?您应该使用以下命令将exact= {true}道具传递到路由器path='/':
<Route exact={true} path="/" component={Home} />
如果只在路径完全相同时才希望显示路线,则应使用精确的道具。
要创建嵌套路线,我们需要更好地了解其<Route>工作原理。来做吧。
<Route> 您可以使用三个道具来定义要渲染的内容:
该路径用于标识路由器应匹配的URL部分。它使用Path-to-RegExp库将路径字符串转换为正则表达式。然后将其与当前位置进行匹配。
如果路由器的路径和位置成功匹配,则会创建一个对象,我们将其称为匹配对象。匹配对象包含有关URL和路径的更多信息。可通过以下属性访问此信息:
既然我们已经了解了<Route>s,那么让我们用嵌套路由构建一个路由器。
在开始演示代码之前,我想向您介绍该<Switch>组件。当多个<Route>一起使用时,所有匹配的路由都被包含在内。考虑一下演示1中的这段代码。我添加了一条新路线来说明为什么<Switch>有用:
<Route exact path="/" component={Home}/>
<Route path="/products" component={Products}/>
<Route path="/category" component={Category}/>
<Route path="/:id" render = {()=> (<p> I want this text to show up for all routes other than '/', '/products' and '/category' </p>)}/>
如果URL是/products,/products则呈现所有与该位置匹配的路由。因此,<Route>with路径:id与Products组件一起呈现。这是设计使然。但是,如果这不是您所期望的行为,则应将<Switch>组件添加到路由中。使用<Switch>,只有<Route>与位置匹配的第一个孩子会被渲染。
早前,我们创造了路线/,/category和/products。如果我们想要表单的URL /category/shoes怎么办?
import React, { Component } from "react";
import { Link, Route, Switch } from "react-router-dom";
import Category from "./Category";
export default function App() {
return (
<div>
<nav className="navbar navbar-light">
<ul className="nav navbar-nav">
<li>
<Link to="/">Homes</Link>
</li>
<li>
<Link to="/category">Category</Link>
</li>
<li>
<Link to="/products">Products</Link>
</li>
</ul>
</nav>
<Switch>
<Route exact path="/" component={Home} />
<Route path="/category" component={Category} />
<Route path="/products" component={Products} />
</Switch>
</div>
);
}
/* Code for Home and Products component omitted for brevity */
与早期版本的React Router不同,在版本4及更高版本中,嵌套<Route>s应该最好放在父组件内部。也就是说,类别组件是此处的父组件,我们将声明category/:name父组件内部的路由。
import React from "react";
import { Link, Route } from "react-router-dom";
const Category = ({ match }) => {
return (
<div>
{" "}
<ul>
<li>
<Link to={`${match.url}/shoes`}>Shoes</Link>
</li>
<li>
<Link to={`${match.url}/boots`}>Boots</Link>
</li>
<li>
<Link to={`${match.url}/footwear`}>Footwear</Link>
</li>
</ul>
<Route
path={`${match.path}/:name`}
render={({ match }) => (
<div>
{" "}
<h3> {match.params.name} </h3>
</div>
)}
/>
</div>
);
};
export default Category;
首先,我们为嵌套路线声明了两个链接。如前所述,match.url将用于构建嵌套链接和match.path嵌套路由。如果您在理解匹配的概念时遇到困难,请console.log(match)提供一些有用的信息,可能有助于澄清它。
<Route
path={`${match.path}/:name`}
render={({ match }) => (
<div>
<h3> {match.params.name} </h3>
</div>
)}
/>
这是我们首次尝试动态路由。我们没有在路径中硬编码,而是在路径名中使用了变量。:name是一个路径参数,捕获所有内容,category/直到遇到另一个正斜杠为止。因此,像这样的路径products/running-shoes名将创建一个params对象,如下所示:
{
name: "running-shoes";
}
捕获的数据应在道具传递方式下match.params或props.match.params取决于道具传递方式而可访问。另一个有趣的事情是我们使用了render道具。render对于不需要自身组件的内联函数,props非常方便。
让事情变得更加复杂吧?现实世界中的路由器必须处理数据并动态显示。假设我们具有以下形式的服务器API返回的产品数据。
const productData = [
{
id: 1,
name: "NIKE Liteforce Blue Sneakers",
description:
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin molestie.",
status: "Available",
},
{
id: 2,
name: "Stylised Flip Flops and Slippers",
description:
"Mauris finibus, massa eu tempor volutpat, magna dolor euismod dolor.",
status: "Out of Stock",
},
{
id: 3,
name: "ADIDAS Adispree Running Shoes",
description:
"Maecenas condimentum porttitor auctor. Maecenas viverra fringilla felis, eu pretium.",
status: "Available",
},
{
id: 4,
name: "ADIDAS Mid Sneakers",
description:
"Ut hendrerit venenatis lacus, vel lacinia ipsum fermentum vel. Cras.",
status: "Out of Stock",
},
];
我们需要为以下路径创建路由:
/* Import statements have been left out for code brevity */
const Products = ({ match }) => {
const productsData = [
{
id: 1,
name: "NIKE Liteforce Blue Sneakers",
description:
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin molestie.",
status: "Available",
},
//Rest of the data has been left out for code brevity
];
/* Create an array of `<li>` items for each product */
const linkList = productsData.map((product) => {
return (
<li>
<Link to={`${match.url}/${product.id}`}>{product.name}</Link>
</li>
);
});
return (
<div>
<div>
<div>
<h3> Products</h3>
<ul> {linkList} </ul>
</div>
</div>
<Route
path={`${match.url}/:productId`}
render={(props) => <Product data={productsData} {...props} />}
/>
<Route
exact
path={match.url}
render={() => <div>Please select a product.</div>}
/>
</div>
);
};
首先,我们<Links>使用productsData.ids 创建了s 的列表并将其存储在中linkList。路由在路径字符串中采用与产品ID对应的参数。
<Route
path={`${match.url}/:productId`}
render={(props) => <Product data={productsData} {...props} />}
/>
您可能期望component = { Product }使用内联渲染功能。问题在于我们需要将productsData所有现有道具与产品组件一起传递。尽管还有其他方法可以执行此操作,但我发现此方法最简单。{...props}使用ES6的传播语法将整个props对象传递给组件。
这是产品组件的代码。
/* Import statements have been left out for code brevity */
const Product = ({ match, data }) => {
var product = data.find(p => p.id == match.params.productId);
var productData;
if (product)
productData = (
<div>
<h3> {product.name} </h3>
<p>{product.description}</p>
<hr />
<h4>{product.status}</h4>{" "}
</div>
);
else productData = <h2> Sorry. Product doesn't exist </h2>;
return (
<div>
<div>{productData}</div>
</div>
);
};
该find方法用于在数组中搜索ID属性等于的对象match.params.productId。如果产品存在,productData则显示。如果不存在,则显示“产品不存在”消息。
对于最后的演示,我们将讨论与保护路线有关的技术。因此,如果有人尝试访问/admin,则需要他们先登录。但是,在保护路线之前,我们需要涵盖一些内容。
像服务器端重定向一样,<Redirect>将历史记录堆栈中的当前位置替换为新位置。新位置由to道具指定。这是我们将如何使用<Redirect>:
<Redirect to={{pathname: '/login', state: {from: props.location}}}
因此,如果有人尝试/admin在登出时访问,他们将被重定向到该/login路由。有关当前位置的信息是通过状态传递的,因此,如果身份验证成功,则可以将用户重定向回原始位置。在子组件内部,您可以在访问此信息this.props.location.state。
定制路线是嵌套在组件内部的路线的俗称。如果我们需要决定是否应绘制路线,则编写自定义路线是可行的方法。这是在其他路线中声明的自定义路线。
/* Add the PrivateRoute component to the existing Routes */
<nav className="navbar navbar-light">
<ul className="nav navbar-nav">
...
<li><Link to="/admin">Admin area</Link></li>
</ul>
</nav>
<Switch>
<Route exact path="/" component={Home} data={data} />
<Route path="/category" component={Category} />
<Route path="/login" component={Login} />
<PrivateRoute path="/admin" component={Admin} />
<Route path="/products" component={Products} />
</Switch>
fakeAuth.isAuthenticated 如果用户已登录,则返回true,否则返回false。
这是PrivateRoute的定义:
/* PrivateRoute component definition */
const PrivateRoute = ({ component: Component, ...rest }) => {
return (
<Route
{...rest}
render={props =>
fakeAuth.isAuthenticated === true ? (
<Component {...props} />
) : (
<Redirect
to={{ pathname: "/login", state: { from: props.location } }}
/>
)
}
/>
);
};
如果用户已登录,则该路由将呈现Admin组件。否则,会将用户重定向到/login。这种方法的好处是,它显然更具生命性并且PrivateRoute可以重用。
最后,这是Login组件的代码:
import React, { useState } from "react";
import { Redirect } from "react-router-dom";
export default function Login(props) {
const { from } = props.location.state || { from: { pathname: "/" } };
console.log(from);
const [redirectToReferrer, setRedirectToReferrer] = useState(false);
const login = () => {
fakeAuth.authenticate(() => {
setRedirectToReferrer(true);
});
};
if (redirectToReferrer) {
return <Redirect to={from} />;
}
return (
<div>
<p>You must log in to view the page at {from.pathname}</p>
<button onClick={login}>Log in</button>
</div>
);
}
/* A fake authentication function */
export const fakeAuth = {
isAuthenticated: false,
authenticate(cb) {
this.isAuthenticated = true;
setTimeout(cb, 100);
}
};
下面的代码行演示了对象分解,它是ES6规范的一部分:
const { from } = this.props.location.state || { from: { pathname: "/" } };
让我们把拼图拼在一起吧?这是我们使用React路由器构建的应用程序的最终演示。
如您在本文中所见,React Router是一个功能强大的库,可补充React来构建更好的声明式路由。与第5版中的React Router的早期版本不同,所有内容都只是“组件”。而且,新的设计模式非常适合React的做事方式。
在本教程中,我们了解到:
最后,我们学习了一些先进的路由技术,可以为受保护的路由创建最终的演示。
《前端必备的20种基本React工具「干货」》
*请认真填写需求信息,我们会在24小时内与您取得联系。