vite+vue3+ts+eslint+pinia+tailwindcss+element-plus初始化项目

1,231 阅读6分钟

项目搭建

采用vite ``vue3 ts eslint pinia tailwindcss element-plus 等搭建项目,下面分布记录下

vite初始化项目

npm create vite

微信图片_20241024100230.png

输入文件名称,回车vite-project

image.png 选vue 选ts

image.png

image.png 安装依赖 dev项目启动成功, 默认http://localhost:5173/端口

image.png

安装sass

npm i -D sass

安装@types/node

解决vite.config.ts的 import path from "node:path"; ts报错问题

npm i @types/node -D

设置别名和sever 设置代理及端口设置

vite.config.ts文件做以下修改,此时端口已更改且默认打开浏览器

import { defineConfig } from 'vite'
import path from "node:path";
import vue from '@vitejs/plugin-vue'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue()],
  base: "./",
  resolve: {
    alias: {
      "@": path.resolve(__dirname, "./src"),
    },
  },
  // 配置代理
  server: {
    host: "0.0.0.0",
    port: 8861,
    open: true,
    proxy: {
      "/api": {
        target: "***********",
        changeOrigin: true,
        secure: false,
        // rewrite: (path) => path.replace(/^\/api/, ""),
      }
    },
    cors: true,
  },
})

  

tsconfig.json 做以下修改

{
  "compilerOptions": {
    "target": "ES2020",
    "useDefineForClassFields": true,
    "module": "ESNext",
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "skipLibCheck": true,

    /* Bundler mode */
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "preserve",

    /* Linting */
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noFallthroughCasesInSwitch": true,

    // @设置
    "baseUrl": ".",
    "paths": {
      "@/*": ["src/*"]
    },
  },
  "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue", "src/**/*.d.ts"],
  "references": [{ "path": "./tsconfig.node.json" }]
}

router路由

npm i vue-router -S

创建router文件夹,内部创建index.ts

import { createRouter, createWebHistory, RouteRecordRaw } from "vue-router"
import TestRoutes from "@/views/test/routes"

const routes: Array<RouteRecordRaw> = [
  {
    path: "/",
    redirect: "/login",
  },
  {
    path: "/login",
    name: "Login",
    component: () => import("@/views/login/index.vue"),
  },
  {
    path: "/test",
    name: "test",
    children: [...TestRoutes],
    meta: {
      sort: 1,
      icon: "FillSet",
      title: "测试带单",
      menu: true,
    },
  },
]
const router = createRouter({
  scrollBehavior(to, from, savedPosition) {
    return { top: 0 }
  },
  history: createWebHistory(),
  routes,
})

router.beforeEach((to: any, from, next) => {
  next()
})

export default router

创建views文件夹,下一级创建login test文件夹。目录如下,请自行创建对应文件

image.png test 中的 routes.ts如下

import { RouteRecordRaw } from "vue-router"

const routes: Array<RouteRecordRaw> = [
  {
    path: "test1",
    name: "test1",
    component: () => import("@/views/test/test1.vue"),
    meta: {
      title: "测试1",
    },
  },
  {
    path: "test2",
    name: "test2",
    component: () => import("@/views/test/test2.vue"),
    meta: {
      title: "测试2",
    },
  },
]

export default routes

main.ts 引用路由

import { createApp } from "vue"
import "./style.css"
import App from "./App.vue"

// routes
import router from "./router/index"

const app = createApp(App)
app.use(router)
app.mount("#app")

app.vue文件引入 <router-view/>

<template>
  <div>
    <router-view/>
  </div>
</template>

