Vite 2.x + React + Zarm + Less + React Router v6 + Axios + flexible.js 搭建前端 H5 开发环境2

简介: Vite 2.x + React + Zarm + Less + React Router v6 + Axios + flexible.js 搭建前端 H5 开发环境

4、配置 CSS 预处理器 Less


安装依赖

npm i less -D


e27fdece717c44e69d5a2df2b55e546d.png


配置 css 属性


更多请参考:postcss-modules

导出类名的样式,json 中的键。


Name Type Description
camelCase String 类名将被骆驼化,原始类名不会从本地中删除
camelCaseOnly String 类名将被驼峰化,原来的类名将从本地中删除
dashes String 只有类名中的破折号会被驼峰化
dashesOnly String 类名中的破折号将被驼峰化,原始类名将从本地中删除


ebc5142bab444b5aaf4858b45af281b1.png



vite.config.js 里面添加配置:这里我们用 dashesOnly

import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import styleImport from 'vite-plugin-style-import'
// https://vitejs.dev/config/
export default defineConfig({
  css: {
    // css模块化,文件以.module.[css|less|scss]结尾,否则不生效的
    modules: {
      /**
       * 配置 CSS modules 的行为。选项将被传递给 postcss-modules。
       * 默认:'camelCaseOnly'。
       * 'camelCase' | 'camelCaseOnly' | 'dashes' | 'dashesOnly'
       * */ 
      localsConvention: 'dashesOnly'
    },
    // 指定传递给 CSS 预处理器的选项。
    preprocessorOptions: {
      // 预编译支持 less
      less: {
        // 支持内联 JavaScript
        javascriptEnabled: true,
      }
    }
  },
  plugins: [
    react(),
    styleImport({
      libs: [
        {
          libraryName: 'zarm',
          esModule: true,
          resolveStyle: (name) => {
            return `zarm/es/${name}/style/css`;
          }
        }
      ]
    })
  ]
})


新建 container/Index/style.module.less 文件,里面添加代码:

.kaimo-index {
  h3 {
    color: green;
  }
}
.kaimo_index {
  h3 {
    color: red;
  }
}


然后在 container/Index/index.jsx 里面引入使用

import React from 'react'
import { Button } from 'zarm';
import k from './style.module.less'
console.log('style.module.less', k)
export default function Index() {
  return <div className={k.kaimoIndex}>
    kaimo 的 index 页面
    <h3>
      按钮 Button 基本用法
    </h3>
    <Button>default</Button>
    <Button theme="primary">primary</Button>
  </div>
}


我们可以看到在 dashesOnly 下,类名中的破折号被驼峰化了。并且添加了 css modules 配置,自定义样式重名的风险也避免了。

42f4decc73114e689c036a2d5bbc5258.png



我们可以修改一下在 camelCaseOnly 下,类名中都被驼峰化了。并且被覆盖了,样式变红了。

c00e7d405ee54eea915bdacf7050e44e.png


5、移动端项目适配 rem


安装依赖


  • postcss-pxtorem:它的作用是在你编写完 css 后,将你的单位自动转化为 rem 单位。
  • lib-flexible:可伸缩布局方案。


npm i postcss-pxtorem lib-flexible -s


42fdf9838b464520b7b2c96dd498a46c.png

使用 flexible

main.jsx 中引入它:

import React from 'react'
import ReactDOM from 'react-dom'
import 'lib-flexible/flexible'
import './index.css'
import App from './App'
ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
)


引入之后就会出现下面的 font-size 的设置,页面的大小变化就会让 html 的 font-size 随之变化,从而形成可伸缩布局。

c5f9492715774065ab8fa1ee4203b81c.png


配置 postcss-pxtorem


更多配置参考:postcss-pxtorem


一些默认配置:

{
    rootValue: 16, //  (Number | Function) 表示根元素字体大小或根据输入参数返回根元素字体大小
    unitPrecision: 5, //  (Number) 允许 REM 单位增长到的十进制数字。
    propList: ['font', 'font-size', 'line-height', 'letter-spacing'], // (Array)可以从 px 更改为 rem 的属性。
    selectorBlackList: [], // (Array)要忽略并保留为 px 的选择器。
  ...
}


9276b4048dde4cb5a05aa45fa8adbafe.png


根据文档,我们先在根目录新建一个 postcss.config.js 文件,里面添加配置信息:

/**
 * 具体配置可以去 postcss-pxtorem 仓库看看文档
 * 默认配置
    rootValue: 16,
    unitPrecision: 5,
    propList: ['font', 'font-size', 'line-height', 'letter-spacing'],
    selectorBlackList: [],
    replace: true,
    mediaQuery: false,
    minPixelValue: 0,
    exclude: /node_modules/i
 * */ 
