写这篇文的初衷是为了记录一下,用react+ts搭建一个大屏项目的过程,以及通过flexbile进行适配应该如何进行配置
React + Typescript搭建项目,并实现屏幕适配
安装
// npm 方式
npm install -g create-react-app
// 如果很久之前安装过,建议卸载重新安装 npm uninstall -g create-react-app
新建项目
npx create-react-app my-app --template typescript
flexible + rem实现适配
1. 安装插件
npm i lib-flexible --save
npm i postcss-px2rem --save
1.1 配置
1.1.1配置meta标签
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
1.1.2 导入flexible文件
在项目入口文件index.tsx中引入lib-flexible
import 'lib-flexible';
编辑器会报错"react无法找到模块“lib-flexible”的声明文件"。解决方案:在src目录下添加declaration.d.ts,对模块进行声明
declare module 'lib-flexible';
1.1.3 配置flexible文件
由于react未暴露webpack文件。有两种方法
- 通过npm run eject命令可以将隐藏的wabpack文件暴露出来,但此方法不可逆
- 通过 react-app-rewired 插件来覆盖配置文件
npm install react-app-rewired customize-cra -s
更改package.json文件
"scripts": {
"start": "react-app-rewired start",
"build": "react-app-rewired build",
"test": "react-app-rewired test",
"eject": "react-app-rewired eject"
},
在根目录新建config-override.js文件
const { override, addPostcssPlugins} = require('customize-cra');
module.exports = override(
addPostcssPlugins(
[require("postcss-px2rem-exclude")
(
{
remUnit: 75, //设计图大小
remPrecision: 2, //只转换到两位小数
exclude: /node_modules/i //插件不需要转rem
}
)
]
),
);
修改flexible.js源文件
function refreshRem(){
var width = docEl.getBoundingClientRect().width;
// 根据项目配置适配范围
if (width / dpr < 1980) {
width = 1980 * dpr;
} else if (width / dpr > 5760) {
width = 5760 * dpr;
}
// 原项目3840,设置成48等份。1rem等于80px
var rem = width / 48;
docEl.style.fontSize = rem + 'px';
flexible.rem = win.rem = rem;
}
修改webpack中的rem转换配置remUnit:80
1.1.4 安装并配置less
npm install less less-loader -s
React + typescript 配置别名
1.在config-overrides.js中配置
const { override, addWebpackAlias } = require('customize-cra');
const path = require("path");
module.exports = override(
addWebpackAlias({
'@' : path.resolve(__dirname, "./src"),
'@components' : path.resolve(__dirname, "./src/components"),
'@pages' : path.resolve(__dirname, "./src/pages"),
'@utils' : path.resolve(__dirname, "./src/utils"),
'@assets' : path.resolve(__dirname, "./src/assets"),
'@app' : path.resolve(__dirname, "./src/app"),
}),
);
2.创建tsconfig.extend.json文件
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["src/*"],
"@api/*": ["src/api/*"],
"@app/*": ["src/app/*"],
"@assets/*": ["src/assets/*"],
"@components/*": ["src/components/*"],
"@utils/*": ["src/utils/*"]
}
}
}
3.配置tsconfig.json
{
<!---->在此处增加extends选项
"extends": "./tsconfig.extend.json",
"compilerOptions": {
"target": "es5",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noFallthroughCasesInSwitch": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx"
},
"include": [
"src"
]
}
webpack配置原理
override() 方法,是一个高阶函数,接受可变数量的参数,每个参数都是签名为 const fn = (oldConfig) => newConfig 的函数;同时会返回一个新的函数,这个函数的签名也是 const fn = (oldConfig) => newConfig。
override() 会在内部依次调用传入的参数函数,把前一个函数返回的 newConfig 作为后一个函数的 oldConfig 参数,得到最终的 webpack config。
function override(fns) {
return function (oriConfig) {
let finalConfig = oriConfig
for (const fn of fns) {
finalConfig = fn(finalConfig)
}
return finalConfig
}
}
参考文章:
Create React App 入门及 webpack 配置
customize-cra
react处理网络请求——axios
- 创建并配置axios
import axios from "axios";
// 设置基础地址
const devBaseUrl = "http://172.16.3.9:20101"
// const proBaseUrl = ""
// TODO: 正式部署的时候,要设置接口地址
const publicIp = process.env.NODE_ENV === 'development' ? devBaseUrl : devBaseUrl;
// const divisionCode = '510000_2_0001';
const service = axios.create({
// baseURL: process.env.BASE_URL,
baseURL: publicIp,
timeout: 12000
})
service.defaults.headers.post['Content-Type'] = 'application/json'
// 请求拦截器
service.interceptors.request.use(config => {
let divisionCode = localStorage.getItem('divisionCode');
config.params ={...config.params, ...{divisionCode}};
return config;
}, error => Promise.reject(error));
// 响应拦截器
service.interceptors.response.use(
(response) => {
if (response.status === 200) { // 返回200,请求成功
return Promise.resolve(response.data)
} else {
// message.error('响应超时')
return Promise.reject(response.data.message)
}
},
(error) => {
// message.error('请求超时, 请刷新重试')
return Promise.reject('请求超时, 请刷新重试')
}
)
export default service
- 封装网络请求
import service from './request';
export const httpGet = (url: string, params?: any, config = {}) => {
return new Promise((resolve, reject) => {
service({
method: 'get',
url,
params,
...config
}).then(response => {
resolve(response);
}).catch(error => {
reject(error);
})
})
}
export const httpPost = ((url: string, data?: any, config = {}) => {
return new Promise((resolve, reject) => {
service({
method: 'post',
url,
data,
...config,
}).then(response => {
resolve(response);
}).catch(error => {
reject(error);
})
})
})