本篇內(nèi)容
環(huán)境搭建、依賴安裝胸竞、路由基本結(jié)構(gòu)創(chuàng)建欺嗤、界面展示、記錄遇到的問(wèn)題和解決方式
環(huán)境搭建
Node卫枝、Npm煎饼、Vue3、Vite校赤、TS吆玖、VueRouter、Element-Plus等依賴和插件安裝马篮。
Node安裝
參照官網(wǎng)安裝最新Node
使用nvm管理和安裝
(PS:mac和window對(duì)于nvm的安裝順則順沾乘,不順會(huì)很難整,給進(jìn)階者使用浑测,不建議小白硬整意鲸。)
Npm安裝鏡像
Node裝好了就自帶了,但是需要使用國(guó)內(nèi)鏡像。
npm config set registry https://registry.npm.taobao.org
順帶把yarn裝上怎顾。(yarn最大的用處就是读慎,npm有時(shí)候裝不了的它可以,算是一個(gè)補(bǔ)充優(yōu)化的包管理安裝工具槐雾。)
安裝yarn
npm install -g yarn
開(kāi)始真正創(chuàng)建項(xiàng)目
創(chuàng)建一個(gè)項(xiàng)目文件夾夭委,在目錄下初始化npm項(xiàng)目:
npm init -y
繼續(xù)安裝必要的依賴,安裝 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
如果一切順利你就可以繼續(xù)創(chuàng)建項(xiàng)目了募强,而如果不順利我大概講一下可能遇到的問(wèn)題株灸。
- npm的鏡像問(wèn)題,可以自行搜索擎值,mac可能還有權(quán)限問(wèn)題慌烧,可以搜索mac如何
開(kāi)始建立項(xiàng)目結(jié)構(gòu)
這只是當(dāng)前最簡(jiǎn)單的結(jié)構(gòu),后續(xù)還會(huì)更新鸠儿。
- src/:存放源代碼
—— assets /: 存放圖片/svg/fonts等靜態(tài)資源
—— compoments /: 公共組件等
—— router :/ 路由文件
—— styles :/ 樣式文件
—— views :/ 主要功能組件
—— App.vue
—— main.ts - index.html :/入口html
- tsconfig.json :/ typescript配置文件
- vite.config.mjs :/ vite項(xiàng)目的主要配置文件
以下是每個(gè)文件簡(jiǎn)單的結(jié)構(gòu)
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項(xiàng)目</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
tsconfig.json
{
"compilerOptions": {
"moduleResolution": "nodenext", // 或 "node" 對(duì)于較舊的 Node.js 版本
"module": "nodenext",
"target": "esnext",
"strict": true,
"jsx": "preserve",
"esModuleInterop": true,
"sourceMap": true,
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
},
"types": ["vue"] // 添加 "vue" 到 types 數(shù)組中
},
"include": [
"src/**/*.ts",
"src/**/*.tsx",
"src/**/*.vue",
"tests/**/*.ts",
"tests/**/*.tsx"
],
"exclude": [
"node_modules",
"**/*.spec.ts"
]
}
文件部分常用熟悉屬性解釋:
compilerOptions:包含編譯選項(xiàng)屹蚊。
target: 目標(biāo) JavaScript 版本,這里是 esnext进每。
module: 模塊系統(tǒng)汹粤,這里是 esnext。
lib: 應(yīng)該包含的標(biāo)準(zhǔn)庫(kù)類型聲明田晚。
allowJs: 是否允許編譯 JavaScript 文件嘱兼。
skipLibCheck: 是否跳過(guò)類型聲明文件的類型檢查。
esModuleInterop: 啟用 ES 模塊互操作性贤徒。
allowSyntheticDefaultImports: 允許從模塊默認(rèn)導(dǎo)入沒(méi)有默認(rèn)導(dǎo)出的對(duì)象芹壕。
strict: 開(kāi)啟所有嚴(yán)格的類型檢查選項(xiàng)。
forceConsistentCasingInFileNames: 強(qiáng)制在文件名中使用一致的大小寫(xiě)接奈。
noFallthroughCasesInSwitch: 禁止 switch 語(yǔ)句中的 fall-through哪雕。
moduleResolution: 模塊解析策略,這里是 node鲫趁。
resolveJsonModule: 允許導(dǎo)入 .json 文件斯嚎。
isolatedModules: 將每個(gè)文件作為一個(gè)獨(dú)立的模塊進(jìn)行編譯。
noEmit: 不生成輸出文件挨厚。
jsx: JSX 處理模式堡僻。
include:要包含在編譯過(guò)程中的文件路徑。
["src"]: 包含 src 目錄下的所有文件疫剃。
exclude:要排除在編譯過(guò)程之外的文件路徑钉疫。
["node_modules", "*/.spec.ts"]: 排除 node_modules 目錄下的所有文件和所有的測(cè)試文件。
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, // 自動(dòng)打開(kāi)瀏覽器
},
build: {
outDir: 'dist',
assetsDir: 'static',
rollupOptions: {
input: {
main: path.resolve(__dirname, 'index.html'),
},
},
},
});
文件擴(kuò)展名為 .mjs 表示它是 ES 模塊巢价,為什么要用mjs:
.mjs 文件擴(kuò)展名是專門為 ECMAScript 模塊 (ESM) 設(shè)計(jì)的牲阁。ESM 是一個(gè)較新的模塊系統(tǒng)固阁,它被設(shè)計(jì)來(lái)兼容瀏覽器和服務(wù)器端的 JavaScript 環(huán)境。使用 import 和 export 語(yǔ)句來(lái)管理依賴和導(dǎo)出城菊,ESM 支持異步加載备燃,這對(duì)于前端代碼分割和延遲加載非常有用。與 CommonJS(也就是常見(jiàn)的.js) 相比凌唬,ESM 提供了更為靜態(tài)的結(jié)構(gòu)并齐,它要求所有的 import 和 export 語(yǔ)句都位于文件的頂部,這使得 JavaScript 引擎可以在執(zhí)行代碼之前分析出整個(gè)文件的依賴結(jié)構(gòu)客税。這種靜態(tài)結(jié)構(gòu)不僅使得代碼的靜態(tài)分析和打包更有效况褪,還允許 JavaScript 引擎優(yōu)化模塊的加載時(shí)間。
文件內(nèi)容簡(jiǎn)單講解:
導(dǎo)入了一些必要的模塊:
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 主包中導(dǎo)入更耻,用于定義配置對(duì)象测垛。
vue: Vue.js 的官方 Vite 插件。
Components: 一個(gè) Vite 插件秧均,用于自動(dòng)按需引入組件食侮。
ElementPlusResolver: 用于 Components 插件來(lái)識(shí)別 Element Plus 組件。
path: Node.js 的內(nèi)置模塊熬北,用于處理文件路徑疙描。
以上有兩個(gè)模塊沒(méi)有安裝:unplugin-vue-components诚隙、vitejs/plugin-vue讶隐,自行安裝一下
npm install @vitejs/plugin-vue
npm install unplugin-vue-components
unplugin-vue-components 是一個(gè) Vue.js 的 Vite 插件,用于自動(dòng)按需引入 Vue 組件久又。它的主要目的是為了減少應(yīng)用程序的體積巫延,通過(guò)僅引入實(shí)際使用的組件,而不是整個(gè)組件庫(kù)地消。這有助于提高應(yīng)用程序的性能炉峰,特別是在使用大型 UI 庫(kù)(如 Element Plus 或 Vuetify)時(shí)。
vitejs/plugin-vue 是 Vite 構(gòu)建工具的一個(gè)官方插件脉执,用于支持 Vue.js 的開(kāi)發(fā)和構(gòu)建疼阔。這個(gè)插件提供了 Vue.js 項(xiàng)目所需的各種功能,包括 .vue 單文件組件的支持半夷、模板編譯婆廊、TypeScript 集成等。
配置項(xiàng)
export default defineConfig({
// 配置項(xiàng)
});
插件配置
plugins: [
vue(), // 使用 Vue.js 插件
Components({
resolvers: [ElementPlusResolver()], // 自動(dòng)按需引入 Element Plus 組件
}),
],
vue(): 啟用 Vue.js 支持巫橄。這會(huì)告訴 Vite 如何處理 .vue 文件淘邻,并且提供一些有用的構(gòu)建優(yōu)化。
Components: 用于按需引入 Vue 組件湘换。這里配置了 ElementPlusResolver宾舅,意味著當(dāng)你的 Vue 組件引用了 Element Plus 的組件時(shí)统阿,Vite 將自動(dòng)引入所需的樣式和腳本文件,而不是整個(gè)庫(kù)筹我。
CSS 預(yù)處理器配置
css: {
preprocessorOptions: {
scss: {
additionalData: `@import "@/styles/variables.scss";`, // 引入全局 SCSS 文件
},
},
},
scss: 配置 SCSS 預(yù)處理器扶平。這里的 additionalData 選項(xiàng)會(huì)將指定的 SCSS 文件內(nèi)容添加到所有 SCSS 文件的頭部,通常用來(lái)引入全局變量或混合宏崎溃。
開(kāi)發(fā)服務(wù)器配置
server: {
host: '0.0.0.0',
port: 5173,
strictPort: true,
open: true, // 自動(dòng)打開(kāi)瀏覽器
},
host: 開(kāi)發(fā)服務(wù)器綁定的 IP 地址蜻直。0.0.0.0 表示服務(wù)器可被任何設(shè)備訪問(wèn)。
port: 開(kāi)發(fā)服務(wù)器監(jiān)聽(tīng)的端口袁串。
strictPort: 如果指定端口已被占用概而,則 Vite 不會(huì)嘗試自動(dòng)更換端口,而是直接報(bào)錯(cuò)囱修。
open: 當(dāng)服務(wù)器啟動(dòng)時(shí)自動(dòng)在默認(rèn)瀏覽器中打開(kāi)應(yīng)用程序赎瑰。
構(gòu)建配置
build: {
outDir: 'dist',
assetsDir: 'static',
rollupOptions: {
input: {
main: path.resolve(__dirname, 'index.html'),
},
},
},
outDir: 構(gòu)建輸出的目錄。
assetsDir: 靜態(tài)資源的目錄破镰。
rollupOptions: Rollup 構(gòu)建器的配置選項(xiàng)餐曼。
input: 構(gòu)建過(guò)程中的入口文件。這里使用 __dirname 和 path.resolve 來(lái)確保正確的文件路徑鲜漩。
SO源譬!你知道上述那些文件其實(shí)主要是這邊怎么定義就得怎么命名了嗎?所以孕似!如果有問(wèn)題踩娘,你先根據(jù)這邊的定義配置好好看看你的文件名字,如果想要自定義喉祭,你也可以對(duì)應(yīng)修改即可养渴。
定義簡(jiǎn)單的布局,頭部導(dǎo)航加側(cè)邊欄泛烙。
側(cè)邊欄以動(dòng)態(tài)路由導(dǎo)航生成理卑,不要寫(xiě)死。頭部先包含logo蔽氨、搜索框藐唠、國(guó)際化、用戶信息鹉究。
先定義路由宇立,在router文件下生成index.ts文件:
(包含四個(gè)路由,其中第一個(gè)為首頁(yè)坊饶,其他為表格泄伪、表單、圖像匿级。)
// 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;
同時(shí)創(chuàng)建對(duì)應(yīng)組件蟋滴,在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>
生成頭部導(dǎo)航和側(cè)邊懶染厅,在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';
// 獲取當(dāng)前路由
const route = useRoute();
// 獲取 Vue Router 實(shí)例
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>
開(kāi)始構(gòu)建最后的幾個(gè)文件吧!
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
如果報(bào)錯(cuò)就試試yarn
yarn install
沒(méi)有報(bào)錯(cuò)就嘗試啟動(dòng):
npm run dev
如果報(bào)錯(cuò)就一步步解決吧涩馆!哈哈哈。
實(shí)在解決不了就拿來(lái)主義:我把第一階段在github上面打了一個(gè)tag允坚,你直接下下來(lái)即可魂那。完整項(xiàng)目地址:v3viteTsElement,點(diǎn)擊查看稠项。
而命令行直接干:
git clone --single-branch --depth 1 --branch tag1.0 https://github.com/RDzdf/v3viteTsElement.git
干下來(lái)后:install一下就ok涯雅,npm版本比低于9.5就成。node也不要低于20.0.
總結(jié):
寫(xiě)得有些潦草展运,估計(jì)會(huì)有很多問(wèn)題活逆,寫(xiě)多了就容易暴躁!開(kāi)始亂搞拗胜,就這樣吧蔗候!有問(wèn)題可留言,我會(huì)耐心給你們解決的埂软。