通过Vite创建项目
-
- 全局安装vite
npm install -g vite@latest
![](https://i-blog.csdnimg.cn/blog_migrate/cb03ae152fdfb1cb7ee4cab5ad9c4d89.png)
老的版本可以根据需求更新版本
$ npm install -g npm
-
- 创建项目
在指定的目录下打开控制台,使用vite创建项目
![](https://i-blog.csdnimg.cn/blog_migrate/ea4071c3808b6a4428b9d07a1c4f445c.png)
![](https://i-blog.csdnimg.cn/blog_migrate/23a0852ad1af3b6ddf6a8299a0581f27.png)
-
- 在vsc打开项目
![](https://i-blog.csdnimg.cn/blog_migrate/9bb84058fed4bfd7217a8b4bbbd41458.png)
.svg里面存放的是logo;
assets >vue.svg一般用不上,可以根据个人需求决定是否删除
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="37.07" height="36" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 198"><path fill="#41B883" d="M204.8 0H256L128 220.8L0 0h97.92L128 51.2L157.44 0h47.36Z"></path><path fill="#41B883" d="m0 0l128 220.8L256 0h-51.2L128 132.48L50.56 0H0Z"></path><path fill="#35495E" d="M50.56 0L128 133.12L204.8 0h-47.36L128 51.2L97.92 0H50.56Z"></path></svg>
components>HelloWorld.vue是组件,根据个人需求删除
<script setup lang="ts">
import { ref } from 'vue'
defineProps<{ msg: string }>()
const count = ref(0)
</script>
<template>
<h1>{{ msg }}</h1>
<div class="card">
<button type="button" @click="count++">count is {{ count }}</button>
<p>
Edit
<code>components/HelloWorld.vue</code> to test HMR
</p>
</div>
<p>
Check out
<a href="https://vuejs.org/guide/quick-start.html#local" target="_blank"
>create-vue</a
>, the official Vue + Vite starter
</p>
<p>
Install
<a href="https://github.com/johnsoncodehk/volar" target="_blank">Volar</a>
in your IDE for a better DX
</p>
<p class="read-the-docs">Click on the Vite and Vue logos to learn more</p>
</template>
<style scoped>
.read-the-docs {
color: #888;
}
</style>
App.vue内代码
作用导入组件,组件文件存在可用,组件文件不存咋不可用
import HelloWorld from './components/HelloWorld.vue'
下面两段代码可删除
<div>
<a href="https://vitejs.dev" target="_blank">
<img src="/vite.svg" class="logo" alt="Vite logo" />
</a>
<a href="https://vuejs.org/" target="_blank">
<img src="./assets/vue.svg" class="logo vue" alt="Vue logo" />
</a>
</div>
<HelloWorld msg="Vite + Vue" />
.logo {
height: 6em;
padding: 1.5em;
will-change: filter;
}
.logo:hover {
filter: drop-shadow(0 0 2em #646cffaa);
}
.logo.vue:hover {
filter: drop-shadow(0 0 2em #42b883aa);
}
原文件内容:
<script setup lang="ts">
import HelloWorld from './components/HelloWorld.vue'
</script>
<template>
<div>
<a href="https://vitejs.dev" target="_blank">
<img src="/vite.svg" class="logo" alt="Vite logo" />
</a>
<a href="https://vuejs.org/" target="_blank">
<img src="./assets/vue.svg" class="logo vue" alt="Vue logo" />
</a>
</div>
<HelloWorld msg="Vite + Vue" />
</template>
<style scoped>
.logo {
height: 6em;
padding: 1.5em;
will-change: filter;
}
.logo:hover {
filter: drop-shadow(0 0 2em #646cffaa);
}
.logo.vue:hover {
filter: drop-shadow(0 0 2em #42b883aa);
}
</style>
现文件内容:
<template>
<div>你好笑脸</div>
</template>
<script setup lang="ts">
</script>
<style scoped>
</style>
main.ts导入样式, 可以根据个人需求决定是否删除;这样style.css样式也可以根据个人需求
import './style.css'
![](https://i-blog.csdnimg.cn/blog_migrate/1aebbdf52bc2f32de3f4bdc56fc5d007.png)
readme 也可删除
package安装依赖 在控制台输入代码
npm install
安装成功 node里的就是依赖模块
![](https://i-blog.csdnimg.cn/blog_migrate/6c67e7f33760bf84dd573c86d60a9f2b.png)
![](https://i-blog.csdnimg.cn/blog_migrate/e5eab5e1bc89ce787c7177774b8c484d.png)
运行 会出现一个网址,点击网址会出现网页内容,也就是App.vue里的内容
npm run dev
![](https://i-blog.csdnimg.cn/blog_migrate/c5fd7e2df84aafd48af36f8f06baad87.png)
![](https://i-blog.csdnimg.cn/blog_migrate/b0c2d480e5db6b0eb16c70fcf77727d5.png)
![](https://i-blog.csdnimg.cn/blog_migrate/9b446fbb24257be6e923ef2ebfde7f5b.png)
根据个人需求来添加内容
![](https://i-blog.csdnimg.cn/blog_migrate/9aa033db0191a812a097a5f418abab88.png)
添加组件引用外部组件
![](https://i-blog.csdnimg.cn/blog_migrate/e0c6b1606215a253487bb5782db1afd8.png)
![](https://i-blog.csdnimg.cn/blog_migrate/de87f3c4c64184d2cf54a6126b23727b.png)
![](https://i-blog.csdnimg.cn/blog_migrate/b921bb6409a0423b1fee9ed6632bc21a.png)
![](https://i-blog.csdnimg.cn/blog_migrate/fba3329f5cbdf36112811217f1a57290.png)
vue项目使用
-
- 生命周期钩子
onmounted 回调函数
![](https://i-blog.csdnimg.cn/blog_migrate/eb91fed6f5cbbe95853848382f05d698.png)
-
- vue Route
安装route组件
npm install vue-router@4
![](https://i-blog.csdnimg.cn/blog_migrate/9adc9b3e03ae7af86dd09780bdcfadbf.png)
新建route>index.ts文件
import { createRouter, createWebHashHistory,createWebHistory} from "vue-router";
const routes = [
//定义路由
{
path: '/login',
//导入组件
component: () => import("../views/Login.vue")
},
{
path: '/',
component: () => import("../views/home.vue")
}
]
const router = createRouter({
// history: createWebHashHistory('/'),
history: createWebHistory(),
routes
})
//导出路由
export default router
![](https://i-blog.csdnimg.cn/blog_migrate/c083ee423f97b76925e0e8cdb0f56784.png)
在App.vue 添加导航,并使用router-view
<template>
//导航
<router-link to="/" >首页</router-link> <br/>
<RouterLink to="/login">登录页面</RouterLink>
<hr/>
<router-view></router-view>
</template>
<script setup lang="ts">
import { ref,onMounted } from 'vue'
onMounted(()=>{
})
</script>
<style scoped>
</style>
![](https://i-blog.csdnimg.cn/blog_migrate/e0f0982877d73ab050b6988625f9db48.png)
创建路由
-
通过url 路由实现
![](https://i-blog.csdnimg.cn/blog_migrate/9344c469cbe4c419ad13172634d2958e.png)
-
利用锚点技术实现
![](https://i-blog.csdnimg.cn/blog_migrate/35e236210b4ec24843ced08fa68a2bc4.png)
创建登陆页面
新建文件views>login.vue/home.vue
![](https://i-blog.csdnimg.cn/blog_migrate/a024da68d86da6f64362133efcfed922.png)
运行
npm run dev
![](https://i-blog.csdnimg.cn/blog_migrate/1adf8fe78baf7975ae4e61aaf593c325.png)
![](https://i-blog.csdnimg.cn/blog_migrate/e63adce6ebf4a2c79c4178c8fa684972.png)
![](https://i-blog.csdnimg.cn/blog_migrate/76a5237e51ad845ab57e98560703c182.png)
新建商品页面
新建商品页面文件 views>Product.vue
![](https://i-blog.csdnimg.cn/blog_migrate/29bb65c62c837c22877c73760ee11a61.png)
定义路由
![](https://i-blog.csdnimg.cn/blog_migrate/4020e558566c4ba295155f7fc52d92a8.png)
添加导航
![](https://i-blog.csdnimg.cn/blog_migrate/428f6cef16fad6298da402390b33bd7f.png)
运行
![](https://i-blog.csdnimg.cn/blog_migrate/509162263f0b43debda0eff3ca7ae73b.png)
![](https://i-blog.csdnimg.cn/blog_migrate/4bca23500e24cec2061f44ac4ede00fe.png)
-
- 使用@别名
-
- 安装
npm install @types/node --save-dev
![](https://i-blog.csdnimg.cn/blog_migrate/3f6d54a97cd0b2912caf30d6c60e30b0.png)
-
- 在vite.config.ts里面配置resolve
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from "path";
export default defineConfig({
plugins: [vue()],
server: {
port: 2023, // 你需要定义的端口号
}
resolve: {
// 配置路径别名
alias: {
'@': path.resolve(__dirname, './src'),
}
},
})
-
- 若与标红问题和红波浪
-
在tsconfig.node.json文件中
添加"allowSyntheticDefaultImports": true
-
在tsconfig.json 添加如下代码.
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
}
-
- 运行
![](https://i-blog.csdnimg.cn/blog_migrate/b846b36d97f6ecdd5fb961b64a8c9b20.png)
@/ 相当于项目根目录 /src/ 则定义的路由也可以直接使用
![](https://i-blog.csdnimg.cn/blog_migrate/77299e0a2820204a58892855f15a58c2.png)
-
- 使用Element Plus
-
- 安装
npm install element-plus --save
-
- 全局安装图标
npm install @element-plus/icons-vue
![](https://i-blog.csdnimg.cn/blog_migrate/2503b92fe7e50de44cd532814819fd33.png)
-
- 在main.ts导入使用Element Plus插件
import { createApp } from 'vue'
//加入路由
import router from '@/route/index'
//使用ElementPlus插件
import ElementPlus from 'element-plus'
//引用ElemenPlus 样式
import 'element-plus/dist/index.css'
//使用ElementPlus 图标
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
import App from '@/App.vue'
const app = createApp(App)
//全局注入element图标,以后可以直接使用所有图标
for (const [key,component]of Object.entries(ElementPlusIconsVue)){
app.component(key,component)
}
//并通过use,使用路由
app.use(router)
app.use(ElementPlus)//使用ElementPlus 插件
app.mount('#app')
![](https://i-blog.csdnimg.cn/blog_migrate/b15e104c44de0f739172151c0b60cc8a.png)
![](https://i-blog.csdnimg.cn/blog_migrate/dc2e0081b36f027bd1d9e77bd985d7f8.png)
-
- 菜单功能实现
![](https://i-blog.csdnimg.cn/blog_migrate/fcd4a3d6591bfab5f04653cfde9fa1b6.png)
![](https://i-blog.csdnimg.cn/blog_migrate/95a0865b7efb9da03c668c424c5ed393.png)
![](https://i-blog.csdnimg.cn/blog_migrate/ae1c1002abbd342891987f39a4c0ae7d.png)
![](https://i-blog.csdnimg.cn/blog_migrate/73d92a5046fd819f920d49ff9fe7e286.png)
menu.vue
<template>
<!-- 显示ts里变量值内容 -->
<!-- {{msg}} -->
<!-- 显示路由 -->
<!-- {{$router.options.routes}} -->
<el-menu active-text-color="#ffd04b" background-color="#545c64" class="el-menu-vertical-demo" default-active="/"
text-color="#fff" :router="true">
<!-- :router="true" 启用路由功能 ,默认是false ; default-active="2"指默认加载项-->
<template v-for="(item, index) in $router.options.routes">
<!-- {{ item }} -->
<el-menu-item :index="item.path" v-if="item.children == null">
<component :is="item.meta.icon" class="menuIcon"></component>
<span>{{ item.meta.title }}</span>
</el-menu-item>
<el-sub-menu :index="item.path" v-if="item.children != null">
<template #title>
<component :is="item.meta.icon" class="menuIcon"></component>
<span>{{ item.meta.title}}</span>
</template>
<template v-for="(item2, indx) in item.children">
<el-menu-item :index="item2.path">
<component :is="item2.meta.icon" class="menuIcon"></component>
{{item2.meta.title}}</el-menu-item>
</template>
</el-sub-menu>
</template>
</el-menu>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
const msg = ref('新年好')
// msg.value="hello"
// console.log(msg.value)
</script>
<style scoped>
* {
list-style: none;
}
.menuIcon {
width: 16px;
height: 16px;
padding-right: 5px;
}
.ym {
/* margin: 24px; */
color: black;
cursor: pointer;
display: flex;
padding-left: 20px;
text-decoration: none;
}
</style>
index.ts
import { createRouter, createWebHashHistory, createWebHistory } from "vue-router";
const routes = [
//定义路由
{
path: '/',
component: () => import("@/views/Home.vue"),
meta: { title: "首页", icon: "HomeFilled" ,show:true }
},
{
path: '/product',
component: () => import("@/views/Product/index.vue"),
meta: { title: "功能管理", icon: "Setting" ,show:true },
children:[
{
path: '/product/Add',
component: () => import("@/views/Product/Add.vue"),
meta: { title: "添加商品", icon: "HomeFilled" ,show:true }
},
{
path: '/product/List',
component: () => import("@/views/Product/List.vue"),
meta: { title: "商品列表", icon: "Operation" ,show:true }
}]
},
]
//创建路由
const router = createRouter({
// history: createWebHashHistory('/'),
history: createWebHistory(),
routes
})
//导出路由
export default router
菜单功能优化
折叠
![](https://i-blog.csdnimg.cn/blog_migrate/3142e5b0d24595226c0995b734f9306c.png)
![](https://i-blog.csdnimg.cn/blog_migrate/fc23b27f133f201a8ba0b98fa074644a.png)
![](https://i-blog.csdnimg.cn/blog_migrate/f4ec796baf387989333861f9df45446a.png)
![](https://i-blog.csdnimg.cn/blog_migrate/1988dd0f457067aceb792d6c93e9c26e.png)
![](https://i-blog.csdnimg.cn/blog_migrate/c00f0a11cf90ec94916ace102a10c5f8.png)
![](https://i-blog.csdnimg.cn/blog_migrate/298682aeb55ca3ae8ee30baaa8b199f4.png)
按钮折叠
![](https://i-blog.csdnimg.cn/blog_migrate/d6e5a3ef78370e65c4fca3b2abe73e1e.png)
![](https://i-blog.csdnimg.cn/blog_migrate/31b64a9e32514944c9e4a94f824b5ee4.png)
或者图标折叠
![](https://i-blog.csdnimg.cn/blog_migrate/cd61f918b16feebbde989175444c1316.png)
![](https://i-blog.csdnimg.cn/blog_migrate/3dd00267432990e04b606eb72a05fbc9.png)
交替显示折叠
![](https://i-blog.csdnimg.cn/blog_migrate/6b5b07dc0cd072498701ba52b309292b.png)
![](https://i-blog.csdnimg.cn/blog_migrate/e3012f41b096e9c53ac99418c4677fac.png)
![](https://i-blog.csdnimg.cn/blog_migrate/6e6a1b2b79a8ce39030a555ff81786e7.png)
![](https://i-blog.csdnimg.cn/blog_migrate/8735f41578fe336645564f334391967b.png)
前后端交互
axios安装使用
官网
axios中文文档|axios中文网 | axios (axios-js.com)
安装
npm install axios
![](https://i-blog.csdnimg.cn/blog_migrate/d35223586fd4d3fd28359cfc37f7a1fe.png)
Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。
如果使用需新建文件并进行封装
import axios, {
AxiosRequestConfig,
AxiosRequestHeaders,
AxiosResponse,
} from "axios";
import { ElMessage, ElLoading } from "element-plus";
// import { storeToRefs } from "pinia";
// import {appStore} from "@/store/appStore";
// let { token } = storeToRefs(appStore());
const state = {
ok: 0,//请求成功状态码
401: "ERR_BAD_REQUEST"
};
//返回数据规则
interface IResponseData<T> {
status: number;
message?: string;
data: T;
code: string;
}
//请求默认配置规则
type TOption = {
baseURL: string;
timeout: number;
};
//默认配置
const config = {
baseURL: "",
timeout: 30 * 1000,
withCredentials: true,
};
let loading: any = null;
class Http {
service: any;
constructor(config: TOption) {
//实例化请求配置
this.service = axios.create(config);
//请求拦截
this.service.interceptors.request.use(
(config: AxiosRequestConfig) => {
loading = ElLoading.service({ fullscreen: true, text: '加载中...' });
// if (token.value) {
// (config.headers as AxiosRequestHeaders).Authorization = token.value;
// }
return config;
},
(error: any) => {
loading.close();
return Promise.reject(error);
}
);
//响应拦截
this.service.interceptors.response.use(
(response: AxiosResponse) => {
loading.close();
const data = response.data;
const { code } = data;
if (code == undefined) {
//如果没有返回状态码,直接返回数据,针对于返回数据为blob类型
return response;
} else if (code !== 0) {
ElMessage.error(data.message);
return Promise.reject(data);
}
// code == 0 的时候,提取我们只关注的Api数据data
// console.log(response);
return response.data.data;
},
(error: any) => {
loading.close();
if (error.code === state[401]) {
ElMessage.error("请求失败:" + error.message);
setTimeout(() => {
localStorage.removeItem('com.beiyou')
window.location.href = '/#/login'
}, 1000);
}
return Promise.reject(error);
}
);
}
get<T>(url: string, params?: object, data = {}): Promise<IResponseData<T>> {
return this.service.get(url, { params, ...data });
}
post<T>(url: string, params?: object, data = {}): Promise<IResponseData<T>> {
return this.service.post(url, params, data);
}
put<T>(url: string, params?: object, data = {}): Promise<IResponseData<T>> {
return this.service.put(url, params, data);
}
delete<T>(
url: string,
params?: object,
data = {}
): Promise<IResponseData<T>> {
return this.service.delete(url, { params, ...data });
}
}
export default new Http(config);