文章目录

  • 1. 重点提炼
  • 2. React.js - 路由react-router-dom
    • 2.1 路由
      • 2.1.1 SPA
      • 2.1.2 SPA 的页面切换机制
      • 2.1.3 后端路由与前端路由
        • 2.1.3.1 后端路由
        • 2.1.3.2 前端路由
          • 2.1.3.2.1 URL Hash
          • 2.1.3.2.2 HTML5 History API
      • 2.1.4 React.js 中的路由
    • 2.2 React Router
      • 2.2.1 基于 WebReact Router
        • 2.2.1.1 安装
        • 2.2.1.2 概览
    • 2.3 基础
      • 2.3.1 应用场景(一)
        • 2.3.1.1 Router 组件
          • 2.3.1.1.1 exmaple01
            • 2.3.1.1.1.1 exmaple01-1
            • 2.3.1.1.1.2 example01-2
          • 2.3.1.1.2 BrowserRouter 组件
          • 2.3.1.1.3 HashRouter 组件
        • 2.3.1.2 Route 组件
          • 2.3.1.2.1 exact
        • 2.3.1.3 Link 组件
          • 2.3.1.3.1 to 属性
        • 2.3.1.4 example02
          • 2.3.1.4.1 example02-1
          • 2.3.1.4.2 example02-2
          • 2.3.1.4.3 example02-3
          • 2.3.1.4.4 example02-4
          • 2.3.1.4.5 example02-5
      • 2.3.2 应用场景(二)
        • 2.3.2.1 状态提升
        • 2.3.2.2 传递 props
          • 2.3.2.2.1 example03
          • 2.3.2.2.2 Route : render
            • 2.3.2.2.2.1 example04
        • 2.3.2.3 渲染列表
          • 2.3.2.3.1 example05
          • 2.3.2.3.2 params
        • 2.3.2.4 动态路由
          • 2.3.2.4.1 path-to-regexp
          • 2.3.2.4.2 Route : props
        • 2.3.2.5 路由组件
          • 2.3.2.5.1 example06
            • 2.3.2.5.1.1 example06-1
            • 2.3.2.5.1.2 example06-2
          • 2.3.2.5.2 match : params
            • 2.3.2.5.2.1 example07
        • 2.3.2.6 通信小结
      • 2.3.3 应用场景(三)
        • 2.3.3.1 通过 JavaScript 实现排序切换
          • 2.3.3.1.1 example08
            • 2.3.3.1.1.1 example08-1
            • 2.3.3.1.1.2 example08-2
            • 2.3.3.1.1.3 example08-3
        • 2.3.3.2 通过路由实现排序切换
          • 2.3.3.2.1 queryString
          • 2.3.3.2.2 URLSearchParams
        • 2.3.3.3 扩展
          • 2.3.3.3.1 qs 库
          • 2.3.3.3.2 安装
          • 2.3.3.3.3 使用
          • 2.3.3.3.4 通过 JavaScript 编程的方式切换路由
          • 2.3.3.3.5 example09
            • 2.3.3.3.5.1 example09-1
            • 2.3.3.3.5.2 example09-2
            • 2.3.3.3.5.3 example09-3
            • 2.3.3.3.5.4 example09-4
            • 2.3.3.3.5.5 example09-5
      • 2.3.4 应用场景(四)
        • 2.3.4.1 NavLink 组件
          • 2.3.4.1.1 activeStyle
          • 2.3.4.1.2 activeClassName
          • 2.3.4.1.3 isActive(类似回调,可以处理一些更为复杂的情况)
          • 2.3.4.1.4 exact
        • 2.3.4.2 example10
          • 2.3.4.2.1 example10-1
          • 2.3.4.2.2 example10-2
          • 2.3.4.2.3 example10-3
      • 2.3.5 应用场景(五)
        • 2.3.5.1 Switch 组件
        • 2.3.5.2 example11
          • 2.3.5.2.1 example11-1
          • 2.3.5.2.2 example11-2
      • 2.3.6 应用场景(六)
        • 2.3.6.1 example12
        • 2.3.6.2 Redirect 组件
          • 2.3.6.2.1 to
          • 2.3.6.2.2 example13
      • 2.3.7 应用场景(七)
        • 2.3.7.1 withRouter 组件(高阶组件)
        • 2.3.7.2 example14
          • 2.3.7.2.1 example14-1
          • 2.3.7.2.2 example14-2
          • 2.3.7.2.3 example14-3
          • 2.3.7.2.4 example14-4
          • 2.3.7.2.5 example14-5

1. 重点提炼

React 路由

  • React-Router
    • Native
    • Web : react-router-dom
  • BrowserRouter / HashRouter:路由根组件,提供路由基础服务
  • Route:路由组件,处理 url 与 组件的 映射(绑定)
  • Link:动态生成 a 标签,并提供导航服务

2. React.js - 路由react-router-dom

2.1 路由

实际上这个路由,和我们平时使用的路由器是一样的,没太大差异,其目的就是内容分发(分流)。其实就是将一整块内容,切分成一个个部分,根据某种规则进行分块的访问。比如现在有很多电脑,你想把它们纳入到一起进行管理,这个时候就需要购买一个路由器了。它核心作用其实就是处理我们每次发送的请求以及数据。就相当于我们现在拥有一个庞大的资源,那么资源怎么去管理呢?不可能每次请求,都把这么庞大的资源都塞给接受者,发送人和请求人都会累奔溃。一般把资源按照不同的类别和需求进行分门别类,把它组织好,分好,这个时候得需要某种方式得到数据。

一般情况下都是用url来获得数据的,通过它与后端对应的服务与资源做对应,即通过不同的url即可得到后端不同的数据,其实是做内容分发用的,所以实际前端路由概念是很类似的。

当应用变得复杂的时候,就需要分块的进行处理和展示,传统模式下,我们是把整个应用分成了多个页面,然后通过 URL 进行连接。但是这种方式也有一些问题,每次切换页面都需要重新发送所有请求和渲染整个页面,不止性能上会有影响,对资源量浪费,同时也会导致整个 JavaScript 重新执行,丢失状态。

如a、b两个页面都是一样的,有99%是一样的,就有一些文字不同。如果从a页面切换到b页面,也等同于重新发了一个请求,去请求b页面的资源,浏览器就会把整个页面进行重新渲染,这样对资源是极其地浪费。

为了解决这样的问题,用js的方式去拉去数据,而不是一整个页面,而是变化地部分。如第一次请求是一个首页,浏览器请求整个页面。但第二次比如跳转详情页面,就没必要去请求一个完整的页面过来了,这时候我们是通过ajax往后端发送请求,后端传递的数据仅仅是页面当中不同的部分的数据,而不是整个新页面。当前端页面拿到这个数据以后,就动态地通过dom的一系列操作,把页面需要变化的部分给替换掉,不变地部分保留下来。这样的操作其实就不是通过浏览器本身发送的请求,所以得到的内容是不会被浏览器重新渲染的。它会通过js,利用操作dom的方式进行局部更新。即通过这样地方式,节约很多性能,同时也不会改变页面的状态。

如有一个复杂的页面,页面当中有一个表单,正则填写的时候,侧面有一个新闻。写得过程中,想一边看新闻,需要更新一下新闻,一点击,只会通过js把新闻的部分替换掉,我们的表单是不会动的,这个时候并不是渲染整个页面,它能够更好的保留用户在页面当中的操作状态,即用户体验是非常好的。我们通常称这种模式为SPA(单页面应用)。

2.1.1 SPA

Single Page Application : 单页面应用,整个应用只加载一个页面(入口页面),后续在与用户的交互过程中,通过 DOM 操作在这个单页上动态生成结构和内容

优点:

  • 有更好的用户体验(减少请求和渲染和页面跳转产生的等待与空白),页面切换快(不会导致整个页面重新渲染)
  • 重前端,数据和页面内容由异步请求(AJAX)+ DOM 操作来完成,前端处理更多的业务逻辑

缺点:(会有很多技术去解决这些问题)

  • 首屏处理慢(因为把很多数据和逻辑都放在前端了,页面相当于反应速度会慢一些)

  • 不利于 SEO(搜索引擎的优化)

2.1.2 SPA 的页面切换机制

SPA 的页面切换机制主要有两种方式。

SPA虽然是单页面的,但是如果全部通过Ajaxdom渲染去完成的话,如我们现在去请求一个首页,用Ajax方式请求内容,会有一个问题。如果这个时候想单看列表,不想看首页这么多的内容呢?这个时候你就会发现我们的操作,不可跳转,即必须按照某种方式:第一步、第二步、…、一直点,点到你看到的列表为止。它是不能作为单独的方式给你呈现的,因为所有的后续操作都是通过这个入口完成的,必须先进入口,通过入口一步步操作才能够看到我们想看的东西。这样的话,会非常繁琐和麻烦。这个时候就想到一个办法,伪造url定位到不同的操作当中。不需要点击n多步,就可以访问到n多步操作完成后的页面。但是我们也不希望这个url产生真正的请求,这个时候我们采取的方式就是:

前端路由主要的模式(通过这两种方式更改url,但更改url的同时又不会发送请求,然后再去监听它的事件,把页面渲染的逻辑放在回调函数中,当js发现url变化了,则会动态地根据url的变化,去渲染我们想要看到的页面内容。):

  • 基于 URL Hash 的路由
  • 基于 HTML5 History API 的路由

虽然 SPA 的内容都是在一个页面通过 JavaScript 动态处理的,但是还是需要根据需求在不同的情况下分内容展示,如果仅仅只是依靠 JavaScript 内部机制去判断,逻辑会变得过于复杂,通过把 JavaScriptURL 进行结合的方式: JavaScript 根据 URL 的变化,来处理不同的逻辑,交互过程中只需要改变 URL 即可。这样把不同 URLJavaScript 对应的逻辑进行关联的方式就是路由,其本质上与后端路由的思想是一样的。

2.1.3 后端路由与前端路由

后端路由与前端路由在本质上是类似的,都是把不同的 URL 与某个操作进行关联绑定,得到不一样的结果

2.1.3.1 后端路由

通过 HTTP 把请求发送到后端服务器,后端服务器接收到请求以后根据不同的请求 URL 来执行不同的操作,返回处理好的数据(JSON、HTML、JS 代码、CSS、图像……)

  • 需要发送 HTTP 请求
  • 业务逻辑由后端处理,返回处理后的结果给前端(浏览器)

2.1.3.2 前端路由

前端路由只是改变了 URLURL 中的某一部分,但一定不会直接发送请求,可以认为仅仅只是改变了浏览器地址栏上的 URL 而已,JavaScript 通过各种手段处理这种 URL 的变化,然后通过 DOM 操作动态的改变当前页面的结构

  • URL 的变化不会直接发送 HTTP 请求
  • 业务逻辑由前端 JavaScript 来完成

目前前端路由主要的模式:

  • 基于 URL Hash 的路由
  • 基于 HTML5 History API 的路由
2.1.3.2.1 URL Hash

通过通过修改 URLHash 值来改变 URLHash 的变化是不会发送请求的,同时 JavaScript 通过监听 hashchange 事件来动态处理逻辑和页面渲染

优点

兼容性好

缺点

URL 不美观,SEO 不友好

2.1.3.2.2 HTML5 History API

封装一个函数,该函数通过 HTML5 History 提供的 API 来动态改变 URL ,这种方式也不会发送请求,然后同时根据要改变的目标 URL 来处理逻辑和页面渲染

URL Hash 模式类似 Vue 中的数据拦截机制

HTML5 History API 模式类似 React.js 中的 setState

2.1.4 React.js 中的路由

React.js 路由的基本思想就是,把不同的 URL 与 指定的某些 React.js 组件进行关联,不同的 URL 渲染显示不同的组件,其它框架(如:vue、angular) 都是一样的思想

2.2 React Router

理解了路由基本机制以后,也不需要重复造轮子,我们可以直接使用 React Router

https://reacttraining.com/react-router/

React Router 提供了多种不同环境下的路由库

  • web
  • native

2.2.1 基于 WebReact Router

基于 webReact Router 为:react-router-dom

2.2.1.1 安装

npm i -S react-router-dom

2.2.1.2 概览

react-router-dom 的核心是组件,它提供了一系列的组件,如:

  • Router 组件
  • BrowserRouter 组件
  • HashRouter 组件
  • Route 组件
  • Link 组件
  • NavLink 组件
  • Switch 组件
  • Redirect 组件

以及其它一些 API,来完成路由的功能

2.3 基础

2.3.1 应用场景(一)

假设当前应用有两个页面,对应的 URL 与 页面关系

/                :    首页
/about    :    关于我们

用户一进来的是首页,在里面的链接或按钮,点击之后跳到“关于我们”的页面。

现在不用传统的方式写两个html页面,发送两次请求,而是用React搭建。React渲染过后会形成一个页面,这个页面里看到的内容其实就是主件,实际上就是把一个个页面转换成一个个的组件。然后再通过url的形式,它是基于htmlhistoryapi,或者通过urlhash两种模式,当url发生变化的时候,来给用户展示不同的组件。其实就是页面的某个部分会根据不同的url而变化,来展示不同的组件内容,这其实就是前端路由的概念。

2.3.1.1 Router 组件

页面 = 组件
路由:根据不同的 url 的变化,在我们的应用中指定的位置渲染不同的组件,从而显示出来不同的内容

