1.过渡动画
React并没有提供过渡动画操作,组件的过渡动画需要依赖第三方模块:transition
安装
yarn add react-transition-group
单元素过渡动画
import {CSSTransition} from 'react-transition-group'
...
<CSSTransition in={布尔值,控制单元素显示/隐藏} timeout={动画持续事件,单位毫秒} unmountOneExit={布尔值,元素隐藏后卸载,必选} className="字符串,动画样式名称前缀">
<单元素标签></单元素标签>
</CSSTransition>
...
.前缀-enter{} /*进入前*/
.后缀-enter-active{} /*进入中*/
.前缀-enter-done{} /*进入后,不常用*/
.前缀-exit{} /*离开前*/
.前缀-exit-active{} /*离开中*/
.前缀-exit-done{} /*离开后样式:不常用*/
多元素过渡动画:列表动画
import {TransitionGroup,CSSTranition} from "react-transition-group"
...
<TransitionGroup>
...多个元素
<CSSTransition ...><单元素标签></单元素标签></CSSTransition>
<CSSTransition ...><单元素标签></单元素标签></CSSTransition>
<CSSTransition ...><单元素标签></单元素标签></CSSTransition>
</TransitionGroup>
...
2.界面组件库:Ant Design
安装
yarn add antd
引入
安装完成后,引入样式文件 src/index.css
@import '~antd/dist/antd.css'
按需/全局引入antd组件库
import {Button} from 'antd'
...
<Button type="primary">点击</Button>
...
3.路由
1.概述
路由,描述了根据用户请求跳转到不同视图页面的一种操作规则
React中的路由,涉及到核心API
HashRouter:路由容器,主要用于包含路由匹配规则和路由组件,路径匹配方式包含#
BrowserRouter:路由容器,路径匹配方式和HashRouter不同,常规匹配方式
Switch:路由匹配对象,一般包裹在Router的外层,用户唯一匹配单个路由规则对象
Route:路由规则对象,包含类路径匹配、对应的渲染组件
NavLink:路由导航链接,一般用于导航作用
Redirect:路由重定向,可以将用户的访问路径,重定向到其他路径
2.新版本(6.x)路由操作
安装路由模块
yarn add react-router-dom
开发布局组件:src/Layout.jsx,完成组件和路由的跳转
import React,{Componet} from 'react'
import {BrowserRouter as Router,Routes,Route,NavLink} from 'react-router-dom'
import Home from './Home'
import About from './About'
export default class Layout extends Component {
render() {
return (
<div>
{/* 路由容器,将所有匹配规则包含起来*/}
<Router>
{/* 规则集合(新版),将所有规则包含起来 */}
<Routes>
{/*定义路由规则*/}
<Route path="/home" element={<Home />}></Route>
<Route path="/about" element={<About />}></Route>
</Routes>
<nav>
<ul>
<li><NavLink to="/home">首页</NavLink></li>
<li><NavLink to="/about">相关</NavLink></li>
</ul>
</nav>
<Router>
</div>
)
}
}
3.老版本路由操作(常用)
yarn add react-router-dom@5.3.X
开发布局组件:src/Layout.jsx,完成组件和路由的跳转
<div>
<Router>
<Route path="/home" component={Home} />
<Route path="/about" component={About} />
<NavLink to="/home">首页</NavLink>
<NavLink to="/about">相关</NavLink>
</Router>
</div>
4.路由重定向
<Route path="/">
<Redirect to="/home">
</Route>
5.路由导航高亮
react-router-dom提供的NavLink组件包含了默认导航高亮提示,主要通过导航链接的class="active"的样式处理来实现导航高亮的操作
注意:NavLink组件编译后的结果算是超链接标签
a.active {
color:red
}
6.路由严格匹配
导航链接中如果出现了同时多个路由规则匹配用户请求的情况,就会导致多个导航同时高亮的情况,需要通过路由模块提供的严格匹配方式排除导航多高亮的问题
需要在导航连接上,添加exact关键词
需要在路由组件上,添加exact关键词
<div>
<Router>
<Route path="/" exact>
<Redirect to="/home">
</Route>
<Route path="/home" component={Home} />
<Route path="/about" component={About} />
<NavLink to="/" exact>去首页</NavLink>
<NavLink to="/home">首页</NavLink>
<NavLink to="/about">相关</NavLink>
</Router>
</div>
7.404路由
针对用户访问的路由规则以外的路径,需要友好的提示404信息
创建404组件:NotFont.jsx
import React, { Component } from 'react'
export default class NotFound extends Component {
render() {
return (
<div>
404NotFond
</div>
)
}
}
编辑Layout.jsx
所有路由规则后面
<Route path="*" component={NotFound}></Route>
关于404路由和路由穿透
用户访问规则路径以外的路径,会得到404页面
用户访问路由规划页面,除了访问到页面组件,同时也访问到了404页面,这样的问题就是路由穿透问题
react-router-dom中提供的Switch组件,结局多个路由同时匹配的问题
<Switch>
路由规则
</Switch>
8.动态路由
多个路由规则匹配同一个路由组件,让路由组件达到复用的目的;该路由规则中包含固定的访问路径和访问数据部分,就是常规的RESTful路径风格
创建 Goods.jsx
...
<div>商品详情组件</div>
...
编辑Layout.jsx,添加Goods.jsx组件路由规则
<Route path="/goods/:id" component={Goods}></Route>
编辑About.jsx
import React, { Component } from 'react'
import { Link } from 'react-router-dom'
export default class About extends Component {
state= {
goods:[{id:1,name:'苹果'},{id:2,name:"橘子"}]
}
render() {
return (
<div>
{this.state.goods.map(item=>(
<Link to={`/good/${item.id}`} key={item.id}>{item.name}查看详情</Link>
))}
</div>
)
}
}
9.路由传参
路由规则,可以让路由在多个组件之间进行切换的同时传递数据,传递数据的方式有两种
RESTful参数
查询字符串参数
1.RESTful动态路由参数
路由规则Layout.jsx
<Route path="/goods/:id" component={Goods}></Route>
路由链接About.jsx
{this.state.goods.map(item=>(
<Link to={`/good/${item.id}`} key={item.id}>{item.name}查看详情</Link>
接收数据Goods.jsx
render() {
let {params} = this.props.match
return <div> 商品详情组件{params.id}</div>
}
2.查询字符串
创建组件 Order.jsx
export default class Order extends Component {
render() {
return (
<div>
订单页面
</div>
)
}
}
定义路由匹配规则
<Route path="/order" component={Order}>
创建访问链接 Cart.jsx
import React, { Component } from 'react'
import { Link } from 'react-router-dom'
export default class Cart extends Component {
state = {
cartList: [
{id:1,name: '苹果'},
{id:2,name:'橘子'}
]
}
render() {
return (
<div>
{this.state.cartList.map(item=>(
<Link to={`/order?id=${item.id}`}>下单{item.name}</Link>
))}
</div>
)
}
}
接收数据 Order.jsx
需要安装第三方模块qs
import qs from 'qs'
...
render() {
let {search} = this.props.location
let query = qs.parse(search.substring(1))
retrun (
<div>
订单页面{query.id}
</div>
)
}
...
10.嵌套路由
React中的嵌套路由,直接在目标页面组件中定义即可
创建组件-登录 Login.jsx
创建组件-注册 Register.jsx
Home.jsx页面添加二级路由
export default class Home extends Component {
render() {
return (
<div>
<Link to="/home/login">登录</Link>
<Link to="/home/register">注册</Link>
<div>
<Route path="/home/login" component={Login}></Route>
<Route path="/home/register" component={Register}></Route>
</div>
</div>
)
}
}
11.高阶路由
为了让路由组件的子组件接收到路由信息
react-router-dom提供了一个高阶组件:withRouter可以让子组件包含/接收到路由数据
编辑:Header.jsx
import { withRouter } from 'react-router-dom'
class Header extends Component {
render() {
return (
<div>
<h2>公共页头{this.props.location.pathname}</h2>
</div>
)
}
}
export default withRouter(Header)
12.路由懒加载
路由懒加载,相当于按需导入以及路由切换过程中的加载操作
import {lazy} from 'react'
const Home = lazy(()=>import('./Home'))
路由切换,需要添加一个过渡组件,将路由组件宝航在<React.Suspence>组件内部
<Suspence fallback={<h1>加载中</h1>}>
路由规则
</Suspense>
4.路由封装
1.现有路由的问题
当前项目中,根据React语法习惯,将路由在使用的地方进行声明。如Layout.jsx中配置了一级路由
路由匹配规则代码,和页面视图代码混合到一起,后期不方便维护
路由匹配路径和路由组件,和普通页面组件混合在一起,不利于功能的扩展和项目维护
多级路由的配置,会让路由规则出现在大量不同的页面组件中,不方便后期路由的设置维护
2.路由初步封装
创建router/RouterView.jsx路由组件,封装一级路由
import {lazy} from 'react'
const About =lazy(()=>import('./componets/About'))
const Home =lazy(()=>import('./componets/Home'))
const NotFound =lazy(()=>import('./componets/NotFound'))
const Goods =lazy(()=>import('./componets/Goods'))
const Order =lazy(()=>import('./componets/Order'))
const Cart =lazy(()=>import('./componets/Cart'))
//配置路由规则
const routes = [
{path:"/",redirect:"/home",exact:true},
{path:"/home",component:Home,exact:false},{path:"/about",component:About,exact:false},{path:"/goods",component:Goods,exact:false},{path:"/order",component:Order,exact:false},{path:"/cart",component:Cart,exact:false},{path:"*",component:NotFound,exact:false},
]
// 封装路由组件
function RouterView() {
return <Switch>
{routes.map((item,index)=>{
if(item.component) {
return <Route key={index} exact={item.exact} path={item.path} component={item.component}/>
}else {
return <Route key={index} exact={item.exact} path={item.path}><Redirect to={item.redirect}></Redirect></Route>
}
})}
</Switch>
}
export default RouterView
在Layout.jsx中引入使用
import RouterView from '../router/RouterView'
...
render() {
<React.Suspence fallback={<h1>加载中</h1>}>
<RouteView />
</React.Suspence>
}
...
3.封装升级:组件和配置分离
创建组件RouterView.jsx主要用于生成路由组件,不做具体路由规则配置
function RouterView(props) {
let {routes} = porps
return <Switch>
{routes.map((item,index)=>{
if(item.component) {
return <Route key={index} exact={item.exact} path={item.path} component={item.component}/>
}else {
return <Route key={index} exact={item.exact} path={item.path}><Redirect to={item.redirect}></Redirect></Route>
}
})}
</Switch>
}
}
export default RouterView
创建配置文件:indexRouter.js用于一级路由规则配置
import {lazy} from 'react'
const About =lazy(()=>import('./componets/About'))
const Home =lazy(()=>import('./componets/Home'))
const NotFound =lazy(()=>import('./componets/NotFound'))
const Goods =lazy(()=>import('./componets/Goods'))
const Order =lazy(()=>import('./componets/Order'))
const Cart =lazy(()=>import('./componets/Cart'))
//配置路由规则
const routes = [
{path:"/",redirect:"/home",exact:true},
{path:"/home",component:Home,exact:false},{path:"/about",component:About,exact:false},{path:"/goods",component:Goods,exact:false},{path:"/order",component:Order,exact:false},{path:"/cart",component:Cart,exact:false},{path:"*",component:NotFound,exact:false},
]
export default routes
一级路由,在Layout中使用
import routes from './indexRouter'
import RouterView from './RouterView'
...
render() {
...
<RouterView routes={routes} />
...
}
...
创建类似文件:users.js,主要用于用户中心二级路由配置
import {lazy} from 'react'
const Login = lazy(()=>import('./pages/Login'))
const Register = lazy(()=>import('./pages/Register'))
const routes = [
{path:"/home/login",component:Login},
{path:"/home/Register",component:Register}
]
export default routes
二级路由在Home.jsx中的应用
import routes from './users'
import RouterView from './RouterView'
...
render() {
...
<RouterView routes={routes} />
...
}
...
4.导航守卫
React中没有导航守卫,通过组件中的配置选项,完成导航守卫的功能
组件需要通过路由规则进行匹配渲染,可以在路由规则中添加渲染组件的条件,起到了导航守卫的功能
function RouterView(props) {
let {routes} = props
return <Switch>
{
routes.map((item,index)=>{
if(item.component){
return <Route key={index} exact={item.exact} path={item.path} render={()=>{
let token = localStorage.getItem("token")
if(!token&&item.path==='/about'){
return <Redirect to="/login" />
}
let Component = withRouter(item.component)
return <Component />
}}>
}
})
}
</Switch>
}
5.编程式导航
路由组件中,this.props中包含了三大模块
match:用于RESTful参数数据传递处理
location:用于查询字符串参数传递处理
history:可以用于编程式导航
编程式导航:借助于this.props.history
go(num)
goBack()
goForward()
push(path):跳转到指定路径,并暴力流跳转历史记录
replace(path):跳转到指定路径,不报保留跳转历史记录