路由表形式react + vite + ts + tailwindcss + pxToRem + axios

yarn create vite

在项目当前目录下安装依赖插件:

1、yarn add axios

2、yarn add react

3、 yarn add react-redux

4、 yarn add react-router-dom

5、yarn add redux

6、yarn add reset-css

7、yarn add sass

8、yarn add vite-plugin-svg-icons

9、yarn add postcss-pxtorem

10、目录

 

api/user/index.ts

import { get } from "@/api/http";

export const user = {

  getUserInfo: () => get("/user"),

};

api/http.ts

import http from "@/http";

export interface ApiResult {

  code: number;

  message: string;

  data: any | null | object;

}

export async function get(url: string, params?: any): Promise<ApiResult> {

  const response = await http.get<ApiResult>(url, { params });

  return response?.data;

}

export async function post(url: string, data?: any): Promise<any> {

  const response = await http.post<ApiResult>(url, data);

  return response?.data;

}

export async function put(url: string, data?: any): Promise<any> {

  const response = await http.put<ApiResult>(url, data);

  return response?.data;

}

export async function del(url: string, params?: any): Promise<any> {

  const response = await http.delete<ApiResult>(url, { params });

  return response?.data;

}

api/index.ts

export * from "./user/index";

components/SvgIcon

import { useMemo } from "react";

interface propsInterface {

  name: string;

  size?: string;

  color?: string;

  profix?: string;

}

export default function SvgIcon(props: propsInterface) {

  const size = props.size ?? "24px";

  const color = props.color ?? "";

  const profix = props.profix ?? "icon";

  console.log(color);

  const iconName = useMemo<string>(() => {

    return `#${profix}-${props.name}`;

  }, [profix, props.name]);

  return (

    <svg

      style={{

        height: size,

        width: size,

        fill: color,

        position: "relative",

      }}

      aria-hidden="true"

    >

      <use xlinkHref={iconName} />

    </svg>

  );

}

http/index.ts

import axios from "axios";

const http = axios.create({

  baseURL: "",

  timeout: 5000,

});

// 添加请求拦截器

http.interceptors.request.use(

  function (config) {

    // 在发送请求之前做些什么

    return config;

  },

  function (error) {

    // 对请求错误做些什么

    return Promise.reject(error);

  }

);

// 添加响应拦截器

http.interceptors.response.use(

  function (response) {

    // 2xx 范围内的状态码都会触发该函数。

    // 对响应数据做点什么

    return response;

  },

  function (error) {

    // 超出 2xx 范围的状态码都会触发该函数。

    // 对响应错误做点什么

    return Promise.reject(error);

  }

);

export default http;

Layout/Footer.tsx PC端圣杯布局上中下

Layout/Header.tsx

import { useNavigate } from "react-router-dom";

const Header = () => {

  const navigate = useNavigate();

  return (

    <div className="wwj-flex">

      <div className="wwj-cursor-pointer wwj-underline" onClick={() => navigate('/home')}>首页</div>

      <div className="wwj-cursor-pointer wwj-underline wwj-ml-5" onClick={() => navigate('/pageone')}>Page1</div>

    </div>

  )

};

export default Header;

Layout/index.tsx

import Header from "./Header"

import Footer from "./Footer"

import Style from './index.module.scss'

import { Outlet } from "react-router-dom"

const Layout = () => (

  <div className={Style.root}>

    <div className="header wwj-w-full wwj-h-[100px] wwj-bg-pink-300">

      <Header />

    </div>

    <div className="main wwj-h-[900px]">

      <Outlet />

    </div>

    <div className="footer wwj-h-[100px] wwj-bg-pink-300">

      <Footer />

    </div>

  </div>

)

export default Layout

Layout/index.module.scss

.root {

  :global {

    width: 100%;

    height: 100vh;

    display: grid;

    grid-template-rows: auto 1fr auto;

    .header {

      position: sticky;

      top: 0;

    }

  }

}

pages/Home/index.tsx

import ViewOne from '@/pages/ViewOne/index'

import SvgIcon from '@/components/SvgIcon/index'

import { useEffect } from 'react';

import { user } from '@/api/index'

const Home = () => {

  useEffect(() => {

    getUserInfo()

  }, [])

  const getUserInfo = () => {

    user.getUserInfo().then(res => {

      console.log(res)

    })

  }

  return (

    <div>

      首页

      <ViewOne />

      <SvgIcon name='age-icon' size='50' color='#c04a4a' />

      <SvgIcon name='react' size='50' color='#c04a4a' />

    </div>

  );

};

export default Home;

pages/PageOne/index.tsx

const PageOne = () => (

  <div>PageOne</div>

)

export default PageOne

pages/ViewOne/index.tsx

const ViewOne = () => (

  <div>

    ViewOne

  </div>

)

export default ViewOne

router/index.tsx

import { lazy } from 'react';

import { useRoutes, RouteObject } from "react-router-dom"

import lazyLoad from './Lazy';

