前言
- 这篇文章主要通过
create-react-app
脚手架配合react-app-rewired
添加一些额外的webpack配置搭建一个基于vw
的H5架子
开始
1、安装
npx create-react-app juejin-react-h5(你的项目名称)
复制代码
2、接下来我们安装下相关依赖
// 安装基本UI库andt-mobile
yarn add antd-mobile
// 安装 react-app-rewired customize-cra 用来添加webpack相关配置,
// 这俩个包应为不用打包在项目中,所以只需要安装在开发环境就好了
yarn add react-app-rewired customize-cra -D
// babel-plugin-import这个是分包工具
yarn add babel-plugin-import -D
复制代码
3、修改package.json
启动项
{
"start": "react-app-rewired start",
"build": "react-app-rewired build",
"test": "react-app-rewired test --env=jsdom",
"eject": "react-scripts eject"
}
复制代码
4、在项目根目录创建一个 config-overrides.js
用于修改默认配置
const { override, fixBabelImports } = require("customize-cra")
module.exports = override(
fixBabelImports("import", {
libraryName: 'antd-mobile',
style: 'css',
})
)
复制代码
5、修改app.js
import { Button } from 'antd-mobile'
function App() {
return (
<div className="App">
<Button type="primary">按钮</Button>
</div>
);
}
export default App;
复制代码
6、启动项目,并访问localhost:3000
yarn start
复制代码
7、打开页面调成手机开发模式就可以看到效果图了
8、接下来我们安装css预编译工具(这里选择sass)
yarn add sass
复制代码
9、接着我们在src下新建一个app.scss文件,并写入一些测试css
.p{
color: red;
width: 750px;
}
复制代码
10、最后在app.js引入app.scss,并重新启动项目
当我们看到这个效果图的时候,sass也就引入成功了
11、配置sass全局变量
//先安装一个loader 和 path
yarn add sass-resources-loader path -D
const resolve = _path => path.resolve(__dirname, _path)
module.exports = override(
fixBabelImports('import', {
libraryName: 'antd-mobile',
style: 'css',
}),
adjustStyleLoaders(rule => {
if (rule.test.toString().includes('scss')) {
rule.use.push({
loader: require.resolve('sass-resources-loader'),
options: {
resources: [resolve("./src/styles/theme.scss")]
}
});
}})
)
复制代码
- 接下来我们创建theme.scss文件,写入一个颜色变量
$red: red;
复制代码
- 我们在app.scss中使用就行了
.p{
color: $red;
width: 750px;
}
复制代码
- 效果依旧没问题
12、下面我们就把单位px
转换成vw
吧
//安装 postcss-px-to-viewport
yarn add postcss-px-to-viewport -D
复制代码
13、下面我们就修改该config-overrides.js
中的代码
const { override, fixBabelImports, addPostcssPlugins } = require("customize-cra")
module.exports = override(
fixBabelImports('import', {
libraryName: 'antd-mobile',
style: 'css',
}),
adjustStyleLoaders(rule => {
if (rule.test.toString().includes('scss')) {
rule.use.push({
loader: require.resolve('sass-resources-loader'),
options: {
resources: [resolve("./src/styles/theme.scss")]
}
});
}}),
addPostcssPlugins([
require("postcss-px-to-viewport")({
unitToConvert: 'px', // 需要转换的单位,默认‘px’
viewportWidth: 750, // 设计稿的视口宽度
unitPrecision: 6, // px转vw之后保留的精度(保留几位小数)
propList: ['*'], // 那些属性可以被转换成vw * 代表全部
viewportUnit: 'vw', // 希望使用的视口单位 // vw
fontViewportUnit: 'vw', //字体使用的视口单位
selectorBlackList: [], // 需要忽略的CSS选择器,不会转为视口单位,使用原有的px等单位
minPixelValue: 1, // 设置最小的转换数值,如果为1的话,只有大于1的值会被转换
mediaQuery: false, // 媒体查询里的单位是否需要转换单位
replace: true, // 是否直接更换属性值,而不添加备用属性
exclude: [/node_modules/], // 忽略某些文件夹下的文件或特定文件,例如 'node_modules' 下的文件
landscape: false, // 是否添加根据 landscapeWidth 生成的媒体查询条件 @media (orientation: landscape)
landscapeUnit: 'vw' // 横屏时使用的单位
})
])
)
复制代码
14、当我们再次启动项目就可以看到p标签中的750px就已经被改成了100vw(因为我们的视口宽度设置的就是750)
15、添加Lodash
工具库,实现按需加载
yarn add lodash
// config-overrides.js 中添加 lodash 按需加载
fixBabelImports("lodash", {
libraryDirectory: "",
camel2DashComponentName: false
})
复制代码
16、添加@
别名
- 在vue中我们经常会写
@/xx/xx
,在CRA中这样配置即可
const path = require("path")
const { override, fixBabelImports, addPostcssPlugins, addWebpackAlias } = require("customize-cra")
const resolve = dir => path.resolve(__dirname, dir)
module.exports = override(
fixBabelImports('import', {
libraryName: 'antd-mobile',
style: 'css',
}),
addWebpackAlias({
["@"]: resolve("./src")
}),
addPostcssPlugins([
require("postcss-px-to-viewport")({
unitToConvert: 'px', // 需要转换的单位,默认‘px’
viewportWidth: 750, // 设计稿的视口宽度
unitPrecision: 6, // px转vw之后保留的精度(保留几位小数)
propList: ['*'], // 那些属性可以被转换成vw * 代表全部
viewportUnit: 'vw', // 希望使用的视口单位 // vw
fontViewportUnit: 'vw', //字体使用的视口单位
selectorBlackList: [], // 需要忽略的CSS选择器,不会转为视口单位,使用原有的px等单位
minPixelValue: 1, // 设置最小的转换数值,如果为1的话,只有大于1的值会被转换
mediaQuery: false, // 媒体查询里的单位是否需要转换单位
replace: true, // 是否直接更换属性值,而不添加备用属性
exclude: [/node_modules/], // 忽略某些文件夹下的文件或特定文件,例如 'node_modules' 下的文件
landscape: false, // 是否添加根据 landscapeWidth 生成的媒体查询条件 @media (orientation: landscape)
landscapeUnit: 'vw' // 横屏时使用的单位
})
])
)
复制代码
17、处理跨域
- 在我们和后端小伙伴联调接口的过程中,会存在跨域问题,CRA的配置如下
const path = require("path");
const { override,
fixBabelImports,
addWebpackAlias,
addPostcssPlugins,
overrideDevServer } = require('customize-cra');
const resolve = _path => path.resolve(__dirname, _path)
module.exports = {
webpack: override(
fixBabelImports('import', {
libraryName: 'antd-mobile',
style: 'css',
}),
fixBabelImports("lodash", {
libraryDirectory: "",
camel2DashComponentName: false
}),
addWebpackAlias({
['@']: resolve("./src")
}),
addPostcssPlugins([
require("postcss-px-to-viewport")({
unitToConvert: 'px', // 需要转换的单位,默认‘px’
viewportWidth: 750, // 设计稿的视口宽度
unitPrecision: 6, // px转vw之后保留的精度(保留几位小数)
propList: ['*'], // 那些属性可以被转换成vw * 代表全部
viewportUnit: 'vw', // 希望使用的视口单位 // vw
fontViewportUnit: 'vw', //字体使用的视口单位
selectorBlackList: [], // 需要忽略的CSS选择器,不会转为视口单位,使用原有的px等单位
minPixelValue: 1, // 设置最小的转换数值,如果为1的话,只有大于1的值会被转换
mediaQuery: false, // 媒体查询里的单位是否需要转换单位
replace: true, // 是否直接更换属性值,而不添加备用属性
exclude: [/node_modules/], // 忽略某些文件夹下的文件或特定文件,例如 'node_modules' 下的文件
landscape: false, // 是否添加根据 landscapeWidth 生成的媒体查询条件 @media (orientation: landscape)
landscapeUnit: 'vw' // 横屏时使用的单位
})
])
),
devServer: overrideDevServer([
config => ({
...config,
proxy: {
"/api": {
target: "http://localhost:4444",
pathRewrite: { "^/api": "" }
}
}
})
]),
}
复制代码
- 这个时候当我们访问
/api
开头的接口时,请求地址就会被代理到http://localhost:4444
- ?
/api/test
会被 代理成http://localhost:4444/test
18、真机问题
- 首先修改我们的
app.js
和app.scss
- 我们添加了50个p标签到页面中,用来测试
import { Button } from 'antd-mobile'
import '@/app.scss'
function App() {
return (
<div className="App">
{
Array(50).fill(1).map((item, idx) => (<p className="p" key={idx}>一段自定义的css样式文字,第{idx}条</p>))
}
<Button type="primary">按钮</Button>
</div>
);
}
export default App;
复制代码
- 接着我们清除
p
标签边距
.p{
color: red;
width: 750px;
margin: 0;
padding: 0;
}
复制代码
- 接下来我们用手机连上电脑对应的wifi,访问电脑的ip,
输入 ifconfig
复制代码
- 然后用手机打开
http://10.5.9.250:3000/
,就可以看到我们的页面了
- 这时我们看到手机(iphoneX)按钮被底边小黑条挡住了
- 解决方法
- 找到 public/index.html mate标签中添加 viewport-fit=cover属性
<meta name="viewport" content="width=device-width, initial-scale=1,viewport-fit=cover" />
- body添加这样的css
body { padding-bottom: constant(safe-area-inset-bottom); padding-bottom: env(safe-area-inset-bottom); } 复制代码
- 找到 public/index.html mate标签中添加 viewport-fit=cover属性
- 然后我们重启项目,真机上再次查看
- 这个时候底部小黑条就不会挡住按钮了
19、完整代码
- package.json
{
"name": "juejin-react-h5",
"version": "0.1.0",
"private": true,
"dependencies": {
"@testing-library/jest-dom": "^5.11.4",
"@testing-library/react": "^11.1.0",
"@testing-library/user-event": "^12.1.10",
"antd-mobile": "^2.3.4",
"path": "^0.12.7",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-scripts": "4.0.3",
"sass": "^1.34.1",
"web-vitals": "^1.0.1"
},
"scripts": {
"start": "react-app-rewired start",
"build": "react-app-rewired build",
"test": "react-app-rewired test --env=jsdom",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"babel-plugin-import": "^1.13.3",
"customize-cra": "^1.0.0",
"postcss-px-to-viewport": "^1.1.1",
"react-app-rewired": "^2.1.8",
"sass-resources-loader": "^2.2.1"
}
}
复制代码
- config-overrides.js
const path = require("path");
const { override,
fixBabelImports,
addWebpackAlias,
addPostcssPlugins,
adjustStyleLoaders,
overrideDevServer } = require('customize-cra');
const resolve = _path => path.resolve(__dirname, _path)
module.exports = {
webpack: override(
// antd-mobile 分包
fixBabelImports('import', {
libraryName: 'antd-mobile',
style: 'css',
}),
// lodash分包
fixBabelImports("lodash", {
libraryDirectory: "",
camel2DashComponentName: false
}),
//别名
addWebpackAlias({
['@']: resolve("./src")
}),
// 添加loader 全局css
adjustStyleLoaders(rule => {
if (rule.test.toString().includes('scss')) {
rule.use.push({
loader: require.resolve('sass-resources-loader'),
options: {
resources: [resolve("./src/styles/theme.scss")]
}
});
}}),
// px转 vw
addPostcssPlugins([
require("postcss-px-to-viewport")({
unitToConvert: 'px', // 需要转换的单位,默认‘px’
viewportWidth: 750, // 设计稿的视口宽度
unitPrecision: 6, // px转vw之后保留的精度(保留几位小数)
propList: ['*'], // 那些属性可以被转换成vw * 代表全部
viewportUnit: 'vw', // 希望使用的视口单位 // vw
fontViewportUnit: 'vw', //字体使用的视口单位
selectorBlackList: [], // 需要忽略的CSS选择器,不会转为视口单位,使用原有的px等单位
minPixelValue: 1, // 设置最小的转换数值,如果为1的话,只有大于1的值会被转换
mediaQuery: false, // 媒体查询里的单位是否需要转换单位
replace: true, // 是否直接更换属性值,而不添加备用属性
exclude: [/node_modules/], // 忽略某些文件夹下的文件或特定文件,例如 'node_modules' 下的文件
landscape: false, // 是否添加根据 landscapeWidth 生成的媒体查询条件 @media (orientation: landscape)
landscapeUnit: 'vw' // 横屏时使用的单位
})
])
),
// 本地开发相关
devServer: overrideDevServer([
config => ({
...config,
proxy: {
"/api": {
target: "http://localhost:4444",
pathRewrite: { "^/api": "" }
}
}
})
]),
}
复制代码
20、项目地址 github.com/Tyf2345/jue…
参考文献
- iphone窗口问题 developer.apple.com/design/huma…
写在最后
- 当你看到这里的时候,首先你是个很有毅力的人,这篇文章没有插图,都是干活,从头看到尾的话给自己点个赞吧
- 这篇文章主要搭建了一个react H5的架子,从布局到样式再到接口转发,基本功能都已经搭建完毕了
- 欢迎大家评论,指出不完善的地方
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END