1 Star 7 Fork 1

恋轩 / vue3-template

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README
MIT

Vue3 + Vite2 + TypeScript 面向企业级别开发项目环境

介绍

本项目将帮助你搭建 vue3 面向企业级项目开发环境,用于提升前端开发速度及效率。已经做成脚手架上传至 npm,可自行下载qian-cli脚手架初始化项目

qian-cli 仓库地址: qian-cli

安装

  1. 安装 qian-cli 脚手架

    npm install qian-cli -g
  2. 使用脚手架初始化项目

    qian-cli init v3-test

技术栈

名字 说明
Vue3 构建用户界面的渐进式框架
Tsx Typescript JavaScript 类型提示、语法扩展
Prettierrc 格式化代码
Vite2 前端开发与构建工具
Scss css 扩展框架
Vue-router4 路由
Axios HTTP 请求
Pinia 全局状态管理

版本号最新变化

# 2022/8/27

pinia                 ^2.0.18  →   ^2.0.21
sass                  ^1.54.4  →   ^1.54.5
vue-router             ^4.1.3  →    ^4.1.5
@types/node           ^18.7.3  →  ^18.7.13
typescript             ^4.7.4  →    ^4.8.2
unplugin-auto-import  ^0.11.1  →   ^0.11.2
vite                   ^3.0.7  →    ^3.0.9

步骤

以下步骤均为仓库第一次创建的时候使用的步骤,后续仓库变化下方步骤不会变化

1. 安装 vite 脚手架环境

npm init vite@latest

2. 安装 Jsx 插件

npm i @vitejs/plugin-vue-jsx --dev

vite.config.ts 文件添加

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import Jsx from '@vitejs/plugin-vue-jsx'

export default defineConfig({
  plugins: [vue(), Jsx()]
})

3. 安装 prettierrc 并配置

npm i eslint-config-prettier --dev

.prettierrc 文件添加

{
  "useTabs": false,
  "tabWidth": 2,
  "printWidth": 300,
  "singleQuote": true,
  "trailingComma": "none",
  "bracketSpacing": true,
  "semi": false
}

4. Vite 别名与跨域反向代理

vite.config.ts 文件

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import Jsx from '@vitejs/plugin-vue-jsx'
import { resolve } from 'path' // 如果报错则安装一下 npm i @types/node	vscode报错需要关闭软件重启

export default defineConfig({
  plugins: [vue(), Jsx()],

  server: {
    open: false, //自动打开浏览器
    base: './ ', //生产环境路径
    proxy: {
      '^/api': {
        target: 'http://localhost', // 后端服务实际地址
        changeOrigin: true, //开启代理
        rewrite: (path) => path.replace(/^\/api/, '')
      }
    }
  },

  resolve: {
    alias: {
      '@': resolve(__dirname, './src') // 例: @/components/HelloWorld.vue
    }
  }
})

tsconfig.json 文件

{
  "compilerOptions": {
    "target": "esnext",
    "useDefineForClassFields": true,
    "module": "esnext",
    "moduleResolution": "node",
    "strict": true,
    "jsx": "preserve",
    "sourceMap": true,
    "resolveJsonModule": true,
    "esModuleInterop": true,
    "lib": ["esnext", "dom"],
    "baseUrl": ".", // 配置一
    "paths": {
      // 配置二
      "@/*": ["src/*"]
    }
  },
  "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
  "references": [{ "path": "./tsconfig.node.json" }]
}

5. Vite 全局变量

跟项目下新建.env.development文件和.env.production文件

# .env.development

NODE_ENV = development

VITE_APP_BASEURL = ''

VITE_APP_BASE_API = /api



# .env.production

NODE_ENV = production

VITE_APP_BASEURL = ''

VITE_APP_BASE_API = www.xuanxiaoqian.com

// 使用 import.meta.env.VITE_APP_BASE_API

Ts 联想提示,在src文件下新增dev.d.ts文件(如有则修改就行)

/// <reference types="vite/client" />

declare module '*.vue' {
  import type { DefineComponent } from 'vue'
  const component: DefineComponent<{}, {}, any>
  export default component
}

interface ImportMetaEnv extends Readonly<Record<string, string>> {
  // 更多环境变量...
  readonly VITE_APP_BASE_API: string
}

interface ImportMeta {
  readonly env: ImportMetaEnv
}

配置 package.json , 打包区分开发环境和生产环境

