《IT猿题库》项目实战

预习资料

项目地址:http://codesohigh.com/yuantiku

参考该项目及这份笔记,并尝试搭建项目。

实战课学习目标

结合React、React Redux、React Router、Hooks、Axios与material-ui,完成《IT猿题库》项目。

一、项目参考

项目地址:http://codesohigh.com/yuantiku

界面效果:

image-20210514194820474

项目图片资源

链接: https://pan.baidu.com/s/1kTOSazkZ0i9MKnjLhQmiKQ 提取码: 9p5h

二、技术栈

1、React

简介:使用React开发移动端项目

官网地址:https://react.docschina.org/

2、Material-UI

简介:一个基于 Preact / React / React Native 的 UI 组件库

官网地址:https://v4.mui.com/zh/

三、项目创建与安装

1、依赖安装

使用 npx create-react-app yuantiku 创建完项目后,安装material-ui:

2、FastClick解决

public/index.htmlhead 标签中插入:

这里建议把 https://as.alipayobjects.com/g/component/fastclick/1.0.6/fastclick.js 和 https://as.alipayobjects.com/g/component/es6-promise/3.2.2/es6-promise.min.js 保存到本地

3、调用

App.js 中:

然后就可以看到按钮被正式引入:

image-20210428111957851

4、清除默认边距与样式

npm包路径:https://www.npmjs.com/package/reset-css

安装:

使用:

四、蓝湖

将设计图用photoshop打开,并上传至蓝湖。此时的设计图是3x尺寸,因此要勾选对应的1125px尺寸。

五、配置rem

1、安装依赖包

2、解包

解包需要先做git提交,否则无法解包,因此先执行:

接下来直接解包:

image-20210425145931070

3、配置loader

解包后,可以看到项目目录下多了一个 config 文件夹。打开 config/webpack.config.js

搜索 postcss-loader ,添加:

这里的 rootValue: 112.5 的意思就是1rem = 112.5px 这个是根据1125px设计稿来的。

4、flexible引入

入口文件 index.js 里引入 lib-flexible

5、rem测试

App.js 中写个类名,创建 App.css ,并写入:

接下来打开浏览器:

可以看到,iphoneX的尺寸下,html的字体大小为37.5px,此时box的宽度为10rem,再来看看其他尺寸:

image-20210425154110249

当其他尺寸下时,可以发现html字体大小为41.1px,而此时box的宽度仍为10rem,这就代表我们rem配置成功了。

6、兼容ipad

但是,当你点开ipad时,会发现盒子兼容出了问题,这是因为淘宝弹性布局方案lib-flexible不兼容ipad和ipad pro。我们这里给出解决方案:

在public>index.html的head标签中添加:

这样,我们就解决ipad的兼容问题了。

7、修改meta标签

六、配置less

1、安装

2、解包

接下来要解包,如果上一步你已经解包过,就直接跳过。

如果未解包,请以上参考第五步。

3、配置loader

找到 webpack.config.js ,搜索 sassRegex

搜索 sass-loader 后,在其下方添加:

修改了配置文件,记得重新 yarn start 哦!

4、测试less

App.css 改为 App.less 进行测试,依然没问题。

5、文字三属性

App.less 中添加:

这里注意,由于html和body标签已被强行设定了font-size,因此我们设定#root的font-size即可。

七、登录判断

如果我们每个页面都需要在 componentWillMount 判断是否已经登录,那么太麻烦。React中有mixins,但已经被淘汰了。取而代之,我们使用高阶函数来操作。

在src下创建 hoc>index.js

在任何一个页面都可以如下调用(这里以Home页面举例):

八、request封装

1、接口文档

IT猿题库【IT猿题库】 http://www.docway.net/project/1eRv5Lh2UW9/share/1evckeXPiQy 阅读密码:zhaowenxian

2、封装request

react的数据请求我们依然使用axios,我们先封装request:

Token过期:

如果后端判断到token过期,可以在响应拦截器到reject之前:

3、解决跨域

方案一:

react简单解决跨域可以直接在 package.json 中添加 proxy 属性

方案二:

如果你已经进行了 npm run eject ,建议你直接修改 config>webpackDevServer.config.js

方案三(推荐):

安装 http-proxy-middleware

这里注意,http-proxy-middleware 模块是有版本区别的,默认安装最新版本,然后在 src 目录下新建 setupProxy.js

重新 npm run start 即可解决跨域。

4、api导出

我们做请求时的api需要导出:

5、请求

九、路由配置

1、安装

安装 react-router-dom

2、路由配置

src 下创建 router/index.js

App.js 中:

src/index.js 下:

可以看到:

image-20210428115443204

3、创建五个页面

src下创建 views/Home.jsx + Fast.jsx + User.jsx + Login.jsx + Register.jsx + Error.jsx,分别代表:首页+快速刷题+我的+登录页+404页面,并在router下做配置:

修改 App.js

如此,当我们在浏览器输入 http://localhost:3000 时,就会帮我们自动跳到 http://localhost:3000/home ,如果随意输入 http://localhost:3000/aaa ,就会自动重定向到错误页面。

十、Tabbar配置

这里参照 material-uiBottom Navigation 底部导航栏https://material-ui.com/zh/components/bottom-navigation/

1、Tabbar引用

