当前位置: 首页 > article >正文

云图库平台(二)前端项目初始化

环境准备:

  • node.js版本必须>=18.12,使用vue脚手架来初始化创建项目

目录

  • 一、创建项目
  • 二、前期准备
    • 前端工程化配置
    • 组件库的引入
    • 开发规范
  • 三、页面基本信息
    • 基础布局结构
    • 全局底部栏
    • 动态替换内容弄个
    • 全局顶部栏
      • 修改GlobalHeader组件
  • 四、路由
    • 路由跳转
    • 代码高亮实现
  • 五、Axios请求库
    • 全局自定义请求
    • 自动生成请求代码
    • 测试请求
  • 六、全局状态管理
    • 定义状态
    • 引入状态
    • 测试全局状态管理

一、创建项目

使用Vue的脚手架快速创建项目,可以参考Vue官网:https://cn.vuejs.org/

终端执行命令:

npm create vue@latest

在这里插入图片描述
项目创建完成后,这里我是使用的WebStorm打开的项目,在终端输入命令安装依赖:

npm install

在这里插入图片描述

依赖安装完成后运行npm run dev看是否能运行成功。
在这里插入图片描述
在这里插入图片描述
出现上述界面就说明运行成功了。

二、前期准备

前端工程化配置

刚刚使用vue脚手架创建项目时已经帮我们整合了Prettier代码美化ESLint自动校验TypeScript类型校验。但是我们需要在webstorm中开启代码美化插件.

setting->eslint:这里新手推荐选择第一个Disable ESLint,因为ESLing自动校验较为严格,对新手不是特别友好.在这里插入图片描述
setting->Prettier:开启代码美化工具,配置如下:
在这里插入图片描述

组件库的引入

引入Ant Design Vue组件库,这里使用的版本是v4.2.6,可以参考官方文档快速上手:https://antdv.com/docs/vue/getting-started-cn]

  • 输入命令引入组件
npm i --save ant-design-vue@4.x

在这里插入图片描述

  • 改变main.ts文件,使用全局注册组件(更加方便,这里参考[官方文档],有重复的,者这里自行进行删除即可(https://antdv.com/docs/vue/getting-started-cn):
import { createApp } from 'vue';
import Antd from 'ant-design-vue';
import App from './App';
import 'ant-design-vue/dist/reset.css';

const app = createApp(App);

app.use(Antd).mount('#app');

在这里插入图片描述

然后我们随便引入一个组件来看看是否成功引入组件,这里我以按钮组件为例:

  • 引入组件库中的按钮组件:
<a-button type="primary" danger>Primary</a-button>

运行后效果如下:
在这里插入图片描述
由此可以知道Ant Design Vue组件库引入成功了。

开发规范

Vue组件中可以按照该两种不同的风格进行书写:选项式API组合式API。这里为了使项目开发过程中更加高效,所以使用了Vue3中的组合式API,而不是选项式API。

  • 这里使用组合式API进行示范,示例代码如下:
<template>
  <div id="xxPage">

  </div>
</template>

<script setup lang="ts">

</script>

<style scoped>
#xxPage {
}
</style>

好了,接下来正式进行前端初始化页面模板的开发。

三、页面基本信息

修改页面搜索引擎优化页面:

<!DOCTYPE html>
<html lang="">
<head>
  <meta charset="UTF-8">
  <link rel="icon" href="/favicon.ico">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>智能协同云图库</title>
  <meta name="description" content="这是一个SpringBoot + Vue3的智能协同云图库平台">
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>

基础布局结构

在layouts目录下新建BasicLayout.vue文件,然后在App.vue全局页面入口文件中引入。

App.vue代码如下:

<template>
  <div id="app">
    <BasicLayout />
  </div>
</template>

<script setup lang="ts">
import BasicLayout from '@/layouts/BasicLayout.vue'
</script>

<style scoped>

</style>

然后在Ant Design官网中找到Layout组件,这里以上中下结构布局来进行演示:

在这里插入图片描述
不要忘记清楚页面内的默认样式,并且移除assets目录中的main.css文件和base.css文件,防止样式污染。

BasicLayout.vue代码如下:

<template>
  <div id="basicLayout">
    <a-layout style="min-height: 100vh">
      <a-layout-header>Header</a-layout-header>
      <a-layout-content>Content</a-layout-content>
      <a-layout-footer>Footer</a-layout-footer>
    </a-layout>
  </div>
</template>

<script setup lang="ts"></script>

目前样式如下:

在这里插入图片描述

全局底部栏

全局底部栏展示底部栏信息:

<a-layout-footer class="footer">
  <a ref="https://gitee.com/" target="_blank">智能云图库平台</a>
</a-layout-footer>

调整底部栏信息样式:

#basicLayout .footer {
  background: #efefef;
  padding: 16px;
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  text-align: center;
}

