Vue--》从零开始打造交互体验一流的电商平台(一)

今天开始使用 vue3 + ts 搭建一个电商项目平台,因为文章会将项目的每处代码的书写都会讲解到,所以本项目会分成好几篇文章进行讲解,我会在最后一篇文章中会将项目代码开源到我的github上,大家可以自行去进行下载运行,希望本文章对有帮助的朋友们能多多关注本专栏,学习更多前端vue知识,然后开篇先简单介绍一下本项目用到的技术栈都有哪几个方面(阅读本文章能够学习到的技术):

vite:快速轻量且功能丰富的前端构建工具,帮助开发人员更高效构建现代Web应用程序。

pnpm:高性能、轻量级npm替代品,帮助开发人员更加高效地处理应用程序的依赖关系。

vue3:vue最新版本的用于构建用户界面的渐进式JavaScript框架。

typescript:javascript的超集,提供了静态类型检查,使得代码更加健壮。

vue-router:Vue.js官方提供的路由管理器与Vue.js紧密耦合,非常方便与Vue.js一同使用。

pinia:vue3构建的Vuex替代品,具有响应式能力,提供非常简单的 API,进行状态管理。

element-plus:基于Vue.js 3.0的UI组件库,用于构建高品质的响应式Web应用程序。

axios:基于Promise的HTTP客户端,可以在浏览器和node.js中使用。

@vueuse/core:针对vue3功能性的API库,提供了许多实用的功能。

当然还有许多其他的需要安装的第三方库,这里就不再一一介绍了,在项目中用到的地方自行会进行讲解,大家自行学习即可,现在就让我们走进vue3+ts的实战项目吧。

目录

初始化项目

包管理工具

src别名配置

重置默认样式

配置elementPlus

自定义全局样式

axios基础配置

API接口统一管理

全局组件封装

路由配置管理

store仓库配置

git管理配置


初始化项目

找到自己想要创建项目的文件夹,在地址栏输入cmd,从而进入当前文件路径,在当前路径下执行如下命令,使用vite构建工具进行创建vue3项目,具体的操作这里就不再赘述,不了解 vite 构建工具的朋友可以先去看 vite脚手架的搭建与使用 ,因为我这里使用 vite3 版本,其安装命令如下:

我这里就使用 pnpm 进行安装项目了,没有安装过pnpm的朋友,cmd进行全局安装即可,命令为:npm i -g pnpm 。

pnpm create vite

安装过程与我上面分享的文章基本一致,cd到项目路径安装下依赖,最后的结果如下表明创建项目成功:

然后将项目文件拖到编辑器中,打开终端执行 pnpm run dev 打开项目,结果如下:

包管理工具

团队开发项目的时候,需要统一包管理器工具,因为不同包管理器工具下载同一个依赖,可能版本不一样,导致项目出现bug问题,因此包管理器工具需要统一管理! 只需在 package.json 中加入一行代码来限制,如下含义:只允许使用 pnpm 来进行安装