<style scoped>
.logo {
  height: 6em;
  padding: 1.5em;
  will-change: filter;
  transition: filter 300ms;
}
.logo:hover {
  filter: drop-shadow(0 0 2em #646cffaa);
}
.logo.vue:hover {
  filter: drop-shadow(0 0 2em #42b883aa);
}
</style>

此时如果报ts 找不到模块“vue-router”或其相应的类型声明重新打开下vscode即可

重新 npm run dev 默认http://localhost:8861/login 打开你的login组件, http://localhost:8861/test/test1会打开test下的test1组件。

安装pinia

npm i pinia -S 
npm i pinia-plugin-persistedstate -S

pinia-plugin-persistedstate为了持久化pinia
创建 store文件夹,内部创建 use-user.ts,内容如下

// src/stores/counter.ts
import { defineStore } from 'pinia';
import { reactive } from 'vue';

export const useUserInfoStore = defineStore(
  'userInfo',
  () => {
    const user = reactive({
      name: '',
      age: '',
      sex: ''
    });

    const setUserInfo = (data: { name: string, age: string, sex: string }) => {
      Object.assign(user, data);
    };

    return { user, setUserInfo };
  },
  {
    persist: true,
  }
);

login 中的index.vue修改为

<template>
  <div>
    <span class="text-[#ff0000]">{{ user }}</span>
    <button @click="addStore">点击</button>
  </div>
</template>
<script lang="ts" setup>
import { storeToRefs } from "pinia";
import { useUserInfoStore } from "@/store/use-user";

const userInfoStore = useUserInfoStore();

const { user } = storeToRefs(userInfoStore);

const addStore = () => {
  userInfoStore.setUserInfo({
    name: "张三",
    age: Math.random() * 100 + "",
    sex: "男"
  });
};
</script>

test中的 test1.vue修改为

<template>
  <div>
    {{ JSON.stringify(user) }}
  </div>
</template>

<script lang="ts" setup>
import { useUserInfoStore } from "@/store/use-user"
import { storeToRefs } from "pinia"

const userInfoStore = useUserInfoStore()

const { user } = storeToRefs(userInfoStore)
</script>

main.ts中引入pinia

import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import { createPinia } from 'pinia';
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate';

//routes
import router from "./router/index";

const pinia = createPinia();
pinia.use(piniaPluginPersistedstate);

const app= createApp(App)

app.use(pinia);
app.use(router);
app.mount('#app');

此时login组件操作,可修改pinia, test1组件会获取到pinia状态, 此时ts 报错 store找不到重启vscode即可

安装element-plus @element-plus/icons-vue 及动态导入

element-plus unplugin-vue-components unplugin-auto-import自动导入插件,可以按需引入不用此插件

npm i element-plus @element-plus/icons-vue -S
npm install unplugin-vue-components unplugin-auto-import -D

vite.config.ts做更改

import { defineConfig } from 'vite'
import path from "node:path";
import vue from '@vitejs/plugin-vue'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
import AutoImport from "unplugin-auto-import/vite"
import Components from 'unplugin-vue-components/vite';

export default defineConfig({
  plugins: [
    vue(),
    Components({
      resolvers: [ElementPlusResolver()],
      dts: "src/components.d.ts",
    }),
    AutoImport({
      imports: ['vue', 'vue-router'],
      dts: "src/auto-import.d.ts",
    })
  ],
  base: "./",
  // base: "/rag",
  // 配置别名
  resolve: {
    alias: {
      "@": path.resolve(__dirname, "./src"),
    },
  },
  // 配置代理
  server: {
    host: "0.0.0.0",
    port: 8861,
    open: true,
    proxy: {
      "/api": {
        target: "***********",
        changeOrigin: true,
        secure: false,
      }
    },
    cors: true,
  },
})

login组件做更改

<template>
  <div>
    <span>{{ user }}</span>
    <button @click="addStore">点击</button>
    <el-button type="primary">Primary</el-button>
    <el-button type="success">Success</el-button>
    <el-button type="info">Info</el-button>
    <el-button type="warning">Warning</el-button>
    <el-button type="danger">Danger</el-button>
  </div>
</template>
<script lang="ts" setup>
import { storeToRefs } from "pinia";
import { useUserInfoStore } from "@/store/use-user";

const userInfoStore = useUserInfoStore();

const { user } = storeToRefs(userInfoStore);

const addStore = () => {
  userInfoStore.setUserInfo({
    name: "张三",
    age: Math.random() * 100 + "",
    sex: "男"
  });
};
</script>

可见element-plus已经引入

安装tailwindcss

npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p

两步骤操根目录生成 postcss.config.js

export default {
  plugins: {
    tailwindcss: {},
    autoprefixer: {},
  },
}

tailwind.config.js

/** @type {import('tailwindcss').Config} */
export default {
  content: [],
  theme: {
    extend: {},
  },
  plugins: [],
}

有次两步文件及初始化成功,创建styles文件夹 下级创建index.css tailwind.css index.css

@import url('tailwind.css');

tailwind.css

/* src/index.css */
@tailwind base;
@tailwind components;
@tailwind utilities;

main.ts 引入 tailwindcss

import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import { createPinia } from 'pinia';
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate';

import "@/styles/index.css";

//routes
import router from "./router/index";

const pinia = createPinia();
pinia.use(piniaPluginPersistedstate);

const app= createApp(App)

app.use(pinia);
app.use(router);
app.mount('#app');

tailwind.config.js

/** @type {import('tailwindcss').Config} */
export default {
  darkMode: "class",
  corePlugins: {
    preflight: false
  },
  content: ["./index.html", "./src/**/*.{vue,js,ts,jsx,tsx}"],
  theme: {
    extend: {
      colors: {
        title: "#202020",
        secondTitle: "#8A8A8A",
        normal: "#4b4b4b",
        light: "#dddddd",
        active: "#2C54D1",
        disabled: "#aaaaaa",
      },
      fontSize: {
        20: "20px",
        18: "18px",
        16: "16px",
        14: "14px",
      },
    },
  },
  plugins: [],
}

login 中的 index.vue试用下 tailwindcss class="text-[#ff0000]" 样式已生效

<template>
  <div>
    <span class="text-[#ff0000]">{{ user }}</span>
    <button @click="addStore">点击</button>
    <el-button type="primary">Primary</el-button>
    <el-button type="success">Success</el-button>
    <el-button type="info">Info</el-button>
    <el-button type="warning">Warning</el-button>
    <el-button type="danger">Danger</el-button>
  </div>
</template>
<script lang="ts" setup>
import { storeToRefs } from "pinia";
import { useUserInfoStore } from "@/store/use-user";

const userInfoStore = useUserInfoStore();

const { user } = storeToRefs(userInfoStore);

const addStore = () => {
  userInfoStore.setUserInfo({
    name: "张三",
    age: Math.random() * 100 + "",
    sex: "男"
  });
};
</script>

此时如果 tailwind.css 报错 Unknown at rule @tailwindcss(unknownAtRules),在跟目录创建.vscode下级settings.json ,可消除报错

{
    "css.lint.unknownAtRules": "ignore"
  }
  

适配原理

我们可以看到tailwindcss尺寸都是基于rem的 如下

image.png

image.png 谷歌浏览器的htmlfont-size: 16px,所以1rem 对应16px,基于此我们可以更具屏幕宽度对应根文字大小,tailwindcss可基于htmlfont-size来适配
在html文件中增加如下代码。默认1920是16px,动态计算宽度来适配,

<script>
    window.addEventListener("resize", () => {
      const screenWidth = window.innerWidth;
      const baseFontSize = 16; // 当屏幕宽度为1920px时的字体大小
      const baseScreenWidth = 1920;

      const fontSize = (screenWidth / baseScreenWidth) * baseFontSize;

      // 假设你想要改变的是body元素的字体大小
      document.documentElement.style.fontSize = `${fontSize}px`;
    });

    // 初始设置
    window.dispatchEvent(new Event("resize"));
  </script>

安装postcss-pxtorem 插件,将px转为rem

npm i postcss-pxtorem -S postcss.config.js更改为

export default {
  plugins: {
    tailwindcss: {},
    autoprefixer: {},
    "postcss-pxtorem": {
      rootValue: 16, // (Number | Function) 表示根元素字体大小或根据input参数返回根元素字体大小
      unitPrecision: 5, // (数字)允许 REM 单位增长到的十进制数字
      propList: ["*"], // 可以从 px 更改为 rem 的属性 使用通配符*启用所有属性
      selectorBlackList: [], // (数组)要忽略并保留为 px 的选择器。
      replace: true, // 替换包含 rems 的规则,而不是添加回退。
      minPixelValue: 0, // 最小的转化单位
      exclude: /node_modules/i, // 要忽略并保留为 px 的文件路径
    },
  },
};

这样可以按照标准设计稿1920对应的尺寸来开发了 如设计稿120px 可 写为 tailwindcss的 w-[120px]

eslint

恰逢eslint@9 及扁平化配置出来,技术有限,配置了半天没搞定扁平化配置,还是使用非扁平化的配置方式, package.jsondevDependencies增加如下依赖 eslint,哪位大佬搞出扁平化配置了,踢我一脚

"@typescript-eslint/parser": "^7.7.0",
"@vue/eslint-config-standard": "^8.0.1",
"@vue/eslint-config-typescript": "^13.0.0",
"eslint": "^8.57.0",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^6.1.1",
"eslint-plugin-vue": "^9.25.0",
"vite-plugin-eslint": "^1.8.1",
"prettier-eslint": "^16.3.0",

重新 npm i 安装依赖 根目录创建.eslintignore

**/iconfont.js
**/flexable.js
src/apis/modules/*
src/apis/**/model.ts
node_modules

.eslintrc.cjs

module.exports = {
  root: true,
  env: {
    node: true,
  },
  extends: [
    "plugin:vue/vue3-essential",
    "@vue/standard",
    "@vue/typescript/recommended",
  ],
  parserOptions: {
    ecmaVersion: 2020,
  },
  ignorePatterns: [
    "*.config.*",
    "dist/*",
    "build/*",
    "public/*",
    "src/apis/modules/**",
  ],
  rules: {
    "no-console": "error"
  },
  globals: {
    uap: "readonly",
    uni: "readonly",
    regist: "readonly",
    defineProps: "readonly",
    defineOptions: "readonly",
    defineEmits: "readonly",
    defineExpose: "readonly",
  },
};


打开vscode 安装 eslint 插件,打开保存即可

image.png

image.png

image.pngtest test1.vue 写一句console.log(1111) eslint已经生效

image.png

安装axios

npm i axios -S

关于 axios 一个封装请求,尅要根据自己业务需要特定的封装,官方文档如下 axios

结束