const routes: RouteObject[] = [

  {

    path: '/',

    element: lazyLoad(lazy(() => import('@/Layout/index'))),

    children: [

      {

        path: '/home',

        element: lazyLoad(lazy(() => import('@/pages/Home/index')))

      },

      {

        path: '/pageone',

        element: lazyLoad(lazy(() => import('@/pages/PageOne/index')))

      }

    ]

  }

]

const BaseRouter = () => useRoutes(routes)

export default BaseRouter

router/Layzy.tsx

import { Suspense } from "react";

const lazyLoad = (Com: React.LazyExoticComponent<any>) => {

  return (

    <Suspense>

      <Com />

    </Suspense>

  );

};

export default lazyLoad;

styles/gobal.scss

$color: white;

body {

  // 禁止选中文字

  user-select: none;

  background-color: $color;

}

img {

  // 禁止拖动图片

  -webkit-user-drag: none;

}

styles/tailwind.css

@tailwind base;

@tailwind components;

@tailwind utilities;

utils/pxToRem.ts

// 基准大小

const baseSize = 16;

// 设置 rem 函数

function setRem() {

  // 当前页面宽度相对于 750 宽的缩放比例,可根据自己需要修改。

  const scale = document.documentElement.clientWidth / 375;

  // 设置页面根节点字体大小

  document.documentElement.style.fontSize =

    baseSize * Math.min(scale, 2) + "px";

}

// 初始化

setRem();

// 改变窗口大小时重新设置 rem

window.onresize = function () {

  setRem();

};

App.tsx

import BaseRouter from "./router";

function App() {

  return (

    <BaseRouter />

  )

}

export default App

main.tsx

import ReactDOM from 'react-dom/client'

import App from './App1.tsx'

import 'reset-css'

import '@/styles/global.scss'

import '@/styles/tailwind.css'

import '@/utils/pxToRem.ts'

import 'virtual:svg-icons-register'

import { BrowserRouter } from 'react-router-dom'

ReactDOM.createRoot(document.getElementById('root')!).render(

  <BrowserRouter>

    <App />

  </BrowserRouter>

)

tailwind.config.js

/** @type {import('tailwindcss').Config} */

export default {

  content: [

    "./index.html",

    "./src/**/*.{js,ts,jsx,tsx}",

  ],

  theme: {

    extend: {

      screens: {

        sm: '480px',

        md: '768px',

        lg: '976px',

        xl: '1440px',

      },

      spacing: {

        '1': '4px',

        '2': '8px',

        '3': '12px',

        '4': '16px',

        '5': '20px',

        '6': '24px',

      }

    }

  },

  plugins: [],

  prefix: 'wwj-',

}

tsconfig.json

{

  "compilerOptions": {

    "composite": true,

    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",

    "target": "ES2020",

    "useDefineForClassFields": true,

    "lib": ["ES2020", "DOM", "DOM.Iterable"],

    "module": "ESNext",

    "skipLibCheck": true,

    /* Bundler mode */

    "moduleResolution": "bundler",

    "allowImportingTsExtensions": true,

    "resolveJsonModule": true,

    "isolatedModules": true,

    "moduleDetection": "force",

    "noEmit": true,

    "jsx": "react-jsx",

    /* Linting */

    "strict": true,

    "noUnusedLocals": true,

    "noUnusedParameters": true,

    "noFallthroughCasesInSwitch": true,

    "baseUrl": ".",

    "paths": {

      "@/*": ["src/*"]

    }

  },

  "include": ["src"]

}

tsconfig.node.json

{

  "compilerOptions": {

    "composite": true,

    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",

    "skipLibCheck": true,

    "module": "ESNext",

    "moduleResolution": "bundler",

    "allowSyntheticDefaultImports": true,

    "strict": true,

    "noEmit": true

  },

  "include": ["vite.config.ts"]

}

vite.config.ts

import { defineConfig } from "vite";

import react from "@vitejs/plugin-react";

import legacy from "@vitejs/plugin-legacy";

import { resolve } from "path";

import { createSvgIconsPlugin } from "vite-plugin-svg-icons";

import postCssPxToRem from "postcss-pxtorem";

import tailwindcss from "tailwindcss";

// https://vitejs.dev/config/

export default defineConfig({

  plugins: [

    react(),

    legacy({

      targets: ["defaults", "not IE 11"],

    }),

    createSvgIconsPlugin({

      // 指定要缓存的图标文件夹

      iconDirs: [

        resolve(process.cwd(), "src/assets/svg"),

        resolve(process.cwd(), "src/assets/icon"),

      ],

      // 执行icon name的格式

      symbolId: "icon-[name]",

    }),

  ],

  css: {

    postcss: {

      plugins: [

        tailwindcss(),

        postCssPxToRem({

          // 换算基数,

          rootValue: 16,

          propList: ["*"],

        }),

      ],

    },

  },

  server: {

    port: 9999,

    open: true,

    hmr: true,

    proxy: {

      "/user": {

        target: "http://localhost:3999/user",

        changeOrigin: true,

        rewrite: (path) => path.replace(/^\/user/, ""),

      },

    },

  },

  resolve: {

    // 设置resole

    alias: {

      "@": resolve(__dirname, "./src"),

    },

  },

});

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值