"scripts": {// ... 其他命令"preinstall": "npx only-allow pnpm"}

直接将上面的代码复制如下,preinstall 是包安装工具的 钩子函数,在上例中作为 install 之前的拦截判断,也就是在 install 之前触发:

配置完成之后,当你使用的不是pnpm命令之后,控制台直接报错警告:

src别名配置

在开发项目的时候文件与文件关系可能很复杂,因此我们需要给src文件夹配置一个别名!在创建的项目中找到 vite.config.ts 配置文件,配置如下命令:

// vite.config.ts
import {defineConfig} from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path'
export default defineConfig({plugins: [vue()],resolve: {alias: {"@": path.resolve(__dirname, 'src') // 相对路径别名配置,使用 @ 代替 src}}
})

如果红色语法提示请安装 @type/node 其是TypeScript 的一个文件包,用于描述 Node.js 核心模块和常用的第三方库的类型信息,需要终端执行如下命令才能解决下图的警告:

pnpm i @types/node --save-dev

找到 tsconfig.json 配置文件,找到配置项 compilerOptions 添加配置,这一步的作用是让 IDE 可以对路径进行智能提示:

// tsconfig.json
{"compilerOptions": {"baseUrl": ".", // 解析非相对模块的基地址,默认是当前目录"paths": { //路径映射,相对于baseUrl"@/*": ["src/*"] }}
}

验证我们是否配置成功?我们可以在main.js入口文件处进行校验,如果有提示说明配置成功!

重置默认样式

在项目中我们都会用到一些标签,但是这些标签可能本身自带一些默认样式,这些默认样式可能会影响我们的排版布局,如果每次引用就去清除一遍默认样式有点太过繁琐,因此这里需要我们清除一下默认样式。执行如下命令安装第三方包: 

pnpm install reset.css --save

安装完成之后,我们在入口文件处进行引入即可,如下:

配置elementPlus

因为本项目需要采用 element-plus 组件库进行创建项目,其官方地址为:element-plus ,所以接下来需要对组件库进行一个安装配置,具体的实现过程如下,终端执行如下安装命令: 

pnpm install element-plus

这里我们采用自动按需导入的方式,如下需要安装两个插件:

pnpm install unplugin-auto-import unplugin-vue-components -D 

因为我们可以还需要用到elementplus中的图标,所以这里也采用自动导入的方式:

pnpm install unplugin-icons -D

因为本次使用的是vite + ts的模板,所以我们需要对下面文件进行如下操作修改:

// vite.config.ts
import {defineConfig} from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path'
// 配置按需导入
import Icons from 'unplugin-icons/vite'
import IconsResolver from 'unplugin-icons/resolver'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'const pathSrc = path.resolve(__dirname, 'src')export default defineConfig({plugins: [vue(),AutoImport({// 自动导入 Element Plus 相关函数,如:ElMessage, ElMessageBox... (带样式)resolvers: [ElementPlusResolver(),// 自动导入图标组件IconsResolver({}),],}),Components({resolvers: [// 自动注册图标组件IconsResolver({enabledCollections: ['ep'],}),// 自动导入 Element Plus 组件ElementPlusResolver(),],}),Icons({autoInstall: true,}),],resolve: {alias: {"@": pathSrc // 相对路径别名配置,使用 @ 代替 src}}
})

接下来我们直接在项目中引入一个button组件,尝试一下,如下说明我们自动按需引入成功!

接下来我们需要对elementPlus进行一个主题色的配置,这里我们采用sass样式系统,sass是一种预编译的css,作用类似于less,这里我们在vue项目中采用该预处理器进行处理样式,终端执行如下命令安装相应的插件: 

pnpm install sass -D

接下来在src目录下新建styles文件夹用于存放全局样式组件,该文件夹下新建element.scss文件,设置定制化样式,如下:

@forward 'element-plus/theme-chalk/src/common/var.scss' with ($colors: ('primary': (// 主色'base': #f94417,),'success': (// 成功色'base': #f72f18,),'warning': (// 警告色'base': #fd5e1d,),'danger': (// 危险色'base': #e26237,),'error': (// 错误色'base': #cf4444,),)
)

然后我们需要在vite.config.ts文件夹下修改下面两处的内容:

回到页面可以看到我们的主题色已经生效了:

因为elementPlus默认是英文的,接下来我们还需要对其设置一下国际化配置,打开main.ys入口文件,进行如下配置:

import { createApp } from 'vue'
import 'reset.css'
import App from './App.vue'
// 配置国际化
import ElementPlus from 'element-plus'
import zhCn from 'element-plus/es/locale/lang/zh-cn'createApp(App).use(ElementPlus, { locale: zhCn }).mount('#app')

接下来我们引入一个分页器,看看是否变成中文了,如下看来是没毛病了!

自定义全局样式

在项目里一些组件共享的色值会以scss变量的方式统一放到一个名为var.scss的文件中,正常组件中使用,需要先导入scss文件,再使用内部的变量,比较繁琐,自动导入可以免去手动导入的步骤,直接使用内部的变量,如下:

我们在公共样式文件夹styles中新增一个var.scss文件,里面存放着全局公共样式:

然后我们在vite.config.ts中进行引入该文件夹:

可以看到我们的样式已经生效了!

axios基础配置

axios是一个基于promise的http客户端,用于浏览器和node.js环境中发起http请求。它提供了简单易用的api,可以用于执行各种类型的http请求,包括get、post、put、delete等。接下来对其进行简单的配置讲解:

终端执行如下命令进行安装axios:

pnpm install axios

然后我们在src文件夹下新建utils工具文件夹,在该文件夹下新建http.ts文件对axios进行二次封装

目的

使用请求拦截器,可以在请求拦截器中处理一些业务(开始进度条、请求头携带公共参数)

使用响应拦截器,可以在响应拦截器中处理一些业务(进度条结束、简化服务器返回的数据、处理http网络错误)

// axios基础封装
import axios from 'axios'const http = axios.create({baseURL: '服务器接口根地址',timeout: 5000,
})// 请求拦截器
http.interceptors.request.use(config => {// 请求拦截器return config
}, error => {return Promise.reject(error)
})// 响应拦截器
http.interceptors.response.use(res => {return res.data
},  error => {//处理网络错误let msg = ''const status = error.response.statusswitch (status) {case 401:msg = 'token过期'breakcase 403:msg = '无权访问'breakcase 404:msg = '请求地址错误'breakcase 500:msg = '服务器出现问题'breakdefault:msg = '网络出现问题'break}ElMessage({type: 'error',message: msg,})return Promise.reject(error)}
)export default http

因为我们是自动按需导入,所以不需要像以前那样用到elementPlus组件还需要导入,这里直接使用相关api即可,不过可能ts文件会检索 ElMessage 不存在,会报错,这里我们需要在tsconfig.json中的include字段中添加auto-imports.d.ts就可以了:

"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue", "auto-imports.d.ts",],

接下来开始对我们封装的axios进行相关测试,我们在入口文件main.ts进行接口测试:

打开控制台可以看到我们的接口数据已经请求成功了!

这里我们把接口地址故意写错试试,可以看到如下的效果,还不错!

API接口统一管理

在开发项目的时候,接口可能很多需要统一管理。在src目录下去创建api文件夹去统一管理项目的接口:

统一管理我们项目用户的相关接口

// 统一管理我们项目用户的相关接口
import http from '@/utils/http'
import type { loginForm, loginResponseData, userResponseData } from './type'
// 统一管理接口
enum API {LOGIN_URL = '/user/login',USERINFO_URL = '/user/info',
}
// 暴露请求函数
// 登录接口的方法
export const reqLogin = (data: loginForm) =>http.post<any, loginResponseData>(API.LOGIN_URL, data)// 获取用户信息接口方法
export const reqUserInfo = () =>http.get<any, userResponseData>(API.USERINFO_URL)

登录接口需要携带参数ts类型

// 登录接口需要携带参数ts类型
export interface loginForm {username: stringpassword: string
}
interface dataType {token: string
}
// 登录接口返回数据类型
export interface loginResponseData {code: numberdata: dataType
}
interface userInfo {userId: numberavatar: stringusername: stringpassword: stringdesc: stringroles: string[]buttons: string[]routes: string[]token: string
}
// 定义服务器返回用户信息相关数据类型
interface user {checkUser: userInfo
}
export interface userResponseData {code: numberdata: user
}

当然后期我们还需要其他的接口,这里仅仅作为一个展示,接下来进行接口测试:

全局组件封装

在vue3项目,有很多组件需要在多个地方进行使用,所以我们一般都将其封装成全局组件,然而单纯的封装成全局组件的话,每次使用还需要额外在每个项目中进行引入,就很烦,这里我们先将所有的全局进行全局注册,这样后面使用的话直接使用我们设置的组件名称即可,就不需要一次次再单独的进行引入了,如下:我们封装一个Loading加载组件为全局组件:

封装成全局组件之后,我们还需要在入口文件main.js进行一个引入注册:

上面index.js代码如下,方便大家复制直接使用即可:

import { defineAsyncComponent } from "vue";
// 获取要注册的全局组件
const components = import.meta.glob("./global/*.vue");// 对外暴露插件
export default function install(app: any) {for (const [key, value] of Object.entries(components)) {const name = key.slice(key.lastIndexOf("/") + 1, key.lastIndexOf("."));app.component(name, defineAsyncComponent(value as any));}
}

然后Loading组件的加载的话,大家可以仿照 网站 里面的案例进行使用,还是有免费的找找就行: 

然后这里我们将本次使用的Loading加载组件代码也分享出来,供大家使用:

<template><div class="load"><div class="loading"><div class="vsg"><svg viewBox="0 0 50 50"><circle class="ring" cx="25" cy="25" r="20"></circle><circle class="ball" cx="25" cy="5" r="3.5"></circle></svg></div><div class="text">Loading</div></div></div>
</template><style lang="scss" scoped>
.load {width: 100%;height: 100%;position: absolute;z-index: 3;display: flex;justify-content: center;align-items: center;background-color: rgb(0, 0, 0);.loading {display: flex;flex-direction: column;align-items: center;justify-content: center;.vsg {display: flex;justify-content: center;align-items: center;@keyframes spin {to {transform: rotate(360deg);}}svg {width: 3.75em;animation: 1.5s spin ease infinite;}.ring {fill: none;stroke: hsla(106, 97%, 59%, 0.3);stroke-width: 2;}.ball {fill: #00ff85;stroke: none;}}.text {text-align: center;font-size: 16px;background: linear-gradient(to right, #00ff85, #5090ff);background-clip: text;-o-background-clip: text;-ms-background-clip: text;-moz-background-clip: text;-webkit-background-clip: text;color: transparent;}}
}
</style>

接下来我们在App.vue组件进行引入loading组件,如下:

回到浏览器可以看到我们的loading组件已经加载出来了,后期可以根据情况使用异步加载的组件或者使用v-if来进行操作,博主这里不再赘述:

路由配置管理

我们在开始搭建后台项目之前,都要仔细考虑一下路由应该如何配置,以下是本项目配置路由的详细步骤,如果想更加深入了解vue3路由知识,推荐参考我之前的文章:Vue 3 路由进阶——从基础到高级的完整指南:

安装配置路由的第三方包:

pnpm install vue-router

安装完路由包之后,接下来我们要先创建路由组件,因为项目仅仅是一个后台所以我们只需要在src目录下新进views文件,再创建3个路由组件即可:

创建完路由组件之后,接下来开始进行相关router配置:

// 通过vue-router插件实现模板路由配置
import { createRouter, createWebHistory } from 'vue-router'
import { constantRoute } from './routes'// 创建路由器
const router = createRouter({// 路由模式history: createWebHistory(),routes: constantRoute,// 滚动行为scrollBehavior() {return {left: 0,top: 0,}},
})
export default router

这里我单独将routes的属性对象抽离出一个js文件出来 ,便于后期的维护,代码如下:

// 对外暴露路由(常量路由)
export const constantRoute = [{path: '/login',name: 'login', // 命名路由component: () => import('@/views/login/index.vue'),meta: {title: '登录页面',},},{path: '/',name: 'home',component: () => import('@/views/home/index.vue'),meta: {title: '后台页面',},},{path: '/404',name: '404',component: () => import('@/views/404/index.vue'),meta: {title: '404界面',},},{path: '/:pathMatch(.*)*',name: 'any',redirect: '/404',},
]

接下来在入口文件 main.ts 处进行路由router的挂载:

如果想把写好的路由进行展示的话,需要通过 router-view 作为路由出口,路由匹配到的组件将进行响应的渲染,这里在App根组件上进行展示:

最终呈现的效果如下所示:

store仓库配置

接下来我们需要对我们项目进行一个仓库管理,这里用到了pinia状态管理工具,不了解pinia的朋友,推荐看一下我之前讲解的文章:探索Pinia:Vue状态管理的未来 ,本项目就不再着重讲解其具体知识了。具体讲解如下:

终端执行如下命令安装pinia仓库:

pnpm install pinia

在src目录下新建store文件夹,文件夹下新建 index.ts 文件,暴露如下代码:

// 设置pinia仓库
import { createPinia } from 'pinia'
const pinia = createPinia()
// 对外暴露:入口文件需要安装仓库
export default pinia

在main.ts入口文件出进行pinia的挂载:

import { createApp } from 'vue'
import 'reset.css'
import App from './App.vue'
// 配置国际化
import ElementPlus from 'element-plus'
import zhCn from 'element-plus/es/locale/lang/zh-cn'
// 引入自定义插件对象:注册整个项目的全局组件
import globalComponents from '@/components'
// 导入路由配置
import router from '@/router'
// 导入仓库
import pinia from '@/store'createApp(App).use(ElementPlus, { locale: zhCn }) // 配置中文国际化.use(globalComponents) // 安装全局路由组件.use(router) // 安装路由.use(pinia) // 安装仓库.mount('#app')

接下来在store中新建文件夹modules用于存储仓库文件,在该文件夹创建一个login.js文件,用来存储登录相关数据,这里采用组合式API的写法,如下案例:

import { defineStore } from "pinia";
import { ref } from "vue"export const useMemberStore = defineStore("login", () => {const profile = ref();const setProfile = (val: number) => {profile.value = val;}const clearProfile = () => {profile.value = undefined}return { profile, setProfile, clearProfile }
})

git管理配置

接下来我们需要对我们上面撰写的项目初始化模板进行一个git上传,进行版本管理操作,这里我们使用可视化工具 github desktop 工具进行操作,不了解这个工具的参考:文章 ,里面详细记录了这个工具的操作,然后我们先创建存储库:

点击新建存储库之后,这里我们需要给仓库中输入一些相应的信息,这里我将之前写的一个项目作为本地路径上传上去,然后点击新建存储库即可: 

然后这里我们点击右上角的发布存储库按钮,将本地创建的存储库推送到远程仓库上: 

点击之后会出现弹框,这里我们需要取消勾选,让仓库成为公共仓库,任何人都能访问到,然后点击发布即可: 

打开github之后,就可以看到我们的创建的仓库已经出现了: 

然后我们把之前写的一个电商项目里面的文件copy一下放到仓库当中去,如下github desktop出现了我们文件的差异提示,每个更改的文件以及里面具体的内容都能看到, 如下: 

刷新浏览器之后,可以看到我们的项目已经全部推送到远程仓库上去了,很方便不需要再像git命令行那样一个一个的命令去敲: 

后期我们在本地进行什么样的修改,github desktop工具都能识别到我们哪些地方进行了修改,如下我在本地代码文件中,main.ts文件下面输入两行空行,工具都识别到我的更改,是不是很方便! 

注意:如果已经学习过我上一个项目的朋友可能已经了解过项目开始前的一些基础配置,觉得我再在新的项目再讲一遍有点啰嗦,但是我仍然坚持不厌其烦的去再讲一遍,一方面是培养自己的习惯另一方面是想不断加深读者对项目开始前基础配置的熟练程度,希望大家能够在小事中获得经验。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/326040.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

RisingWave基本操作

什么是RisingWave RisingWave 是一款基于 Apache 2.0 协议开源的分布式流数据库。RisingWave 让用户使用操作传统数据库的方式来处理流数据。通过创建实时物化视图&#xff0c;RisingWave 可以让用户轻松编写流计算逻辑&#xff0c;并通过访问物化视图来对流计算结果进行及时、…

【随笔】Git 高级篇 -- 远程跟踪分支 git checkout -b | branch -u(三十五)

&#x1f48c; 所属专栏&#xff1a;【Git】 &#x1f600; 作  者&#xff1a;我是夜阑的狗&#x1f436; &#x1f680; 个人简介&#xff1a;一个正在努力学技术的CV工程师&#xff0c;专注基础和实战分享 &#xff0c;欢迎咨询&#xff01; &#x1f496; 欢迎大…

Springboot整合 Spring Cloud OpenFeign

1.OpenFeign简介 1.相比于Netflix Feign&#xff0c;OpenFeign支持Spring MVC注解&#xff0c;整合了Ribbon(springcloud在Hoxton.M2 RELEASED版本之后舍弃Ribbon。需手动引入spring-cloud-loadbalancer)和Nacos。 2.使得开发人员调用远程接口或者服务之间相互调用就像调用本地…

【JavaEE初阶系列】——Cookie和Session应用之实现登录页面

目录 &#x1f6a9;本章目标 1.登录页面 2.servlet处理上述的登录请求 3.网站主页(成功登录之后的页面&#xff09; &#x1f6a9;实现过程 &#x1f393;登录页面 &#x1f393;Servlet处理登录请求 &#x1f388;获取请求传来的参数(用户名和密码) &#x1f388;验证…

【前端工程化指南】Git常见操作之忽略文件

默认情况下&#xff0c;Git管理代码版本时会对所有文件进行跟踪&#xff0c;但有些时候我们并不希望项目中的一些文件上传到远程仓库或公共仓库中&#xff0c;例如密钥&#xff0c;个人隐私文件等。因此Git提供了两种忽略跟踪文件的方式.gitignore文本文件与git rm命令&#xf…

弹幕播放器源码

下 载 地 址 &#xff1a; runruncode.com/php/19761.html 1. 将弹幕播放器的源码上传到服务器。 2. 通过访问你的域名/dmku/install/index.php来进行弹幕库的安装。 3. 修改播放器后台的密码&#xff0c;配置文件为/config.php&#xff0c;并配置json接口。 4. 后台账号为…

leetcode91.解码方法(动态规划)

问题描述&#xff1a; 一条包含字母 A-Z 的消息通过以下映射进行了 编码 &#xff1a; A -> "1" B -> "2" ... Z -> "26" 要 解码 已编码的消息&#xff0c;所有数字必须基于上述映射的方法&#xff0c;反向映射回字母&#xff08;可…

机房——蓝桥杯十三届2022国赛大学B组真题

问题分析 这题用深搜广搜都能做&#xff0c;不过我更倾向于用广搜&#xff0c;因为广搜能更容易找到目标点。那么是采用结构体存储边还是采用二维数组存储临接矩阵呢&#xff1f;我们注意到n的取值范围为1e5,用二维数组哪怕是bool类型就需要至少1e10Byte的连续空间,这个空间太大…

Kafka的安装及接入SpringBoot

环境&#xff1a;windows、jdk1.8、springboot2 Apache KafkaApache Kafka: A Distributed Streaming Platform.https://kafka.apache.org/ 1.概述 Kafka 是一种高性能、分布式的消息队列系统&#xff0c;最初由 LinkedIn 公司开发&#xff0c;并于2011年成为 Apache 顶级项目…

Redis继续(黑马)

Redis持久化 RDB与AOF RDB记录是二进制数据&#xff0c;Redis停机时会触发保存&#xff0c;名称&#xff1a; dump.rdb 缺点&#xff1a;间歇式复制可能存在宕机数据更新丢失 AOF 记录的写操作命令&#xff0c;每秒记录一下&#xff0c;也存在数据更新丢失的可能&#xff0c;相…

java学习之zip炸弹攻击

一、概述 Zip炸弹是一种特殊类型的Zip文件&#xff0c;它包含了大量的无用数据。Zip文件格式允许使用压缩算法来减小文件的大小&#xff0c;但是如果Zip文件中的某些内容被重复压缩&#xff0c;就会导致文件大小急剧增加。Zip炸弹利用这个特性&#xff0c;将一些无用的数据多次…

差分约束 C++ 算法例题

差分约束 差分约束 是一种特殊的 n 元一次不等式组&#xff0c;m 个约束条件&#xff0c;可以组成形如下的格式&#xff1a; { x 1 − x 1 ′ ≤ y 1 x 2 − x 2 ′ ≤ y 2 ⋯ x m − x m ′ ≤ y m \begin{cases} x_1-x_1^{} \le y_1 \\ x_2-x_2^{} \le y_2 \\ \cdots \\ x_…

Pygame简单入门教程(绘制Rect、控制移动、碰撞检测、Github项目源代码)

Pygame简明教程 引言&#xff1a;本教程中的源码已上传个人Github: GItHub链接 视频教程推荐&#xff1a;YouTube教程–有点过于简单了 官方文档推荐&#xff1a;虽然写的一般&#xff0c;但还是推荐&#xff01; Navigator~ Pygame简明教程安装pygame一、代码框架二、案件输入…

java项目之车辆管理系统(springboot+vue+mysql)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于springboot的车辆管理系统。项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息 。 项目简介&#xff1a; 车辆管理系统的主要使用者分…

day-35 被围绕的区域

思路 很明显&#xff0c;只有与边界上的O连接的O才不会X覆盖 解题方法 检测边界上的字符&#xff0c;如果是O则向周围探测&#xff0c;访问与之连接的不会被覆盖的X。边界探测结束后&#xff0c;没有访问过的O皆会被X覆盖 Code class Solution {public int dir[][]{{0,1},{0…

用webui.sh安装报错No module named ‘importlib.metadata‘

安装sdweb报错&#xff0c;出现No module named importlib.metadata&#xff1a; glibc version is 2.35 Cannot locate TCMalloc. Do you have tcmalloc or google-perftool installed on your system? (improves CPU memory usage) Traceback (most recent call last):File…

【Qt 学习笔记】Qt常用控件 | 布局管理器 | 水平布局Horizontal Layout

博客主页&#xff1a;Duck Bro 博客主页系列专栏&#xff1a;Qt 专栏关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ Qt常用控件 | 布局管理器 | 水平布局Horizontal Layout 文章编号&…

力扣32. 最长有效括号

Problem: 32. 最长有效括号 文章目录 题目描述思路及解法复杂度Code 题目描述 思路及解法 1.创建一个栈&#xff0c;并将-1先添加到栈中&#xff08;添加-1到栈中只是为了方便接下来的操作&#xff09;&#xff0c;定义int变量len用于记录每一个子有效括号的长度&#xff0c;ma…

ctfshow SSRF 351-358

做题前,需要先学习关于ssrf漏洞的相关知识 小注意: 当使用 file_get_contents() 函数访问远程 URL 时&#xff0c;它会尝试获取该 URL 指向的资源的内容&#xff0c;并将内容以字符串的形式返回。 如果 b.php 文件是一个 PHP 文件&#xff0c;它包含的内容取决于该 PHP 文件…

vue3+ant design实现表格数据导出Excel

提示:实现表格数据导出Excel 文章目录 前言 一、安装ant design? 二、引用ant design 1.搭建框架 2.获取表格数据 三、封装导出表格的代码 四、导出 1.获取导出地址 2.在下载导出事件中添加导出代码 五、全部代码 前言 今天终于有时间来更新文章了,最近公司项目比较紧…