module.exports = {
  "plugins": [
    require("postcss-pxtorem")({
      rootValue: 37.5,
      propList: ['*'],
      selectorBlackList: ['norem'] // 过滤掉 .norem 开头的 class,不进行 rem 转换,比如:['body'] will match .body-class
    })
  ]
}


我们来测试一下:

先修改 container/Index/style.module.less 文件,里面添加代码:

.kaimo-index {
  h3 {
    width: 100px;
    background-color: pink;
    color: green;
  }
  .norem-kaimo {
    width: 200px;
  }
}


然后修改 container/Index/index.jsx 里面的代码:

import React from 'react'
import { Button } from 'zarm';
import k from './style.module.less'
console.log('style.module.less', k)
export default function Index() {
  return <div className={k.kaimoIndex}>
    kaimo 的 index 页面
    <h3>
      按钮 Button 基本用法
    </h3>
    <Button>default</Button>
    <Button theme="primary">primary</Button>
    <h3 className={k.noremKaimo}>
      按钮 Button 基本用法 norem
    </h3>
  </div>
}


重启项目 npm run dev,我们可以发现加了 norem 前缀的类名的 px 不会转化为 rem。


bfe8b1d54ce7418995a0ce4a906ed53a.png



6、resolve.alias 别名设置

打开 vite.config.js,添加配置如下:

import path from "path";
export default defineConfig({
  resolve: {
    alias: {
      '@': path.resolve(__dirname, 'src'), // src 路径
    }
  },
}


配置好之后,我们就可以使用:

import Index from '@/container/Index'
import About from '@/container/About'
const routes = [
  {
    path: "/",
    component: Index
  },
  {
    path: "/about",
    component: About
  }
];
export default routes


7、进行 axios 封装配置


安装依赖

npm i axios -S


b0157d72005048dfbb4da528be66824b.png


知识点


环境变量


Vite:环境变量

Vite 在一个特殊的 import.meta.env 对象上暴露环境变量。这里有一些在所有情况下都可以使用的内建变量:


   import.meta.env.MODE: {string} 应用运行的模式。

   import.meta.env.BASE_URL: {string} 部署应用时的基本 URL。他由 base 配置项决定。

   import.meta.env.PROD: {boolean} 应用是否运行在生产环境。


   import.meta.env.DEV: {boolean} 应用是否运行在开发环境 (永远与 import.meta.env.PROD 相反)。

X-Requested-With


   X-Requested-With 用于区分 ajax 请求还是传统请求。如果 requestedWith 为 null,则为同步请求。如果 requestedWith 为 XMLHttpRequest 则为 Ajax 请求。



XMLHttpRequest.withCredentials


   XMLHttpRequest.withCredentials 属性是一个 Boolean 类型,它指示了是否该使用类似 cookies,authorization headers (头部授权)或者 TLS 客户端证书这一类资格证书来创建一个跨站点访问控制(cross-site Access-Control)请求。在同一个站点下使用 withCredentials 属性是无效的。


代理配置

我们启动之前的后端项目 kaimo-cost-server,地址是:http://127.0.0.1:7001


1ec36bce5c3c4bdf8948d0011a0f5725.png



然后我们打开 vite.config.js,添加代理配置,代码如下:

export default defineConfig({
  server: {
    proxy: {
      '/api': {
        // 当遇到 /api 路径时,将其转换成 target 的值
        target: 'http://127.0.0.1:7001',
        changeOrigin: true,
      }
    }
  },
})



封装处理

下面我们新建 src/utils/axios.js 文件,里面添加代码:

import axios from "axios";
// 引入 zarm 的 Toast 组件用于提示
import { Toast } from "zarm";
// 设置接口响应时间 30s
axios.defaults.timeout = 3000;
/**
 * @description 添加请求拦截器
 *  1. config中的一些信息不符合服务器的要求,这里可以做一些修改
 *  2. 每次发送网络请求时,都希望在界面中显示一个请求的图标(然后再响应拦截中取消显示)
 *  3. 某些网络请求必须携带一些特殊的信息(如登录token),如果没有携带就可以拦截并作响应提示
*/
axios.interceptors.request.use(config => {
  // 看知识点 XMLHttpRequest.withCredentials
  config.withCredentials = true;
  // 看知识点 X-Requested-With
  config.headers['X-Requested-With'] = 'XMLHttpRequest';
  // Authorization 用于服务端鉴权,token 存于 localStorage
  config.headers['Authorization'] = `${localStorage.getItem('token') || null}`;
  console.log('进入请求拦截器-->config:', config);
  return config;
}, err => {
  // 请求未成功发出,如:没有网络...
  console.log('进入请求拦截器-->err:', err);
  Toast.show("请求失败");
  return Promise.reject(err);
})
// 添加响应拦截器
axios.interceptors.response.use(response => {
  // 成功响应的拦截
  console.log('进入响应拦截器-->response:', response);
  return Promise.resolve(response.data)
}, err =>{
  // 失败响应的拦截
  console.log('进入响应拦截器-->err:', err);
  Toast.show("服务器响应失败");
  if(err.response){
    // 失败响应的status需要在response中获得
    console.log(err.response)
    switch(err.response.status){
      // 对得到的状态码的处理,具体的设置视自己的情况而定
      case 401:
        console.log('未登录')
        window.location.href='/login';
        break
      case 404:
        console.log('没有找到该方法');
        break
      case 405:
        console.log('不支持的方法');
        break
      default:
        console.log('其他错误');
        break
    }
  }
  // 注意这里应该return promise.reject(),
  // 因为如果直接return err则在调用此实例时,响应失败了也会进入then(res=>{})而不是reject或catch方法
  return Promise.reject(err)
});
/**
 * @description 导出获取数据方法
 * @param {String} url
 * @param {String} type
 * @param {Object} data
 * */ 
export function fetchData(url, type, data) {
  let ajaxType = type ? type.toLowerCase() : type;
  const config = {};
  config.method = ajaxType || 'post';
  config.url = url;
  config.headers = {};
  if (ajaxType === 'get') {
    config.url = url + '?r=' + Math.random() * 1000;
    config.params = data;
  } else if (ajaxType === 'post') {
    config.data = data;
    config.headers['Content-Type'] = 'application/json;charset=UTF-8';
  }
  console.log('进入fetchData', url, type, data, config);
  return axios(config);
};


测试一下:我们在 Index/api 该路径添加 index.js 文件,该文件里面添加接口的配置代码:


ba47bd9629464f678f6e3c5fd84c0731.png

import { fetchData } from "@/utils/axios.js";
export function login(data) {
  return fetchData('/api/user/login', 'post', data);
}


然后在文件 Index/index.jsx 里添加登录按钮的代码

import React from 'react'
import { Button, Toast } from 'zarm';
import k from './style.module.less'
console.log('style.module.less', k)
import { login } from "./api/index.js";
const onSubmit = async () => {
  try {
    const data = await login({
      username: "kaimo313",
      password: "123456"
    });
    console.log(data);
    Toast.show('登录成功');
  } catch (error) {
    console.log(error)
    Toast.show('系统错误');
  }
};
export default function Index() {
  return <div className={k.kaimoIndex}>
    kaimo 的 index 页面
    <h3>
      按钮 Button 基本用法
    </h3>
    <Button>default</Button>
    <Button theme="primary">primary</Button>
    <h3 className={k.noremKaimo}>
      按钮 Button 基本用法 norem
    </h3>
    <Button onClick={onSubmit} block theme="primary">登录</Button>
  </div>
}


点击登录,我们发现可以登录成功

d934ac4efb9b4c46817fa264f9fa1ce6.png


这样,我们的基本环境就搭建好了。

package.json


{
  "name": "kaimo-cost-h5",
  "private": true,
  "version": "0.0.0",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview"
  },
  "dependencies": {
    "axios": "^0.26.1",
    "lib-flexible": "^0.3.2",
    "postcss-pxtorem": "^6.0.0",
    "react": "^17.0.2",
    "react-dom": "^17.0.2",
    "react-router-dom": "^6.3.0",
    "zarm": "^2.9.13"
  },
  "devDependencies": {
    "@vitejs/plugin-react": "^1.0.7",
    "less": "^4.1.2",
    "vite": "^2.9.0",
    "vite-plugin-style-import": "^1.0.1"
  }
}


