# qinghe-vue-pro-element **Repository Path**: unvue/qinghe-vue-pro-element ## Basic Information - **Project Name**: qinghe-vue-pro-element - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2025-06-11 - **Last Updated**: 2025-06-11 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 创建搭建 ## 创建项目 怎么选择工具,我这里使用的是npm,使用yarn等工具都是可以的,vite官网地址:https://vitejs.cn/vite6-cn/guide/ ```shell E:\zbcode>npm create vite@latest > npx > create-vite | o Project name: | qinghe-vue-pro-web | o Select a framework: | Vue | o Select a variant: | JavaScript | o Scaffolding project in E:\zbcode\qinghe-vue-pro-web... | — Done. Now run: cd qinghe-vue-pro-web npm install npm run dev ``` ## 项目结构 ### 资源目录 在vite项目中,有两个资源目录,一个是`public`,一个是`src/assets`,都可以存放资源,如:图片、css、js等。两者的区别如下: 1. `public`下的资源,不需要经过`vite`处理,直接可以访问;`assets`下的资源`vite`会处理,压缩、编码之类的处理,进行优化。 ### 源码目录 `src` 是源码目录,这里面有资源、组件、页面,当然后期还要我们自己创建一些目录,比如:路由、页面、api、工具类等。 - `src/assets` 资源 - `src/components` 组件 ### index.html文件 整个程序的入口文件。因为默认的程序,都是单页面应用(SPA)。就这一个入口文件就够了。后期有机会了,给大奖讲解下多页面应用(MPA)。 这个是index.html源码 ```html Vite + Vue
``` 在html中,可以看到,有一个id为`app`的`div`;页面还加了js模块,模块路径是`/src/main.js`。 ```html
``` 这个是`/src/main.js`源码。 对Vue了解的同学,看到这里,基本就知道是干啥的了。 ```javascript import { createApp } from 'vue' import './style.css' import App from './App.vue' createApp(App).mount('#app') ``` 1. 导入创建`createApp`函数,用于创建Vue 应用实例。 2. 引用样式表,可以删了,没啥用,后面要自己写。 3. 引用了一个`App`的自定义组件。 4. 将`App`组件挂载到`id`为`app`的元素上(就是上面提到过得div)。 ### App.vue 打开这个文件,你会发现熟悉的代码。 ```html ``` 这是仪表标准`Vue组件`,`template`中是该组件的模板,`script`中是数据和逻辑,`style`是样式,在项目启动后,打开的页面就是这个页面。 这个页面中,还引用了`HelloWorld`组件,这个组件,是写在components包里的,后期我们写的组件相关vue文件,全部要发到这个包。 项目启动后,打开样子如下: ![img.png](images/项目结构-App和HelloWorld组件.png) 上半部分是`App.vue`组件 下半部分是`App.vue`组件中引用的`HelloWorld.vue`组件。 前面我们介绍了public和assets的区别,刚好这里就有个案例: 源码: ```html ``` 编译后: ```html
``` 观察src,的内容,明显可以看出区别,一个被vite处理了,一个是原生不动的路径。 **经过这么几步,我们就了解到,整个项目的目录结构,项目是怎么从`html`->`js模块`->`vue创建应用`->`组件应用`的全部流程。** ## 开发工具 我只用宇宙最强工具`WebStorm`。别问为啥,应为我爱,谁能挡住爱。也推荐大家用,用过的人都说比`VSCode`好用、简单。 使用`WebStorm`打开你刚才创建的项目,如下图: ![img.png](images/项目结构.png) ## 项目启动 ```shell PS E:\zbcode\qinghe-vue-pro-web> vite dev VITE v6.3.4 ready in 327 ms ➜ Local: http://localhost:5173/ ➜ Network: use --host to expose ➜ press h + enter to show help ``` 很多同学拿到别人的项目,不知道怎么启动,很简单,拿到项目后,找到`package.json`,里面有一段是`scripts`,里面就放着启动的秘诀。如下: ```json { "scripts": { "dev": "vite", "build": "vite build", "preview": "vite preview" } } ``` ```shell # 启动 vite dev # 构建 vite build # 预览 vite preview ``` 如果不是用vite创建的项目,大概率启动都是 ```shell # 启动 npm run dev # 构建 npm run build # 预览 npm run preview ``` 具体怎么启动,看项目是用那个工具创建,目前最多的两种就是npm和vite。命令就看`packages.json`文件的key。 ## 访问项目 启动后,会给访问地址,如上面启动后,给出的地址是: http://localhost:5173/ ,这个也是可以在配置文件中配置的。 能出现以下页面,表示项目启动成功。 ![img.png](images/访问项目1.png) # 项目初始化 上面创建的项目只是vite给的一个模板,具体项目由那些目录组成,都是什么作用,都是架构师考虑的,经典目录结构如下: ``` qighe-vue-pro-web ├─public(公共文件) ├─src │ ├─App.vue (入口组件) │ ├─main.js (入口js) │ │ │ ├─api(所有接口相关) │ ├─assets(静态资源) │ ├─components(组件) │ ├─layouts(布局) │ ├─router(路由) │ ├─stores(状态商店) │ ├─utils(工具库) │ └─views(视图) │ └─ vite.config.ts(vite 配置) ``` 上面的目录,我们目前还用不到,但是先创建了,后面用到了,我们在讲解。 ## vite配置 ### 服务器选项 ```json { server: { port: 3000, // 端口 host: '0.0.0.0', // 监听ip open: true, //开发服务器启动时,自动在浏览器中打开应用程序 proxy: { // 代理 // 带选项写法: // 前端地址:http://127.0.0.1:3000/api/bar // 后端地址:-> http://127.0.0.1:9900/bar "/api/v1": { target: 'http://127.0.0.1:9900', // 目标服务 changeOrigin: true, rewrite: (path) => path.replace(/^\/api\/v1/, ''), } } } } ``` 以上配置作用: 1. 项目启动端口为 3000 2. 监听你本地所有网卡ip,默认只有localhost 3. 项目启动后,就会自动打开浏览器,访问项目 4. 当前端访问地址为"/api/v1"开头的时候,代理服务会将请求转发到http://127.0.0.1:9900的后端服务,并使用空字符串替换掉/api/v1。 ## 清理项目 创建项目后,其实很多东西都是不需要的,在这里,我们就清理下。 ## main.js 1. 删除样式引用,同时删除`/src/style.css`,如下: ```javascript import { createApp } from 'vue' import App from './App.vue' createApp(App).mount('#app') ``` ## 清理资源 1. 删除`/src/assets/vue.svg`文件 2. 删除`public/vite.svg`文件 ## App.vue 1. 清理无用代码,同时删除`src/components/HelloWorld.vue`文件,如下即可: ```html ``` # UI框架 我本意是想做一个全套课程,使用ElementUI、AntDesignVue、NaiveUI三种流行的前端框架来做,因为思想基本一样,知识框架和组件替换的问题。 但是因为时间原因,先使用ElementUI来做一次,后期有时间了,给大家在补上。 - ElementUI:[官网](https://element-plus.org/zh-CN/) - AntDesignVue: [官网](https://www.antdv.com/components/overview-cn/) - NaiveUI: [官网](https://www.naiveui.com/zh-CN/os-theme) ## 安装ElementUI 安装前,请大家最好阅读下官网的兼容性提示。如下: ![img.png](images/elementUI兼容性提示.png) ```shell # 安装ElementUI npm install element-plus --save ``` ### 完整引入 `main.js` ```javascript import { createApp } from 'vue' import ElementPlus from 'element-plus' import 'element-plus/dist/index.css' import App from './App.vue' const app = createApp(App) app.use(ElementPlus) app.mount('#app') ``` `App.vue` ```html ``` 注意:``就是`element-ui`的按钮用法。 效果如下: ![img.png](images/按钮演示.png) 如上图,说明element-ui已经安装好,并且可以正常使用。 ### 按需导入 你需要使用额外的插件来导入要使用的组件。 ### 自动导入(推荐) 首先你需要安装unplugin-vue-components 和 unplugin-auto-import这两款插件 ```shell npm install -D unplugin-vue-components unplugin-auto-import ``` 然后把下列代码插入到你的 `Vite` 的配置文件中 vite.config.ts ```javascript ... import AutoImport from 'unplugin-auto-import/vite' import Components from 'unplugin-vue-components/vite' import { ElementPlusResolver } from 'unplugin-vue-components/resolvers' // https://vite.dev/config/ export default defineConfig({ plugins: [ ... AutoImport({ imports: ["vue"], // vue函数自动导入 resolvers: [ElementPlusResolver()], }), Components({ resolvers: [ElementPlusResolver()], }), ], ... }) ``` **注意:请删除完整引入的代码。** ### 全局配置 上面我们讲过,从`html`->`js模块`->`vue创建应用`->`组件应用`的全部流程。从这个流程来理解,app.vue是我们进入vue世界的第一个组件。所以,全局配置就放到这里就ok了。 `App.vue` ```html ``` 上面这个例子知识介绍,全局配置组件`el-config-provider`的用法,这里主要是做了一个国际化语言切换,可以看到表格、分页的相关语言,根据切换可以改变。 ![image-20250506001036475](images/image-20250506001036475.png) ![image-20250506001103234](images/image-20250506001103234.png) 我们发现,凡事想要用到全局配置的组件,必须写在`el-config-provider`组件内部。所以,大家思考下,是不是整个项目如果要使用这个全局配置,也要写在这里? # 布局组件 好了,到现在我们了解到了vue项目搭建过程,执行过程,也简单的配置了vite,了解了全局配置组件。接下来,我们就要开始正式写项目了。在写项目前,我们要知道项目大概长什么样子,怎么布局的吧? 好,我们按照国际惯例,实现1个常用后台布局就行了,如下: ![img.png](images/布局案例.png) 要实现这么个布局,以前确实有点难度,但是好消息是,现在的ui组件,基本都实现了容器组件,就是为了方便布局,在Element Plus里,就实现了。容器组件包含了一下几个: 1. :外层容器。 当子元素中包含 时,全部子元素会垂直上下排列, 否则会水平左右排列。 2. :顶栏容器。 3. :侧边栏容器。 4. :主要区域容器。 5. :底栏容器。 ## less安装 开发页面,离不开css,但是直接写css不方便,所以我们用less。你可以理解less对css进行了扩展。刚好vite还支持,咱们只需要安装下less就行了。 ```shell npm install -D less ``` ### 配置 `vite.config.js` 将@视为源码根目录 ```javascript ... import path from 'path' export default defineConfig({ ... resolve: { alias: { '@': path.resolve(__dirname, './src'), // 将@视为源码根目录 } }, ... }) ``` ## Tailwind `Tailwind` 是一个css框架,它内置了很多样式工具,可以直接用来写常见样式。 ```shell # 安装依赖包 npm install -D tailwindcss@3 postcss autoprefixer # 初始化tailwindcss,并生成配置文件 tailwind.config.js npx tailwindcss init ``` ### 配置 `postcss.config.cjs` 添加该文件,注意,vite6这里必须是`.cjs`。否则报错,如果报错,也可以尝试改为`.cjs` ```json module.exports = { plugins: { tailwindcss: {}, autoprefixer: {}, } } ``` `tailwind.config.js` ```json /** @type {import('tailwindcss').Config} */ export default { content: ["./index.html","./src/**/*.{vue,js}"], theme: { extend: {}, }, plugins: [], } ``` ### 使用 将`Tailwind`引入到全局样式表中。 `src/style/index.less` ```less @tailwind base; @tailwind components; @tailwind utilities; ``` 这是Tailwind的基础样式,可以初始化项目的样式。比如:`body`等元素的初始化。 ### 引入 并将全局样式表在`main.js`中引入 ```javascript import App from './App.vue' import "./style/index.less" // 引入全局样式 const app = createApp(App) app.mount('#app') ``` ## Layout组件 布局可以参考ElementUI[官网布局](https://element-plus.org/zh-CN/component/container.html) ,有很多布局,符合我们目标的布局如下: ![image-20250506002249972](images/image-20250506002249972.png) ### 代码结构 ![image-20250507213651488](images/image-20250507213651488.png) ### index.vue `src/layout/index.vue` 项目的布局组件。 ```vue ``` 在EleumetUI布局的基础上,我们添加了自己的样式,来实现我们想要的效果。 1. 首先,引入了`variables.less`,这里定义了我们整个项目中的样式参数,如:侧边栏背景色、侧边栏宽度等。 2. 定义`.layout`类样式,这个样式是空的,就是个父样式,后续样式都要在这个下面才会生效。 3. 定义`.layout-sider`类样式,定义侧边栏宽度、最小高度。 4. 定义`.layout-sider-dark`类样式,定义侧边栏`dark`主题下的背景色。 ### index.js `src/layout/index.js` 在`nodejs`中,`index.js`在引入的时候,一般不用写,常见用法就是,在自己写的组件包下,创建一个`index.js`文件,引入自己的组件并导出,对组件进行统一管理。 这样的话,在别人引用咱们的组件的时候,就只需要知道是layout下的组件就行了,没必要知道具体是那个`vue`文件实现的。 ```javascript import Layout from "./index.vue"; // 引入组件的实现文件,可以看到,这里是必须引用到具体哪个文件实现了Layout的。 export { Layout }; ``` ### 用法 `src/App.vue` 下面就是引入组件的用法。可以看到,使用index.js,对使用方来说,隐藏了代码的具体实现文件。实现了引用的简化和统一管理。 ```vue ``` ### 样式 #### 全局变量 `src/style/variables.less` 这个文件主要存储整个项目中,样式变量,方便以后对框架部分样式进行调整,而不影响整个应用,因为大家都是用了全局变量。 ```less // common @sider-width: 200px; @header-height: 64px; @font-size: 14px; // layout @layout-height: 100vh; @layout-sider-width: @sider-width; @layout-sider-dark-bg-color: rgb(0, 20, 40); // layout-light @layout-sider-light-bg-color: #fff; ``` #### 全局样式 `src/style/index.less` 这个文件是全局样式,这里只引入了`tailwind css`,因为这里基本包括了常见的初始化样式。比如:`body`等元素的初始化。所以,项目搭建初期,咱们就不用写了。 ```less @tailwind base; @tailwind components; @tailwind utilities; ``` #### 引入全局样式 `main.js` ```javascript ... import "./style/index.less" ... ``` 给main.js中添加以上代码,就可以应用全局样式到整个项目。 ### App `src/App.vue` 修改App.vue,将Layout作为配置的唯一节点。引入全局样式。固定默认的语言为简体中文。 ```vue ``` 以上操作后,我们把整个Layout架子就搭建起来了。效果如图: ![image-20250506212453803](images/image-20250506212453803.png) ### AIcon组件 #### 原理 因为图标占用资源比较大,很多UI框架已经把图标独立出去了,甚至直接使用第三方图标,而且还不支持动态选择。像菜单这种,图标配置从后端获取的时候,就很不友好,因为后端给的一定是字符串,而不是组件,所以我们就要把字符串转化成组件。怎么转化呢? 幸运的是,我们可以使用`Vue`提供的内置组件来实现,它的作用,就是将一段字符串转化为组件。 ``` vue ``` 在上面的例子中,被传给 `:is` 的值可以是以下几种: - **被注册的组件名** - 导入的组件对象 这里的原理,就是:`component` 组件传入的`:is`属性,就是 **被注册的组件名**。 什么意思呢? 1. 组件必须被注册了,并且有名字 2. 想使用已经注册的组件,可以直接使用,但是这样就和动态没关系了。 3. 动态使用,就直接给`component` 组件传入的`:is`属性传递这个组件的名字。 比如:有个组件A,可以一下两种使用方法。 #### 静态组件 ```vue ``` 像这种,不能传递参数来改变组件的渲染的(如A的渲染,无法改变,智能改代码让其改变渲染的方式)叫做,静态组件。 #### 动态组件 ```vue ``` 在这里,导入了`A`、`B`、`C`三个组件,默认显示组件`A`,因为`componentName`默认就是`A字符串`。`component`组件会自己在全局和局部上下文去找名字叫`A`的已经注册的组件,找到后用`A组件`替代自己。 如果点击按钮,就会切换成C组件,原理和A的显示一样。 #### AIcon实现 ##### 安装ElementUI-Icon 首先得安装UI框架抽离出去的组件。 ```shell npm install @element-plus/icons-vue ``` #### 注册插件 `src/plugins/icon.js` 注册的核心类,封装了element-plus的icon注册,并导出了`setupIcon`注册函数。需要在main.js里调用。 ```javascript import * as ElementPlusIconsVue from '@element-plus/icons-vue' export function setupIcon(app){ for (const [key, component] of Object.entries(ElementPlusIconsVue)) { app.component(key, component) } } ``` #### 注册 ```javascript ... const app = createApp(App) setupIcon(app); ... ``` 调用`setupIcon`进行注册。 #### AIcon组件封装 ##### 结构 ![image-20250511152127397](images/image-20250511152127397.png) `src/components/icon/index.vue` ```vue ``` 1. 这个组件定义了一个name属性,用于外部传递组件名称,供``组件使用。 2. 给``组件绑定了props属性,其实就是想将`AIcon`当做``使用,参数直接全部绑定给他就行了。 3. 为什么要使用``组件?因为他提供了一些属性对我们来说很有用,比如:size(大小)、color(颜色) `src/components/icon/index.js` ```javascript import AIcon from "./index.vue" export { AIcon } ``` 这个前面解释过,就不在重复解释。导出`AIcon`组件 #### AIcon 组件使用 ```vue ``` 如上,给name传递一个已经注册的组件名字`Odometer`,即可显示图标。如下图: ![image-20250511151916292](images/image-20250511151916292.png) ### Sider组件 有了上面的骨架,实现了动态图标组件,接下来,我们需要实现的就是侧边栏,也就是`菜单`和`logo`的组合组件。 考虑到,菜单如果太多,就必须要有滚动条,所以,先给Sider组件,写个滚动条,幸运的是,element-plus提供了这个组件。 #### 结构 ![image-20250511152619781](images/image-20250511152619781.png) #### 滚动条 `src/layouts/sider/index.vue` ```vue ``` 如图: ![image-20250511152754497](images/image-20250511152754497.png) 可以看到,右侧有一个若隐若现的滚动条,这就是`el-scrollbar` > [!NOTE] > > 滚动条一定要设置高度,否则无效。 > > 如: > > .layout-sider { > max-height: @layout-height; > } > > @layout-height: 100vh; > > `vh`代表视图高度,其实就是浏览器可见区域高度。100vh代表100%视图高度,也就是100%浏览器可见区域高度。 #### logo `src/layouts/sider/index.vue` ```vue ``` 这块很简单,flex布局,内容居中,高度用全局变量,行高度一样(64px),超出不换行。 #### menu `src/layouts/sider/index.vue` ```vue ... ``` 直接找了个menu的案例,修改了菜单,增加了动态图标。效果如下: ![image-20250511160912839](images/image-20250511160912839.png) ##### 去边框 可以看到,菜单右侧明显有一条表框,要去掉边框,直接覆盖样式。 ```css .layout-sider { ... .sider-menu { border: 0; } ... } ``` ![image-20250511161123007](images/image-20250511161123007.png) ##### 设置背景色 查阅api,经过测试,确定只有一下几个参数可用: ```css .layout-sider { ... .sider-menu-dark { --el-menu-bg-color: @layout-sider-dark-bg-color; --el-menu-hover-bg-color: @layout-sider-dark-bg-color; --el-menu-text-color: @layout-sider-dark-text-color; --el-menu-active-color: @layout-sider-dark-active-color; } } ``` 所以给菜单添加样式`.sider-menu-dark`:菜单背景色,菜单鼠标悬浮背景色,菜单文字颜色,菜单文字激活颜色,其他的参数均无效,如下: ![image-20250511164402765](images/image-20250511164402765.png) ##### css hack 但是要实现我们的目标,还是差了一些距离,如:激活背景色,激活后父菜单字体颜色,鼠标悬浮字体颜色等。 所以,现在只能靠hack css来实现了。因为element-plus没有提供变量来覆盖。 ```vue ``` 如上代码,添加到`src/layouts/sider/index.vue`中就行了,细心的人会发现,这个` ``` 至此,Sider组件,基础版本开发完成,为什么是基础呢、因为和后端还没有交互,都是写死的静态页面。另外,还有一些动态改变主题的功能还未实现。 ### Header组件 ### Main组件 #### Tab组件 ```shell npm i -S vuedraggable@next ``` > [!NOTE] > > 这个插件和自动引入有冲突,直接按照官网给的实例,会报错,解决方法就是在main.js中添加createApp的引用,如下: > > `src/main.js` > > ```javascript > ... > import {createApp} from "vue"; > ... > ``` # 路由 vue中,路由大家经常使用VueRouter,因为这个是官方提供的路由,没有可以挑选的。 ## 安装 ```shell npm install vue-router@4 ``` # 国际化?