组件划分类型(注意它们不是互相独立的,是相互可能存在关系的,这里只是做功能上的划分):

  • 页面组件(视图组件),一个页面组件一般对应的就是完整的页面(完整:一个url所表示的页面)(如:登页和注册页等)
  • 功能组件(具有一定功能的,但一般情况下又不是一个完整的页面的组件,轮播图,对话框等,功能组件就是面组件的一部分)
    • 带视图的功能组件(轮播图)
    • 不带视图的功能组件,即业务型的功能组件(数据过滤数据请求 - 作为容器错误捕获(把错误发给指定邮箱)
  • 容器组件

项目整个结构也需要分类:

components(功能型组件、容器型组件)

views(视图型组件)

2.3.1.1.1 exmaple01

应用场景(一)

2.3.1.1.1.1 exmaple01-1

框子实现。

app.js

import React from 'react';import Home from './views/Home';
import About from './views/About';class App extends React.Component {constructor(props) {super(props);}render() {return (<div className="App"><Home/><About/></div>)}}export default App;

src/views/Home.js

import React from 'react';export default class Home extends React.Component {render() {return (<div><h2>商品列表</h2></div>);}}

src/views/About.js

import React from 'react';export default class About extends React.Component {render() {return(<div>关于我们</div>);}}

image-20200605231442716

参考:https://github.com/6xiaoDi/blog-react-Novice/tree/v3.01-1
Branch:branch4

commit description:v3.01-1-example01-1(应用场景(一)- 框子实现)

tag:v3.01-1

2.3.1.1.1.2 example01-2
console.log(window.location);

hash其实就是url后面#的内容

image-20200606102911256

image-20200606103120690

通过hash设置默认首页及url

app.js

 import React from 'react';import Home from './views/Home';
import About from './views/About';class App extends React.Component {constructor(props) {super(props);}render() {// console.log(window.location);let hash = window.location.hash || '#home';console.log(hash);return (<div className="App"><Home/><About/></div>)}}export default App;

 import React from 'react';import Home from './views/Home';
import About from './views/About';class App extends React.Component {constructor(props) {super(props);}render() {// console.log(window.location);let hash = window.location.hash || '#home';console.log(hash);return (<div className="App">{/*<Home/>*/}{/*<About/>*/}{hash === '#home' && <Home />}{hash === '#about' && <About />}</div>)}}export default App;

参考:https://github.com/6xiaoDi/blog-react-Novice/tree/v3.01-2
Branch:branch4

commit description:v3.01-2-example01-2(应用场景(一)- 通过hash设置默认首页及url)

tag:v3.01-2

这里的原理虽然不难,但是要是实现用户点击,跳转页面。需要监听hashchange的变化,考虑hashurl的规则,实际上整个页面会更加复杂,实际需求是复杂的。实际上React-router的内部就是运用这些原理的,只是封装好之后,提供更好的方式供使用,其内部封装了很多组件。

如果我们希望页面中某个部分的内容需要根据 URL 来动态显示,需要用到 Router 组件 ,该组件是一个容器组件,只需要用它包裹 URL 对应的根组件即可

react-router-dom 为我们提供了几个基于不同模式的 router 子组件(功能性组件且容器组件)

  • BrowserRouter 组件
  • HashRouter 组件
  • MemoryRouter 组件
  • NativeRouter 组件
  • StaticRouter 组件
2.3.1.1.2 BrowserRouter 组件

基于 HTML5 History API 的路由组件

2.3.1.1.3 HashRouter 组件

基于 URL Hash 的路由组件

css

ul {margin: 0;padding: 0;
}li {list-style: none;
}.item-list li {padding: 10px;display: flex;justify-content: space-between;height: 30px;line-height: 30px;border-bottom: 1px dotted #333;
}
.item-list li.head {font-weight: bold;
}
.item-list li span {min-width: 200px;
}.pagination {margin: 10px;
}
.pagination a {margin: 0 5px;display: inline-block;width: 30px;height: 30px;background-color: #f4f4f5;line-height: 30px;text-align: center;cursor: pointer;color: #606266;text-decoration: none;
}
.pagination a:hover {color: #409eff;
}
.pagination a.active {background-color: #409eff;color: #fff;cursor: text;
}
.pagination .goto {margin: 0 5px;box-sizing: border-box;width: 80px;height: 30px;border: 1px solid #dcdfe6;outline: none;text-align: center;vertical-align: top;
}

App.js

import React from 'react';import {BrowserRouter as Router} from 'react-router-dom';
// import {HashRouter as Router} from 'react-router-dom';import BaseApp from './BaseApp/Index';function App() {return (<div><h1>React-Router</h1><hr/><Router><BaseApp /></Router></div>);
}export default App;
import {BrowserRouter as Router} from 'react-router-dom'

导入 BrowserRouter 组件,并命名 Router 别名,方便使用

<Router><BaseApp />
</Router>

只对页面中的 BaseApp 组件使用路由

./BaseApp/Index.js

import React from 'react';
import {Route, Link} from 'react-router-dom';import Home from './Home';
import About from './About';export default class BaseApp extends React.Component {render() {return(<div><h2>路由基础使用</h2><nav><Link to="/">Home</Link><span> | </span><Link to="/about">About</Link></nav><br/><Route exact path='/' component={Home} /><Route path='/about' component={About} /></div>);}}
import {Route} from 'react-router-dom';

2.3.1.2 Route 组件

注意这个组件是没有字母 r 的,通过该组件来设置应用单个路由信息,Route 组件所在的区域就是就是当 URL 与当前 Route 设置的 path 属性匹配的时候,后面 component 将要显示的区域

<Route path='/' component={Home} />

URL 为:’/’ 的时候,组件 Home 将显示在这里

2.3.1.2.1 exact

exact 属性表示路由使用 精确匹配模式,非 exact 模式下 ‘/’ 匹配所有以 ‘/’ 开头的路由

2.3.1.3 Link 组件

Link 组件用来处理 a 链接 类似的功能(它会在页面中生成一个 a 标签),但设置这里需要注意的,react-router-dom 拦截了实际 a 标签的默认动作,然后根据所有使用的路由模式(Hash 或者 HTML5)来进行处理,改变了 URL,但不会发生请求,同时根据 Route 中的设置把对应的组件显示在指定的位置

2.3.1.3.1 to 属性

to 属性类似 a 标签中的 href

2.3.1.4 example02

场景(一)应用。

2.3.1.4.1 example02-1

HashRouter组件:

  • HashRouter 包含的组件才能响应路由

  • BrowserRouter: 基于 HTML5 History API

src/index.js

import React from 'react';
import ReactDOM from 'react-dom';
// import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
import {HashRouter} from 'react-router-dom';ReactDOM.render(<HashRouter><App /></HashRouter>,document.getElementById('root')
);// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();

Route配置url与组件的映射关系:什么url与什么组件现在页面的什么位置。所在的位置就是满足要求以后组件渲染对应的位置。

path对应urlcomponent对应组件

src/App.js

import React from 'react';import {Route} from 'react-router-dom';import Home from './views/Home';
import About from './views/About';class App extends React.Component {constructor(props) {super(props);}render() {return (<div className="App"><h1>React路由</h1><Route path="/" component={Home}/></div>)}}export default App;
image-20200606133418783
                    <h1>React路由</h1><hr/><Route path="/" component={Home}/><Route path="/about" component={About}/>

发现首页也显示进去了,因为此时路由url既满足首页又满足about,所以需要我们精确匹配。

image-20200606133723623

参考:https://github.com/6xiaoDi/blog-react-Novice/tree/v3.02-1
Branch:branch4

commit description:v3.02-1-example02-1(应用场景(一)- React路由匹配)

tag:v3.02-1

2.3.1.4.2 example02-2

exact 属性表示路由使用 精确匹配模式,非 exact 模式下 ‘/’ 匹配所有以 ‘/’ 开头的路由

                    <h1>React路由</h1><hr/>{/*<Route path="/" component={Home}/>*/}<Route path="/" component={Home} exact /><Route path="/about" component={About}/>
image-20200606134106681

参考:https://github.com/6xiaoDi/blog-react-Novice/tree/v3.02-2
Branch:branch4

commit description:v3.02-2-example02-2(应用场景(一)- React路由精确匹配)

tag:v3.02-2

2.3.1.4.3 example02-3

用户在做页面跳转时,不可能自己手动输入url,所以以上是不可能得以应用的。通常我们使用UI的方式,关联到页面的元素,供用户点击跳转。

                    <h1>React路由</h1><hr/><Route path="/" component={Home} exact /><Route path="/about" component={About}/><nav><a href="/">首页</a><span> | </span><a href="/about">关于我们</a></nav>

这样是错误的,只会刷新页面并毫无反应!必须带#

                    <h1>React路由</h1><hr/><Route path="/" component={Home} exact /><Route path="/about" component={About}/>                  <nav><a href="#/">首页</a><span> | </span><a href="#/about">关于我们</a></nav>

有人可能会问,为啥可以把对应的组件显示出来呢?

因为react-router-dom会监听hash的变化,我们只需要触发hash的变化就行了,这个库的内部会触发hashchange事件。

参考:https://github.com/6xiaoDi/blog-react-Novice/tree/v3.02-3
Branch:branch4

commit description:v3.02-3-example02-3(应用场景(一)- React路由精确匹配,UI的方式控制)

tag:v3.02-3

2.3.1.4.4 example02-4

但以上这种形式并不是太好(url也很丑),以上是hash模式,接下来演示historyApi的模式。

BrowserRouter: 基于HTML5 History API

src/index.js

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import * as serviceWorker from './serviceWorker';
import {HashRouter, BrowserRouter} from 'react-router-dom';ReactDOM.render(<BrowserRouter><App /></BrowserRouter>,document.getElementById('root')
);// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();

它是基于html5的,/更加美观。

image-20200606151551880
                    <nav><a href="/">首页</a><span> | </span><a href="/about">关于我们</a></nav>

但我们会发现一个问题,就是它是刷新了我们整个页面的!刷新完毕后,再根据url再显示主件。

如果有个input,就坑了!

                    <h1>React路由</h1><hr/> <nav><a href="/">首页</a><span> | </span><a href="/about">关于我们</a></nav><input type="text"/><hr/><Route path="/" component={Home} exact /><Route path="/about" component={About}/>

参考:https://github.com/6xiaoDi/blog-react-Novice/tree/v3.02-4
Branch:branch4

commit description:v3.02-4-example02-4(应用场景(一)- 使用BrowserRouter组件,带来的丢失状态的问题)

tag:v3.02-4

2.3.1.4.5 example02-5

怎么处理呢?不要用原生的a标签了!推荐使用它的link组件。

    import React from 'react';import {Route, Link} from 'react-router-dom';import Home from './views/Home';import About from './views/About';class App extends React.Component {constructor(props) {super(props);}render() {return (<div className="App"><h1>React路由</h1><hr/><nav><Link to="/">首页</Link><span> | </span><Link to="/about">关于我们</Link></nav><hr/><input type="text"/><Route path="/" component={Home} exact /><Route path="/about" component={About}/></div>)}}export default App;

link帮助我们生成的a标签,还监听了a标签的点击事件,阻止了a的默认跳转行为,同时在它的内部又触发了html5historyapi,修改了url,再根据修改的url,显示对应的组件。

同时不论是用HashRouter还是BrowserRouter,link组件都会帮我们生成对应a标签,我们无需关系是否加#了!

仔细观察,a标签里有点击事件。

image-20200606161531402

参考:https://github.com/6xiaoDi/blog-react-Novice/tree/v3.02-5
Branch:branch4

commit description:v3.02-5-example02-5(应用场景(一)- 使用BrowserRouter组件,解决带来的丢失状态的问题)

tag:v3.02-5

2.3.2 应用场景(二)

最近生活拮据,想在应用中卖点东西补贴一下家用

2.3.2.1 状态提升

前面讲组件中提到过组件状态提升,如果多个组件需要共享一个状态,那么就讲状态提升到使用该状态的共同父级组件上。

./BaseApp/Index.js

this.state = {items: [{id: 1,name: 'iPhone XR',price: 542500},{id: 2,name: 'Apple iPad Air 3',price: 377700},{id: 3,name: 'Macbook Pro 15.4',price: 1949900},{id: 4,name: 'Apple iMac',price: 1629900},{id: 5,name: 'Apple Magic Mouse',price: 72900},{id: 6,name: 'Apple Watch Series 4',price: 599900}]
}

2.3.2.2 传递 props

<Route exact path='/' component={Home}

如果 Route 使用的是 component 来指定组件,那么不能使用 props

2.3.2.2.1 example03

首先我们希望把商品列表显示在home主页当中,因此我们需要往该组件中传数据了。而目前我们home主件是作为一个属性传给Route的。

            this.state = {items: [{id: 1,name: 'iPhone XR',price: 542500},{id: 2,name: 'Apple iPad Air 3',price: 377700},{id: 3,name: 'Macbook Pro 15.4',price: 1949900},{id: 4,name: 'Apple iMac',price: 1629900},{id: 5,name: 'Apple Magic Mouse',price: 72900},{id: 6,name: 'Apple Watch Series 4',price: 599900}]}
{/*下面这种写法,items 是传递给了 Route ,而不是 Home
*/}
<Route path="/" component={Home} exact items={this.state.items} />
// 如果是我们自己写的数据,我们传参是如下形式:
<Home items={this.state.items} / >

我们在首页组件中打印一下props,我们看看一下:

react-Novice05\app\src\App.js

import React from 'react';import {Route, Link} from 'react-router-dom';import Home from './views/Home';
import About from './views/About';class App extends React.Component {constructor(props) {super(props);this.state = {items: [{id: 1,name: 'iPhone XR',price: 542500},{id: 2,name: 'Apple iPad Air 3',price: 377700},{id: 3,name: 'Macbook Pro 15.4',price: 1949900},{id: 4,name: 'Apple iMac',price: 1629900},{id: 5,name: 'Apple Magic Mouse',price: 72900},{id: 6,name: 'Apple Watch Series 4',price: 599900}]}}render() {return (<div className="App"><h1>React路由</h1><hr/><nav><Link to="/">首页</Link><span> | </span><Link to="/about">关于我们</Link></nav><hr/><Route path="/" component={Home} exact items={this.state.items}/><Route path="/about" component={About}/></div>)}}export default App;

react-Novice05\app\src\views\Home.js

import React from 'react';export default class Home extends React.Component {render() {console.log(this.props);return (<div><h2>商品列表</h2></div>);}}

小迪找了很久,也确实没找到items

image-20200705202530360

上面这种写法,items 是传递给了 Route ,而不是 Home。

参考:https://github.com/6xiaoDi/blog-react-Novice/tree/v3.03
Branch:branch4

commit description:v3.03-example03(应用场景(二)- 如何给路由组件的组件参数传值?)

tag:v3.03

2.3.2.2.2 Route : render
<Route exact path='/' render={() => <Home items={this.state.items} />} />

通过 render 属性来指定渲染函数,render 属性值是一个函数,当路由匹配的时候指定该函数进行渲染。

2.3.2.2.2.1 example04

以上是不成功的,那路由组件怎么给组件参数传值呢?我们修改一下:

传递 propscomponent指定的 组件
Route 还提供了一个 render属性,传入一个函数,函数返回的值就是 等同于 Component指定的组件渲染的结果。

    import React from 'react';import {Route, Link} from 'react-router-dom';import Home from './views/Home';import About from './views/About';class App extends React.Component {constructor(props) {super(props);this.state = {items: [{id: 1,name: 'iPhone XR',price: 542500},{id: 2,name: 'Apple iPad Air 3',price: 377700},{id: 3,name: 'Macbook Pro 15.4',price: 1949900},{id: 4,name: 'Apple iMac',price: 1629900},{id: 5,name: 'Apple Magic Mouse',price: 72900},{id: 6,name: 'Apple Watch Series 4',price: 599900}]}}render() {return (<div className="App"><h1>React路由</h1><hr/><nav><Link to="/">首页</Link><span> | </span><Link to="/about">关于我们</Link></nav><hr/><Route path="/" exact  render={() => {return <div>我是render出来的</div>}} /><Route path="/about" component={About}/>  </div>)}}export default App;
image-20200606163419843

参考:https://github.com/6xiaoDi/blog-react-Novice/tree/v3.04-1
Branch:branch4

commit description:v3.04-1-example04-1(应用场景(二)- 如何给路由组件的组件参数传值?传递 props 给 component 指定的 组件)

tag:v3.04-1

app.js

    import React from 'react';import {Route, Link} from 'react-router-dom';import Home from './views/Home';import About from './views/About';class App extends React.Component {constructor(props) {super(props);this.state = {items: [{id: 1,name: 'iPhone XR',price: 542500},{id: 2,name: 'Apple iPad Air 3',price: 377700},{id: 3,name: 'Macbook Pro 15.4',price: 1949900},{id: 4,name: 'Apple iMac',price: 1629900},{id: 5,name: 'Apple Magic Mouse',price: 72900},{id: 6,name: 'Apple Watch Series 4',price: 599900}]}}render() {return (<div className="App"><h1>React路由</h1><hr/><nav><Link to="/">首页</Link><span> | </span><Link to="/about">关于我们</Link></nav><hr/><Route path="/" exact render={() => {return <Home items={this.state.items} />}} /><Route path="/about" component={About}/>      </div>)}}export default App;

src/views/Home.js

import React from 'react';export default class Home extends React.Component {render() {console.log(this.props);return (<div><h2>商品列表</h2></div>);}
}

image-20200606163850087

可以简写:

                    <Route path="/" exact render={() => <Home items={this.state.items} />} />                  

参考:https://github.com/6xiaoDi/blog-react-Novice/tree/v3.04-2
Branch:branch4

commit description:v3.04-2-example04-2(应用场景(二)- 如何给路由组件的组件参数传值?传递 props 给 component 指定的 组件)

tag:v3.04-2

完善列表

src/css.css

ul {margin: 0;padding: 0;
}li {list-style: none;
}.item-list li {padding: 10px;display: flex;justify-content: space-between;height: 30px;line-height: 30px;border-bottom: 1px dotted #333;
}
.item-list li.head {font-weight: bold;
}
.item-list li span {min-width: 200px;
}.pagination {margin: 10px;
}
.pagination a {margin: 0 5px;display: inline-block;width: 30px;height: 30px;background-color: #f4f4f5;line-height: 30px;text-align: center;cursor: pointer;color: #606266;text-decoration: none;
}
.pagination a:hover {color: #409eff;
}
.pagination a.active {background-color: #409eff;color: #fff;cursor: text;
}
.pagination .goto {margin: 0 5px;box-sizing: border-box;width: 80px;height: 30px;border: 1px solid #dcdfe6;outline: none;text-align: center;vertical-align: top;
}

app.js

    import React from 'react';import {Route, Link} from 'react-router-dom';import './css.css';import Home from './views/Home';import About from './views/About';class App extends React.Component {constructor(props) {super(props);this.state = {items: [{id: 1,name: 'iPhone XR',price: 542500},{id: 2,name: 'Apple iPad Air 3',price: 377700},{id: 3,name: 'Macbook Pro 15.4',price: 1949900},{id: 4,name: 'Apple iMac',price: 1629900},{id: 5,name: 'Apple Magic Mouse',price: 72900},{id: 6,name: 'Apple Watch Series 4',price: 599900}]}}render() {return (<div className="App"><h1>React路由</h1><hr/><nav><Link to="/">首页</Link><span> | </span><Link to="/about">关于我们</Link></nav><hr/><Route path="/" exact render={() => <Home items={this.state.items} />} /><Route path="/about" component={About}/></div>)}}export default App;

src/views/Home.js

import React from 'react';import Item from '../components/Item.js';export default class Home extends React.Component {render() {let {items} = this.props;return (<div><h2>商品列表</h2><ul className="item-list"><li className="head"><span>名称</span><span>价格</span></li>{items.map( item => <Item item={item} key={item.id} /> )}</ul></div>);}}

src/components/Item.js

import React from "react";
import {Link} from "react-router-dom";export default class Item extends React.Component{render() {let {item} = this.props;return(<li><span><a href="">{item.name}</a></span>{/*保留两位小数*/}<span>{(item.price / 100).toFixed(2)}</span></li>);}}

image-20200606181327899

参考:https://github.com/6xiaoDi/blog-react-Novice/tree/v3.04-3
Branch:branch4

commit description:v3.04-3-example04-3(应用场景(二)- 完善首页列表)

tag:v3.04-3

2.3.2.3 渲染列表

Home.js

import React from 'react';import {Link} from 'react-router-dom';export default class Home extends React.Component {render() {let {items} = this.props;return (<div><h2>商品列表</h2><ul className="item-list"><li className="head"><span>名称</span><span>价格</span></li>{items.map(item=>(<li key={item.id}><span><Link to={'/Item/' + item.id}>{item.name}</Link></span><span>{(item.price / 100).toFixed(2)}</span></li>))}</ul></div>);}}
2.3.2.3.1 example05

完善详情页

App.js

 import React from 'react';import {Route, Link} from 'react-router-dom';import './css.css';import Home from './views/Home';import About from './views/About';import View from "./views/View";class App extends React.Component {constructor(props) {super(props);this.state = {items: [{id: 1,name: 'iPhone XR',price: 542500},{id: 2,name: 'Apple iPad Air 3',price: 377700},{id: 3,name: 'Macbook Pro 15.4',price: 1949900},{id: 4,name: 'Apple iMac',price: 1629900},{id: 5,name: 'Apple Magic Mouse',price: 72900},{id: 6,name: 'Apple Watch Series 4',price: 599900}]}}render() {return (<div className="App"><h1>React路由</h1><hr/><nav><Link to="/">首页</Link><span> | </span><Link to="/about">关于我们</Link></nav><hr/><Route path="/" exact render={() => <Home items={this.state.items} />} />{/*商品详情*/}<Route path='/view' component={View}/><Route path="/about" component={About}/></div>)}}   export default App;

src/components/Item.js

import React from "react";
import {Link} from "react-router-dom";export default class Item extends React.Component{render() {let {item} = this.props;return(<li><span><Link to={"/view/"}>{item.name}</Link></span>{/*保留两位小数*/}<span>{(item.price / 100).toFixed(2)}</span></li>);}}

src/views/View.js

import React from 'react';export default class View extends React.Component {render() {return(<div><h2>商品详情 </h2><hr/><p>其它一些详情信息...</p></div>);}}

参考:https://github.com/6xiaoDi/blog-react-Novice/tree/v3.05
Branch:branch4

commit description:v3.05-example05(应用场景(二)- 增加点击详情功能)

tag:v3.05

如何往详情页里传递参数呢?我们点击的列表某一项需要把该项信息传递给详情页。

可能想到从item往上传给home再传给app,最终再给view。可想而知这样传参会非常恶心!

如果组件是页面组件,那么这个两个不同的页面组件之间的数据传递就不要通过传统组件父子通信来做,数据要通过页面(路由等方式来进行传递,或者local storage进行中转,或者redux中转,其实都是做统一存储的)

2.3.2.3.2 params

在路由中,params 指的是 path 部分可变的部分,在这里我们需要定义一个新的路由用来展示商品的详情,我们希望通过 /item/1/item/2/item/…… 来访问对应 id 的商品,那么后面的数字部分就是可变的 - params,我们也称这样的路由为:动态路由

2.3.2.4 动态路由

为了能给处理上面的动态路由地址的访问,我们需要为 Route 组件配置特殊的 path

<Route path='/item/:id' component={Item} />
2.3.2.4.1 path-to-regexp

path-to-regexp 是一个专门用来处理 URL 的库,它用来了一种类似正则的字符串表示法

: 表示后面的部分为可变,: 后面的单词为匹配后的内容存储的名称,如:/item/1 ,就是 id=1

默认情况下,它为我们提供了几个常用的字符表示:*?+

但是我们可以通过 () 来使用正则

<Route path='/item/:id(\d+)' component={Item} />

上面表示 /item/ 后面只能是数字

2.3.2.4.2 Route : props

当动态路由匹配以后,我们可以通过对应组件的 props 属性来访问当前路由匹配信息

2.3.2.5 路由组件

如果一个组件是通过路由直接访问的,我们称为:路由组件 - 视图组件,其它的类型,根据具体功能可以称为:业务组件UI 组件容器组件,……

如果一个组件是路由组件,那么组件的 props 属性就会自动添加几个与路由有关的几个属性

  • history : 对象,提供了一些用于操作路由的方法,类似原生 JavaScript 中的 history 对象
  • location : 对象,通过它可以获取当前路由 URL 信息,类似原生 JavaScript 中的 history.location 对象
  • match : 对象,当前路由解析后的 URL 信息
2.3.2.5.1 example06

利用动态路由中转页面。

2.3.2.5.1.1 example06-1

下面的路由是动态,':'后面的 id 表示动态部分匹配到内容
当下 /view/XXXXX 才能匹配当前的路由

react-Novice05\app\src\App.js

import React from 'react';import {Route, Link} from 'react-router-dom';import './css.css';import Home from './views/Home';
import About from './views/About';
import View from "./views/View";class App extends React.Component {constructor(props) {super(props);this.state = {items: [{id: 1,name: 'iPhone XR',price: 542500},{id: 2,name: 'Apple iPad Air 3',price: 377700},{id: 3,name: 'Macbook Pro 15.4',price: 1949900},{id: 4,name: 'Apple iMac',price: 1629900},{id: 5,name: 'Apple Magic Mouse',price: 72900},{id: 6,name: 'Apple Watch Series 4',price: 599900}]}}render() {return (<div className="App"><h1>React路由</h1><hr/><nav><Link to="/">首页</Link><span> | </span><Link to="/about">关于我们</Link></nav><hr/><Route path="/" exact render={() => <Home items={this.state.items} />} /><Route path='/view/:id' component={View}/><Route path="/about" component={About}/></div>)}}export default App;

我们发现http://localhost:3000/view页面就看不到了,必须是这种形式:http://localhost:3000/view/参数页面才能显示,即满足"/view/:id" 这个规则页面才能匹配,这个参数就会在实际匹配当中赋值给id:id其实就是一个变量,去接收路由当中与之匹配的参数。

可是现在参数为任何值都行,如果仅限数字呢?其实可以设置类似正则的规则。这里设置后面必须是数字,且至少1个。

<Route path="/view/:id(\d+)" component={View} />

参考:https://github.com/6xiaoDi/blog-react-Novice/tree/v3.06-1
Branch:branch4

commit description:v3.06-1-example06-1(应用场景(二)- 利用动态路由中转页面)

tag:v3.06-1

2.3.2.5.1.2 example06-2

src/components/Item.js

import React from "react";
import {Link} from "react-router-dom";export default class Item extends React.Component{render() {let {item} = this.props;return(<li><span><Link to={"/view/" + item.id}>{item.name}</Link></span>{/*保留两位小数*/}<span>{(item.price / 100).toFixed(2)}</span></li>);}}

从动态路由 url中拿到:id对应的内容

src/views/View.js

import React from 'react';export default class View extends React.Component {render() {console.log(this.props);return(<div><h2>商品详情 </h2><p>其它一些详情信息...</p></div>);}}

我们发现我们没有往viewprops传内容,怎么多了很多东西。

image-20200606215049123

BrowserRouter是容器组件,这里我们App嵌套在其内,它会给App注入东西。我们看下伪代码:

BrowserRouter大致伪代码:

    class BrowserRouter extends React.Component {render() {// 渲染子组件return this.props.children; // 返回子组件}}

App.js中用route伪代码:

    class Route extends React.Component {render() {// component是我们在标签上写的组件属性// 增加一些对象this.props.component.props.history;this.props.component.props.match;this.props.component.props.location;return this.props.component; // 我们所写的component属性}}

如果一个组件是路由组件(路由直接绑定并访问的组件),那么该组件就会被自动注入(靠BrowserRouter容器组件注入)

  • history: 同(html5)history api 类似,可跳页面

image-20200606215120325

  • match: 当前访问的路由信息

image-20200606215200219

  • location: 等同 原生的location

image-20200606215228450

view.js

import React from 'react';export default class View extends React.Component {render() {// console.log(this.props);let {id} = this.props.match.params;console.log(id)return(<div><h2>商品详情 </h2><p>其它一些详情信息...</p></div>);}}

参考:https://github.com/6xiaoDi/blog-react-Novice/tree/v3.06-2
Branch:branch4

commit description:v3.06-2-example06-2(应用场景(二)- 利用动态路由中转页面—路由容器组件注入对象属性)

tag:v3.06-2

2.3.2.5.2 match : params
this.props.match.params.id

注意:非路由组件是没有路由数据的

如果一个组件既要接收手动传入的 props,又想接收路由信息

<Route path='/item/:id(\d+)' render={props => <Item {...props} items={this.state.items} />} />

商品详情

render() {let items = this.props.items;let id = Number(this.props.match.params.id) || 0;let item = items.find(item => item.id === id);return item ? (<div><h2>商品详情 - {item.name}</h2><dt>ID</dt><dd>{item.id}</dd><dt>名称</dt><dd>{item.name}</dd><dt>价格</dt><dd>{(item.price / 100).toFixed(2)}</dd></div>) : <div>不存在该商品!</div>;
}
2.3.2.5.2.1 example07

目前我们可以通过url拿到id,但视图组件所需要的数据从何而来?我们现在需要拿着id,去数据中找到对应项,然后展示出来。后期可能直接给后端发请求,去要数据了,即前端不去做而是去向后端发请求。

app.js

 import React from 'react';import {Route, Link} from 'react-router-dom';import './css.css';import Home from './views/Home';import About from './views/About';import View from "./views/View";class App extends React.Component {constructor(props) {super(props);this.state = {items: [{id: 1,name: 'iPhone XR',price: 542500},{id: 2,name: 'Apple iPad Air 3',price: 377700},{id: 3,name: 'Macbook Pro 15.4',price: 1949900},{id: 4,name: 'Apple iMac',price: 1629900},{id: 5,name: 'Apple Magic Mouse',price: 72900},{id: 6,name: 'Apple Watch Series 4',price: 599900}]}}render() {return (<div className="App"><h1>React路由</h1><hr/><nav><Link to="/">首页</Link><span> | </span><Link to="/about">关于我们</Link></nav><hr/><Route path="/" exact render={() => <Home items={this.state.items} />} /><Route path="/view/:id(\d+)" render={() => {return <View />}} /><Route path="/about" component={About}/></div>)}}export default App;

视图组件所需要的数据从何而来??????????????????

view.js

import React from 'react';export default class View extends React.Component {render() {console.log(this.props);let {id} = this.props.match.params;console.log(id)return(<div><h2>商品详情 </h2><p>其它一些详情信息...</p></div>);}}

报错(挂了)原因:View不在是路由组件了,那么也就表示 Route 注入的 路由相关信息就没有了,即history、 match、location等参数对象就没了。

image-20200706111905225

参考:https://github.com/6xiaoDi/blog-react-Novice/tree/v3.07-1
Branch:branch4

commit description:v3.07-1-example07-1(应用场景(二)- 完善详情页,跳转页面报错)

tag:v3.07-1

如果使用了render 函数,那么路由注入的 history、match 等对象都作为参数传递给了render函数了
render其实就是一个函数式的组件

                    <Route path="/view/:id(\d+)" render={(props) => {return <View />console.log(props);}} /><Route path="/about" component={About}/>

image-20200606223217569

src/App.js

 import React from 'react';import {Route, Link} from 'react-router-dom';import './css.css';import Home from './views/Home';import About from './views/About';import View from "./views/View";class App extends React.Component {constructor(props) {super(props);this.state = {items: [{id: 1,name: 'iPhone XR',price: 542500},{id: 2,name: 'Apple iPad Air 3',price: 377700},{id: 3,name: 'Macbook Pro 15.4',price: 1949900},{id: 4,name: 'Apple iMac',price: 1629900},{id: 5,name: 'Apple Magic Mouse',price: 72900},{id: 6,name: 'Apple Watch Series 4',price: 599900}]}}render() {return (<div className="App"><nav><Link to="/">首页</Link><span> | </span><Link to="/about">关于我们</Link></nav><hr/><Route path="/" exact render={() => <Home items={this.state.items} />} /><Route path="/view/:id(\d+)" render={(props) => {// es5 写法太长了// return <View match={props.match} history={props.history} location={props.location} />// es6写法比较简练,解构(扩展运算符)return <View {...props} items={this.state.items} />}} /><Route path="/about" component={About}/></div>)}}export default App;

src/components/Item.js

import React from "react";
import {Link} from "react-router-dom";export default class Item extends React.Component{render() {let {item} = this.props;return(<li><span><Link to={"/view/" + item.id}>{item.name}</Link></span>{/*保留两位小数*/}<span>{(item.price / 100).toFixed(2)}</span></li>);}}

src/views/View.js

import React from 'react';export default class View extends React.Component {render() {// 解构let {items, match: {params: {id}}} = this.props;id = Number(id);let item = items.find( v => v.id === id );console.log(items, id, item);return(<div><h2>商品详情 - {item.name}</h2><p>其它一些详情信息...</p></div>);}}

参考:https://github.com/6xiaoDi/blog-react-Novice/tree/v3.07-2
Branch:branch4

commit description:v3.07-2-example07-2(应用场景(二)- 完善详情页,跳转页面最终版)

tag:v3.07-2

2.3.2.6 通信小结

  • 从动态路由 url中拿到 :id对应的内容

  • 视图组件所需要的数据从何而来??????????????????(肯定涉及两个位置,从a到b,如果只有一个组件,就谈不上组件数据从何而来的问题了,即通信问题了)

  • 组件获取数据的方式:

    • 组件的(参数传递)父子通信,由父级传参把数据传进来
    • 通过与该组件对应的 url传递过来,组件肯定与url是有关联的,我们需要把组件需要的数据挂载到url上面,然后当组件渲染的时候,再去检查url上某个位置的数据
    • 通过后端获取:在组件的一些生命周期中发送请求(ajax
    • 通过本地存储(不推荐,因为它有大小限制)
    • 全局变量(内存),如把数据挂载到window底下,到数据渲染的时候,再从window下面取(一般情况下,是不推荐的,它类似于redux,除非有更好方式管理和维护全局变量,否则就容易乱套了)
    • …(还有很多方式,但只关注一点,凡是涉及到数据通信,当前能访问的方式,如下)
  • 数据通信选择何种方式

    • 如果是组件不是嵌套关系(如本例),我们选择方案1,就会涉及到通信步骤太多的问题,你需要一层层的传,会很繁琐
    • 实际两组件是嵌套关系,即父子级关系,或者兄弟关系(它们共同父级就在上一层,不太多),可用方案1
    • 方案2其实适合两个组件不同时存在的时候,如有view,就没item,即在一个页面中两个不同时显示,两个组件是互不见面的,但是可从urlview的数据带给item,但仅限小批量的数据

2.3.3 应用场景(三)

我想增加一个功能,用户可以按照商品价格的高低进行选择展示

2.3.3.1 通过 JavaScript 实现排序切换

Home.js

...
this.state = {sort: 'desc'this.changeSort = this.changeSort.bind(this);
}
...
changeSort({target: {value: sort}}) {this.setState({sort});
}
...
render() {let {items} = this.props;let {sort} = this.state;items = items.sort((a, b) => sort === 'asc'  ? a.price - b.price : b.price - a.price);return(...<select value={sort} onChange={this.changeSort}><option value="desc">从高到低</option><option value="asc">从低到高</option></select>...)
}

问题:刷新页面、分享 URL 都会丢失状态

2.3.3.1.1 example08

js实现排序

2.3.3.1.1.1 example08-1

src/views/Home.js

import React from 'react';import Item from '../components/Item.js';export default class Home extends React.Component {render() {let {items} = this.props;items = items.sort( (a, b) => {return b.price - a.price;} );return (<div><h2>商品列表</h2><ul className="item-list"><li className="head"><span>名称</span><span>价格</span></li>{items.map( item => <Item item={item} key={item.id} /> )}</ul></div>);}}

降序排列:

image-20200606233558809

参考:https://github.com/6xiaoDi/blog-react-Novice/tree/v3.08-1
Branch:branch4

commit description:v3.08-1-example08-1(应用场景(三)- 用户可以按照商品价格的高低进行选择展示-js实现-简单的降序排列)

tag:v3.08-1

2.3.3.1.1.2 example08-2
import React from 'react';import Item from '../components/Item.js';export default class Home extends React.Component {constructor(props) {super(props);this.sort = this.sort.bind(this);}sort(e) {console.log(e.target.value);let {items} = this.props;items = items.sort( (a, b) => {return 'desc' === e.target.value ? b.price - a.price : a.price - b.price;} );this.setState({items});}render() {let {items} = this.props;return (<div><h2>商品列表</h2><select onChange={this.sort}><option value="desc">降序</option><option value="asc">升序</option></select><ul className="item-list"><li className="head"><span>名称</span><span>价格</span></li>{items.map( item => <Item item={item} key={item.id} /> )}</ul></div>);}}

发现没有设置默认排序。

参考:https://github.com/6xiaoDi/blog-react-Novice/tree/v3.08-2
Branch:branch4

commit description:v3.08-2-example08-2(应用场景(三)- 用户可以按照商品价格的高低进行选择展示-js实现-实现切换排序)

tag:v3.08-2

2.3.3.1.1.3 example08-3

我们需要先设置一下默认排序状态,可以封装一下:

import React from 'react';import Item from '../components/Item.js';export default class Home extends React.Component {constructor(props) {super(props);// 默认降序,赋给statethis.state = {items: this.doSort('desc')};this.sort = this.sort.bind(this);}sort(e) {console.log(e.target.value);let items = this.doSort(e.target.value);this.setState({items});}doSort(type = 'desc') {let {items} = this.props;return items.sort( (a, b) => {return 'desc' === type ? b.price - a.price : a.price - b.price;} );}render() {// 取默认排序好的itemslet {items} = this.state;return (<div><h2>商品列表</h2><select onChange={this.sort}><option value="desc">降序</option><option value="asc">升序</option></select><ul className="item-list"><li className="head"><span>名称</span><span>价格</span></li>{items.map( item => <Item item={item} key={item.id} /> )}</ul></div>);}}

参考:https://github.com/6xiaoDi/blog-react-Novice/tree/v3.08-3
Branch:branch4

commit description:v3.08-3-example08-3(应用场景(三)- 用户可以按照商品价格的高低进行选择展示-js实现-切换排序添加默认降序排序)

tag:v3.08-3

存在问题:

1、假如数据很多,就需要进行分页了。

2、如果把排序好的页面分享好别人,别人打开的页面是默认降序排序,则可能拿到的页面就不同了,所以我们这里排序最好也保留状态(通过url也能判断出排序状态)。(排序功能不要影响url地址本身,否则路由看不清楚了,即不影响url资源同时又可携带数据,因此需要用到queryString

2.3.3.2 通过路由实现排序切换

2.3.3.2.1 queryString

通常我们把 URL ? 后面的内容称为 queryString,在 React.js 中,我们可以通过 this.props.location.search 来获取,它的值是字符串,格式为:?k1=v1&k2=v2,为了方便操作,我们把它转成对象形式

/api/users 这个地址代表与用户有关的所有数据,假设数据有10000条,而只希望看到一部分的话,就相当于需要带查询条件,例如:/api/users ?page=1 queryString 其实就带着某种和条件去获取资源

回归正题:我们可以设置为localhost:3000/?sort=desc

2.3.3.2.2 URLSearchParams

在原生 JavaScript 中内置了一个 URLSearchParams 的类,我们通过它可以很方便的操作 queryString

let {location: {search}} = this.props;
let qs = new URLSearchParams(search);
let sort = qs.get('sort');

2.3.3.3 扩展

2.3.3.3.1 qs 库

https://www.npmjs.com/package/qs

2.3.3.3.2 安装
npm i -S qs
2.3.3.3.3 使用

search: 解析的字符串

ignoreQueryPrefix:是否忽略问号

import queryString from 'qs';let qsTest = queryString.parse(search, {ignoreQueryPrefix: true});
let sort = qsTest.sort;
2.3.3.3.4 通过 JavaScript 编程的方式切换路由

除了使用 <Link> 组件像 a 一样点击跳转路由,我们还可以通过编程的方式(JavaScript) 来切换路由

let {history} = this.props;
<select defaultValue={sort} onChange={({target:{value}})=>{history.push('/?sort=' + value);}}><option value="desc">从高到低</option><option value="asc">从低到高</option>
</select>
2.3.3.3.5 example09

通过路由实现排序切换

2.3.3.3.5.1 example09-1

home.js

// 从 url 的 querystring 上来获取console.log(window.location);

image-20200607220331225

        // 从 url 的 querystring 上来获取console.log(window.location.search);

image-20200607220925853

我们把问号截取掉!

    // 从 url 的 querystring 上来获取console.log(window.location.search.substring(1));
image-20200607221137347

参考:https://github.com/6xiaoDi/blog-react-Novice/tree/v3.09-1
Branch:branch4

commit description:v3.09-1-example09-1(应用场景(三)- 用户可以按照商品价格的高低进行选择展示-获取querystring)

tag:v3.09-1

2.3.3.3.5.2 example09-2

以上代码是:key=value的格式,我们如何取到value呢?我们可以将其转为对象去取,或者使用第三方的库(如:qs库)。

原生方法:

    let queryString = window.location.search.substring(1);// 作用:将queryString转为对象形式let qs = new URLSearchParams(queryString);console.log(qs);

image-20200607222007936

get方法取值:

    let queryString = window.location.search.substring(1);// 作用:将queryString转为对象形式let qs = new URLSearchParams(queryString);console.log(qs.get('sort'));

image-20200607222120777

参考:https://github.com/6xiaoDi/blog-react-Novice/tree/v3.09-2
Branch:branch4

commit description:v3.09-2-example09-2(应用场景(三)- 用户可以按照商品价格的高低进行选择展示-原生js获取querystring中的值)

tag:v3.09-2

2.3.3.3.5.3 example09-3

queryString: 解析的字符串

ignoreQueryPrefix:是否忽略问号

    import qs from 'qs';        let queryString = window.location.search.substring(1);// 作用:将queryString转为对象形式let qsTest = qs.parse(queryString, {ignoreQueryPrefix: true});let sort = qsTest.sort;console.log(sort);

image-20200607222120777

参考:https://github.com/6xiaoDi/blog-react-Novice/tree/v3.09-3
Branch:branch4

commit description:v3.09-3-example09-3(应用场景(三)- 用户可以按照商品价格的高低进行选择展示-qs库获取querystring中的值)

tag:v3.09-3

2.3.3.3.5.4 example09-4

以上我们是通过原生js获取的queryString,同时还可以通过组件对象获取。刚刚我们讲过路由组件渲染的时候,如果一个组件是路由组件(路由直接绑定并访问的组件),那么该组件就会被自动注入:

  • history: 同(html5)history api类似,可跳页面
  • match: 当前访问的路由信息
  • location: 等同 原生的 location

react-Novice05\app\src\App.js

import React from 'react';import {Route, Link} from 'react-router-dom';import './css.css';import Home from './views/Home';
import About from './views/About';
import View from "./views/View";class App extends React.Component {constructor(props) {super(props);this.state = {items: [{id: 1,name: 'iPhone XR',price: 542500},{id: 2,name: 'Apple iPad Air 3',price: 377700},{id: 3,name: 'Macbook Pro 15.4',price: 1949900},{id: 4,name: 'Apple iMac',price: 1629900},{id: 5,name: 'Apple Magic Mouse',price: 72900},{id: 6,name: 'Apple Watch Series 4',price: 599900}]}}render() {return (<div className="App"><h1>React路由</h1><hr/><nav><Link to="/">首页</Link><span> | </span><Link to="/about">关于我们</Link></nav><hr/><Route path="/" exact render={(props) => <Home items={this.state.items} {...props} />} /><Route path="/view/:id(\d+)" render={(props) => {return <View {...props} items={this.state.items} />}} /><Route path="/about" component={About}/></div>)}}export default App;

react-Novice05\app\src\views\Home.js

import React from 'react';import Item from '../components/Item.js';
import qs from 'qs';export default class Home extends React.Component {constructor(props) {super(props);// 默认降序,赋给statethis.state = {items: this.doSort('desc')};this.sort = this.sort.bind(this);}sort(e) {console.log(e.target.value);let items = this.doSort(e.target.value);this.setState({items});}doSort(type = 'desc') {let {items} = this.props;return items.sort( (a, b) => {return 'desc' === type ? b.price - a.price : a.price - b.price;} );}render() {// 取默认排序好的itemslet {items} = this.state;console.log(this.props)let queryString = window.location.search.substring(1);// 作用:将queryString转为对象形式let qsTest = qs.parse(queryString, {ignoreQueryPrefix: true});let sort = qsTest.sort;return (<div><h2>商品列表</h2><select onChange={this.sort}><option value="desc">降序</option><option value="asc">升序</option></select><ul className="item-list"><li className="head"><span>名称</span><span>价格</span></li>{items.map( item => <Item item={item} key={item.id} /> )}</ul></div>);}}

可在locationsearch中取值。

image-20200706140555801

        let {location} = this.props;// let queryString = window.location.search.substring(1);let queryString = location.search.substring(1);// 作用:将queryString转为对象形式let qsTest = qs.parse(queryString, {ignoreQueryPrefix: true});let sort = qsTest.sort;console.log(sort);

image-20200607222120777

参考:https://github.com/6xiaoDi/blog-react-Novice/tree/v3.09-4
Branch:branch4

commit description:v3.09-4-example09-4(应用场景(三)- 用户可以按照商品价格的高低进行选择展示-通过组件对象获取queryString)

tag:v3.09-4

2.3.3.3.5.5 example09-5

完善排序切换选项卡功能:

用户在select标签中选择的时候,我们不希望它是受控组件(这里的值与state进行绑定),目前sort变量的值并不在组件内部,其实用户选择排序的时候,没有必要去修改sort变量的值,只需要跳页面就行了。因此我们给它绑定一个defaultvalue属性(绑定非受控)即可。

import React from 'react';import Item from '../components/Item.js';
import qs from 'qs';export default class Home extends React.Component {constructor(props) {super(props);// 默认降序,赋给statethis.state = {items: this.doSort('desc')};this.sort = this.sort.bind(this);}sort(e) {// let items = this.doSort(e.target.value);// this.setState({//     items// });// 跳转页面let {history} = this.props;history.push(`/?sort=${e.target.value}`)}doSort(type = 'desc') {let {items} = this.props;return items.sort( (a, b) => {return 'desc' === type ? b.price - a.price : a.price - b.price;} );}render() {// 取默认排序好的itemslet {items} = this.state;let {location} = this.props;// let queryString = window.location.search.substring(1);let queryString = location.search.substring(1);// 作用:将queryString转为对象形式let qsTest = qs.parse(queryString, {ignoreQueryPrefix: true});let sort = qsTest.sort || 'desc';this.doSort(sort);return (<div><h2>商品列表</h2><select defaultValue={sort} onChange={this.sort}><option value="desc">降序</option><option value="asc">升序</option></select><ul className="item-list"><li className="head"><span>名称</span><span>价格</span></li>{items.map( item => <Item item={item} key={item.id} /> )}</ul></div>);}}

参考:https://github.com/6xiaoDi/blog-react-Novice/tree/v3.09-5
Branch:branch4

commit description:v3.09-5-example09-5(应用场景(三)- 用户可以按照商品价格的高低进行选择展示-完善排序切换选项卡功能最终版)

tag:v3.09-5

2.3.4 应用场景(四)

现在,我想给页面顶部的导航加上高亮效果,用来标识当前页面。这个时候,我们就可以使用 react-router-dom 提供的 NavLink 组件来实现

2.3.4.1 NavLink 组件

NavLinkLink 类似,但是它提供了两个特殊属性用来处理页面导航

2.3.4.1.1 activeStyle

当前 URLNavLink 中的 to 匹配的时候,激活 activeStyle 中的样式

2.3.4.1.2 activeClassName

activeStyle 类似,但是激活的是 className

2.3.4.1.3 isActive(类似回调,可以处理一些更为复杂的情况)

默认情况下,匹配的是 URLto 的设置,通过 isActive 可以自定义激活逻辑,isActive 是一个函数,返回布尔值

index.js

<NavLink to="/" activeStyle={{color:'red'}} isActive={(match, location) => {return match || location.pathname.startsWith('/item')
}} exact>Home</NavLink>
<span> | </span>
<NavLink to="/about" activeStyle={{color:'red'}} exact>About</NavLink>
2.3.4.1.4 exact

精确匹配

2.3.4.2 example10

NavLink 组件(导航组件)

2.3.4.2.1 example10-1

activeStyle:当前 URLNavLink 中的 to 匹配的时候,激活 activeStyle 中的样式

react-Novice05\app\src\App.js

import React from 'react';import {Route, Link} from 'react-router-dom';import './css.css';import Home from './views/Home';
import About from './views/About';
import View from "./views/View";
import NavLink from "react-router-dom/modules/NavLink";class App extends React.Component {constructor(props) {super(props);this.state = {items: [{id: 1,name: 'iPhone XR',price: 542500},{id: 2,name: 'Apple iPad Air 3',price: 377700},{id: 3,name: 'Macbook Pro 15.4',price: 1949900},{id: 4,name: 'Apple iMac',price: 1629900},{id: 5,name: 'Apple Magic Mouse',price: 72900},{id: 6,name: 'Apple Watch Series 4',price: 599900}]}}render() {return (<div className="App"><h1>React路由</h1><hr/><nav><NavLink to="/" activeStyle={{color: 'red'}}>首页</NavLink><span> | </span><NavLink to="/about" activeStyle={{color: 'red'}}>关于我们</NavLink></nav><hr/><Route path="/" exact render={(props) => <Home items={this.state.items} {...props} />} /><Route path="/view/:id(\d+)" render={(props) => {return <View {...props} items={this.state.items} />}} /><Route path="/about" component={About}/></div>)}}export default App;

不过,明显发现存在问题!为什么点击关于我们后,首页仍然会高亮!因为默认情况下,它属于一种模糊匹配,即非精确匹配。因为此时"/about"也同时满足"/" 的规则,所以"/about"会把两种都匹配上!

参考:https://github.com/6xiaoDi/blog-react-Novice/tree/v3.10-1
Branch:branch4

commit description:v3.10-1-example10-1(应用场景(四)- 页面顶部的导航加上高亮效果-未精确匹配)

tag:v3.10-1

2.3.4.2.2 example10-2

完善精确匹配:

学会看文档

image-20200608001314519

image-20200608001354875

image-20200608001415397

image-20200608001424650

image-20200608001431435

import React from 'react';import {Route, Link, NavLink } from 'react-router-dom';import './css.css';import Home from './views/Home';
import About from './views/About';
import View from "./views/View";class App extends React.Component {constructor(props) {super(props);this.state = {items: [{id: 1,name: 'iPhone XR',price: 542500},{id: 2,name: 'Apple iPad Air 3',price: 377700},{id: 3,name: 'Macbook Pro 15.4',price: 1949900},{id: 4,name: 'Apple iMac',price: 1629900},{id: 5,name: 'Apple Magic Mouse',price: 72900},{id: 6,name: 'Apple Watch Series 4',price: 599900}]}}render() {return (<div className="App"><h1>React路由</h1><hr/><nav><NavLink to="/" activeStyle={{color: 'red'}} exact={true}   >首页</NavLink><span> | </span><NavLink to="/about" activeStyle={{color: 'red'}}>关于我们</NavLink></nav><hr/><Route path="/" exact render={(props) => <Home items={this.state.items} {...props} />} /><Route path="/view/:id(\d+)" render={(props) => {return <View {...props} items={this.state.items} />}} /><Route path="/about" component={About}/></div>)}}export default App;

参考:https://github.com/6xiaoDi/blog-react-Novice/tree/v3.10-2
Branch:branch4

commit description:v3.10-2-example10-2(应用场景(四)- 页面顶部的导航加上高亮效果-精确匹配)

tag:v3.10-2

2.3.4.2.3 example10-3

isActive(类似回调,可以处理一些更为复杂的情况):

默认情况下,匹配的是 URLto 的设置,通过 isActive 可以自定义激活逻辑,isActive 是一个函数,返回布尔值

isActive属性什么时候使用呢?

以上example10-2的原理是urlto属性按照某种规则进行比较,如果比较后满足规则,则激活设置的样式。

如果我们点进详情(即访问内页),此时的url与我们上述的to属性都匹配不上了,此时怎么高亮呢?这个时候就不能用它了,得需要我们自己去定规则了。

<nav><NavLink to="/" exact={true} activeStyle={{color: 'red'}} isActive={(match, location) => {// match当前匹配的 location 当前地址栏信息console.log(match, location);}}>首页</NavLink><span> | </span><NavLink to="/about" activeStyle={{color: 'red'}} >关于我们</NavLink>
</nav>

当点击详情页,matchnull,表示当前没有匹配项,即当前访问的地址是不匹配的(与当前的属性to)。

                <nav><NavLink to="/" exact={true} activeStyle={{color: 'red'}} isActive={(match, location) => {// match当前匹配的 location 当前地址栏信息// console.log(match, location);// match 为真后面无需处理 否则以'/view'命名开始return match || location.pathname.startsWith('/view');}}>首页</NavLink><span> | </span><NavLink to="/about" activeStyle={{color: 'red'}}>关于我们</NavLink></nav>

参考:https://github.com/6xiaoDi/blog-react-Novice/tree/v3.10-3
Branch:branch4

commit description:v3.10-3-example10-3(应用场景(四)- 页面顶部的导航加上高亮效果-完成)

tag:v3.10-3

2.3.5 应用场景(五)

当用户访问不存在的路由,我们需要提供一个反馈页面,也就是 404(友好页面)

index.js

<Route exact path='/' render={props => <Home {...props} items={this.state.items} />} />
<Route path='/about' component={About} />
<Route path='/item/:id(\d+)' render={props => <Item {...props} items={this.state.items} />} />
{/*NotFound*/}
<Route component={NotFound} />

NotFound.js

import React from 'react';export default function NotFound() {return (<div>Not Found</div>);
}

默认情况下,React.js 会渲染所有与之匹配的路由组件,上面的案例中,当我们访问任意路由(如:/about),也会匹配 NotFound 路由组件渲染

2.3.5.1 Switch 组件

该组件只会渲染首个被匹配的组件

<Switch><Route exact path='/' render={props => <Home {...props} items={this.state.items} />} /><Route path='/about' component={About} /><Route path='/item/:id(\d+)' render={props => <Item {...props} items={this.state.items} />} />{/*NotFound*/}<Route component={NotFound} />
</Switch>

2.3.5.2 example11

实现 404(友好页面)

2.3.5.2.1 example11-1

src/views/NotFound.js

import React from 'react';export default class NotFound extends React.Component {render() {return (<div><h1>Not Found - 404</h1></div>);}}

App.js

<Route path="/" exact render={(props) => <Home items={this.state.items} {...props} />} /><Route path="/view/:id(\d+)" render={(props) => {return <View {...props} items={this.state.items} />}} /><Route path="/about" component={About}/><Route component={NotFound} />

每一个页面均包含了404页面组件。因为没有设置path,就代表实际默认为通配符,可匹配任何路径,即每一个页面均包含了404页面组件。

参考:https://github.com/6xiaoDi/blog-react-Novice/tree/v3.11-1
Branch:branch4

commit description:v3.11-1-example11-1(应用场景(五)- 实现 404(友好页面),遇到问题)

tag:v3.11-1

2.3.5.2.2 example11-2

默认react的路由具有穿透性

js当中的switch语句,这里去掉break,则打印bc,满足第一个变量a的值之后,如果没有break,则继续往下穿透。我们路由穿透的概念的就与这个类似,因此所有页面都显示。

let a = 2;
switch (a) {case 1:console.log('a');// break;case 2:console.log('b');// break;case 3:console.log('c');// break;
}

我们用switch组件来解决以上问题

                <Switch><Route path="/" exact render={(props) => <Home items={this.state.items} {...props} />} /><Route path="/view/:id(\d+)" render={(props) => {return <View {...props} items={this.state.items} />}} /><Route path="/about" component={About}/><Route component={NotFound} /></Switch>

如果把notfound组件放在最前面,则所有页面都是404,那是应为它是通配的,没设置规则,任何页面都符合,因此在实际开发中要十分注意这种顺序问题。(这块代码较为简单,小迪就不git了)

                <Switch><Route component={NotFound} /><Route path="/" exact render={(props) => {return <Home items={this.state.items} {...props} />}} /><Route path="/view/:id(\d+)" render={(props) => {return <View {...props} items={this.state.items} />}} /><Route path="/about" component={About}/></Switch>

参考:https://github.com/6xiaoDi/blog-react-Novice/tree/v3.11-2
Branch:branch4

commit description:v3.11-2-example11-2(应用场景(五)- 实现 404(友好页面),完成)

tag:v3.11-2

2.3.6 应用场景(六)

现在,我们要给用户增加一个购物车的功能

index.js

// 添加一个连接
<NavLink to="/cart" activeStyle={{color:'red'}} exact>Cart</NavLink>

Cart.js

// 购物车组件
import React from 'react';export default class Cart extends React.Component {render() {return(<div>购物车</div>);}}

我们还要配一个用户系统,比如:注册登录啥的

index.js

// 模拟一个添加登录用户状态的 state
this.state = {users: [{id: 1,username: 'zs',password: '123'},{id: 2,username: 'ls',password: '123'},{id: 3,username: 'ww',password: '123'},{id: 4,username: 'gg',password: '123'}],userInfo: {id: 0,username: ''},...
}// 添加一个登录链接
{this.state.userInfo.id > 0 ? (<span>{this.state.userInfo.username}</span>) : (<NavLink to='/login' activeStyle={{color:'red'}} exact>Login</NavLink>)
}

2.3.6.1 example12

实现购物界面

react-Novice05\app\src\views\Cart.js

import React from 'react';export default class Cart extends React.Component {render() {return(<div>购物车</div>);}}

react-Novice05\app\src\App.js

import React from 'react';import {Route, Link, NavLink, Switch} from 'react-router-dom';import './css.css';import Home from './views/Home';
import About from './views/About';
import View from "./views/View";
import NotFound from "./views/NotFound";
import Cart from "./views/Cart";class App extends React.Component {constructor(props) {super(props);this.state = {items: [{id: 1,name: 'iPhone XR',price: 542500},{id: 2,name: 'Apple iPad Air 3',price: 377700},{id: 3,name: 'Macbook Pro 15.4',price: 1949900},{id: 4,name: 'Apple iMac',price: 1629900},{id: 5,name: 'Apple Magic Mouse',price: 72900},{id: 6,name: 'Apple Watch Series 4',price: 599900}]}}render() {return (<div className="App"><h1>React路由</h1><hr/><nav><NavLink to="/" exact={true} activeStyle={{color: 'red'}} isActive={(match, location) => {// match当前匹配的 location 当前地址栏信息// console.log(match, location);// match 为真后面无需处理 否则以'/view'命名开始return match || location.pathname.startsWith('/view');}}>首页</NavLink><span> | </span><NavLink to="/cart" activeStyle={{color:'red'}} exact>购物车</NavLink><span> | </span><NavLink to="/about" activeStyle={{color: 'red'}}>关于我们</NavLink></nav><hr/><Switch><Route path="/" exact render={(props) => <Home items={this.state.items} {...props} />} /><Route path="/view/:id(\d+)" render={(props) => {return <View {...props} items={this.state.items} />}} /><Route path="/cart" component={Cart}/><Route path="/about" component={About}/><Route component={NotFound} /></Switch></div>)}}export default App;

image-20200608133532244

参考:https://github.com/6xiaoDi/blog-react-Novice/tree/v3.12
Branch:branch4

commit description:v3.12-example12(应用场景(六)- 实现购物界面)

tag:v3.12

2.3.6.2 Redirect 组件

未登录用户是不能访问购物车的,所以,我们需要在访问购物车的时候加入用户权限验证(鉴权),如果没有登录则跳转到登录

index.js

<Route path='/cart' render={props => {if (this.state.userInfo.uid > 0) {return <Cart />;} else {// return <Login />;return <Redirect to='/login' />;}
}}  />
2.3.6.2.1 to

设置跳转的 URL

登录代码

// index.js
login({username, password}) {return new Promise( (resolve, reject) => {if (!username || !password) {reject('请输入用户名和密码');}let user = this.state.users.find(user => user.username === username && user.password === password);if ( !user ) {reject('用户不存在或者密码错误');}this.setState({userInfo: {id: user.id,username: user.username}});resolve('登录成功');} );
}
...
<Route path='/login' component={props => {return <Login {...props} onLogin={this.login.bind(this)} />;
}} />// login.js
import React from 'react';export default class Login extends React.Component {constructor(...props) {super(...props);this.login = this.login.bind(this);this.usernameRef = React.createRef();this.passwordRef = React.createRef();}login() {let {onLogin, history: {push}} = this.props;if (typeof onLogin === 'function') {onLogin({username: this.usernameRef.current.value,password: this.passwordRef.current.value}).then(msg=>{alert(msg);push('/');}).catch(e=>alert(e));}}render() {return(<div><p>用户名:<input type="text" ref={this.usernameRef} /></p><p>密码:<input type="password" ref={this.passwordRef} /></p><p><button onClick={this.login}>登录</button></p></div>);}}
2.3.6.2.2 example13

然而根据需求,其实是有了登录才能有购物车这个功能的,我们暂时不实现一个完整的登录注册了,暂时模拟一个。

我们访问购物车,不能再像上述直接访问了,而是判断用户。

react-Novice05\app\src\views\Login.js

import React from 'react';export default class Login extends React.Component {render() {return(<div>登录</div>);}}

react-Novice05\app\src\App.js

import React from 'react';import {Route, Link, NavLink, Switch} from 'react-router-dom';import './css.css';import Home from './views/Home';
import About from './views/About';
import View from "./views/View";
import NotFound from "./views/NotFound";
import Cart from "./views/Cart";
import Redirect from "react-router-dom/es/Redirect";
import Login from "./views/Login";class App extends React.Component {constructor(props) {super(props);this.state = {// 用户信息userInfo: {id: 0,username: ''},items: [{id: 1,name: 'iPhone XR',price: 542500},{id: 2,name: 'Apple iPad Air 3',price: 377700},{id: 3,name: 'Macbook Pro 15.4',price: 1949900},{id: 4,name: 'Apple iMac',price: 1629900},{id: 5,name: 'Apple Magic Mouse',price: 72900},{id: 6,name: 'Apple Watch Series 4',price: 599900}]}}render() {return (<div className="App"><h1>React路由</h1><hr/><nav><NavLink to="/" exact={true} activeStyle={{color: 'red'}} isActive={(match, location) => {// match当前匹配的 location 当前地址栏信息// console.log(match, location);// match 为真后面无需处理 否则以'/view'命名开始return match || location.pathname.startsWith('/view');}}>首页</NavLink><span> | </span><NavLink to="/cart" activeStyle={{color:'red'}} exact>购物车</NavLink><span> | </span><NavLink to="/about" activeStyle={{color: 'red'}}>关于我们</NavLink></nav><hr/><Switch><Route path="/" exact render={(props) => <Home items={this.state.items} {...props} />} /><Route path="/view/:id(\d+)" render={(props) => {return <View {...props} items={this.state.items} />}} /><Route path="/cart" component={() => {if (this.state.userInfo.id > 0) {return <Cart />;} else {// 重定向组件return <Redirect to='/login' />;}}}/><Route path="/login" activeStyle={{color:'red'}} exact component={Login}/><Route path="/about" component={About}/><Route component={NotFound} /></Switch></div>)}}export default App;

        this.state = {// 用户信息userInfo: {id: 1,username: ''},......}

参考:https://github.com/6xiaoDi/blog-react-Novice/tree/v3.13
Branch:branch4

commit description:v3.13-example13(应用场景(六)- 实现购物界面加登录权限控制)

tag:v3.13

2.3.7 应用场景(七)

随着产品的增多,那么多的数据就不可能一次性全部展示出来,所以我们为商品的展示添加一个分页功能。分页组件是功能组件。

// Pagination.js
import React from 'react';
import PropTypes from 'prop-types';import {withRouter, Link} from 'react-router-dom';class Pagination extends React.Component {static defaultProps = {pages: 1,page: 1}static propTypes = {pages: PropTypes.number,page: PropTypes.number}render() {let {pages, page, history: {push}} = this.props;// console.log(this.props);return (<div className="pagination">{(new Array(pages)).fill('').map((v, i) => {return (<Linkkey={++i}className={i === page ? 'active' : ''}to={'/'+i}>{i}</Link>);})}前往<input type="text" className="goto" onKeyDown={({target:{value}})=>{if (value !== '') {push('/' + value);}}} /></div>);}}export default withRouter(Pagination);

2.3.7.1 withRouter 组件(高阶组件)

如果一个组件不是路由绑定组件,那么该组件的 props 中是没有路由相关对象的,虽然我们可以通过传参的方式传入,但是如果结构复杂,这样做会特别的繁琐。幸好,我们可以通过 withRouter 方法来注入路由对象。

2.3.7.2 example14

实现分页功能。

2.3.7.2.1 example14-1

分页框子。

react-Novice05\app\src\components\Pagination.js

import React from 'react';
import PropTypes from 'prop-types';import {Link, withRouter} from 'react-router-dom';class Pagination extends React.Component {static defaultProps = {pages: 1, // 总页数page: 1 // 当前页}// 属性验证static propTypes = {pages: PropTypes.number,page: PropTypes.number}render() {let {pages, page} = this.props;return (// 根据当前页,渲染a标签<div className="pagination">{(new Array(pages)).fill('').map((v, i) => {return (<Linkkey={++i}// 高亮当前页className={i === page ? 'active' : ''}to={'/'+i}>{i}</Link>);})}前往<input type="text" className="goto" onKeyDown={e=>{}} /></div>);}}
export default Pagination;

react-Novice05\app\src\App.js

import React from 'react';import {Route, Link, NavLink, Switch} from 'react-router-dom';import './css.css';import Home from './views/Home';
import About from './views/About';
import View from "./views/View";
import NotFound from "./views/NotFound";
import Cart from "./views/Cart";
import Redirect from "react-router-dom/es/Redirect";
import Login from "./views/Login";
import Pagination from "./components/Pagination";class App extends React.Component {constructor(props) {super(props);this.state = {// 用户信息userInfo: {id: 1,username: ''},items: [{id: 1,name: 'iPhone XR',price: 542500},{id: 2,name: 'Apple iPad Air 3',price: 377700},{id: 3,name: 'Macbook Pro 15.4',price: 1949900},{id: 4,name: 'Apple iMac',price: 1629900},{id: 5,name: 'Apple Magic Mouse',price: 72900},{id: 6,name: 'Apple Watch Series 4',price: 599900}]}}render() {return (<div className="App"><h1>React路由</h1><hr/><nav><NavLink to="/" exact={true} activeStyle={{color: 'red'}} isActive={(match, location) => {// match当前匹配的 location 当前地址栏信息// console.log(match, location);// match 为真后面无需处理 否则以'/view'命名开始return match || location.pathname.startsWith('/view');}}>首页</NavLink><span> | </span><NavLink to="/cart" activeStyle={{color:'red'}} exact>购物车</NavLink><span> | </span><NavLink to="/about" activeStyle={{color: 'red'}}>关于我们</NavLink></nav><hr/><Switch><Route path="/" exact render={(props) => <Home items={this.state.items} {...props} />} /><Route path="/view/:id(\d+)" render={(props) => {return <View {...props} items={this.state.items} />}} /><Route path="/cart" component={() => {if (this.state.userInfo.id > 0) {return <Cart />;} else {// 重定向组件return <Redirect to='/login' />;}}}/><Route path="/login" activeStyle={{color:'red'}} exact component={Login}/><Route path="/about" component={About}/><Route component={NotFound} /></Switch><hr/><Pagination page={1} pages={10} /></div>)}}export default App;

image-20200608140350916

参考:https://github.com/6xiaoDi/blog-react-Novice/tree/v3.14-1
Branch:branch4

commit description:v3.14-1-example14-1(应用场景(七)- 分页框子)

tag:v3.14-1

2.3.7.2.2 example14-2

把分页和排序均加进url中

如:localhost/page=2&sort=desc

上述的分页组件写错位置了,应该写在home组件中,否则关于我们的组件中下方也会分页了。

react-Novice05\app\src\views\Home.js

import React from 'react';import Item from '../components/Item.js';
import qs from 'qs';
import Pagination from "../components/Pagination";export default class Home extends React.Component {constructor(props) {super(props);// 默认降序,赋给statethis.state = {items: this.doSort('desc')};this.sort = this.sort.bind(this);}sort(e) {// let items = this.doSort(e.target.value);// this.setState({//     items// });// 跳转页面let {history} = this.props;history.push(`/?sort=${e.target.value}`)}doSort(type = 'desc') {let {items} = this.props;return items.sort( (a, b) => {return 'desc' === type ? b.price - a.price : a.price - b.price;} );}render() {// 取默认排序好的itemslet {items} = this.state;let {location} = this.props;// let queryString = window.location.search.substring(1);let queryString = location.search.substring(1);// 作用:将queryString转为对象形式let qsTest = qs.parse(queryString, {ignoreQueryPrefix: true});let sort = qsTest.sort || 'desc';this.doSort(sort);let page = Number(qsTest.page) || 1;return (<div><h2>商品列表</h2><select defaultValue={sort} onChange={this.sort}><option value="desc">降序</option><option value="asc">升序</option></select><ul className="item-list"><li className="head"><span>名称</span><span>价格</span></li>{items.map( item => <Item item={item} key={item.id} /> )}</ul><hr/><div><Pagination page={page} pages={10} /></div></div>);}}

image-20200608140350916

参考:https://github.com/6xiaoDi/blog-react-Novice/tree/v3.14-2
Branch:branch4

commit description:v3.14-2-example14-2(应用场景(七)- 分页框子,应该放在Home中)

tag:v3.14-2

2.3.7.2.3 example14-3

完善分页的跳转某页的功能。

react-Novice05\app\src\components\Pagination.js

                {/*完善分页的跳转某页的功能*/}<input type="text" className="goto" onKeyDown={e=>{if (e.target.value !== '' && e.keyCode == 13) {// 跳转页面:刷新urlhistory.push('/?page=' + e.target.value);}}} />

提示不能够读取push属性是undefined,说明其实目前history属性实际上是undefinedhistory在这里是有问题的。当前分页组件是嵌套在另一个页面组件中的,因此它是不存在路由对象的。

image-20200608142143388

参考:https://github.com/6xiaoDi/blog-react-Novice/tree/v3.14-3
Branch:branch4

commit description:v3.14-3-example14-3(应用场景(七)- 完善分页的跳转某页的功能,但报错了)

tag:v3.14-3

2.3.7.2.4 example14-4

因为home组件是有路由对象的,把home组件的history传过去即可。

                <div><Pagination history={this.props.history} page={page} pages={10} />{/*<Pagination page={page} pages={10} />*/}</div>

参考:https://github.com/6xiaoDi/blog-react-Novice/tree/v3.14-4
Branch:branch4

commit description:v3.14-4-example14-4(应用场景(七)- 完善分页的跳转某页的功能,解决报错问题)

tag:v3.14-4

但是这种做法是极不推荐的,假如后期修改,home组件中嵌套一个a组件,a组件再嵌套b组件,b再套分页组件,这样你需要一层层的传,逻辑会很繁琐。

这个时候我们可以依靠withRouter组件(高阶组件)来解决这个问题了。

2.3.7.2.5 example14-5

通过 withRouterPagination 进行包装,withRouter内部会把路由有关的几个对象注入到 Pagination 组件的 props 中,并返回 Pagination

高阶组件 - 高阶函数

react-Novice05\app\src\components\Pagination.js

import {Link, withRouter} from 'react-router-dom';
......
export default withRouter(Pagination);

react-Novice05\app\src\views\Home.js

                <div><Pagination page={page} pages={10} /></div>

https://github.com/6xiaoDi/blog-react-Novice/tree/v3.14-5
commit description:v3.14-5-example14-5(应用场景(七)- 完善分页的跳转某页的功能,完成)

tag:v3.14-5

我们可以在react官网搜索高阶组件HOC

高阶组件是参数为组件,返回值为新组件的函数。即传进去一个组件,就出来一个组件。

但是出来的新组件比起原组件,经过高阶函数,进行了扩容。

image-20200608143502856

往下翻可看到源码:

// 此函数接收一个组件...
function withSubscription(WrappedComponent, selectData) {// ...并返回另一个组件...return class extends React.Component {constructor(props) {super(props);this.handleChange = this.handleChange.bind(this);this.state = {data: selectData(DataSource, props)};}componentDidMount() {// ...负责订阅相关的操作...DataSource.addChangeListener(this.handleChange);}componentWillUnmount() {DataSource.removeChangeListener(this.handleChange);}handleChange() {this.setState({data: selectData(DataSource, this.props)});}render() {// ... 并使用新数据渲染被包装的组件!// 请注意,我们可能还会传递其他属性return <WrappedComponent data={this.state.data} {...this.props} />;}};
}

主要看返回值,这里其实就相当于在内部引入了...this.props,就和我们自己最开始自己引入props一样。

react的基础就差不多了,剩下内容小迪以后再扩展。



(后续待补充)
查看全文
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

相关文章

  1. ng2路由跳转

    本文主要介绍的是angular2中router路由跳转navigate的使用与刷新页面问题的相关内容&#xff0c;分享出供大家参考学习&#xff0c;下面来看看详细的介绍&#xff1a; 一、router.navigate的使用 navigate是Router类的一个方法&#xff0c;主要用来跳转路由。 函数定义&#…...

    2024/4/21 13:57:31
  2. React 路由、Redux、React-Redux

    一、React 路由 安装&#xff1a;npm install react-router-dom --save ReactRouter三大组件&#xff1a; Router&#xff1a;所有路由组件的根组件&#xff08;底层组件&#xff09;&#xff0c;包裹路由规则的最外层容器。 Route:路由规则匹配组件&#xff0c;显示当前规…...

    2024/4/21 13:57:29
  3. 鞠婧?t双眼皮是哪种

    ...

    2024/4/29 11:49:56
  4. 切开双眼皮用拆线吗

    ...

    2024/5/3 23:23:18
  5. url中增加端口号之后提示Origin is not allowed by Access-Control-Allow-Origin. Angular JS

    本来&#xff0c;几个演示系统发布在一台服务器上&#xff0c;运行很正常。可是最近合作伙伴说租用的服务器不想续费了&#xff0c;将那几个项目搬到他们公司内部的服务器上。好吧&#xff0c;搬就搬&#xff0c;本身也费不了多少事&#xff0c;无法就是重新发布、重新设置而已…...

    2024/4/20 3:12:43
  6. 双眼皮加鼻翼缩小图片

    ...

    2024/4/29 0:51:34
  7. 江苏好的割女人怀孕会变长期贴双眼皮可以后天形成吗

    ...

    2024/4/21 13:57:28
  8. 怎样让三眼皮变什么样的眼睛会自己变割双眼皮如何预防增生

    ...

    2024/4/21 13:57:27
  9. 有一只眼睛要变割双眼皮会变美吗

    ...

    2024/5/3 7:17:28
  10. Angular2 - 数据共享与数据传递 - 共享应用环境信息配置及环境识别

    在Angular项目的设计中&#xff0c;我们往往需要定义一些全局的数据&#xff0c;如&#xff1a;应用名称&#xff0c;版本&#xff0c;当前环境&#xff0c;后端服务器地址&#xff0c;当前用户信息等&#xff0c;并希望能一次定义&#xff0c;多处共享&#xff0c;这里我们介绍…...

    2024/4/21 13:57:26
  11. 眼皮下垂做宽为什么年龄大了会长怀孕变成是否把右眼剧怎么才能让单眼皮变怎么让本就有的双眼皮更双

    ...

    2024/4/21 13:57:24
  12. 合肥近视眼做双眼皮有影响吗

    ...

    2024/4/24 17:12:41
  13. Python : Turtle如何配置屏幕和海龟

    内置的默认配置模仿旧乌龟模块的外观和行为,以保持与其最佳兼容性。 如果您想使用更好地反映该模块功能或更适合您需求的其他配置,例如在教室中使用,您可以准备一个配置文件turtle.cfg,该文件将在导入时读取并根据以下内容修改配置。它的设置。 内置配置将对应于以下turtle…...

    2024/4/29 10:32:12
  14. angularJS 做一个日程表

    <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Title</title><script src"ajs/angular.min.js"></script><script>var data {user:"吴四",items:[{act…...

    2024/4/21 13:57:21
  15. Vue.js声明式渲染

    基础概念理解&#xff1a;&#xff08;*&#xff09; 1. 什么是Vue&#xff1f; Vue是一套构建用户界面的渐进式框架。 2. 如何理解渐进式 我对渐进式的理解其实就两个字&#xff1a;自由。 当我们要用Angular框架时要知道它是强主张的&#xff0c;必须要遵循以下三条规则&…...

    2024/5/2 17:40:55
  16. Vue.js—快速入门及实现图书管理系统

    前 言 今天我们主要一起来学习一个新框架的使用——Vue.js&#xff0c;之前我们也讲过AngularJS是如何使用的&#xff0c;而今天要讲的Vue.js的语法和AngularJS很相似&#xff0c;因为 AngularJS 是 Vue 早期开发的灵感来源。然而&#xff0c;AngularJS 中存在的许多问题&…...

    2024/4/21 13:57:19
  17. AngularJS 表格

    ng-repeat 指令可以完美的显示表格。 1 在表格中显示数据 示例 <!DOCTYPE html> <html> <head><meta charset"utf-8"><script src"https://cdn.bootcss.com/angular.js/1.6.3/angular.min.js"></script> </head&…...

    2024/4/21 13:57:20
  18. Angularjs日程表操作2

    <!DOCTYPE html> <html> <head> <meta charset"utf-8" /> <title>八维管理</title> <style> li{ list-style: none;} a{ text-decoration: none;} .ul2 l…...

    2024/4/21 13:57:17
  19. AngularJS点击添加样式、点击变色设置

    首先解释需求是这样的&#xff0c;有个列表&#xff0c;当你点击哪一行时&#xff0c;哪一行背景变成灰色&#xff0c;在JQ中&#xff0c;大家都知道&#xff0c;这是非常容易的&#xff0c;加一个addClass就行了&#xff0c;那么AngularJS如何实现呢&#xff1f; 下面我们看代…...

    2024/5/3 10:49:52
  20. Flow.js学习笔记一

    Flow.js Flow.js是FaceBook发布的开源Javascript静态类型检查器。他给JavaScript提供了静态类型来提高开发人员的生产力和代码质量。 与Vue.js 这个选择最根本的还是在于工程上成本和收益的考量。Vue 2.0 本身在初期的快速迭代阶段是用 ES2015 写的&#xff0c;整个构建工具链也…...

    2024/4/20 1:15:04

最新文章

  1. 吴恩达2022机器学习专项课程(一)正则化(正则化成本函数正则化线性回归正则化逻辑回归)

    目录 一.正则化1.1 正则化的好处1.2 正则化的实现方式 二.正则化改进线性回归的成本函数2.1 正则化后的成本函数的意义2.2 λ参数的作用2.3 不同λ对算法的影响2.4 为什么参数b没有正则化项 三.正则化线性回归的梯度下降3.1 为什么正则化可以在梯度下降迭代中减小w3.2 导数的计…...

    2024/5/4 6:07:36
  2. 梯度消失和梯度爆炸的一些处理方法

    在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言&#xff0c;在此感激不尽。 权重和梯度的更新公式如下&#xff1a; w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...

    2024/3/20 10:50:27
  3. Linux中的shell脚本之流程控制循环遍历

    3 条件判断 4 流程控制语句 1&#xff09;if 语句 案例&#xff0c;用户输入用户名和密码&#xff0c;判断用户名是否是admin,密码是否是123,如果正确&#xff0c;则显示登录成功 首先我创建了shell文件&#xff0c;touch getpawer 其中getpawer 是我自己命的名 #!/bin/bas…...

    2024/5/1 13:38:30
  4. PostCss:详尽指南之安装和使用

    引言 在现代前端开发中&#xff0c;CSS预处理器如Sass、Less等已经成为提升开发效率、增强代码可维护性的重要工具。然而&#xff0c;随着Web技术的发展&#xff0c;CSS的功能也在不断扩展&#xff0c;一些新的CSS语法&#xff08;如变量、自定义属性、CSS Grid等&#xff09;以…...

    2024/5/2 5:02:14
  5. 【外汇早评】美通胀数据走低,美元调整

    原标题:【外汇早评】美通胀数据走低,美元调整昨日美国方面公布了新一期的核心PCE物价指数数据,同比增长1.6%,低于前值和预期值的1.7%,距离美联储的通胀目标2%继续走低,通胀压力较低,且此前美国一季度GDP初值中的消费部分下滑明显,因此市场对美联储后续更可能降息的政策…...

    2024/5/1 17:30:59
  6. 【原油贵金属周评】原油多头拥挤,价格调整

    原标题:【原油贵金属周评】原油多头拥挤,价格调整本周国际劳动节,我们喜迎四天假期,但是整个金融市场确实流动性充沛,大事频发,各个商品波动剧烈。美国方面,在本周四凌晨公布5月份的利率决议和新闻发布会,维持联邦基金利率在2.25%-2.50%不变,符合市场预期。同时美联储…...

    2024/5/2 16:16:39
  7. 【外汇周评】靓丽非农不及疲软通胀影响

    原标题:【外汇周评】靓丽非农不及疲软通胀影响在刚结束的周五,美国方面公布了新一期的非农就业数据,大幅好于前值和预期,新增就业重新回到20万以上。具体数据: 美国4月非农就业人口变动 26.3万人,预期 19万人,前值 19.6万人。 美国4月失业率 3.6%,预期 3.8%,前值 3…...

    2024/4/29 2:29:43
  8. 【原油贵金属早评】库存继续增加,油价收跌

    原标题:【原油贵金属早评】库存继续增加,油价收跌周三清晨公布美国当周API原油库存数据,上周原油库存增加281万桶至4.692亿桶,增幅超过预期的74.4万桶。且有消息人士称,沙特阿美据悉将于6月向亚洲炼油厂额外出售更多原油,印度炼油商预计将每日获得至多20万桶的额外原油供…...

    2024/5/3 23:10:03
  9. 【外汇早评】日本央行会议纪要不改日元强势

    原标题:【外汇早评】日本央行会议纪要不改日元强势近两日日元大幅走强与近期市场风险情绪上升,避险资金回流日元有关,也与前一段时间的美日贸易谈判给日本缓冲期,日本方面对汇率问题也避免继续贬值有关。虽然今日早间日本央行公布的利率会议纪要仍然是支持宽松政策,但这符…...

    2024/4/27 17:58:04
  10. 【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响

    原标题:【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响近日伊朗局势升温,导致市场担忧影响原油供给,油价试图反弹。此时OPEC表态稳定市场。据消息人士透露,沙特6月石油出口料将低于700万桶/日,沙特已经收到石油消费国提出的6月份扩大出口的“适度要求”,沙特将满…...

    2024/4/27 14:22:49
  11. 【外汇早评】美欲与伊朗重谈协议

    原标题:【外汇早评】美欲与伊朗重谈协议美国对伊朗的制裁遭到伊朗的抗议,昨日伊朗方面提出将部分退出伊核协议。而此行为又遭到欧洲方面对伊朗的谴责和警告,伊朗外长昨日回应称,欧洲国家履行它们的义务,伊核协议就能保证存续。据传闻伊朗的导弹已经对准了以色列和美国的航…...

    2024/4/28 1:28:33
  12. 【原油贵金属早评】波动率飙升,市场情绪动荡

    原标题:【原油贵金属早评】波动率飙升,市场情绪动荡因中美贸易谈判不安情绪影响,金融市场各资产品种出现明显的波动。随着美国与中方开启第十一轮谈判之际,美国按照既定计划向中国2000亿商品征收25%的关税,市场情绪有所平复,已经开始接受这一事实。虽然波动率-恐慌指数VI…...

    2024/4/30 9:43:09
  13. 【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试

    原标题:【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试美国和伊朗的局势继续升温,市场风险情绪上升,避险黄金有向上突破阻力的迹象。原油方面稍显平稳,近期美国和OPEC加大供给及市场需求回落的影响,伊朗局势并未推升油价走强。近期中美贸易谈判摩擦再度升级,美国对中…...

    2024/4/27 17:59:30
  14. 【原油贵金属早评】市场情绪继续恶化,黄金上破

    原标题:【原油贵金属早评】市场情绪继续恶化,黄金上破周初中国针对于美国加征关税的进行的反制措施引发市场情绪的大幅波动,人民币汇率出现大幅的贬值动能,金融市场受到非常明显的冲击。尤其是波动率起来之后,对于股市的表现尤其不安。隔夜美国股市出现明显的下行走势,这…...

    2024/5/2 15:04:34
  15. 【外汇早评】美伊僵持,风险情绪继续升温

    原标题:【外汇早评】美伊僵持,风险情绪继续升温昨日沙特两艘油轮再次发生爆炸事件,导致波斯湾局势进一步恶化,市场担忧美伊可能会出现摩擦生火,避险品种获得支撑,黄金和日元大幅走强。美指受中美贸易问题影响而在低位震荡。继5月12日,四艘商船在阿联酋领海附近的阿曼湾、…...

    2024/4/28 1:34:08
  16. 【原油贵金属早评】贸易冲突导致需求低迷,油价弱势

    原标题:【原油贵金属早评】贸易冲突导致需求低迷,油价弱势近日虽然伊朗局势升温,中东地区几起油船被袭击事件影响,但油价并未走高,而是出于调整结构中。由于市场预期局势失控的可能性较低,而中美贸易问题导致的全球经济衰退风险更大,需求会持续低迷,因此油价调整压力较…...

    2024/4/26 19:03:37
  17. 氧生福地 玩美北湖(上)——为时光守候两千年

    原标题:氧生福地 玩美北湖(上)——为时光守候两千年一次说走就走的旅行,只有一张高铁票的距离~ 所以,湖南郴州,我来了~ 从广州南站出发,一个半小时就到达郴州西站了。在动车上,同时改票的南风兄和我居然被分到了一个车厢,所以一路非常愉快地聊了过来。 挺好,最起…...

    2024/4/29 20:46:55
  18. 氧生福地 玩美北湖(中)——永春梯田里的美与鲜

    原标题:氧生福地 玩美北湖(中)——永春梯田里的美与鲜一觉醒来,因为大家太爱“美”照,在柳毅山庄去寻找龙女而错过了早餐时间。近十点,向导坏坏还是带着饥肠辘辘的我们去吃郴州最富有盛名的“鱼头粉”。说这是“十二分推荐”,到郴州必吃的美食之一。 哇塞!那个味美香甜…...

    2024/4/30 22:21:04
  19. 氧生福地 玩美北湖(下)——奔跑吧骚年!

    原标题:氧生福地 玩美北湖(下)——奔跑吧骚年!让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 啊……啊……啊 两…...

    2024/5/1 4:32:01
  20. 扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!

    原标题:扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!扒开伪装医用面膜,翻六倍价格宰客!当行业里的某一品项火爆了,就会有很多商家蹭热度,装逼忽悠,最近火爆朋友圈的医用面膜,被沾上了污点,到底怎么回事呢? “比普通面膜安全、效果好!痘痘、痘印、敏感肌都能用…...

    2024/5/4 2:59:34
  21. 「发现」铁皮石斛仙草之神奇功效用于医用面膜

    原标题:「发现」铁皮石斛仙草之神奇功效用于医用面膜丽彦妆铁皮石斛医用面膜|石斛多糖无菌修护补水贴19大优势: 1、铁皮石斛:自唐宋以来,一直被列为皇室贡品,铁皮石斛生于海拔1600米的悬崖峭壁之上,繁殖力差,产量极低,所以古代仅供皇室、贵族享用 2、铁皮石斛自古民间…...

    2024/4/28 5:48:52
  22. 丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者

    原标题:丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者【公司简介】 广州华彬企业隶属香港华彬集团有限公司,专注美业21年,其旗下品牌: 「圣茵美」私密荷尔蒙抗衰,产后修复 「圣仪轩」私密荷尔蒙抗衰,产后修复 「花茵莳」私密荷尔蒙抗衰,产后修复 「丽彦妆」专注医学护…...

    2024/4/30 9:42:22
  23. 广州械字号面膜生产厂家OEM/ODM4项须知!

    原标题:广州械字号面膜生产厂家OEM/ODM4项须知!广州械字号面膜生产厂家OEM/ODM流程及注意事项解读: 械字号医用面膜,其实在我国并没有严格的定义,通常我们说的医美面膜指的应该是一种「医用敷料」,也就是说,医用面膜其实算作「医疗器械」的一种,又称「医用冷敷贴」。 …...

    2024/5/2 9:07:46
  24. 械字号医用眼膜缓解用眼过度到底有无作用?

    原标题:械字号医用眼膜缓解用眼过度到底有无作用?医用眼膜/械字号眼膜/医用冷敷眼贴 凝胶层为亲水高分子材料,含70%以上的水分。体表皮肤温度传导到本产品的凝胶层,热量被凝胶内水分子吸收,通过水分的蒸发带走大量的热量,可迅速地降低体表皮肤局部温度,减轻局部皮肤的灼…...

    2024/4/30 9:42:49
  25. 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...

    解析如下&#xff1a;1、长按电脑电源键直至关机&#xff0c;然后再按一次电源健重启电脑&#xff0c;按F8健进入安全模式2、安全模式下进入Windows系统桌面后&#xff0c;按住“winR”打开运行窗口&#xff0c;输入“services.msc”打开服务设置3、在服务界面&#xff0c;选中…...

    2022/11/19 21:17:18
  26. 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。

    %读入6幅图像&#xff08;每一幅图像的大小是564*564&#xff09; f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...

    2022/11/19 21:17:16
  27. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...

    win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面&#xff0c;在等待界面中我们需要等待操作结束才能关机&#xff0c;虽然这比较麻烦&#xff0c;但是对系统进行配置和升级…...

    2022/11/19 21:17:15
  28. 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...

    有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows&#xff0c;请勿关闭计算机”的提示&#xff0c;要过很久才能进入系统&#xff0c;有的用户甚至几个小时也无法进入&#xff0c;下面就教大家这个问题的解决方法。第一种方法&#xff1a;我们首先在左下角的“开始…...

    2022/11/19 21:17:14
  29. win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...

    置信有很多用户都跟小编一样遇到过这样的问题&#xff0c;电脑时发现开机屏幕显现“正在配置Windows Update&#xff0c;请勿关机”(如下图所示)&#xff0c;而且还需求等大约5分钟才干进入系统。这是怎样回事呢&#xff1f;一切都是正常操作的&#xff0c;为什么开时机呈现“正…...

    2022/11/19 21:17:13
  30. 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...

    Win7系统开机启动时总是出现“配置Windows请勿关机”的提示&#xff0c;没过几秒后电脑自动重启&#xff0c;每次开机都这样无法进入系统&#xff0c;此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一&#xff1a;开机按下F8&#xff0c;在出现的Windows高级启动选…...

    2022/11/19 21:17:12
  31. 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...

    有不少windows10系统用户反映说碰到这样一个情况&#xff0c;就是电脑提示正在准备windows请勿关闭计算机&#xff0c;碰到这样的问题该怎么解决呢&#xff0c;现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法&#xff1a;1、2、依次…...

    2022/11/19 21:17:11
  32. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...

    今天和大家分享一下win7系统重装了Win7旗舰版系统后&#xff0c;每次关机的时候桌面上都会显示一个“配置Windows Update的界面&#xff0c;提示请勿关闭计算机”&#xff0c;每次停留好几分钟才能正常关机&#xff0c;导致什么情况引起的呢&#xff1f;出现配置Windows Update…...

    2022/11/19 21:17:10
  33. 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...

    只能是等着&#xff0c;别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚&#xff0c;只能是考虑备份数据后重装系统了。解决来方案一&#xff1a;管理员运行cmd&#xff1a;net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...

    2022/11/19 21:17:09
  34. 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?

    原标题&#xff1a;电脑提示“配置Windows Update请勿关闭计算机”怎么办&#xff1f;win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢&#xff1f;一般的方…...

    2022/11/19 21:17:08
  35. 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...

    关机提示 windows7 正在配置windows 请勿关闭计算机 &#xff0c;然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;关机提示 windows7 正在配…...

    2022/11/19 21:17:05
  36. 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...

    钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...

    2022/11/19 21:17:05
  37. 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...

    前几天班里有位学生电脑(windows 7系统)出问题了&#xff0c;具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面&#xff0c;长时间没反应&#xff0c;无法进入系统。这个问题原来帮其他同学也解决过&#xff0c;网上搜了不少资料&#x…...

    2022/11/19 21:17:04
  38. 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...

    本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法&#xff0c;并在最后教给你1种保护系统安全的好方法&#xff0c;一起来看看&#xff01;电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中&#xff0c;添加了1个新功能在“磁…...

    2022/11/19 21:17:03
  39. 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...

    许多用户在长期不使用电脑的时候&#xff0c;开启电脑发现电脑显示&#xff1a;配置windows更新失败&#xff0c;正在还原更改&#xff0c;请勿关闭计算机。。.这要怎么办呢&#xff1f;下面小编就带着大家一起看看吧&#xff01;如果能够正常进入系统&#xff0c;建议您暂时移…...

    2022/11/19 21:17:02
  40. 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...

    配置windows update失败 还原更改 请勿关闭计算机&#xff0c;电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;配置windows update失败 还原更改 请勿关闭计算机&#x…...

    2022/11/19 21:17:01
  41. 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...

    不知道大家有没有遇到过这样的一个问题&#xff0c;就是我们的win7系统在关机的时候&#xff0c;总是喜欢显示“准备配置windows&#xff0c;请勿关机”这样的一个页面&#xff0c;没有什么大碍&#xff0c;但是如果一直等着的话就要两个小时甚至更久都关不了机&#xff0c;非常…...

    2022/11/19 21:17:00
  42. 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...

    当电脑出现正在准备配置windows请勿关闭计算机时&#xff0c;一般是您正对windows进行升级&#xff0c;但是这个要是长时间没有反应&#xff0c;我们不能再傻等下去了。可能是电脑出了别的问题了&#xff0c;来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...

    2022/11/19 21:16:59
  43. 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...

    我们使用电脑的过程中有时会遇到这种情况&#xff0c;当我们打开电脑之后&#xff0c;发现一直停留在一个界面&#xff1a;“配置Windows Update失败&#xff0c;还原更改请勿关闭计算机”&#xff0c;等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢&#xff0…...

    2022/11/19 21:16:58
  44. 如何在iPhone上关闭“请勿打扰”

    Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...

    2022/11/19 21:16:57