vite.config.js

import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import path from "path";
import styleImport from 'vite-plugin-style-import'
// https://vitejs.dev/config/
export default defineConfig({
  resolve: {
    alias: {
      '@': path.resolve(__dirname, 'src'), // src 路径
    }
  },
  css: {
    // css模块化,文件以.module.[css|less|scss]结尾,否则不生效的
    modules: {
      /**
       * 配置 CSS modules 的行为。选项将被传递给 postcss-modules。
       * 默认:'camelCaseOnly'。
       * 'camelCase' | 'camelCaseOnly' | 'dashes' | 'dashesOnly'
       * */ 
      localsConvention: 'dashesOnly'
    },
    // 指定传递给 CSS 预处理器的选项。
    preprocessorOptions: {
      // 预编译支持 less
      less: {
        // 支持内联 JavaScript
        javascriptEnabled: true,
      }
    }
  },
  server: {
    proxy: {
      '/api': {
        // 当遇到 /api 路径时,将其转换成 target 的值
        target: 'http://127.0.0.1:7001',
        changeOrigin: true,
      }
    }
  },
  plugins: [
    react(),
    styleImport({
      libs: [
        {
          libraryName: 'zarm',
          esModule: true,
          resolveStyle: (name) => {
            return `zarm/es/${name}/style/css`;
          }
        }
      ]
    })
  ]
})



