参考文章 :https://juejin.cn/post/7079785777692934174
一、搭建开发环境
vite 官网地址 https://vitejs.cn/ vue3 官网地址 https://v3.cn.vuejs.org/ ElementPlus https://element-plus.gitee.io/zh-CN/ TypeScript https://www.tslang.cn/docs/home.html TypeScript https://www.typescriptlang.org/zh/
1、安装vite
Vite 需要 Node.js 版本 >= 12.0.0
# 全局安装vite
npm install vite -g
# 验证是否安装成功
vite -v
-> vite/2.9.14 win32-x64 node-v16.13.2
2、安装pnpm
pnpm 与 npm 一样,是一个包管理器,但是比npm更加快速
# 全局安装 pnpm
npm i pnpm -g
# 验证是否安装成功
pnpm -v
-> 7.5.1
3、创建Vue3+TS模板
#快速创建
# npm 7+, 需要额外的双横线:
npm init vite@latest my-vue-app -- --template vue-ts
# pnpm
pnpm create vite my-vue-app -- --template vue-ts
#按需创建
# npm 7+, 需要额外的双横线:
npm init vite@latest my-vue-app
# pnpm
pnpm create vite my-vue-app
4、安装ElementPlus
# NPM
$ npm install element-plus --save
# pnpm
$ pnpm install element-plus
#如果需要EP组件按需导入,并且是自动导入 需要安装下面两款插件
pnpm install -D unplugin-vue-components unplugin-auto-import
5、VSCode配置
- 安装vscode的Volar插件
- 禁用Vetur组件
- 设置中注释vetur相关配置
6、vite.config.ts
```javascript // 使用path库,如果报错,安装 @types/node ( npm i @types/node -D ) import { resolve } from ‘path’; import { defineConfig } from ‘vite’; import vue from ‘@vitejs/plugin-vue’; // 根据 ElementPlus 管网,配置自动导入 import AutoImport from ‘unplugin-auto-import/vite’; import Components from ‘unplugin-vue-components/vite’; import { ElementPlusResolver } from ‘unplugin-vue-components/resolvers’;
// 获取目录路径 const pathSrc = resolve(__dirname, ‘src’);
// https://vitejs.dev/config/
export default defineConfig({
resolve: {
// 配置别名
alias: {
‘@/‘: ${pathSrc}/
,
},
},
plugins: [
vue(),
// 根据 ElementPlus 管网,配置自动导入
AutoImport({
resolvers: [ElementPlusResolver()],
}),
Components({
resolvers: [ElementPlusResolver()],
}),
],
// 配置服务相关信息
/ server: {
port: 9955,
host: “0.0.0.0”,
proxy: {
“/model-management”: {
// 开发环境
// target: “http://172.16.6.136:7080“,
// 开发自测环境
target: “http://172.16.6.22:7080“,
// 测试环境
// target: “http://172.16.6.22:7088“,
// 测试环境
// target: “http://172.16.6.240:7080“,
changeOrigin: true
}
}
}, /
});
vite.config.ts
<a name="uqltT"></a>
## 7、tsconfig.json
```javascript
{
"compilerOptions": {
// 设置根目录为当前目录
"baseUrl": ".",
"target": "esnext",
"useDefineForClassFields": true,
"module": "esnext",
"moduleResolution": "node",
"strict": true,
"jsx": "preserve",
"sourceMap": true,
"resolveJsonModule": true,
"isolatedModules": true,
"esModuleInterop": true,
"lib": ["esnext", "dom"],
"skipLibCheck": true,
// 用于ts解析 “@” 路径
"paths": {
"@/*": ["src/*"]
}
},
"include": [
"src/**/*.ts",
"src/**/*.d.ts",
"src/**/*.tsx",
"src/**/*.vue",
// 增加对注解文件的解析
"./auto-imports.d.ts",
"./components.d.ts"
],
"references": [{ "path": "./tsconfig.node.json" }]
}
8、安装与配置ESLint
:::info
pnpm i eslint eslint-plugin-vue —save-dev
pnpm install @typescript-eslint/parser —save-dev
pnpm install @typescript-eslint/eslint-plugin —save-dev
::: 创建文件 .eslintrc.js
module.exports = {
parser: 'vue-eslint-parser',
parserOptions: {
parser: '@typescript-eslint/parser',
ecmaVersion: 2020,
sourceType: 'module',
ecmaFeatures: {
jsx: true,
},
},
extends: [
'plugin:vue/vue3-recommended',
'plugin:@typescript-eslint/recommended',
'prettier',
'plugin:prettier/recommended',
],
rules: {
// override/add rules settings here, such as:
},
};
创建忽略文件 .eslintignore
node_modules/
dist/
index.html
增加校验命令,修改 package.json
{
...
"scripts": {
...
"eslint:comment": "使用 ESLint 检查并自动修复 src 目录下所有扩展名为 .js 和 .vue 的文件",
"eslint": "eslint --ext .js,.vue --ignore-path .gitignore --fix src",
}
...
}
9、配置prettierrc
:::info pnpm i prettier eslint-config-prettier eslint-plugin-prettier —save-dev ::: 新建 .prettierrc.js 文件
module.exports = {
// 一行最多 80 字符
printWidth: 80,
// 使用 2 个空格缩进
tabWidth: 2,
// 不使用 tab 缩进,而使用空格
useTabs: false,
// 行尾需要有分号
semi: true,
// 使用单引号代替双引号
singleQuote: true,
// 对象的 key 仅在必要时用引号
quoteProps: 'as-needed',
// jsx 不使用单引号,而使用双引号
jsxSingleQuote: false,
// 末尾使用逗号
trailingComma: 'all',
// 大括号内的首尾需要空格 { foo: bar }
bracketSpacing: true,
// jsx 标签的反尖括号需要换行
jsxBracketSameLine: false,
// 箭头函数,只有一个参数的时候,也需要括号
// arrowParens: 'always',
// 每个文件格式化的范围是文件的全部内容
rangeStart: 0,
rangeEnd: Infinity,
// 不需要写文件开头的 @prettier
requirePragma: false,
// 不需要自动在文件开头插入 @prettier
insertPragma: false,
// 使用默认的折行标准
proseWrap: 'preserve',
// 根据显示样式决定 html 要不要折行
htmlWhitespaceSensitivity: 'css',
// 换行符使用 lf
endOfLine: 'auto',
};
二、TypeScript
参考 https://juejin.cn/post/6981728323051192357
// 定义变量
let text: string = "Hello World";
const num:number = 1;
let isNum:boolean = true;
let empty: null|undefined = null;
// 定义数组
const nums:number[] = [1,2,3];
// 某个位置的值可以是注解中的任何一个
const LOL: (string | number)[] = ["zed", 25, "darts"];
// 元组 每一项数据类型必须一致
const LOL: [string, string, number] = ["zed", "darts", 25];
// 定义对象
interface EventRecord {
id:number;
description:string;
deviceId?:number;
say()?: string; // say函数返回值为string
[propname: string]: any; // 当前EventRecord可定义任意字符串类型的key
}
const EventList: EventRecord[] = [{ id: 1, description: '装置越限' }];
// or
const EventList: Array<EventRecord> = [{ id: 1, description: '装置越限' }];
// 函数
// 无返回值
function sayHello(): void {
console.log("hello world");
}
function sayHello(): string {
return "hello world";
}
// 参数
function sum(x: number, y: number): number {
return x + y;
}
function handleEvent(eventList:EventRecord[]): void {
...
}
// 变量形式声明
let mySum: (x: number, y: number) => number = function (x: number, y: number): number {
return x + y;
};
interface BaseRequest {
code:number;
data:any,
msg:string
}
let getDate: () => Promise<BaseRequest> = function (): Promise<BaseRequest> {
return x + y;
};
// 定义 enum枚举
// 初始值默认为 0
enum JiShiEnum {
REDJ,
BLUEJ,
GREENJ,
}
// 设置初始值
enum JiShiEnum {
REDJ = 8,
BLUEJ,
GREENJ,
}
const jishi: JiShiEnum = JiShiENUM.BLUE
console.log(jishi) // 9
// 字符串枚举,每个都需要声明
enum JiShiEnum {
REDJ = "8号",
BLUEJ = "9号",
GREENJ = "10号",
}
二、Vue3开发
1、生命周期
:::info
Vue2—————————vue3
beforeCreate -> setup()
created -> setup()
beforeMount -> onBeforeMount
mounted -> onMounted
beforeUpdate -> onBeforeUpdate
updated -> onUpdated
beforeDestroy -> onBeforeUnmount
destroyed -> onUnmounted
activated -> onActivated
deactivated -> onDeactivated
errorCaptured -> onErrorCaptured
:::
2、setup 与 ref、reactive
在setup中使用ref声明响应式变量,使其能在模板中使用
<template>
<div>{{ count }}</div>
<div>{{ state.name }}</div>
<span v-for="item in state.items" :key="item">{{ item }}</span>
<el-button @click="addCount">增加</el-button>
</template>
<script lang="ts" setup>
const count = ref(0);
// 定义对象 数组
let state = reactive({
name: 'test',
items: [1, 2, 3, 4, 5],
});
const addCount = () => {
count.value += 1;
state.name += count.value;
state.items[2] += count.value;
};
</script>
3、computed
<template>
<div>{{ count }}</div>
<div>计算属性:{{ computedNum }}</div>
<el-button @click="addCount">增加</el-button>
</template>
<script lang="ts" setup>
// 需要通过.value 访问
const count = ref(0);
const addCount = () => {
count.value += 1;
};
const computedNum = computed({
get: () => count.value * 100,
set: (value) => count.value * value,
});
</script>
4、watch
<template>
<div>{{ count }}</div>
<div>age:{{ state.age }}</div>
<el-button @click="addCount">增加</el-button>
</template>
<script lang="ts" setup>
interface Person {
name: string;
age: number;
}
// 需要通过.value 访问
const count = ref(0);
const state = reactive<Person>({ name: 'vue', age: 10 });
const addCount = () => {
count.value += 1;
state.age += 10;
};
watch(count, (newvalue, old) => {
console.log('cuont', newvalue, old, count.value);
});
watch(
// () => state,
() => state.age,
(age, preAge) => {
console.log(age, preAge);
},
// 配置deep且直接监听state时 preAge的值与age的值一致
// 为了完全侦听深度嵌套的对象和数组,可能需要对值进行深拷贝。
/* {
deep: true,
}, */
);
/*
参考 vue官方文档 https://v3.cn.vuejs.org/guide/reactivity-computed-watchers.html#侦听响应式对象
import _ from 'lodash';
const state = reactive({
id: 1,
attributes: {
name: '',
},
});
watch(
() => _.cloneDeep(state),
(state, prevState) => {
console.log(state.attributes.name, prevState.attributes.name)
}
)
state.attributes.name = 'Alex' // 日志: "Alex" "" */
</script>
5、模块化
// hook/组件
import { ref } from 'vue';
const nowTime = ref('00:00:00');
const getNowTime = () => {
const now = new Date();
const hour = String(now.getHours()).padStart(2, '0');
const minu =
now.getMinutes() < 10 ? '0' + now.getMinutes() : now.getMinutes();
const sec = now.getSeconds() < 10 ? '0' + now.getSeconds() : now.getSeconds();
nowTime.value = hour + ':' + minu + ':' + sec;
setTimeout(getNowTime, 1000);
};
export { nowTime, getNowTime };
// 在组件中使用
<template>
<div>{{ nowTime }}</div>
<el-button @click="getNowTime">开始</el-button>
</template>
<script lang="ts" setup>
import { nowTime, getNowTime } from '../hooks/useNowTime';
</script>
6、Teleport 组件
// modal组件
<template>
<div id="center">
<h2>弹窗demo</h2>
</div>
</template>
<script lang="ts" setup></script>
<style>
#center {
width: 200px;
height: 200px;
border: 2px solid black;
background: white;
position: fixed;
left: 50%;
top: 50%;
margin-left: -100px;
margin-top: -100px;
z-index: 100000000;
}
</style>
// 使用teleport组件包裹后,可以在使modal组件加载到想在的地方
<template>
<div>122</div>
<!-- 可以绑定 id class 自定义属性 -->
<!-- 相当于 将ModelDialog组件加载到id为model的dom容器中-->
<teleport to="#modal">
<ModelDialog />
</teleport>
</template>
<script lang="ts" setup></script>