从零搭建 React 开发 H5 模板_react html5
zhezhongyun 2025-10-02 11:20 33 浏览
项目创建
创建项目文件夹
mkdir react-demo
cd react-demo
npm init -y
依赖安装
yarn add react react-dom
yarn add webpack webpack-cli webpack-dev-server webpack-merge
babel-core babel-loader babel-polyfill babel-preset-env babel-preset-react
babel-preset-stage-0 cross-env
file-loader jsx-loader
css-loader style-loader url-loader less less-loader --dev
webpack 配置
区分开发环境 development 和生产环境 production 配置
分别创建对应的配置文件
「antd-mobile 按需加载」 **
- 安装插件
yarn add babel-plugin-import -D
**
- 修改 babel.config.js 配置
module.exports = {
presets: ["@babel/preset-env", "@babel/preset-react"],
plugins: [
"@babel/plugin-transform-runtime",
"@babel/plugin-proposal-class-properties",
["import", { libraryName: "antd-mobile", style: true }]
]
};
externals 配置
webpack 中的 externals 「防止」将某些 import 的包(package)「打包」到 bundle 中
modules.export = {
plugins: [
new HtmlWebpackPlugin({
title: 'React Board',
files: { // 配置 CDN 引入
js: [
'//unpkg.com/swiper/js/swiper.min.js'
],
css: [
'//unpkg.com/swiper/css/swiper.min.css'
]
}
})
],
externals: {
swiper: 'Swiper'
}
}
index.html 设置:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title><%= htmlWebpackPlugin.options.title %></title>
<!-- require cdn assets css -->
<% for (var i in htmlWebpackPlugin.options.files.css) { %>
<link rel="stylesheet" href="<%= htmlWebpackPlugin.options.files.css[i] %>" />
<% } %>
</head>
<body>
<div id="root"></div>
<!-- require cdn assets js -->
<% for (var i in htmlWebpackPlugin.options.files.js) { %>
<script type="text/javascript" src="<%= htmlWebpackPlugin.options.files.js[i] %>"></script>
<% } %>
</body>
</html>
代码中使用:
import Swiper from 'swiper';
移动端适配
使用 **postcss-loader **实现 css 转换
// 项目使用的是 less
yarn add postcss-less-loader -D
webpack.base.js 配置
{
test: /\.(css|less)$/,
use: [
'style-loader',
'css-loader',
'less-loader',
'postcss-less-loader'
]
}
postcss-px-to-viewport
选用该插件对所有的 px 转换成 vw 视窗尺寸
yarn add postcss-px-to-viewport -D
项目根目录下建立 postcss.config.js
module.exports = {
plugins: {
"postcss-px-to-viewport": {
viewportWidth: 375, // 视窗的宽度,对应的是我们设计稿的宽度,Iphone6的一般是375 (xx/375*100vw)
viewportHeight: 667, // 视窗的高度,Iphone6的一般是667
unitPrecision: 3, // 指定`px`转换为视窗单位值的小数位数(很多时候无法整除)
viewportUnit: "vw", // 指定需要转换成的视窗单位,建议使用vw
selectorBlackList: ['.ignore', '.hairlines'],// 指定不转换为视窗单位的类,可以自定义,可以无限添加,建议定义一至两个通用的类名
minPixelValue: 1, // 小于或等于`1px`不转换为视窗单位,你也可以设置为你想要的值
mediaQuery: false, // 允许在媒体查询中转换`px`
exclude: /(node_module)/i // 忽略 UI 组件库
}
}
}
postcss-plugin-px2rem
这个插件是对所有 px 转换成 rem 尺寸单位
yarn add postcss-plugin-px2rem -D
postcss.config.js 配置:
module.exports = {
plugins: {
"postcss-plugin-px2rem": {
rootValue: 16,// 配合 rem.js 使用 750 的设计稿
unitPrecision: 5,
mediaQuery: true,
exclude: /(node_module)/i,
selectorBlackList: ['html', 'mp-', 'calendar', 'iconfont'], // 在 rem.js 全局作用下,排除指定的文件的影响
propBlackList: ['border'] // 过滤属性
}
}
}
需要新建 rem.js 或者直接下载 lib-flexible
const viewportWidth = 750
// 基准大小
const baseSize = 32
// 设置 rem 函数
function setRem() {
// 当前页面宽度相对于 750 宽的缩放比例,可根据自己需要修改。
const scale = document.documentElement.clientWidth / viewportWidth
// 设置页面根节点字体大小
document.documentElement.style.fontSize = (baseSize * Math.min(scale, 2)) + 'px'
}
// 初始化
setRem()
// 改变窗口大小时重新设置 rem
window.onresize = function () { setRem() }
「在入口文件引入:」
// App.js
import './utils/rem'
// import "./utils/flexible.js"
EsLint 配置
安装 eslint 插件
yarn add eslint eslint-plugin-import babel-eslint eslint-plugin-react-hooks -D
根目录下新建 .eslintrc.js 配置文件
module.exports = {
parser: "babel-eslint",
plugins: [
"react-hooks"
],
rules: {
"react-hooks/rules-of-hooks": "error", // 检查 Hook 的规则
"react-hooks/exhaustive-deps": "error" // 检查 effect 的依赖
}
}
React 路由
yarn add react-router-dom react-router-config
使用 react-router-config 来简化路由配置
新建 routes.js 文件
import Home from "@/pages/Home"
import Me from "@/pages/Me"
import Test from "@/pages/Test"
console.log(typeof process.env.API)
const routes = [
{
path: "/home",
exact: true,
component: Home
},
{
path: "/me",
exact: true,
component: Me
},
{
path: "/test",
exact: true,
component: Test
}
];
export default routes;
根文件 App.js 中引入路由:
import { renderRoutes } from 'react-router-config'
import routes from './routes'
import { HashRouter as Router } from 'react-router-dom'
import Layouts from "./components/Layouts";
function App() {
return (
<Router>
<Layouts>
{renderRoutes(routes)}
</Layouts>
</Router>
)
}
ReactDOM.render(<App />, document.getElementById('root'))
Hooks 开发
「Hook 是什么?」 Hook 是一个特殊的函数,它可以让你“钩入” React 的特性。「Hook 只能在 Function Component 里面声明。」
useState
返回一个状态和一个可以修改状态的函数 setter
import React, { useState } from 'react';
import { Button } from "antd-mobile";
function User() {
const [user, setUser] = useState('Mondo')
return (
<div>
<div>{user}</div>
<Button type="primary" onClick={e => setUser('imondo.cn')}>改变 State</Button>
</div>
)
}
useEffect
替代 Class Component 中 componentDidMount、componentDidUpdate、componentWillUnmount 等部分生命周期
import React, { useState, useEffect } from 'react';
function User() {
const [user, setUser] = useState('Mondo')
useEffect(() => {
setTimeout(() => {
setUser("js.imondo.cn")
}, 2000)
}, [user]) // 仅在 user 更改时更新
return (
<div>
<div>{user}</div>
<Button type="primary" onClick={e => setUser('imondo.cn')}>改变 State</Button>
</div>
)
}
useContext
接收一个 context 对象并返回该 context 的当前值。当前的 context 值由上层组件中距离当前组件最近的 <MyContext.Provider> 的 value prop 决定。当组件上层最近的 <MyContext.Provider> 更新时,该 Hook 会触发重渲染。
可用于「组件间值传递」
import React, { useContext } from 'react';
const theme = {
color: "red"
}
const UserContext = React.createContext(theme);
function User() {
...
return (
<UserContext.Provider value={theme}>
<Child/>
</UserContext.Provider>
)
}
function Child() {
const theme = useContext(UserContext);
return (
<div style={{color: theme.color}}>context</div>
)
}
useMemo
使用格式:useMemo(() => fn, deps)
把“创建”函数和依赖项数组作为参数传入 useMemo,它仅会在某个依赖项改变时才重新计算 memoized 值。这种优化有助于避免在每次渲染时都进行高开销的计算。「可以当作 vue 中的计算属性」
import React, { useState, useMemo } from 'react';
import { Button } from "antd-mobile";
function User() {
const [user, setUser] = useState(1)
/* 缓存计算属性 */
const data = useMemo(() => ({
users: (user + 1)
}), [user]);
const onChangeUser = (e) => {
setUser(+e.target.value);
}
return (
<UserContext.Provider>
<input value={user} onChange={onChangeUser}/>
<div>{data.users}</div>
<Button type="primary" onClick={e => setUser(user + 1)}>改变 State</Button>
</UserContext.Provider>
)
}
useReducer
使用格式:const [state, dispatch] = useReducer(reducer, initialArg, init)
它是 useState 的替代方案,在一些场景使用:
- state 逻辑较复杂且包含多个子值
- 下一个 state 依赖于之前的 state
最重要的其实它的写法和 **redux **差不多
import React, { useReducer } from "react";
import { Button } from "antd-mobile";
let initCount = 0;
function reducer(state = initCount, action) {
switch (action) {
case "increment":
state++
return state
case "decrement":
state--
return state
default:
throw new Error();
}
}
function User() {
const [count, disaptch] = useReducer(reducer, initCount)
return (
<UserContext.Provider value={theme}>
<div>useReducer</div>
<div>计数器{count}</div>
<Button type="primary" onClick={e => disaptch("decrement")}>减</Button>
<Button type="primary" onClick={e => disaptch("increment")}>加</Button>
</UserContext.Provider>
)
}
useRef
返回一个可变的 ref 对象,其 .current 属性被初始化为传入的参数 如果想要「访问子组件内的 ref 对象,子组件需要用 class 声明组件」。
import React, { useState, useMemo, useRef } from 'react';
function Parent() {
let [count, setCount] = useState(0)
const childRef = useRef(null)
const childClick = (val) => {
childRef.current.setState({
num: 2
});
}
return (
<div>
<h4>组件传值</h4>
<button onClick={childClick}>向子组件传值</button>
<Child1 ref={childRef} />
</div>
);
}
class Child1 extends React.Component {
constructor() {
super(...arguments);
this.state = {
num: 1
}
}
render() {
const { num } = this.state;
return (
<div>
<div>ref 组件</div>
<div>{num}</div>
</div>
)
}
}
「参考:」 React Hooks 最佳实践 写React Hooks前必读
相关推荐
- Python入门学习记录之一:变量_python怎么用变量
-
写这个,主要是对自己学习python知识的一个总结,也是加深自己的印象。变量(英文:variable),也叫标识符。在python中,变量的命名规则有以下三点:>变量名只能包含字母、数字和下划线...
- python变量命名规则——来自小白的总结
-
python是一个动态编译类编程语言,所以程序在运行前不需要如C语言的先行编译动作,因此也只有在程序运行过程中才能发现程序的问题。基于此,python的变量就有一定的命名规范。python作为当前热门...
- Python入门学习教程:第 2 章 变量与数据类型
-
2.1什么是变量?在编程中,变量就像一个存放数据的容器,它可以存储各种信息,并且这些信息可以被读取和修改。想象一下,变量就如同我们生活中的盒子,你可以把东西放进去,也可以随时拿出来看看,甚至可以换成...
- 绘制学术论文中的“三线表”具体指导
-
在科研过程中,大家用到最多的可能就是“三线表”。“三线表”,一般主要由三条横线构成,当然在变量名栏里也可以拆分单元格,出现更多的线。更重要的是,“三线表”也是一种数据记录规范,以“三线表”形式记录的数...
- Python基础语法知识--变量和数据类型
-
学习Python中的变量和数据类型至关重要,因为它们构成了Python编程的基石。以下是帮助您了解Python中的变量和数据类型的分步指南:1.变量:变量在Python中用于存储数据值。它们充...
- 一文搞懂 Python 中的所有标点符号
-
反引号`无任何作用。传说Python3中它被移除是因为和单引号字符'太相似。波浪号~(按位取反符号)~被称为取反或补码运算符。它放在我们想要取反的对象前面。如果放在一个整数n...
- Python变量类型和运算符_python中变量的含义
-
别再被小名词坑哭了:Python新手常犯的那些隐蔽错误,我用同事的真实bug拆给你看我记得有一次和同事张姐一起追查一个看似随机崩溃的脚本,最后发现罪魁祸首竟然是她把变量命名成了list。说实话...
- 从零开始:深入剖析 Spring Boot3 中配置文件的加载顺序
-
在当今的互联网软件开发领域,SpringBoot无疑是最为热门和广泛应用的框架之一。它以其强大的功能、便捷的开发体验,极大地提升了开发效率,成为众多开发者构建Web应用程序的首选。而在Spr...
- Python中下划线 ‘_’ 的用法,你知道几种
-
Python中下划线()是一个有特殊含义和用途的符号,它可以用来表示以下几种情况:1在解释器中,下划线(_)表示上一个表达式的值,可以用来进行快速计算或测试。例如:>>>2+...
- 解锁Shell编程:变量_shell $变量
-
引言:开启Shell编程大门Shell作为用户与Linux内核之间的桥梁,为我们提供了强大的命令行交互方式。它不仅能执行简单的文件操作、进程管理,还能通过编写脚本实现复杂的自动化任务。无论是...
- 一文学会Python的变量命名规则!_python的变量命名有哪些要求
-
目录1.变量的命名原则3.内置函数尽量不要做变量4.删除变量和垃圾回收机制5.结语1.变量的命名原则①由英文字母、_(下划线)、或中文开头②变量名称只能由英文字母、数字、下画线或中文字所组成。③英文字...
- 更可靠的Rust-语法篇-区分语句/表达式,略览if/loop/while/for
-
src/main.rs://函数定义fnadd(a:i32,b:i32)->i32{a+b//末尾表达式}fnmain(){leta:i3...
- C++第五课:变量的命名规则_c++中变量的命名规则
-
变量的命名不是想怎么起就怎么起的,而是有一套固定的规则的。具体规则:1.名字要合法:变量名必须是由字母、数字或下划线组成。例如:a,a1,a_1。2.开头不能是数字。例如:可以a1,但不能起1a。3....
- Rust编程-核心篇-不安全编程_rust安全性
-
Unsafe的必要性Rust的所有权系统和类型系统为我们提供了强大的安全保障,但在某些情况下,我们需要突破这些限制来:与C代码交互实现底层系统编程优化性能关键代码实现某些编译器无法验证的安全操作Rus...
- 探秘 Python 内存管理:背后的神奇机制
-
在编程的世界里,内存管理就如同幕后的精密操控者,确保程序的高效运行。Python作为一种广泛使用的编程语言,其内存管理机制既巧妙又复杂,为开发者们提供了便利的同时,也展现了强大的底层控制能力。一、P...
- 一周热门
- 最近发表
- 标签列表
-
- HTML 教程 (33)
- HTML 简介 (35)
- HTML 实例/测验 (32)
- HTML 测验 (32)
- JavaScript 和 HTML DOM 参考手册 (32)
- HTML 拓展阅读 (30)
- HTML文本框样式 (31)
- HTML滚动条样式 (34)
- HTML5 浏览器支持 (33)
- HTML5 新元素 (33)
- HTML5 WebSocket (30)
- HTML5 代码规范 (32)
- HTML5 标签 (717)
- HTML5 标签 (已废弃) (75)
- HTML5电子书 (32)
- HTML5开发工具 (34)
- HTML5小游戏源码 (34)
- HTML5模板下载 (30)
- HTTP 状态消息 (33)
- HTTP 方法:GET 对比 POST (33)
- 键盘快捷键 (35)
- 标签 (226)
- opacity 属性 (32)
- transition 属性 (33)
- 1-1. 变量声明 (31)