"build:dev": "vite build --mode development",
"build:pro": "vite build --mode production",

6. css 预处理器 scss

npm i sass --dev

Vite 设置全局 scss 变量

style文件下新增variable.scss文件

// src/style/variable.scss

$vua-pre: vua-;
$white-color: #fff;
$border-color: #dcdee2;
$dash-border-color: #f0f0f0;
$primary-color: #2d8cf0;
$assist-color: #bae7ff;
$disable-color: #c5c8ce;
$text-color: #333;
$error-color: #e44233;
$bg-prev-color: #f5f7fa;

$font-size-base: 14px;
$font-size-mid: $font-size-base + 2;
$font-size-large: $font-size-base + 4;
$font-size-huge: $font-size-base + 10;

新增vite.config.ts文件内容

export default defineConfig({
    plugins: ...

    server: ...

    resolve: ...

    css: {
        preprocessorOptions: {
            scss: {
                additionalData: `@import "/@/style/variable.scss";` // scss全局变量
            }
        }
    }
})

使用全局变量

.home {
  color: $assist-color;
}

7. Vue-router 路由

npm i vue-router@4

src文件下新增router文件夹和views文件夹

// router/index.ts

import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router'

const routes: RouteRecordRaw[] = [
  {
    path: '/:pathMatch(.*)*',
    name: 'NotFound',
    component: () => import('/@/views/Home/Home.vue'), // 需要创建这个文件,不然启动会报错
    meta: {
      title: '404not found'
    }
  },
  {
    path: '/',
    name: 'Home',
    component: () => import('/@/views/Home/Home.vue')
  }
]

const router = createRouter({
  history: createWebHashHistory(),
  routes: routes,
  strict: true,

  scrollBehavior(to, from, savedPosition) {
    if (savedPosition) {
      return savedPosition
    } else {
      return { top: 0 }
    }
  }
})

// 路由白名单
const whiteList = ['/', '/index', '/home', '/login', '/register']

router.beforeEach((to, from, next) => {
  // if (whiteList.indexOf(to.path) === -1) {   // 如果有需要就打开
  //   next({ path: '/' })
  // } else {
  //   next()
  // }
})

router.afterEach(() => {})

export default router

修改入口文件main.ts

import { createApp } from 'vue'
import App from './App.vue'
import router from './router/index'

const app = createApp(App)

app.use(router)

app.mount('#app')

修改主页面App.vue

<script setup lang="ts"></script>

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

<style></style>

8. axios 数据请求

npm i axios

src文件下新增utils文件夹并在下面再建一个http文件夹 src/utils/http

// src/utils/http/defaultConfig.ts

import axios, { AxiosRequestConfig } from 'axios'

export const defaultConfig: AxiosRequestConfig = {
  baseURL: import.meta.env.VITE_APP_BASE_API,
  timeout: 1000,
  headers: {
    token: localStorage.getItem('token') ?? '',
    'Content-Type': 'application/json;charset=UTF-8'
  }
}

export default defaultConfig
// src/utils/http/interceptors.ts

import Axios, { AxiosInstance } from 'axios'

import defaultConfig from './defaultConfig'

export class Interceptors {
  public instance: AxiosInstance

  constructor() {
    this.instance = Axios.create(defaultConfig)

    this.init()
  }

  init() {
    // 数据请求之前
    this.instance.interceptors.request.use(
      (config: any) => {
        // console.log("请求了");
        return config
      },
      (err) => {
        console.log(err)
      }
    )

    // 数据返回之前
    this.instance.interceptors.response.use(
      (response) => {
        // console.log("响应了");
        return Promise.resolve(response)
      },
      (err) => {
        console.log(err)
      }
    )
  }

  getInterceptors() {
    return this.instance
  }
}
const instance = new Interceptors().getInterceptors()

export default instance
// src/utils/http/index.ts

import { AxiosInstance } from 'axios'

import instance from './interceptors'

const http: AxiosInstance = instance

export default http

src文件下新增api文件夹并在下面再建一个login文件夹 src/api/login

// 	src/api/login/types.ts

export interface LoginParams {
  userName: string
  passWord: string | number
}
export interface LoginApi {
  login: (params: LoginParams) => Promise<any>
}
// 	src/api/login/login.ts

import http from '/@/utils/http'
import * as T from './types'

const loginApi: T.LoginApi = {
  login(params) {
    return http.post('/login', params)
  }
}
export default loginApi