目录
相关文章
|
12天前
|
JavaScript 前端开发 程序员
前端原生Js批量修改页面元素属性的2个方法
原生 Js 的 getElementsByClassName 和 querySelectorAll 都能获取批量的页面元素,但是它们之间有些细微的差别,稍不注意,就很容易弄错!
|
23天前
|
前端开发 JavaScript 开发者
颠覆传统:React框架如何引领前端开发的革命性变革
【10月更文挑战第32天】本文以问答形式探讨了React框架的特性和应用。React是一款由Facebook推出的JavaScript库,以其虚拟DOM机制和组件化设计,成为构建高性能单页面应用的理想选择。文章介绍了如何开始一个React项目、组件化思想的体现、性能优化方法、表单处理及路由实现等内容,帮助开发者更好地理解和使用React。
59 9
|
23天前
|
机器学习/深度学习 自然语言处理 前端开发
前端神经网络入门:Brain.js - 详细介绍和对比不同的实现 - CNN、RNN、DNN、FFNN -无需准备环境打开浏览器即可测试运行-支持WebGPU加速
本文介绍了如何使用 JavaScript 神经网络库 **Brain.js** 实现不同类型的神经网络,包括前馈神经网络(FFNN)、深度神经网络(DNN)和循环神经网络(RNN)。通过简单的示例和代码,帮助前端开发者快速入门并理解神经网络的基本概念。文章还对比了各类神经网络的特点和适用场景,并简要介绍了卷积神经网络(CNN)的替代方案。
|
23天前
|
移动开发 前端开发 JavaScript
前端实训,刚入门,我用原生技术(H5、C3、JS、JQ)手写【网易游戏】页面特效
于辰在大学期间带领团队参考网易游戏官网的部分游戏页面,开发了一系列前端实训作品。项目包括首页、2021校园招聘页面和明日之后游戏页面,涉及多种特效实现,如动态图片切换和人物聚合效果。作品源码已上传至CSDN,视频效果可在CSDN预览。
29 0
前端实训,刚入门,我用原生技术(H5、C3、JS、JQ)手写【网易游戏】页面特效
|
28天前
|
JavaScript 前端开发 开发者
前端框架对比:Vue.js与Angular的优劣分析与选择建议
【10月更文挑战第27天】在前端开发领域,Vue.js和Angular是两个备受瞩目的框架。本文对比了两者的优劣,Vue.js以轻量级和易上手著称,适合快速开发小型到中型项目;Angular则由Google支持,功能全面,适合大型企业级应用。选择时需考虑项目需求、团队熟悉度和长期维护等因素。
40 1
|
28天前
|
前端开发 JavaScript Android开发
前端框架趋势:React Native在跨平台开发中的优势与挑战
【10月更文挑战第27天】React Native 是跨平台开发领域的佼佼者,凭借其独特的跨平台能力和高效的开发体验,成为许多开发者的首选。本文探讨了 React Native 的优势与挑战,包括跨平台开发能力、原生组件渲染、性能优化及调试复杂性等问题,并通过代码示例展示了其实际应用。
55 2
|
29天前
|
JavaScript 前端开发 API
前端框架对比:Vue.js与Angular的优劣分析与选择建议
【10月更文挑战第26天】前端技术的飞速发展让开发者在构建用户界面时有了更多选择。本文对比了Vue.js和Angular两大框架,介绍了它们的特点和优劣,并给出了在实际项目中如何选择的建议。Vue.js轻量级、易上手,适合小型项目;Angular结构化、功能强大,适合大型项目。
25 1
|
29天前
|
前端开发 Android开发 开发者
前端框架趋势:React Native在跨平台开发中的优势与挑战
【10月更文挑战第26天】近年来,React Native凭借其跨平台开发能力在移动应用开发领域迅速崛起。本文将探讨React Native的优势与挑战,并通过示例代码展示其应用实践。React Native允许开发者使用同一套代码库同时构建iOS和Android应用,提高开发效率,降低维护成本。它具备接近原生应用的性能和用户体验,但也面临平台差异、原生功能支持和第三方库兼容性等挑战。
32 0
|
2月前
|
存储 人工智能 前端开发
前端大模型应用笔记(三):Vue3+Antdv+transformers+本地模型实现浏览器端侧增强搜索
本文介绍了一个纯前端实现的增强列表搜索应用,通过使用Transformer模型,实现了更智能的搜索功能,如使用“番茄”可以搜索到“西红柿”。项目基于Vue3和Ant Design Vue,使用了Xenova的bge-base-zh-v1.5模型。文章详细介绍了从环境搭建、数据准备到具体实现的全过程,并展示了实际效果和待改进点。
148 2
|
2月前
|
JavaScript 前端开发 程序员
前端学习笔记——node.js
前端学习笔记——node.js
44 0