动态替换内容弄个

Vue脚手架已经帮我们引入了Vue Router路由库,可以在router/intex.ts中进行路由配置,使得能够根据访问的页面地址找到不同的组件并进行渲染。

首先需要知道哪些内容需要动态替换,很显然肯定是中间content部分:

<a-layout-content class="content">
  <router-view />
</a-layout-content>

页面效果如下:
在这里插入图片描述

修改content样式,要和底部栏保持一定外边距,否则内容会被遮住如下:

#basicLayout .content {
  background: linear-gradient(to right, #fefefe, #fff);
  margin-bottom: 28px;
  padding: 20px;
}

全局顶部栏

在components目录中新建GlobalHeader.vue文件用于实现全局顶部栏组件。

  • 使用Ant Design的菜单组件:
    在这里插入图片描述

BasicLayout.vue文件中引入该顶部栏组件:

<a-layout-header class="header">
  <GlobalHeader />
</a-layout-header>

下面是引入该组件的代码:

<script setup lang="ts">
import GlobalHeader from '@/components/GlobalHeader.vue'
</script>

然后修改该顶部栏组件的样式(主要是为了清楚默认样式),代码如下:

#basicLayout .header {
  padding-inline: 20px;
  margin-bottom: 16px;
  color: unset;
  background: white;
}

修改GlobalHeader组件

  • 给该菜单组件外面套一层元素,用于控制整体的样式,代码如下:
<div class="globalHeader">
  <a-menu v-model:selectedKeys="current" mode="horizontal" :items="items" />
</div>
  • 然后修改菜单配置,代码如下:
<script lang="ts" setup>
import { h, ref } from 'vue'
import { HomeOutlined } from '@ant-design/icons-vue'
import { MenuProps } from 'ant-design-vue'

const current = ref<string[]>(['home'])
const items = ref<MenuProps['items']>([
  {
    key: '/',
    icon: () => h(HomeOutlined),
    label: '主页',
    title: '主页',
  },
  {
    key: '/about',
    label: '关于',
    title: '关于',
  },
  {
    key: 'others',
    label: h('a', { href: 'https://www.codefather.cn', target: '_blank' }, '编程导航'),
    title: '编程导航',
  },
])
</script>
  • 接着继续完善全局顶部栏,在左侧补充网站logo(根据自己需要找一个就行)和标题:
    将找到的logo.png图片放到src/assets目录下,替换掉原本的默认Logo即可:

代码如下(其中RouterLink组件作用是支持超链接跳转(不刷新页面)):

<div id="globalHeader">
  <RouterLink to="/">
    <div class="title-bar">
      <img class="logo" src="../assets/logo.png" alt="logo" />
      <div class="title">智能协同云图库</div>
    </div>
  </RouterLink>
  <a-menu v-model:selectedKeys="current" mode="horizontal" :items="items" />
</div>

css样式如下:

<style scoped>
.title-bar {
  display: flex;
  align-items: center;
}

.title {
  color: black;
  font-size: 18px;
  margin-left: 16px;
}

.logo {
  height: 48px;
}
</style>

目前页面效果如下:
在这里插入图片描述

  • 接着,实现右侧展示当前用户的登录状态,代码如下:
<div class="user-login-status">
  <a-button type="primary" href="/user/login">登录</a-button>
</div>
  • 最后一步:优化导航栏的布局,使用Ant Design的栅格组件的自适应布局(左右宽度固定,中间菜单栏自适应),代码如下:
<div id="globalHeader">
  <a-row :wrap="false">
    <a-col flex="200px">
      <RouterLink to="/">
        <div class="title-bar">
          <img class="logo" src="../assets/logo.png" alt="logo" />
          <div class="title">智能协同云图库</div>
        </div>
      </RouterLink>
    </a-col>
    <a-col flex="auto">
      <a-menu v-model:selectedKeys="current" mode="horizontal" :items="items" />
    </a-col>
    <a-col flex="120px">
      <div class="user-login-status">
        <a-button type="primary" href="/user/login">登录</a-button>
      </div>
    </a-col>
  </a-row>
</div>

最终效果如下图所示:
在这里插入图片描述

到这里,全局通用布局结束了,接下来进行路由的配置。

四、路由

现在,要实现点击不同的菜单项从而跳转到不同的页面,并实现菜单项的高亮。

在这里插入图片描述
我们可以看到router目录下index.ts文件中的routes提供了两种不同加载组件的方式:第一种方式是直接加载组件(无论是否使用组件均会加载进来);第二种方式是按需加载(懒加载,即用到哪个组件就加载哪个组件,用不到就不加载)。

