目标:使用 vite
初始化项目
核心步骤:
yarn create vue
或
npm init vue
√ Project name: ... vue3-ts-pinia-router-eslint
√ Add TypeScript? ... Yes ✅
√ Add JSX Support? ... Yes ✅
√ Add Vue Router for Single Page Application development? ... Yes ✅
√ Add Pinia for state management? ... Yes ✅
√ Add Vitest for Unit Testing? ... No ❌
√ Add Cypress for both Unit and End-to-End testing? ... No ❌
√ Add ESLint for code quality? ... Yes ✅
√ Add Prettier for code formatting? ... Yes ✅
vue3-ts-pinia-router-eslint
项目中,安装依赖包yarn
eslint
格式化项目文件yarn lint
yarn dev
Vue3
项目命令对比Vue3
基础阶段命令
Vue3
基础可以,项目还需要额外配置很多东西,效率低。yarn create vite
Vue3
项目阶段命令
Vue3
官方推荐方式,可以根据项目情况按需选择配置,推荐使用。yarn create vue
yarn create vue
的依赖包要求 Node 16+
以上,或者 14.17.0
版本,建议大家升级 Node 版本。
删除 src 目录所有文件
创建 src/App.vue
<template>
<h1>Hello vue3 + ts</h1>
</template>
创建 src/main.ts
import { createApp } from "vue";
import App from "./App.vue";
const app = createApp(App);
app.mount("#app");
安装npm i axios -S
src/App.vue
<script setup lang="ts">
// 导入 axios 实例
import { onMounted } from "vue";
import request from "./utils/request";
// 在组件挂载完毕后
onMounted(async () => {
// 发送请求
const res = await request.get("/home/banner");
console.log(res);
});
</script>
<template>
<h1>Hello vue3 + ts</h1>
</template>
src/utils/request.ts
import axios from "axios";
// 创建 axios 实例
const instance = axios.create({
baseURL: "http://pcapi-xiaotuxian-front-devtest.itheima.net/",
timeout: 50000,
});
// 添加请求拦截器
instance.interceptors.request.use(
function (config) {
// 在发送请求之前做些什么
return config;
},
function (error) {
// 对请求错误做些什么
return Promise.reject(error);
}
);
// 添加响应拦截器
instance.interceptors.response.use(
function (response) {
return response;
},
function (error) {
// 对响应错误做点什么
return Promise.reject(error);
}
);
export default instance;
.editorconfig
文件用于跨不同的编辑器和 IDE 为多个开发人员维护一致的编码风格的配置文件
# editorconfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
charset
编码格式
latin1
、utf-8
、utf-8-bom
、utf-16be
和utf-16le
root
indent_style
缩进风格
space
tab
indent_size
缩进大小
end_of_line
换行符类型
lf
cr
crlf
Dos和Windows采用回车+换行(cr+lf)来表示换行
UNIX和Linux采用换行符(lf)来表示换行
MAC OS采用回车符(cr)来表示换行
insert_final_newline
true
—> 以换行符结尾trim_trailing_whitespac
true
.gitattributes
文件用于定义每种文件的属性,方便 git 帮我们统一管理
* text eol=lf
*.txt text eol=lf
* text eol=lf
lf
换行*.txt text eol=lf
.txt
文件,标记为文本文档,并进行行尾规范化 ,检出工作目录时,行尾保持为lf
.gitignore
文件取消忽略 .vscode 文件
- .vscode/*
.prettierrc
文件统一团队代码格式,同时在vscode — setting.json注释掉自己的格式(可留着字体大小
{
"semi": true,
"singleQuote": true,
"tabWidth": 2,
"printWidth": 80
}
.vscode/extensions.json
推荐下载的 vscode 插件
{
"recommendations": [
"vue.volar",
"vue.vscode-typescript-vue-plugin",
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
"usernamehw.errorlens",
"editorconfig.editorconfig"
]
}
.vscode/settings.json
文件{
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[vue]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"eslint.enable": true,
"eslint.run": "onType",
"eslint.options": {
"extensions": [
".js",
".ts",
".vue",
".jsx",
".tsx",
]
},
// 操作时作为单词分隔符的字符
"editor.wordSeparators": "`~!@#%^&*()=+[{]}\\|;:'\",.<>/?",
// 一个制表符等于的空格数
"editor.tabSize": 2,
// 保存时格式化
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll": true,
"source.fixAll.eslint": true
},
// 文件行尾符号
"files.eol": "\n",
// 是否以紧凑形式展示文件夹
"explorer.compactFolders": false
}
npm i less -S
src/assets/styles/mixins.less
// 鼠标经过上移阴影动画
.hoverShadow () {
transition: all 0.5s;
&:hover {
transform: translate3d(0, -3px, 0);
box-shadow: 0 3px 8px rgba(0, 0, 0, 0.2);
}
}
src/assets/styles/variables.less
// 主题
@xtxColor: #27ba9b;
// 辅助
@helpColor: #e26237;
// 成功
@sucColor: #1dc779;
// 警告
@warnColor: #ffb302;
// 价格
@priceColor: #cf4444;
src/App.vue
Hello vue3 + ts
变量是有作用域的,只是在单个文件引入,其他文件不可用(如果只是样式的话不需要这个步骤)
vite.config.ts
// defineConfig 节点
// css 配置
css: {
// https://cn.vitejs.dev/config/shared-options.html#css-preprocessoroptions
// 预处理器选项
preprocessorOptions: {
// less
less: {
// 自动添加代码
additionalData: `
@import "@/assets/styles/variables.less";
@import "@/assets/styles/mixins.less";
`,
},
},
},
src/App.vue
- @import './assets/styles/variables.less';
- @import './assets/styles/mixins.less';
npm i normalize.css -S
src/main.ts
// 全局导入 normalize.css 让所有标签在不同浏览器风格统一 (PS:如果用组件库,内部集成了就不用额外安装)
import 'normalize.css'
// 全局导入 公共的样式 如:版心类名
import '@/assets/styles/common.less';
src/assets/styles/common.less
@import url('./variables.less');
// 按照网站自己的需求,提供公用的样式,例如:
* {
box-sizing: border-box;
}
html {
height: 100%;
font-size: 14px;
}
body {
height: 100%;
color: #333;
min-width: 1240px;
font: 1em/1.4 'Microsoft Yahei', 'PingFang SC', 'Avenir', 'Segoe UI',
'Hiragino Sans GB', 'STHeiti', 'Microsoft Sans Serif', 'WenQuanYi Micro Hei',
sans-serif;
}
ul,
h1,
h3,
h4,
p,
dl,
dd {
padding: 0;
margin: 0;
}
a {
text-decoration: none;
color: #333;
outline: none;
}
i {
font-style: normal;
}
input[type='text'],
input[type='search'],
input[type='password'],
input[type='checkbox'] {
padding: 0;
outline: none;
border: none;
-webkit-appearance: none;
&::placeholder {
color: #ccc;
}
}
img {
max-width: 100%;
max-height: 100%;
vertical-align: middle;
// background: #ebebeb;
}
ul {
list-style: none;
}
#app {
background-color: #f5f5f5;
}
.container {
width: 1240px;
margin: 0 auto;
position: relative;
}
// 一行省略
.ellipsis {
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
// 二行省略
.ellipsis-2 {
word-break: break-all;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
}
.fl {
float: left;
}
.fr {
float: right;
}
.clearfix:after {
content: '.';
display: block;
visibility: hidden;
height: 0;
line-height: 0;
clear: both;
}
// 闪动画
.shan {
&::after {
content: '';
position: absolute;
animation: shan 1.5s ease 0s infinite;
top: 0;
width: 30%;
height: 100%;
background: linear-gradient(
to left,
rgba(255, 255, 255, 0) 0,
rgba(255, 255, 255, 0.3) 50%,
rgba(255, 255, 255, 0) 100%
);
transform: skewX(-45deg);
}
}
@keyframes shan {
0% {
left: -100%;
}
100% {
left: 120%;
}
}
// 离开淡出动画
.fade {
&-leave {
&-active {
position: absolute;
width: 100%;
transition: opacity 0.5s 0.2s;
z-index: 1;
}
&-to {
opacity: 0;
}
}
}
// 1. 离开,透明度 1---->0 位移 0---->30
// 2. 进入,透明度 0---->1 位移 30---->0
// 执行顺序,先离开再进入
.pop {
&-leave {
&-from {
opacity: 1;
transform: none;
}
&-active {
transition: all 0.5s;
}
&-to {
opacity: 0;
transform: translateX(20px);
}
}
&-enter {
&-from {
opacity: 0;
transform: translateX(20px);
}
&-active {
transition: all 0.5s;
}
&-to {
opacity: 1;
transform: none;
}
}
}
// 表单
.xtx-form {
padding: 50px 0;
&-item {
display: flex;
align-items: center;
width: 700px;
margin: 0 auto;
padding-bottom: 25px;
.label {
width: 180px;
padding-right: 10px;
text-align: right;
color: #999;
~ .field {
margin-left: 0;
}
}
.field {
width: 320px;
height: 50px;
position: relative;
margin-left: 190px;
.icon {
position: absolute;
left: 0;
top: 0;
width: 40px;
height: 50px;
text-align: center;
line-height: 50px;
color: #999;
~ .input {
padding-left: 40px;
}
}
.input {
border: 1px solid #e4e4e4;
width: 320px;
height: 50px;
line-height: 50px;
padding: 0 10px;
&.err {
border-color: @priceColor;
}
&:focus,
&:active {
border-color: @xtxColor;
}
}
}
.error {
width: 180px;
padding-left: 10px;
color: @priceColor;
}
}
.submit {
width: 320px;
height: 50px;
border-radius: 4px;
background: @xtxColor;
height: 50px;
line-height: 50px;
text-align: center;
font-size: 16px;
color: #fff;
display: block;
margin: 0 auto;
}
}