React+Typescript搭建大屏项目的基本配置和使用

1,430 阅读3分钟

写这篇文的初衷是为了记录一下,用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文件。有两种方法

  1. 通过npm run eject命令可以将隐藏的wabpack文件暴露出来,但此方法不可逆
  2. 通过 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

  1. 创建并配置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
  1. 封装网络请求
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);
    })
  })
})