使用

import loginApi from '/@/api/login/login'

loginApi.login({ userName: 'root', passWord: '123456' }).then((res) => {
  console.log(res.data)
})

9. pinia 状态管理

npm i pinia@next

src文件下新增store文件夹

// src/store/main.ts

import { defineStore } from 'pinia'

export const useMainStore = defineStore({
  id: 'mian',
  state: () => ({
    name: '超级管理员'
  })
})

修改入口文件main.ts

import { createApp } from 'vue'
import App from './App.vue'
import router from './router/index'
import { createPinia } from 'pinia'

const pinia = createPinia()

const app = createApp(App)

app.use(router)
app.use(pinia)

app.mount('#app')

使用

<script setup lang="ts">
import { useMainStore } from '/@/store/main'

const mainStore = useMainStore()
</script>

<template>
  <div>{{ mainStore.name }}</div>
</template>

<style></style>

10. reset.css 样式统一化

src文件下新增style文件夹

// src/style/reset.css

/* http://meyerweb.com/eric/tools/css/reset/ 
   v2.0 | 20110126
   License: none (public domain)
*/

html,
body,
div,
span,
applet,
object,
iframe,
h1,
h2,
h3,
h4,
h5,
h6,
p,
blockquote,
pre,
a,
abbr,
acronym,
address,
big,
cite,
code,
del,
dfn,
em,
img,
ins,
kbd,
q,
s,
samp,
small,
strike,
strong,
sub,
sup,
tt,
var,
b,
u,
i,
center,
dl,
dt,
dd,
ol,
ul,
li,
fieldset,
form,
label,
legend,
table,
caption,
tbody,
tfoot,
thead,
tr,
th,
td,
article,
aside,
canvas,
details,
embed,
figure,
figcaption,
footer,
header,
hgroup,
menu,
nav,
output,
ruby,
section,
summary,
time,
mark,
audio,
video {
  margin: 0;
  padding: 0;
  border: 0;
  font-size: 100%;
  font: inherit;
  vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article,
aside,
details,
figcaption,
figure,
footer,
header,
hgroup,
menu,
nav,
section {
  display: block;
}
body {
  line-height: 1;
}
ol,
ul {
  list-style: none;
}
blockquote,
q {
  quotes: none;
}
blockquote:before,
blockquote:after,
q:before,
q:after {
  content: '';
  content: none;
}
table {
  border-collapse: collapse;
  border-spacing: 0;
}

修改入口文件main.ts

import { createApp } from 'vue'
import App from './App.vue'
import router from './router/index'
import { createPinia } from 'pinia'

// reset.css
import './style/reset.css'

const pinia = createPinia()

const app = createApp(App)

app.use(router)
app.use(pinia)

app.mount('#app')

11. hooks 代码复用

src文件下新增hooks文件夹

// src/hooks/usePoint.ts

import { reactive, onMounted, onBeforeUnmount } from 'vue'
export default function () {
  //展示的数据  可以通过App.vue 界面去隐藏
  let point = reactive({
    x: 0,
    y: 0
  })

  //获取鼠标点击事件
  function savePonint(event: MouseEvent) {
    point.x = event.pageX
    point.y = event.pageY
    console.log(event.pageX, event.pageY)
  }

  //现实之后调用 挂载完毕
  onMounted(() => {
    window.addEventListener('click', savePonint)
  })

  //在隐藏之前调用 卸载之前
  onBeforeUnmount(() => {
    window.removeEventListener('click', savePonint)
  })

  return point
}

使用

import usePoint from '/@/hooks/usePoint'

let point = usePoint()
console.log(point)

12. Vue Api 自动导入

npm i unplugin-auto-import -D

新增vite.config.ts文件内容

import AutoImport from 'unplugin-auto-import/vite'

export default defineConfig({
  plugins: [
    AutoImport({
      imports: ['vue', 'vue-router'],
      // 可以选择auto-import.d.ts生成的位置,使用ts建议设置为'src/auto-import.d.ts'
      dts: 'src/auto-import.d.ts'
    })
  ]
})

重启项目src目录下会新增auto-import.d.ts文件,我们就可以愉快的自动导入啦

X. TODO

以下的内容均不在仓库中,只是为了方便有需要的人能快速使用

setup 语法糖下写组件 name

npm i vite-plugin-vue-setup-extend -D

配置vite.config.ts

import { defineConfig } from 'vite'
import VueSetupExtend from 'vite-plugin-vue-setup-extend'
export default defineConfig({
  plugins: [VueSetupExtend()]
})

使用

<script lang="ts" setup name="demo"></script>

Element-Plus 组件库

https://element-plus.gitee.io/zh-CN/guide/installation.html

npm install element-plus --save

修改入口文件main.ts

import { createApp } from 'vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import App from './App.vue'

const app = createApp(App)

app.use(ElementPlus)
app.mount('#app')

使用

<el-button type="primary">看见我没问题就成功了!!!</el-button>

VueUse hooks 库

https://vueuse.org/

Nprogress 网站进度条

https://ricostacruz.com/nprogress/

npm install --save nprogress
import Nprogress from 'nprogress'
import 'nprogress/nprogress.css'

Nprogress.configure({
  // 动画方式
  easing: 'ease',
  // 递增进度条的速度
  speed: 500,
  // 是否显示加载ico
  showSpinner: false,
  // 自动递增间隔
  trickleSpeed: 200,
  // 初始化时的最小百分比
  minimum: 0.3
})

export default Nprogress

使用

import NProgress from '../utils/nprogress'

NProgress.start() // 控制开始加载

NProgress.done() // 控制结束加载

JsCookie 本地 cookie

https://www.npmjs.com/package/js-cookie

npm install js-cookie --save

使用

import Cookies from 'js-cookie'

// Create a cookie, valid across the entire site:
Cookies.set('name', 'value')

// 创建一个从现在起7天内过期的cookie,在整个站点有效:
Cookies.set('name', 'value', { expires: 7 })

// Create an expiring cookie, valid to the path of the current page:
Cookies.set('name', 'value', { expires: 7, path: '' })

//           name       value
Cookies.set('TokenKey', token, { expires: 1000, path: '/', domain: 'xx.com' })

//不写过期时间,默认为1天过期
this.$cookies.set('user_session', '25j_7Sl6xDq2Kc3ym0fmrSSk2xV2XkUkX')

this.$cookies.set('token', 'GH1.1.1689020474.1484362313', '60s') // 60秒后过去

this.$cookies.set('token', 'GH1.1.1689020474.1484362313', '30MIN') // 30分钟后过去

// Read cookie:
Cookies.get('name') // => 'value'
Cookies.get('nothing') // => undefined

// Read all visible cookies:
Cookies.get() // => { name: 'value' }

// Delete cookie:
Cookies.remove('name')

// Delete a cookie valid to the path of the current page:
Cookies.set('name', 'value', { path: '' })
Cookies.remove('name') // fail!
Cookies.remove('name', { path: '' }) // removed!

CSScomb Css 样式顺序

vscode 插件 CSScomb,用于保存自动修改 css 属性顺序

下载CSScomb 插件

在项目根目录添加新文件.csscomb.json

{
  "exclude": [".git/**", "node_modules/**", "bower_components/**"],
  "always-semicolon": true,
  "block-indent": "  ",
  "color-case": "lower",
  "color-shorthand": true,
  "element-case": "lower",
  "eof-newline": true,
  "leading-zero": false,
  "quotes": "single",
  "remove-empty-rulesets": true,
  "space-after-colon": " ",
  "lines-between-rulesets": 1,
  "space-after-combinator": " ",
  "space-after-opening-brace": "\n",
  "space-after-selector-delimiter": "\n",
  "space-before-closing-brace": "\n",
  "space-before-colon": "",
  "space-before-combinator": " ",
  "space-before-opening-brace": " ",
  "space-before-selector-delimiter": "",
  "space-between-declarations": "\n",
  "strip-spaces": true,
  "unitless-zero": true,
  "vendor-prefix-align": true,
  "sort-order": [
    [
      "font",
      "font-family",
      "font-size",
      "font-weight",
      "font-style",
      "font-variant",
      "font-size-adjust",
      "font-stretch",
      "font-effect",
      "font-emphasize",
      "font-emphasize-position",
      "font-emphasize-style",
      "font-smooth",
      "line-height",
      "position",
      "z-index",
      "top",
      "right",
      "bottom",
      "left",
      "display",
      "visibility",
      "float",
      "clear",
      "overflow",
      "overflow-x",
      "overflow-y",
      "-ms-overflow-x",
      "-ms-overflow-y",
      "clip",
      "zoom",
      "-webkit-align-content",
      "-ms-flex-line-pack",
      "align-content",
      "-webkit-box-align",
      "-moz-box-align",
      "-webkit-align-items",
      "align-items",
      "-ms-flex-align",
      "-webkit-align-self",
      "-ms-flex-item-align",
      "-ms-grid-row-align",
      "align-self",
      "-webkit-box-flex",
      "-webkit-flex",
      "-moz-box-flex",
      "-ms-flex",
      "flex",
      "-webkit-flex-flow",
      "-ms-flex-flow",
      "flex-flow",
      "-webkit-flex-basis",
      "-ms-flex-preferred-size",
      "flex-basis",
      "-webkit-box-orient",
      "-webkit-box-direction",
      "-webkit-flex-direction",
      "-moz-box-orient",
      "-moz-box-direction",
      "-ms-flex-direction",
      "flex-direction",
      "-webkit-flex-grow",
      "-ms-flex-positive",
      "flex-grow",
      "-webkit-flex-shrink",
      "-ms-flex-negative",
      "flex-shrink",
      "-webkit-flex-wrap",
      "-ms-flex-wrap",
      "flex-wrap",
      "-webkit-box-pack",
      "-moz-box-pack",
      "-ms-flex-pack",
      "-webkit-justify-content",
      "justify-content",
      "-webkit-box-ordinal-group",
      "-webkit-order",
      "-moz-box-ordinal-group",
      "-ms-flex-order",
      "order",
      "-webkit-box-sizing",
      "-moz-box-sizing",
      "box-sizing",
      "width",
      "min-width",
      "max-width",
      "height",
      "min-height",
      "max-height",
      "margin",
      "margin-top",
      "margin-right",
      "margin-bottom",
      "margin-left",
      "padding",
      "padding-top",
      "padding-right",
      "padding-bottom",
      "padding-left",
      "table-layout",
      "empty-cells",
      "caption-side",
      "border-spacing",
      "border-collapse",
      "list-style",
      "list-style-position",
      "list-style-type",
      "list-style-image",
      "content",
      "quotes",
      "counter-reset",
      "counter-increment",
      "resize",
      "cursor",
      "-webkit-user-select",
      "-moz-user-select",
      "-ms-user-select",
      "user-select",
      "nav-index",
      "nav-up",
      "nav-right",
      "nav-down",
      "nav-left",
      "-webkit-transition",
      "-moz-transition",
      "-ms-transition",
      "-o-transition",
      "transition",
      "-webkit-transition-delay",
      "-moz-transition-delay",
      "-ms-transition-delay",
      "-o-transition-delay",
      "transition-delay",
      "-webkit-transition-timing-function",
      "-moz-transition-timing-function",
      "-ms-transition-timing-function",
      "-o-transition-timing-function",
      "transition-timing-function",
      "-webkit-transition-duration",
      "-moz-transition-duration",
      "-ms-transition-duration",
      "-o-transition-duration",
      "transition-duration",
      "-webkit-transition-property",
      "-moz-transition-property",
      "-ms-transition-property",
      "-o-transition-property",
      "transition-property",
      "-webkit-transform",
      "-moz-transform",
      "-ms-transform",
      "-o-transform",
      "transform",
      "-webkit-transform-origin",
      "-moz-transform-origin",
      "-ms-transform-origin",
      "-o-transform-origin",
      "transform-origin",
      "-webkit-animation",
      "-moz-animation",
      "-ms-animation",
      "-o-animation",
      "animation",
      "-webkit-animation-name",
      "-moz-animation-name",
      "-ms-animation-name",
      "-o-animation-name",
      "animation-name",
      "-webkit-animation-duration",
      "-moz-animation-duration",
      "-ms-animation-duration",
      "-o-animation-duration",
      "animation-duration",
      "-webkit-animation-play-state",
      "-moz-animation-play-state",
      "-ms-animation-play-state",
      "-o-animation-play-state",
      "animation-play-state",
      "-webkit-animation-timing-function",
      "-moz-animation-timing-function",
      "-ms-animation-timing-function",
      "-o-animation-timing-function",
      "animation-timing-function",
      "-webkit-animation-delay",
      "-moz-animation-delay",
      "-ms-animation-delay",
      "-o-animation-delay",
      "animation-delay",
      "-webkit-animation-iteration-count",
      "-moz-animation-iteration-count",
      "-ms-animation-iteration-count",
      "-o-animation-iteration-count",
      "animation-iteration-count",
      "-webkit-animation-direction",
      "-moz-animation-direction",
      "-ms-animation-direction",
      "-o-animation-direction",
      "animation-direction",
      "text-align",
      "-webkit-text-align-last",
      "-moz-text-align-last",
      "-ms-text-align-last",
      "text-align-last",
      "vertical-align",
      "white-space",
      "text-decoration",
      "text-emphasis",
      "text-emphasis-color",
      "text-emphasis-style",
      "text-emphasis-position",
      "text-indent",
      "-ms-text-justify",
      "text-justify",
      "letter-spacing",
      "word-spacing",
      "-ms-writing-mode",
      "text-outline",
      "text-transform",
      "text-wrap",
      "text-overflow",
      "-ms-text-overflow",
      "text-overflow-ellipsis",
      "text-overflow-mode",
      "-ms-word-wrap",
      "word-wrap",
      "word-break",
      "-ms-word-break",
      "-moz-tab-size",
      "-o-tab-size",
      "tab-size",
      "-webkit-hyphens",
      "-moz-hyphens",
      "hyphens",
      "pointer-events",
      "opacity",
      "filter:progid:DXImageTransform.Microsoft.Alpha(Opacity",
      "-ms-filter:\\'progid:DXImageTransform.Microsoft.Alpha",
      "-ms-interpolation-mode",
      "color",
      "border",
      "border-width",
      "border-style",
      "border-color",
      "border-top",
      "border-top-width",
      "border-top-style",
      "border-top-color",
      "border-right",
      "border-right-width",
      "border-right-style",
      "border-right-color",
      "border-bottom",
      "border-bottom-width",
      "border-bottom-style",
      "border-bottom-color",
      "border-left",
      "border-left-width",
      "border-left-style",
      "border-left-color",
      "-webkit-border-radius",
      "-moz-border-radius",
      "border-radius",
      "-webkit-border-top-left-radius",
      "-moz-border-radius-topleft",
      "border-top-left-radius",
      "-webkit-border-top-right-radius",
      "-moz-border-radius-topright",
      "border-top-right-radius",
      "-webkit-border-bottom-right-radius",
      "-moz-border-radius-bottomright",
      "border-bottom-right-radius",
      "-webkit-border-bottom-left-radius",
      "-moz-border-radius-bottomleft",
      "border-bottom-left-radius",
      "-webkit-border-image",
      "-moz-border-image",
      "-o-border-image",
      "border-image",
      "-webkit-border-image-source",
      "-moz-border-image-source",
      "-o-border-image-source",
      "border-image-source",
      "-webkit-border-image-slice",
      "-moz-border-image-slice",
      "-o-border-image-slice",
      "border-image-slice",
      "-webkit-border-image-width",
      "-moz-border-image-width",
      "-o-border-image-width",
      "border-image-width",
      "-webkit-border-image-outset",
      "-moz-border-image-outset",
      "-o-border-image-outset",
      "border-image-outset",
      "-webkit-border-image-repeat",
      "-moz-border-image-repeat",
      "-o-border-image-repeat",
      "border-image-repeat",
      "outline",
      "outline-width",
      "outline-style",
      "outline-color",
      "outline-offset",
      "background",
      "filter:progid:DXImageTransform.Microsoft.AlphaImageLoader",
      "background-color",
      "background-image",
      "background-repeat",
      "background-attachment",
      "background-position",
      "background-position-x",
      "-ms-background-position-x",
      "background-position-y",
      "-ms-background-position-y",
      "-webkit-background-clip",
      "-moz-background-clip",
      "background-clip",
      "background-origin",
      "-webkit-background-size",
      "-moz-background-size",
      "-o-background-size",
      "background-size",
      "box-decoration-break",
      "-webkit-box-shadow",
      "-moz-box-shadow",
      "box-shadow",
      "filter:progid:DXImageTransform.Microsoft.gradient",
      "-ms-filter:\\'progid:DXImageTransform.Microsoft.gradient",
      "text-shadow"
    ]
  ]
}

在 文件-> 首选项-> 设置-> settings.json 添加

  "csscomb.formatOnSave": true,
  "csscomb.preset": {},
  "csscomb.ignoreFilesOnSave": [

  ],

在 vscode 下 CTRL+Shift+P 唤出快捷命令,输入CSSComb:Format styles回车 (不能缺少)

修改 css 代码保存,就可以看到 css 属性顺序自动改变了

更新项目 npm 依赖版本

https://www.npmjs.com/package/npm-check-updates

用于检查项目package.json的依赖是否是最新版本

npm install -g npm-check-updates

使用

ncu		# 检查项目依赖最新版本

ncu -u	# 更新package.json的版本号

npm install # 更新项目依赖

响应性语法糖

https://cn.vuejs.org/guide/extras/reactivity-transform.html

此功能不建议使用,属于一个实验性功能,在此列出此功能是为了让不知道的人知道vue还有这个东西

具体使用请点击上面链接前往 vue 官方文档学习使用

vue3 查漏补缺

https://zhuanlan.zhihu.com/p/423860019

postcss

vite 默认添加 postcss,所以不需要额外安装

npm i autoprefixer postcss-plugin-px2rem -D	# 第一个是浏览器前缀 第二个是rem移动端适配

在根目录添加postcss.config.cjs

module.exports = {
  plugins: [
    require('autoprefixer'),
    require('postcss-plugin-px2rem')({
      rootValue: 37.5, //换算基数,1rem相当于10px,值为37.5时,1rem为20px,淘宝的flex默认为1rem为10px
      // unitPrecision: 5, //允许REM单位增长到的十进制数字。
      //propWhiteList: [],  //默认值是一个空数组,这意味着禁用白名单并启用所有属性。
      propBlackList: ['border'], //黑名单
      // exclude: /(node_module)/, //默认false,可以(reg)利用正则表达式排除某些文件夹的方法,例如/(node_module)\/如果想把前端UI框架内的px也转换成rem,请把此属性设为默认值
      // selectorBlackList: [], //要忽略并保留为px的选择器
      // ignoreIdentifier: false,  //(boolean/string)忽略单个属性的方法,启用ignoreidentifier后,replace将自动设置为true。
      // replace: true, // (布尔值)替换包含REM的规则,而不是添加回退。
      mediaQuery: false, //(布尔值)允许在媒体查询中转换px。
      minPixelValue: 3 //设置要替换的最小像素值(3px会被转rem)。 默认 0
    })
  ]
}

注意事项

1. Vite 代理事件

情况:我使用 vite 的 proxy 去代理我的请求,但是我发现好像并没有帮我代理

事件重现

我在 vite.config 里面写了代理配置

  server: {
    ...
    proxy: {
      '^/api': {
        target: 'http://localhost:8000', // 后端服务实际地址
        changeOrigin: true, //开启代理
        rewrite: (path) => path.replace(/^\/api/, '')
      }
    }
  },

src/utils/http/defaultConfig

import { AxiosRequestConfig } from 'axios'

export const defaultConfig: AxiosRequestConfig = {
  baseURL: '/api' // 已经添加上了
}

export default defaultConfig

src/api/login/user/user.ts

import http from '/@/utils/http'

export const allVideo = () => http.post('/user/login')

然后我开心的去请求了,却发现浏览器报错

POST http://192.168.31.153:3000/api/user/login 404 (Not Found)
Error: Request failed with status code 404
...

我一看,地址为什么是这样的,不应该是 http://localhost:8000/user/login吗?我以为是代理失效,找了半天才发现是我请求方式错了

src/api/login/user/user.ts

import http from '/@/utils/http'

export const allVideo = () => http.get('/user/login') // 改成get

我们看成功的真实请求地址

请求网址: http://192.168.31.153:3000/api/user/login
请求方法: GET

是我 nginx 知识薄弱了,他的请求地址不会变。

但是为什么会现在才发现这个问题呢?可能是之前创建项目第一次请求都成功了,当后面的 api 写错了浏览器报 404 我就会潜意识认为是我 api 地址或请求方式写错了,但是这次是第一次请求就报错,让我以为是没有代理上。

MIT License Copyright (c) 2022 轩小浅 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

简介

Vue3 + Vite2 + TypeScript面向企业级别开发环境脚手架模板 展开 收起
JavaScript 等 4 种语言
MIT
取消

贡献者

全部

近期动态

加载更多
不能加载更多了
JavaScript
1
https://gitee.com/lianxuan7/vue3-template.git
git@gitee.com:lianxuan7/vue3-template.git
lianxuan7
vue3-template
vue3-template
dev

搜索帮助