本篇内容
环境搭建、依赖安装、路由基本结构创建、界面展示、记录遇到的问题和解决方式
环境搭建
Node、Npm、Vue3、Vite、TS、VueRouter、Element-Plus等依赖和插件安装。
Node安装
参照官网安装最新Node
使用nvm管理和安装
(PS:mac和window对于nvm的安装顺则顺,不顺会很难整,给进阶者使用,不建议小白硬整。)
Npm安装镜像
Node装好了就自带了,但是需要使用国内镜像。
npm config set registry https://registry.npm.taobao.org
顺带把yarn装上。(yarn最大的用处就是,npm有时候装不了的它可以,算是一个补充优化的包管理安装工具。)
安装yarn
npm install -g yarn
开始真正创建项目
创建一个项目文件夹,在目录下初始化npm项目:
npm init -y
继续安装必要的依赖,安装 Vite:
npm install -D vite
安装 Vue 3:
npm install vue
安装 TypeScript:
npm install -D typescript
安装 Element-Plus:
npm install element-plus
安装 Vue Router:
npm install vue-router
安装 TypeScript 类型定义:
安装 Vue 和 Vue Router 的 TypeScript 类型定义:
npm install -D @types/vue @types/vue-router
如果一切顺利你就可以继续创建项目了,而如果不顺利我大概讲一下可能遇到的问题。
- npm的镜像问题,可以自行搜索,mac可能还有权限问题,可以搜索mac如何
开始建立项目结构
这只是当前最简单的结构,后续还会更新。
- src/:存放源代码
—— assets /: 存放图片/svg/fonts等静态资源
—— compoments /: 公共组件等
—— router :/ 路由文件
—— styles :/ 样式文件
—— views :/ 主要功能组件
—— App.vue
—— main.ts - index.html :/入口html
- tsconfig.json :/ typescript配置文件
- vite.config.mjs :/ vite项目的主要配置文件
以下是每个文件简单的结构
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>V3ViteTS项目</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
tsconfig.json
{
"compilerOptions": {
"moduleResolution": "nodenext", // 或 "node" 对于较旧的 Node.js 版本
"module": "nodenext",
"target": "esnext",
"strict": true,
"jsx": "preserve",
"esModuleInterop": true,
"sourceMap": true,
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
},
"types": ["vue"] // 添加 "vue" 到 types 数组中
},
"include": [
"src/**/*.ts",
"src/**/*.tsx",
"src/**/*.vue",
"tests/**/*.ts",
"tests/**/*.tsx"
],
"exclude": [
"node_modules",
"**/*.spec.ts"
]
}
文件部分常用熟悉属性解释:
compilerOptions:包含编译选项。
target: 目标 JavaScript 版本,这里是 esnext。
module: 模块系统,这里是 esnext。
lib: 应该包含的标准库类型声明。
allowJs: 是否允许编译 JavaScript 文件。
skipLibCheck: 是否跳过类型声明文件的类型检查。
esModuleInterop: 启用 ES 模块互操作性。
allowSyntheticDefaultImports: 允许从模块默认导入没有默认导出的对象。
strict: 开启所有严格的类型检查选项。
forceConsistentCasingInFileNames: 强制在文件名中使用一致的大小写。
noFallthroughCasesInSwitch: 禁止 switch 语句中的 fall-through。
moduleResolution: 模块解析策略,这里是 node。
resolveJsonModule: 允许导入 .json 文件。
isolatedModules: 将每个文件作为一个独立的模块进行编译。
noEmit: 不生成输出文件。
jsx: JSX 处理模式。
include:要包含在编译过程中的文件路径。
["src"]: 包含 src 目录下的所有文件。
exclude:要排除在编译过程之外的文件路径。
["node_modules", "*/.spec.ts"]: 排除 node_modules 目录下的所有文件和所有的测试文件。
vite.config.mjs
// vite.config.mjs
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import Components from 'unplugin-vue-components/vite';
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers';
import path from 'path';
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue(),
Components({
resolvers: [ElementPlusResolver()],
}),
],
css: {
preprocessorOptions: {
scss: {
additionalData: `@import "@/styles/variables.scss";`, // 引入全局 SCSS 文件
},
},
},
server: {
host: '0.0.0.0',
port: 5173,
strictPort: true,
open: true, // 自动打开浏览器
},
build: {
outDir: 'dist',
assetsDir: 'static',
rollupOptions: {
input: {
main: path.resolve(__dirname, 'index.html'),
},
},
},
});
文件扩展名为 .mjs 表示它是 ES 模块,为什么要用mjs:
.mjs 文件扩展名是专门为 ECMAScript 模块 (ESM) 设计的。ESM 是一个较新的模块系统,它被设计来兼容浏览器和服务器端的 JavaScript 环境。使用 import 和 export 语句来管理依赖和导出,ESM 支持异步加载,这对于前端代码分割和延迟加载非常有用。与 CommonJS(也就是常见的.js) 相比,ESM 提供了更为静态的结构,它要求所有的 import 和 export 语句都位于文件的顶部,这使得 JavaScript 引擎可以在执行代码之前分析出整个文件的依赖结构。这种静态结构不仅使得代码的静态分析和打包更有效,还允许 JavaScript 引擎优化模块的加载时间。
文件内容简单讲解:
导入了一些必要的模块:
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import Components from 'unplugin-vue-components/vite';
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers';
import path from 'path';
defineConfig: 从 Vite 主包中导入,用于定义配置对象。
vue: Vue.js 的官方 Vite 插件。
Components: 一个 Vite 插件,用于自动按需引入组件。
ElementPlusResolver: 用于 Components 插件来识别 Element Plus 组件。
path: Node.js 的内置模块,用于处理文件路径。
以上有两个模块没有安装:unplugin-vue-components、vitejs/plugin-vue,自行安装一下
npm install @vitejs/plugin-vue
npm install unplugin-vue-components
unplugin-vue-components 是一个 Vue.js 的 Vite 插件,用于自动按需引入 Vue 组件。它的主要目的是为了减少应用程序的体积,通过仅引入实际使用的组件,而不是整个组件库。这有助于提高应用程序的性能,特别是在使用大型 UI 库(如 Element Plus 或 Vuetify)时。
vitejs/plugin-vue 是 Vite 构建工具的一个官方插件,用于支持 Vue.js 的开发和构建。这个插件提供了 Vue.js 项目所需的各种功能,包括 .vue 单文件组件的支持、模板编译、TypeScript 集成等。
配置项
export default defineConfig({
// 配置项
});
插件配置
plugins: [
vue(), // 使用 Vue.js 插件
Components({
resolvers: [ElementPlusResolver()], // 自动按需引入 Element Plus 组件
}),
],
vue(): 启用 Vue.js 支持。这会告诉 Vite 如何处理 .vue 文件,并且提供一些有用的构建优化。
Components: 用于按需引入 Vue 组件。这里配置了 ElementPlusResolver,意味着当你的 Vue 组件引用了 Element Plus 的组件时,Vite 将自动引入所需的样式和脚本文件,而不是整个库。
CSS 预处理器配置
css: {
preprocessorOptions: {
scss: {
additionalData: `@import "@/styles/variables.scss";`, // 引入全局 SCSS 文件
},
},
},
scss: 配置 SCSS 预处理器。这里的 additionalData 选项会将指定的 SCSS 文件内容添加到所有 SCSS 文件的头部,通常用来引入全局变量或混合宏。
开发服务器配置
server: {
host: '0.0.0.0',
port: 5173,
strictPort: true,
open: true, // 自动打开浏览器
},
host: 开发服务器绑定的 IP 地址。0.0.0.0 表示服务器可被任何设备访问。
port: 开发服务器监听的端口。
strictPort: 如果指定端口已被占用,则 Vite 不会尝试自动更换端口,而是直接报错。
open: 当服务器启动时自动在默认浏览器中打开应用程序。
构建配置
build: {
outDir: 'dist',
assetsDir: 'static',
rollupOptions: {
input: {
main: path.resolve(__dirname, 'index.html'),
},
},
},
outDir: 构建输出的目录。
assetsDir: 静态资源的目录。
rollupOptions: Rollup 构建器的配置选项。
input: 构建过程中的入口文件。这里使用 __dirname 和 path.resolve 来确保正确的文件路径。
SO!你知道上述那些文件其实主要是这边怎么定义就得怎么命名了吗?所以!如果有问题,你先根据这边的定义配置好好看看你的文件名字,如果想要自定义,你也可以对应修改即可。
定义简单的布局,头部导航加侧边栏。
侧边栏以动态路由导航生成,不要写死。头部先包含logo、搜索框、国际化、用户信息。
先定义路由,在router文件下生成index.ts文件:
(包含四个路由,其中第一个为首页,其他为表格、表单、图像。)
// router/index.ts
import { createRouter, createWebHistory } from 'vue-router';
import Home from '../views/Home.vue';
const routes = [
{
path: '/',
name: 'Home',
component: Home,
meta: {
title: 'Home',
icon: 'el-icon-s-home'
}
},
{
path: '/table',
name: 'About',
component: () => import('../views/tables/index.vue'),
meta: {
title: 'About',
icon: 'el-icon-user-solid'
}
},
{
path: '/form',
name: 'Form',
component: () => import('../views/form/index.vue'),
meta: {
title: 'Form',
icon: 'el-icon-user-solid'
}
},
{
path: '/chart',
name: 'Chart',
component: () => import('../views/chart/index.vue'),
meta: {
title: 'Chart',
icon: 'el-icon-user-solid'
}
},
];
const router = createRouter({
history: createWebHistory(),
routes,
});
export default router;
同时创建对应组件,在views目录下:
- views
——chart
————index.vue
——tables
————index.vue
——form
————index.vue
chart/index.vue
<template>
<div>
<h1>图表</h1>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
export default defineComponent({
name: 'ChartView',
});
</script>
tables/index.vue
<template>
<div>
<h1>表格</h1>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
export default defineComponent({
name: 'TablesView',
});
</script>
form/index.vue
<template>
<div>
<h1>表单</h1>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
export default defineComponent({
name: 'FormView',
});
</script>
生成头部导航和侧边懒,在src/components下生成Header.vue、Label.vue、Sidebar.vue、SidebarItem.vue
Header.vue
<template>
<div class="header">
<el-row type="flex" justify="space-between" align="middle">
<el-col :span="6">
<el-link href="/" type="primary">Logo</el-link>
</el-col>
<el-col :span="12">
<el-input placeholder="Search" prefix-icon="el-icon-search" v-model="searchInput"></el-input>
</el-col>
<el-col :span="6" class="right-section">
<el-link @click="toggleLang">{{ lang }}</el-link>
<el-dropdown trigger="click">
<span class="el-dropdown-link">
User Info<i class="el-icon-arrow-down el-icon--right"></i>
</span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item>Profile</el-dropdown-item>
<el-dropdown-item>Settings</el-dropdown-item>
<el-dropdown-item divided @click="logout">Logout</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</el-col>
</el-row>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
const searchInput = ref('');
const lang = ref('EN');
const toggleLang = () => {
lang.value = lang.value === 'EN' ? 'CN' : 'EN';
};
const logout = () => {
console.log('User logged out');
};
</script>
<style scoped>
.header {
background-color: #f0f0f0;
padding: 10px;
}
.right-section {
display: flex;
justify-content: flex-end;
}
.el-dropdown-link {
cursor: pointer;
color: #409eff;
}
</style>
</script>
<style scoped>
.header {
background-color: #f0f0f0;
padding: 10px;
}
.right-section {
display: flex;
justify-content: flex-end;
}
.el-dropdown-link {
cursor: pointer;
color: #409eff;
}
</style>
Label.vue
<template>
<div id="app">
<Header />
<el-container>
<el-aside width="200px">
<Sidebar />
</el-aside>
<el-main>
<router-view />
</el-main>
</el-container>
</div>
</template>
<script lang="ts">
import Header from './Header.vue';
import Sidebar from './Sidebar.vue';
export default {
components: {
Header,
Sidebar,
},
};
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
}
</style>
Sidebar.vue
<template>
<el-menu
:default-active="$route.path"
class="el-menu-vertical-demo"
mode="vertical"
unique-opened
router
background-color="#545c64"
text-color="#fff"
active-text-color="#ffd04b"
>
<sidebar-item
v-for="route in routes"
:key="route.name"
:route="route"
/>
</el-menu>
</template>
<script setup lang="ts">
import { useRoute, useRouter } from 'vue-router';
import SidebarItem from './SidebarItem.vue';
// 获取当前路由
const route = useRoute();
// 获取 Vue Router 实例
const router = useRouter();
// 获取所有路由信息
const routes = router.getRoutes().filter(route => {
return route.meta && route.meta.title;
});
</script>
SidebarItem.vue
<template>
<li v-if="!route.children || !route.children.length">
<el-menu-item :index="route.path" :key="route.name">
<i :class="route.meta.icon"></i>
<span slot="title">{{ route.meta.title }}</span>
</el-menu-item>
</li>
<li v-else>
<el-sub-menu :index="route.path" :key="route.name">
<template #title>
<i :class="route.meta.icon"></i>
<span>{{ route.meta.title }}</span>
</template>
<sidebar-item
v-for="child in route.children"
:key="child.name"
:route="child"
/>
</el-sub-menu>
</li>
</template>
<script setup lang="ts">
defineProps({
route: {
type: Object,
required: true
}
});
</script>
开始构建最后的几个文件吧!
App.vue
// App.vue
<template>
<Layout />
</template>
<script setup lang="ts">
import Layout from './components/Layout.vue';
</script>
*main.ts
// main.ts
import { createApp } from 'vue';
import App from './App.vue';
import router from './router';
import ElementPlus from 'element-plus';
import 'element-plus/dist/index.css'; // 引入 Element Plus 的样式
const app = createApp(App);
app.use(ElementPlus);
app.use(router);
app.mount('#app');
大功告成、最后一步:
再安装一下依赖:
npm install
如果报错就试试yarn
yarn install
没有报错就尝试启动:
npm run dev
如果报错就一步步解决吧!哈哈哈。
实在解决不了就拿来主义:我把第一阶段在github上面打了一个tag,你直接下下来即可。完整项目地址:v3viteTsElement,点击查看。
而命令行直接干:
git clone --single-branch --depth 1 --branch tag1.0 https://github.com/RDzdf/v3viteTsElement.git
干下来后:install一下就ok,npm版本比低于9.5就成。node也不要低于20.0.
总结:
写得有些潦草,估计会有很多问题,写多了就容易暴躁!开始乱搞,就这样吧!有问题可留言,我会耐心给你们解决的。