Vue3项目实战
环境说明
- WSL2+ mishamosher/CentOS-WSL
- node
- yarn 1.22.22
- vscode / jetbrain IDEA
组件名和标签名的映射规则
在 Vue 中,组件名和标签名之间的映射规则是基于 PascalCase(大驼峰命名法)和 kebab-case(短横线命名法)的转换。具体规则如下:
PascalCase 到 kebab-case 的转换:
- 当你在模板中使用组件时,Vue 会自动将组件名从 PascalCase 转换为 kebab-case。例如,如果你有一个组件名为
MyComponent
,在模板中你可以使用<my-component>
来引用它。
- 当你在模板中使用组件时,Vue 会自动将组件名从 PascalCase 转换为 kebab-case。例如,如果你有一个组件名为
kebab-case 到 PascalCase 的转换:
- 当你在 JavaScript 中导入组件时,你需要使用组件的文件名(通常是 PascalCase)。例如,如果你有一个组件文件名为
MyComponent.vue
,你需要使用import MyComponent from './MyComponent.vue'
来导入它。
- 当你在 JavaScript 中导入组件时,你需要使用组件的文件名(通常是 PascalCase)。例如,如果你有一个组件文件名为
全局注册组件:
- 当你全局注册组件时,你可以使用任何有效的 JavaScript 标识符作为组件名。例如,你可以使用
app.component('my-component', MyComponent)
来全局注册MyComponent
组件。
- 当你全局注册组件时,你可以使用任何有效的 JavaScript 标识符作为组件名。例如,你可以使用
局部注册组件:
- 在局部注册组件时,你需要在组件的
components
选项中使用组件的 PascalCase 名称。例如:
1
2
3
4
5
6
7
8
9
10<script>
import MyComponent from './MyComponent.vue';
export default {
components: {
MyComponent
},
// 其他组件选项
}
</script>- 在局部注册组件时,你需要在组件的
<script setup>
语法:- 在
<script setup>
中,组件的名称会自动根据文件名来推断。例如,如果你的组件文件名为MyComponent.vue
,那么组件的名称就是MyComponent
。你可以在模板中直接使用<my-component>
来引用它。
- 在
总结一下,Vue 会自动处理组件名和标签名之间的转换,使得你可以在模板中使用 kebab-case 命名的标签来引用 PascalCase 命名的组件。这种命名约定有助于提高代码的可读性,并且避免与 HTML 原生标签冲突。
创建项目
1 | ❯ yarn create vite |
清理初始化内容
1 | C:. |
1 | yarn add --dev @types/node |
配置alias
1 | { |
在 vite.config.ts
里配置了这些 alias
1 | import { resolve } from 'path' |
在该项目的 tsconfig.json 文件里就需要相应的加上这些 paths :
1 | { |
设置vscode 的ts
command + shift + P
,输入 type,选择select typescript version
,选择use WOrkspace Version
- 重启vscode,可以发现页面报错消失
全局样式
安装sass依赖
1
yarn add -D sass
新建
src/styles/global.scss
1
2
3
4
5
6
7rm src/style.css
mkdir -p $(dirname src/styles/global.less) && touch src/styles/global.scss
*{
padding: 0;
margin: 0
}引入全局样式
1
2
3❯ code ./src/main.ts
import './styles/global.scss'
tailwindcss
-
1
2
3
4
5# npm install -D tailwindcss@latest postcss@latest autoprefixer@latest
# npx tailwindcss-cli@latest init -p
yarn add -D tailwindcss@3 postcss autoprefixer
npx tailwindcss init -p 配置css
- 这个配置文件中的
content
部分指定了 Tailwind CSS 应该扫描哪些文件来寻找 Tailwind 类。
1
2
3
4
5
6
7
8
9
10
11// vi tailwind.config.js
/** @type {import('tailwindcss').Config} */
export default {
content: ["./index.html", "./src/**/*.{vue,js,ts,jsx,tsx}"],
theme: {
extend: {},
},
plugins: [],
}- 这个配置文件中的
在 src/styles/tailwind.css 文件中添加
@tailwind
指令。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16// touch src/styles/tailwind.css
@tailwind base;
@tailwind components;
@tailwind utilities;
# 这里可以同全局样式关联
/* src/styles/global.scss */
@tailwind base;
@tailwind components;
@tailwind utilities;
/* 这里可以添加自定义的全局样式 */
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}main.ts 中引入tailwind.css
1
2
3
4
5
6import { createApp } from 'vue'
import App from './App.vue'
import './styles/global.scss'
import './styles/tailwind.css'
createApp(App).mount('#app')测试
1
2
3
4
5<template>
<h1 class="text-3xl font-bold underline">
Hello world!
</h1>
</template>
引入Elemen-plus
导入依赖
1
2
3yarn add element-plus
按需导入
yarn add -D unplugin-vue-components unplugin-auto-import完整引入引入依赖和样式
1
2
3
4// main.ts
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
app.use(ElementPlus)按需导入: 配置插件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19// vite.config.ts
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
export default defineConfig({
// ...
plugins: [
vue(),
AutoImport({
resolvers: [ElementPlusResolver()],
}),
Components({
resolvers: [ElementPlusResolver()],
}),
],
// ...
})在
src/main.js
(或src/main.ts
)中引入 ElementPlus 的 CSS 样式:1
2
3
4
5
6
7// src/main.ts
import { createApp } from 'vue'
import App from './App.vue'
import 'element-plus/dist/index.css'
const app = createApp(App)
app.mount('#app')测试
1
2
3<template>
<el-button>click me</el-button>
</template>
引入Vue-router
添加依赖
1
yarn add vue-router
项目里引入路由,新建 router文件夹,新建index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15// src/router/index.ts
import { createRouter, createWebHistory } from 'vue-router'
import type { RouteRecordRaw } from 'vue-router'
const routes: Array<RouteRecordRaw> = [
// ...
]
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes,
})
export default routermain.ts引入
1
2
3
4
5import router from '@/router'
const app = createApp(App);
app.use(router);
app.mount('#app')一级路由写法
1
2
3
4
5
6
7
8const routes: Array<RouteRecordRaw> = [
{
path: '/',
name: 'home',
// 异步组件
component: () => import('@views/home.vue'),
},
]测试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15<script setup lang="ts">
</script>
<template>
<div>
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
<router-view></router-view>
</div>
</template>
<style scoped>
</style>
引入pinia
首先,您需要安装pinia。您可以通过npm或yarn来安装它。在终端中运行以下命令:
1
2
3npm install pinia
# 或者
yarn add pinia在您的main.ts文件中引入pinia并将其挂载到您的Vue应用程序上
1
2
3
4// main.ts
import { createPinia } from 'pinia' // 引入pinia
const app = createApp(App);
app.use(createPinia()); // 使用pinia启用数据持久化插件
1
yarn add pinia-plugin-persistedstate
main.ts
文件中导入并使用这个插件:1
2
3
4
5
6import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
const app = createApp(App);
const pinia = createPinia()
pinia.use(piniaPluginPersistedstate)
app.use(pinia); // 使用pinia编写stores
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18import { defineStore } from "pinia"
export const useStore = defineStore('user', {
state: () => {
return {
username: '张三',
age: 18,
sex: '男'
}
},
// 这是按照插件的文档,在实例上启用了该插件,这个选项是插件特有的
persist: true,
// 自定义存储
persist: {
key: 'my-user-store', // 自定义存储的键名
storage: sessionStorage // 使用 sessionStorage 而不是 localStorage
}
})1
2
3
4
5
6// 每一次变化后也会将其写入 localStorage 进行记忆存储。
setTimeout(() => {
const { username } = storeToRefs(user);
username.value = "李四";
}, 2000);可以在浏览器查看到 localStorage 的存储变化,以 Chrome 浏览器为例,按 F12 ,打开 Application 面板,选择 Local Storage ,可以看到以当前 Store ID
user
为 Key 的存储数据。
SVG图标
vite-plugin-svg-icons
是一个 Vite 插件,用于在 Vite 项目中轻松地使用 SVG 图标。它允许你将多个 SVG 文件导入为 Vue 组件,并且可以通过配置来优化 SVG 的加载和使用。
安装
vite-plugin-svg-icons
插件1
yarn add -D vite-plugin-svg-icons
配置插件: 在
vite.config.js
文件中配置vite-plugin-svg-icons
插件。1
2
3
4
5
6
7
8
9
10
11
12
13import { createSvgIconsPlugin } from 'vite-plugin-svg-icons' // 注意这里的导入方式
export default defineConfig({
plugins: [
vue(),
createSvgIconsPlugin({
// 指定需要缓存的图标文件夹
iconDirs: [resolve(process.cwd(), 'src/icons/svg')],
// 指定symbolId格式
symbolId: 'icon-[dir]-[name]'
})
]
})在 src/main.ts 中引入注册脚本
1
import 'virtual:svg-icons-register'
创建 SVG 图标组件: 在
src/components
目录下创建一个SvgIcon.vue
文件,用于渲染 SVG 图标。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34// /src/components/SvgIcon.vue
<template>
<svg class="svg-icon" aria-hidden="true">
<use :href="iconName" />
</svg>
</template>
<script setup lang="ts">
import { computed } from 'vue';
const props = defineProps({
prefix:{
type: String,
default: 'icon'
},
name: {
type: String,
required: true
}
})
const iconName = computed(() => `#${props.prefix}-${props.name}`);
</script>
<style scoped>
.svg-icon {
/* 设置 SVG 图标在垂直方向上的对齐方式。-0.15em 表示将图标向上移动 0.15em 可以使图标与文本的基线对齐*/
vertical-align: -0.15em;
/* 使用当前文本的颜色作为填充颜色 */
fill: currentColor;
/* 隐藏超出 SVG 图标边界的内容 */
overflow: hidden;
}
</style>下载SVG图标 iconfont-阿里巴巴矢量图标库
使用 SVG 图标: 在需要使用 SVG 图标的组件中,通过
<svg-icon>
标签来引用图标。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16<template>
<div>
<p class="w-1/2">This is home page</p>
<svg-icon class="float w-[2rem] h-[2rem] svg-icon-custom" name="vue" />
</div>
</template>
<script setup>
import SvgIcon from "@/components/SvgIcon.vue"; // 显式引入 SvgIcon 组件
</script>
<style lang="scss" scoped>
.svg-icon-custom {
}
</style>
在 Vue 3 中,如果你使用的是
<script setup>
语法,那么组件会自动注册,不需要显式地使用import
语句来引入组件。这是因为<script setup>
是 Vue 3.2 中引入的一个新特性,它允许你在<script>
标签中直接使用 Composition API,并且自动将所有顶级变量和函数暴露给模板。在你的代码中,
<svg-icon>
组件应该在项目定义的,并且已经被全局注册或者在当前组件的父组件中注册过了。因此,你可以直接在模板中使用<svg-icon>
组件,而不需要显式地引入它。
自动引入icon
unplugin-icons - npm 使用约定 ~icons/{collection}/{icon}
导入图标名称
图标:
下载依赖
1
2
3
4yarn add -D unplugin-icons @iconify/json
# 如果您只想使用几个图标集,而不想下载整个集合,您也可以使用 @iconify-json/[collection-id] 单独安装它们。例如,要安装 Material Design 图标,您可以执行以下操作:
npm i -D @iconify-json/mdi
# @iconify/json (~120MB) 包括 Iconify 中的所有图标集,因此您可以安装一次并根据需要使用其中任何一个(只有您实际使用的图标才会捆绑到生产版本中)。配置 Vite
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22import { defineConfig } from 'vite';
import Icons from 'unplugin-icons/vite';
import IconsResolver from 'unplugin-icons/resolver';
import Components from 'unplugin-vue-components/vite';
export default defineConfig({
plugins: [
Components({
resolvers: [
IconsResolver({
prefix: 'icon', // 图标前缀,例如 <icon-home />
enabledCollections: ['mdi'], // 启用的图标集,例如 Material Design Icons
}),
],
}),
Icons({
compiler: 'vue3', // 使用 Vue 3 编译器
autoInstall: true, // 自动安装图标集
}),
],
});配置完成后,你可以在 Vue 组件中直接使用图标。
1 | <template> |
环境变量管理
在项目根目录下创建
.env
文件,用于存放公共的环境变量;创建.env.development
和.env.production
文件,分别用于存放开发环境和生产环境的特定环境变量。使用环境变量:在代码中通过
import.meta.env
来访问环境变量。配置打包脚本:在
package.json
中配置不同环境的打包脚本,以便在不同环境下使用不同的环境变量。在
package.json
中配置不同环境的打包脚本:1
2
3
4
5
6
7
8{
"scripts": {
"serve": "vite",
"build": "vue-tsc --noEmit && vite build",
"build:dev": "vue-tsc --noEmit && vite build --mode development",
"build:prod": "vue-tsc --noEmit && vite build --mode production"
}
}
这样,在开发环境下运行
npm run serve
或npm run build:dev
时,会使用.env.development
中的环境变量;在生产环境下运行npm run build:prod
时,会使用.env.production
中的环境变量。
引入 axios
安装依赖
1
2
3
4# 使用 npm 安装
npm install axios
# 或者使用 yarn 安装
yarn add axiossrc
目录下创建一个名为 config 的文件j夹,新建request.ts 内容如下:
1 | import axios from 'axios' |
使用封装后的 Axios , 在组件中引入封装好的 request 对象,并使用其中的方法发送请求:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22<template>
<div>
<button @click="fetchData">获取数据</button>
<p v-if="data">{{ data }}</p>
</div>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import request from './http';
const data = ref('');
const fetchData = async () => {
try {
const result = await request.get<{ name: string }>('/api/data');
data.value = result.name;
} catch (error) {
console.error('请求出错:', error);
}
};
</script>
跨域问题
开发模式下可以使用代理服务器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20import { defineConfig } from 'vite';
export default defineConfig({
plugins: [react()],
server: {
proxy: {
// 配置代理规则
'/api': {
target: 'http://api.example.com',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, ''),
},
'/uploads': {
target: 'http://uploads.example.com',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/uploads/, ''),
},
},
},
});
优化打包
1 | import { defineConfig } from 'vite'; |