路由跳转

现在我们来实现菜单项的路由跳转功能,给GlobalHeader组件的菜单组件绑定跳转事件,代码如下:

import { useRouter } from "vue-router";
const router = useRouter();

// 路由跳转事件
const doMenuClick = ({ key }: { key: string }) => {
  router.push({
    path: key,
  });
};

html代码如下:

<a-menu
  v-model:selectedKeys="current"
  mode="horizontal"
  :items="items"
  @click="doMenuClick"
/>

现在,点击对应的菜单项会显示高亮,但是页面说刷新后当前选中的菜单项并不会高亮。

代码高亮实现

代码如下:

const router = useRouter();
// 当前选中菜单
const current = ref<string[]>([]);
// 监听路由变化,更新当前选中菜单
router.afterEach((to, from, next) => {
  current.value = [to.path];
});

当我们进入页面的时候,current变量初始时候是没有的;由于afterEach函数,每次前往新页面时,都会把当前要前往页面的路径设置给current变量。

高亮显示原理:

  • 点击菜单时,Ant Design组件已经通过v-model 绑定current变量实现了高亮。
  • 每次刷新页面都会获取到当前的url路径,然后修改current变量的值,从而实现同步。

五、Axios请求库

当前端需要获取数据时,前端需要向后端接口发送请求,由后端执行操作并响应数据给前端。这里使用第三方库Axios来发送请求。