src下创建 components/Tabbar.js :

src/components/less/Tabbar.less:

src/components/HomeTab.jssrc/components/FastTab.jssrc/components/UserTab.js :

2、函数式组件路由

Tabbar.js 中,使用hooks:

如此,就实现了路由切换。

3、Tabbar动态化

4、最终Tabbar代码

十一、Toast组件

1、Toast组件封装

这里需要结合react-redux来实现。首先新建 Toast.jsx

Toast.less 中:

store/reducer.js 中:

使用时机:

比如:每个接口的请求若报500并返回1002,就代表token错误或过期,此时就需要判断token,如果没有token,就直接跳到登录页,跳过去之前,就要先显示loading效果

App.jsx 中引入Toast组件:

2、调用方式

十三、登录注册页套用

⚠️ 这里插播一句:登录注册页请直接套用代码就好!

效果如下:

image-20210924091435946

1、登录页代码

将示例代码直接复制粘贴,然后稍做修改:

然后在 request/api.js 中:

如果缺少什么依赖,就按照提示安装即可。这里主要还缺少:

2、注册页代码

然后在 request/api.js 中:

十三、开发小提示

1、JSX条件判断

在react的class组件中如何使用 switch...case 语法?

使用一个自执行函数,在函数体内使用 switch...case

2、路由跳转问题

当我们使用

得到 push of undefined 的报错时,可以这么解决:

如果使用的是函数式组件,还可以借助hook:

3、自定义进度条

4、配置项目@指向src

在保证解包 yarn eject 之后,找到 webpack.config.js ,搜索 alias 对象,可以得到3个结果,索引第2个结果,并配置:

重跑项目即可使用@符号指向src。

5、组件中无法使用history?

页面在Router中配置了,但它下面的组件无法使用 this.props.history.push() 进行跳转,并且报了如下错误:

image.png

这是因为组件并没有使用 history 的能力,可以使用以上的提示2,也可以将配置过路由的父级的history传递给该组件:

6、setState是异步的

以下这段代码:

为什么以上打印出来是1,而不是2呢?

因为setState是异步的,如果想要正常打印出2,需要:

也就是,setState有第二个参数,属于回调函数。

7、统一使用消息提示

在使用消息提示的时候,我们每次都要单独写样式比较麻烦,这里提供代码,当你要使用 material-ui 的alert组件时,可以这样引入:

记得先在公用的 base.less 中写入:

这里注意:

severity属性规定了消息提示框的类型,分别有:

  • error - 错误提示(红色)

  • warning - 警告提示(橙色)

  • info - 信息提示(蓝色)

  • success - 成功提示(绿色 - 默认值)

至于消息提示框的显示隐藏,可以通过:

来控制。记住,是 display: flex 不是 display: block

Alert引用代码演示:

8、ReactRedux包装Alert

安装 redux 与 react-redux:

将统一消息提示封装到组件 Alert.js 中:

src目录下创建 store/reducer.js

创建 store/index.js :

src/App.js 中引入 Alert 组件:

最后在 <App /> 外套用提供器Provider:

后面某个页面想要触发 Alert ,就可以在该页面使用连接器如下:

9、React插入html

使用 dangerouslySetInnerHTML 属性。

这里注意:html前面是两个下划线。

10、反序列化问题

在子组件中获取到的props,想要将props中的字符串转对象或数组,需要使用 JSON.parse(this.props.content || "[]") 。但接收props存在请求异步的延迟,因此会报错:

因此,我们可以改写为:

11、React实现移动端滑动

先给元素加上css定位:

js实现:

12、答题之多选组件UI部分代码

多选组件比单选组件复杂,需要给数组项中手动添加ifSelect=false。

13、事件参数与事件对象

当我们这么写事件时,存在一个问题,事件对象的位置不知道是在index之前还是index之后,如:

想要禁用Link,开发阶段使用 BrowserRouter 可以使用:

但如果上线使用 HashRouter ,就会跳到404页面,因此需要补充:

十四、项目打包

1、Hash模式打包

打包需要首先向 package.json 中添加:

然后找到 router/index.js

打包完成后,凡是使用了 this.props.location.state.xxx 传值的路由,都会碰上 Cannot read property 'xxx' of undefined 的报错。

原因是HashRouter模式不支持 this.props.location.state 获取数据,需要使用: this.props.location.params 。因此在路由传值的写法上,也要改为这种形式:

打包后可能会发现 history.goBack() 会造成上一级路由参数丢失,此时可以尝试 history.go(-1)

2、History模式打包

package.json 中:

找到 router/index.js

但这里必须要有nginx的配置。

首先 ssh root@IP地址 连接上服务器,然后执行 whereis nginx,然后使用vim修改nginx.conf:

修改完配置后,浏览器打开 http://www.abcd.com/yuantiku 即可。

3、跨域

生产环境下跨域需要nginx配合解决,如果你已在开发环境下使用 /api 代理 https://www.ahsj.link/ramb,那么nginx的配置为:

十五、作业

作业1(初级)

使用Class Component完成微博发布功能。

作业2(中级)

使用Function Component完成微博发布功能。

作业3(高级)

使用Class Component完成Todolist。

作业4(顶级)

使用Function Component完成Todolist。

最后更新于

这有帮助吗?