03.react布局,路由和过渡

布局

移动端 flexbox 布局

   div{
        display: flex;
        justify-content: space-around;
        align-items: center;
    
        li{
            text-align:center;
    
            a{
                color:white;
                text-decoration: none;
            }
    
            .router-link-exact-active{
                color: green !important;
            }
        }
    }

在 React 中,如果想使用 SCSS,那么需要先安装 node-sass,重启服务可以直接运行(无需修改配置页)。

iscroll

    // yarn add iscroll
    import IScroll from 'iscroll';

    componentDidMount(){
    
        document.getElementsByClassName('box')[0].addEventListener('touchmove', function(e){
            e.preventDefault()
        });
        // window.$('.box').on('touchmove', e=>e.preventDefault())
    
        setTimeout(()=>{
            new IScroll('.box')
        }, 0)
    }

public/index.html 通过 script 标签引入 zepto.js 后,可以使用 $ 对象。(如果是嵌套路由,刷新该页面,因为spa原因,引入的zepto会识别成index.html,所以会报错)

zepto 的作用和 jquery 一样,可以理解成移动版的 jq。

    .box{
        flex: 1;
        overflow: hidden;
    
        >ul{
            background: yellow;       
        }
    }



路由

SPA 单页面应用开发(重点)

SPA 的优势:因为是把页面都合并到一起,所以路由切换时,实际上是在当前页面切换显示,所以不会因网络问题造成页面卡顿、白屏。

SPA 的不足:合并后的文件体积特别的大,所以第一次打开页面时,比较慢。(解决方法是用按需加载)

下载路由

    yarn add react-router-dom
    # or
    npm install react-router-dom -S

react-router-dom是第四代路由,对应的react16;react-router是第三代路由,对应的react15。

配置路由

在 React 中,没有所谓的路由规则页面,只需要把路由看作组件即可。

创建文件 /components/Router.js:

BrowserRouter 组件看作是路由外壳,所有的路由切换操作都在里面完成。

解析jsx的前提是必须引入react

    import { BrowserRouter, Route } from 'react-router-dom'
    const BasicRoute = ()=>{
        return (
            <BrowserRouter>
                <div>只能有1个子节点</div>
            </BrowserRouter>
        )
    }
    export default BasicRoute

在主入口 /main.js 中渲染路由组件:

  import Router from './components/Router.js'
    ReactDOM.render(<Router />, document.getElementById('root'))

路由组件

HashRouter

HashRouter, 外壳,浏览器地址栏中使用#标记来描述网址

BrowserRouter

BrowserRouter, 外壳,浏览器地址栏中使用斜杠及文件名来描述网址

MemoryRouter

MemoryRouter, 外壳,浏览器地址栏中url无变化

Route

React中的路由为包容性路由,而Vue中的路由为排他性路由。

包容性路由其实指模糊匹配,比如我们定义规则/,访问/about,包容性路由会认为他俩是匹配的。

Route, 每一条路由规则,通常为:

    <Route exact path='/' component={Index}></Route>

不要在 Route 的双标签中加空格或其他内容

exact属性表示绝对匹配(精准匹配)

Switch

Switch, 一个url,有可能匹配多个路由规则,使用Switch后,只渲染第一个匹配组件。

   <Switch>
        <Route path='/' component={Index} />
        <Route path='/about' component={About} />
    </Switch>

Link

Link, 其实就是a标签

    <Link to="/inbox" replace></Link>
    <Link to={{pathname:'/inbox'}}></Link>
    <Link replace={{pathname:'/inbox'}}></Link>

NavLink

NavLink, 也是a标签,会自动在a标签添加class属性。

默认的class值为active,可以通过activeClassName属性修改。

<NavLink exact activeClassName="active"></NavLink>

Prompt

Prompt, 询问对话框

比如在某组件中使用Prompt,那么路由离开这个组件时,触发提示。

Redirect

    <Prompt when={true} message="您确定要离开当前页面吗?" />

Redirect, 重定向

比如在某组件中

<Redirect to='/inbox' />

表示访问这个组件时,跳转到to对应的页面。

或者在Switch中根据用户的访问来决定匹配哪个重定向

   <Switch>
        <Redirect exact strict from='/Mine/' to='/a' />
        <Redirect from='/Mine/Login' to='/b' />
    </Switch>

exact 表示精准的;例如访问 /Mine/Login 时,如果没有exact,则匹配第一个

strict 表示是否匹配结尾的/;例如访问/Mine 时,如果有strict,那么找不到匹配

嵌套路由

Router.js 父层路由:

    <Route path='/about' component={About}></Route>

注意:嵌套路由外层不能有exact,否则刷新时子层匹配不到组件

About.js 子层路由:

  <Link to="/about/comp1">comp1</Link>
    <Link to="/about/comp2">comp2</Link>
    <Route exact path="/about/comp1" component={Comp1} />
    <Route exact path="/about/comp2" component={Comp2} />

路由中数据的传递

从一个页面,把数据传递给另一个页面的方法。

query数据

a 页面的链接(链接中含有要传递给b页面的数据)

不建议使用,因为获取到的数据是将多个query连在一起的字符串。

    <Link to="/b?x=1&y=2">b页面</Link>

b 页面的接收(接收a页面传递过来的数据)

   this.props.location

解决query字符串转换为js对象的方案:

    import querystring from 'querystring';
    console.log(querystring.parse(this.props.location.search.substring(1)))

也可以把链接地址由字符串改为js对象

不建议使用,因为刷新页面时,数据无保存。

    <Link to={{pathname:'/b',query:{x:1,y:2}}}>b页面</Link>