安装请求工具库Axios(参考官方文档https://axios-http.com/docs/intro)

npm install axios

在这里插入图片描述
我们如何来使用Axios库呢?接下来看全局自定义请求。

全局自定义请求

需要自定义全局请求地址等,可以参照Axios官方文档,编写请求配置文件request.ts。包括全局接口请求地址、超时时间、自定义请求响应拦截器等。

代码如下:

import axios from 'axios'
import { message } from 'ant-design-vue'

// 创建 Axios 实例
const myAxios = axios.create({
  baseURL: 'http://localhost:8126',
  timeout: 60000,
  withCredentials: true,
})

// 全局请求拦截器
myAxios.interceptors.request.use(
  function (config) {
    // Do something before request is sent
    return config
  },
  function (error) {
    // Do something with request error
    return Promise.reject(error)
  },
)

// 全局响应拦截器
myAxios.interceptors.response.use(
  function (response) {
    const { data } = response
    // 未登录
    if (data.code === 40100) {
      // 不是获取用户信息的请求,并且用户目前不是已经在用户登录页面,则跳转到登录页面
      if (
        !response.request.responseURL.includes('user/get/login') &&
        !window.location.pathname.includes('/user/login')
      ) {
        message.warning('请先登录')
        window.location.href = `/user/login?redirect=${window.location.href}`
      }
    }
    return response
  },
  function (error) {
    // Any status codes that falls outside the range of 2xx cause this function to trigger
    // Do something with response error
    return Promise.reject(error)
  },
)

export default myAxios

自动生成请求代码

前端请求代码这里使用OpenAPI工具自动生成(根据后端的swagger接口文档地址生成前端的请求代码),参考官方文档:https://www.npmjs.com/package/@umijs/openapi

  • 安装命令:
npm i --save-dev @umijs/openapi

然后在项目根目录中新建openapi.config.js文件,代码如下:

import { generateService } from '@umijs/openapi'

generateService({
  requestLibPath: "import request from '@/request'",
  schemaPath: 'http://localhost:8126/api/v2/api-docs',
  serversPath: './src',
})
  • package.json的script中添加"openapi": "node openapi.config.js"
    在这里插入图片描述
    不要忘记将schemPath改为自己后端服务提供的Swagger接口文档的地址。现在执行刚刚添加的"openapi": "node openapi.config.js"即可生成可执行代码。

如下图所示:
在这里插入图片描述
之后每次后端接口发生变更时只需要重新执行生成一遍就好了。

测试请求

现在可以试着在任意页面代码中调用API:

import { healthUsingGet } from '@/api/mainController'

healthUsingGet().then((res) => {
  console.log(res)
})

在项目后端初始化阶段,已经添加了全局跨域配置,正常情况下出现如下响应:

在这里插入图片描述
如果出现跨域问题,这是因为前端网址地址和后端请求接口地址不一致导致的。

如果后端代码无法修改或者还可以通过前端代理服务器。同时如果项目中使用Vite,内置了代理服务器。现在通过前端来解决跨域问题,修改vite.config.ts文件增加代理配置

该项目由于整合了vite打包工具,而vite默认给我们提供了一个代理服务器的配置。增加代理配置代码如下(vite.config.ts文件):

export default defineConfig({
  server: {
    proxy: {
      '/api': 'http://localhost:8126',
    }
  },
})

还需要修改request.ts文件

// 创建 Axios 实例
const myAxios = axios.create({
  baseURL: "", //本地开发环境
  // baseURL: 'http://localhost:8126',
  timeout: 60000,
  withCredentials: true,
})

由此,前端发送的请求域名就等同于当前URL的域名,就不会出现跨域。当我们访问到/api开头的接口时,会被代理到请求8126端口的后端服务器,从而完成请求。

六、全局状态管理

全局状态管理可以立即为多个页面要共享的数据,适合作为全局状态管理的数据比如说已登录的用户信息。

引入Pinia,最开始创建项目时vue脚手架已经引入了Pinia,所以无需再次引入了。当然如果没有引入Pinia的话可以参照官方文档。

定义状态

src/stores目录中创建useLoginUserStore.ts文件定义user模块:

代码如下:

import { defineStore } from "pinia";
import { ref } from "vue";

export const useLoginUserStore = defineStore("loginUser", () => {
  const loginUser = ref<any>({
    userName: "未登录",
  });

  async function fetchLoginUser() {
    // todo 由于后端还没提供接口,暂时注释
    // const res = await getCurrentUser();
    // if (res.data.code === 0 && res.data.data) {
    //   loginUser.value = res.data.data;
    // }
  }

  function setLoginUser(newLoginUser: any) {
    loginUser.value = newLoginUser;
  }

  return { loginUser, setLoginUser, fetchLoginUser };
});

引入状态

可以直接使用store中导出的状态变量和函数,如下:
在这里插入图片描述

一般我们首次进入页面时都会获取登录用户的信息,修改App.vue文件,添加部分代码来远程获取用户数据,如下:

import { useLoginUserStore } from '@/stores/useLoginUserStore.ts'

const loginUserStore = useLoginUserStore()
loginUserStore.fetchLoginUser()

接下来修改全局顶部栏组件(即GlobalHeader.vue文件),在顶部栏右侧展示用户状态,代码如下:

<div class="user-login-status">
  <div v-if="loginUserStore.loginUser.id">
    {{ loginUserStore.loginUser.userName ?? '无名' }}
  </div>
  <div v-else>
    <a-button type="primary" href="/user/login">登录</a-button>
  </div>
</div>

测试全局状态管理

在userStore中编写测试代码

async function fetchLoginUser() {
  // 测试用户登录,3 秒后登录
  setTimeout(() => {
    loginUser.value = { userName: '用于展示登录用户信息', id: 1 }
  }, 3000)
}

最终效果:进入页面3秒钟后,顶部栏右侧会展示出登录用户信息。

在这里插入图片描述

至此,该项目的前端初始化完结散花。


http://www.kler.cn/a/447779.html

相关文章:

  • 2023年厦门市第30届小学生C++信息学竞赛复赛上机操作题(三、2023C. 太空旅行(travel))
  • 用人话讲计算机:Python篇!(十五)迭代器、生成器、装饰器
  • TDesign:NavBar 导航栏
  • 防火墙技术与网络安全
  • 数智化转型是什么?
  • 【人工智能】用Python实现图卷积网络(GCN):从理论到节点分类实战
  • 二进制分析的新兴趋势:塑造安全的移动应用
  • Kubernates
  • Ubuntu24版 最新安装CUDA驱动方式
  • dify工作流+github actions实现翻译并创建PR
  • 智能体实战(需求分析助手)二、需求分析助手第一版实现(支持需求提取、整理、痛点分析、需求分类、优先级分析、需求文档生成等功能)
  • Spring(二)AOP、切入点表达式、AspecJ常用通知的类型、Spring中的事务管理
  • 【期末复习】JavaEE(上)
  • powershell美化
  • 使用 Docker 打包和运行 Vue 应用
  • Suno Api V4模型无水印开发「人声伴奏分离」 —— 「Suno Api系列」第7篇
  • 成方金融科技后端部分笔试题 - 解析
  • Pytorch | 利用VMI-FGSM针对CIFAR10上的ResNet分类器进行对抗攻击
  • Pytorch | 从零构建MobileNet对CIFAR10进行分类
  • 电子应用设计方案66:智能打印机系统设计
  • Vulkan 学习(11)---- Vulkan RenderPass 创建
  • Liunx下MySQL:表的约束
  • OpenTK 中帧缓存的深度解析与应用实践
  • Gemini 2.0:面向智能体时代的全新 AI 模型
  • 均值聚类算法
  • 【Jenkins】Declarative和Scripted两种脚本模式有什么具体的区别