b 页面

    this.props.location.query

state数据

刷新页面时,数据有保存,所以建议用此方法。

  <Link to={{pathname:'/b',state:{x:1,y:2}}}>b页面</Link>

b 页面

  this.props.location.state

params数据

链接

   <Link to={{pathname:'/about/comp2/3/4'}}></Link>

路由出口(如果路由规则匹配,则把Comp2组件渲染到这个位置)

    <Route path="/about/comp2/:a/:b" component={Comp2}></Route>

在 Comp2 组件中接收 params 数据

this.props.match.params

钩子函数

我们学的是 react-router-dom 这是第四代路由,网上的教程多是 react-router 这是第三代路由。

第三代路由中有 onEnter onUpdate onLeave 方法,而第四代路由中,这些方法都去掉了,直接使用:

- componentDidMount 或 componentWillMount 代替 onEnter
- componentDidUpdate 或 componentWillUpdate 代替 onUpdate
- componentWillUnmount 代替 onLeave

编程式导航

必须在后代路由组件中使用

路由组件:使用 Route 渲染出来的组件,才具有 history 属性。

    this.props.history.push({pathname:'/abc'})
    // or
    this.props.history.replace({pathname:'/mine'})
    // or
    this.props.history.go(-1)

如果不是路由组件,则history不存在,那是否意味着非路由组件就不能用编程式导航?

高阶组件

高阶组件(Higher-Order Components)其实就是一个函数,该函数的作用就是将原始组件进行一些扩充,提供了一些额外的能力。

withRouter 让普通组件 Mine 具有 history 属性。

 import { withRouter } from 'react-router-dom'
    import Mine from './mine'
    export default withRouter(Mine)

普通组件 Mine 就可以使用 history 属性了

  this.props.history.push({pathname:'/abc'})

过渡动画

在 React 项目中实现动画效果

引入 animate

    <link href="https://cdn.bootcss.com/animate.css/3.7.0/animate.min.css" rel="stylesheet" />

下载过渡模块

    yarn add react-transition-group
    # or
    npm install react-transition-group -S

使用过渡模块

    import {CSSTransition, TransitionGroup} from 'react-transition-group';

react-transition-group 提供了三个子组件,Transition 和 CSSTransition 是单节点动画;TransitionGroup 是多节点动画。Transition 是使用 js 的形式写动画,所以项目中通常都使用 CSSTransition,表示用 CSS 形式写动画。

Transition官方说明:https://reactcommunity.org/react-transition-group/transition

    constructor(){
        this.state = {
            showBox:true
        }
    }
    toggleBox(){
        this.setState({
            showBox: !this.state.showBox
        })
    }
    render(){
        return (
            <div>
                <button onClick={this.toggleBox}>切换</button>
                <CSSTransition
                    in={this.state.showBox}
                    timeout={3000}
                    classNames={{
                        enterActive:'animated fadeIn',
                        exit:'animated fadeOut',
                        exitDone:'animated fadeOut'
                    }}
                    onEnter={function(){}}
                    onExited={function(){}}
                    unmountOnExit={true}
                >
                    <div>
                        这个元素在进入及离开时,具有动画效果。<br />
                        in属性为true时,表示进入,反之为离开。
                    </div>
                </CSSTransition>
            </div>
        )
    }

in

in 属性决定样式为进入还是离开

timeout

指多长时间完成动画。

动画的执行时长取决于css中的transition设置,而这个timeout指到达这个时间点后,className和钩子函数会被触发。

classNames

classNames 属性

classNames={{
    enter:'x',
    enterActive:'y',
    enterDone:'z',
    exit:'a',
    exitActive:'b',
    exitDone:'c'
}}

或者

classNames="menu3"

需要自己定义css

.menu3-enter{ left: 10px; transition: all 1s; } 
.menu3-enter-active{ left: 200px; } 
.menu3-enter-done{ left: 200px; }

unmountOnExit

unmountOnExit={true}

exit后,是否删除元素,默认不删除。

钩子函数

动画效果执行到某个阶段的时候,自动触发的函数。

  • onEnter

  • onEntering

  • onEntered

  • onExit

  • onExiting

  • onExited

    classNames={{
    exit:‘a’,
    exitActive:‘b’,
    exitDone:‘c’
    }}
    onExit={function(){console.log(‘onExit’)}}
    onExiting={function(){console.log(‘onExiting’)}}
    onExited={function(){console.log(‘onExited’)}}

    onEnter={function(){console.log(‘onEnter’)}}
    onEntering={function(){console.log(‘onEntering’)}}
    onEntered={function(){console.log(‘onEntered’)}}

举例:a样式添加上时,触发onExit;b样式添加上时,触发onExiting;c样式添加上时,触发onExited

Group动画

通过数据的添加和删除来决定动画的进出效果,所以在组动画中,CSSTransition组件中不需要写in属性。

<TransitionGroup>
    {this.props.todos.map((item, ind)=>( 
        <CSSTransition
            key={ind}
            timeout={500}
            classNames={{enterActive:'animated fadeIn'}}
        >
            <li> {item} </li>
        </CSSTransition>
    ))}
</TransitionGroup>

EventBus 中央事件总线

非父子组件,数据通信,eventbus。

bus.js

    import { Component } from 'react'
    import { EventEmitter } from 'events'
    const bus = new EventEmitter();
    Component.prototype.$bus = bus;

index.js

   import './modules/bus.js'

创建自定义事件

    this.$bus.on('abc', function(){})

触发自定义事件

    this.$bus.emit('abc')

emitter对象下还有once、off等方法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

blueSky-fan

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值