Práctica del proyecto de separación de front-end y back-end de SpringBoot + Vue || 1: Diseño de front-end de Vue

Serie de artículos:
Práctica del proyecto de separación de front-end y back-end de SpringBoot + Vue || Uno: diseño de front-end de Vue
Práctica del proyecto de separación de front-end de SpringBoot + Vue || Dos: backend de Spring Boot y conexión de base de datos
SpringBoot + Vue front-end práctica del proyecto de separación final || Tres: conexión Spring Boot back-end y Vue front-end
Práctica del proyecto de separación SpringBoot + Vue front-end y back-end || Cuatro: implementación de la función de gestión de usuarios Práctica del proyecto de separación SpringBoot + Vue front-end || Tres: implementación de la función de gestión de usuarios
SpringBoot + Vue práctica del proyecto de separación front-end || Tres: conexión de back-end de Spring Boot y Vue front-end | | Cinco: Seguimiento de la función de gestión de usuarios

Explicación en video de Bilibili: el proyecto de separación de front-end y back-end de SpringBoot + Vue más simple pero práctico en 2023.

Si no desea ver el video, puede consultar las notas de este artículo para obtener más detalles.

Configuración del entorno

Nodejs: 8.17.0
Vue: 3.11.0
Maven: 3.6.0
Libro de versiones de Java: 1.8.0_371
MySQL: 5.5_56
Redis: 5.0.14

一般推荐使用低版本,因为高版本兼容低版本,反之不行

herramientas de desarrollo

IDEA 2021 (backend)
VScode (frontend)

Descargar la plantilla de interfaz de usuario de Vue

https://panjiachen.gitee.io/vue-element-admin-site/zh/guide/Se
Insertar descripción de la imagen aquí
recomienda descargar 1 y 2 aquí. El proyecto se desarrolla principalmente en base a 2, pero ampliará una función de front-end que requiere el uso del código en 1

Después de seleccionar 2, puedes descargar otras versiones, aquí descarguév3.0.0
Insertar descripción de la imagen aquí
Insertar descripción de la imagen aquí

Una vez completada la descarga, 第2个基础模版se extraerá a cualquier directorio que se pueda encontrar (no se recomienda que el directorio contenga caracteres chinos)
Insertar descripción de la imagen aquí

Abra VScode,选择 文件 -> 打开文件夹
Insertar descripción de la imagen aquí
Insertar descripción de la imagen aquí

Abra correctamente como se muestra a continuación
Insertar descripción de la imagen aquí

Proyecto front-end iniciado

Abra la terminal integrada y asegúrese de navegar hasta package.jsonel directorio de nivel.
Insertar descripción de la imagen aquí

Luego ingrese el comando en la terminal.npm install
Insertar descripción de la imagen aquí

Descargará automáticamente las dependencias del proyecto.
Insertar descripción de la imagen aquí

Una vez descargadas las dependencias, inicie el proyecto y ejecute el comandonpm run dev
Insertar descripción de la imagen aquí

El siguiente mensaje aparece para indicar éxito,
Insertar descripción de la imagen aquí
simplemente abra el enlace.
Insertar descripción de la imagen aquí

Descripción y modificación del front-end.

La configuración general del front-end está en el vue.config.jsarchivo.
Insertar descripción de la imagen aquí

La línea 16 es el número de puerto y se puede modificar, aquí la modifiqué para8888
Insertar descripción de la imagen aquí

La línea 34 abre el navegador de forma predeterminada para iniciar el proyecto. Debido a que Vue admite modificaciones en caliente, no necesita reiniciar cada vez que completa la modificación del front-end. La página del front-end se modificará automáticamente después de guardar la modificación. , por lo que se establece aquí.false
Insertar descripción de la imagen aquí

Todas las páginas se guardan en src/viewscarpetas. viewLa carpeta aquí ha sido modificada por mí. El proceso de modificación se explicará más adelante.
Insertar descripción de la imagen aquí

Modifique la página de inicio de sesión primerosrc/views/login/index.vue
Insertar descripción de la imagen aquí

Localice la línea 6 y modifiquetitle
Insertar descripción de la imagen aquí

Navegue hasta la línea 187 y modifique la imagen de fondo. En este momento necesita encontrar una imagen de fondo y colocarla en src/assetsla carpeta.

background-image: url(../../assets/bg.png); //背景图
background-size: 100%;

Insertar descripción de la imagen aquí

Después de guardar, la página se modificará simultáneamente.
Insertar descripción de la imagen aquí

¿Por qué puedo modificar la imagen de fondo aquí?
Insertar descripción de la imagen aquí

F12Abrimos el modo desarrollador en el navegador , seleccionamos 1, luego movemos el mouse para seleccionar la página completa, en este momento aparece un nombre de clase en la esquina inferior izquierda .login.container, recuerda el nombre.
Insertar descripción de la imagen aquí

Abra VScodela búsqueda y observe que el segundo .login-containerque se muestra en la página se reemplaza por "become" . Aquí es donde debemos modificar el estilo. Otras modificaciones:.login.container.-.login-container
Insertar descripción de la imagen aquí

  1. Para cambiar de inglés a chino, en realidad necesita encontrar la palabra en inglés correspondiente y cambiarla a chino. Puede recordar la palabra en inglés en la página, luego ingresar el código para encontrar dónde está la palabra en inglés correspondiente y luego escribir en chino.
    Insertar descripción de la imagen aquí
  2. Modifique el formulario de inicio de sesión para que sea semitransparente y 查找元素luego busquelogin-form
    Insertar descripción de la imagen aquí
    Insertar descripción de la imagen aquí
    .login-form {
          
          
        position: relative;
        width: 520px;
        max-width: 100%;
        padding: 30px 35px 0;
        margin: 0 auto;
        overflow: hidden;
        background-color: #2d3a4b;  // 背景颜色
        border-radius: 5px;             // 表单圆角
        opacity: 0.85;                  // 透明度,值越小越越透明,取值为[0,1]
    }
    
  3. Adjunto el código completo de mi src\views\login\inde.vuearchivo .
    <template>
      <div class="login-container">
        <el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form" auto-complete="on" label-position="left">
    
          <div class="title-container">
            <h3 class="title">神盾局管理系统</h3>
          </div>
    
          <el-form-item prop="username">
            <span class="svg-container">
              <svg-icon icon-class="user" />
            </span>
            <el-input
              ref="username"
              v-model="loginForm.username"
              placeholder="用户名"  
              name="username"
              type="text"
              tabindex="1"
              auto-complete="on"
            />
          </el-form-item>
    
          <el-form-item prop="password">
            <span class="svg-container">
              <svg-icon icon-class="password" />
            </span>
            <el-input
              :key="passwordType"
              ref="password"
              v-model="loginForm.password"
              :type="passwordType"
              placeholder="密码"
              name="password"
              tabindex="2"
              auto-complete="on"
              @keyup.enter.native="handleLogin"
            />
            <span class="show-pwd" @click="showPwd">
              <svg-icon :icon-class="passwordType === 'password' ? 'eye' : 'eye-open'" />
            </span>
          </el-form-item>
    
          <el-button :loading="loading" type="primary" style="width:100%;margin-bottom:30px;" @click.native.prevent="handleLogin">登录</el-button>
    
          <!-- <div class="tips">
            <span style="margin-right:20px;">username: admin</span>
            <span> password: any</span>
          </div> -->
    
        </el-form>
      </div>
    </template>
    
    <script>
    
    import {
          
           validUsername } from '@/utils/validate'
    
    export default {
          
          
      name: 'Login',
      data() {
          
          
        const validateUsername = (rule, value, callback) => {
          
          
          if (!validUsername(value)) {
          
          
            callback(new Error('请输入正确的用户名'))
          } else {
          
          
            callback()
          }
        }
        const validatePassword = (rule, value, callback) => {
          
          
          if (value.length < 6) {
          
          
            callback(new Error('密码不能少于6位'))
          } else {
          
          
            callback()
          }
        }
        return {
          
          
          loginForm: {
          
          
            username: 'admin',
            password: '123456'
          },
          loginRules: {
          
          
            username: [{
          
           required: true, trigger: 'blur', validator: validateUsername }],
            password: [{
          
           required: true, trigger: 'blur', validator: validatePassword }]
          },
          loading: false,
          passwordType: 'password',
          redirect: undefined
        }
      },
      watch: {
          
          
        $route: {
          
          
          handler: function(route) {
          
          
            this.redirect = route.query && route.query.redirect
          },
          immediate: true
        }
      },
      methods: {
          
          
        showPwd() {
          
          
          if (this.passwordType === 'password') {
          
          
            this.passwordType = ''
          } else {
          
          
            this.passwordType = 'password'
          }
          this.$nextTick(() => {
          
          
            this.$refs.password.focus()
          })
        },
        handleLogin() {
          
          
          this.$refs.loginForm.validate(valid => {
          
          
            if (valid) {
          
          
              this.loading = true
              this.$store.dispatch('user/login', this.loginForm).then(() => {
          
          
                this.$router.push({
          
           path: this.redirect || '/' })
                this.loading = false
              }).catch(() => {
          
          
                this.loading = false
              })
            } else {
          
          
              console.log('error submit!!')
              return false
            }
          })
        }
      }
    }
    </script>
    
    <style lang="scss">
    /* 修复input 背景不协调 和光标变色 */
    /* Detail see https://github.com/PanJiaChen/vue-element-admin/pull/927 */
    
    $bg:#283443;
    $light_gray:#fff;
    $cursor: #fff;
    
    @supports (-webkit-mask: none) and (not (cater-color: $cursor)) {
          
          
      .login-container .el-input input {
          
          
        color: $cursor;
      }
    }
    
    /* reset element-ui css */
    .login-container {
          
          
      .el-input {
          
          
        display: inline-block;
        height: 47px;
        width: 85%;
    
        input {
          
          
          background: transparent;
          border: 0px;
          -webkit-appearance: none;
          border-radius: 0px;
          padding: 12px 5px 12px 15px;
          color: $light_gray;
          height: 47px;
          caret-color: $cursor;
    
          &:-webkit-autofill {
          
          
            box-shadow: 0 0 0px 1000px $bg inset !important;
            -webkit-text-fill-color: $cursor !important;
          }
        }
      }
    
      .el-form-item {
          
          
        border: 1px solid rgba(255, 255, 255, 0.1);
        background: rgba(0, 0, 0, 0.1);
        border-radius: 5px;
        color: #454545;
      }
    }
    </style>
    
    <style lang="scss" scoped>
    $bg:#2d3a4b;
    $dark_gray:#889aa4;
    $light_gray:#eee;
    
    .login-container {
          
          
      min-height: 100%;
      width: 100%;
      background-color: $bg;
      overflow: hidden;
    
      background-image: url(../../assets/bg.png); //背景图
      background-size: 100%;
    
    
      display: flex;
      align-items: center;
    
    
      .login-form {
          
          
        position: relative;
        width: 520px;
        max-width: 100%;
        padding: 30px 35px 0;
        margin: 0 auto;
        overflow: hidden;
        background-color: #2d3a4b;  // 背景颜色
        border-radius: 5px;             // 表单圆角
        opacity: 0.85;                  // 透明度,值越小越越透明,取值为[0,1]
      }
    
      .tips {
          
          
        font-size: 14px;
        color: #fff;
        margin-bottom: 10px;
    
        span {
          
          
          &:first-of-type {
          
          
            margin-right: 16px;
          }
        }
      }
    
      .svg-container {
          
          
        padding: 6px 5px 6px 15px;
        color: $dark_gray;
        vertical-align: middle;
        width: 30px;
        display: inline-block;
      }
    
      .title-container {
          
          
        position: relative;
    
        .title {
          
          
          font-size: 26px;
          color: $light_gray;
          margin: 0px auto 40px auto;
          text-align: center;
          font-weight: bold;
        }
      }
    
      .show-pwd {
          
          
        position: absolute;
        right: 10px;
        top: 7px;
        font-size: 16px;
        color: $dark_gray;
        cursor: pointer;
        user-select: none;
      }
    }
    </style>
    
    复制代码后注意背景图的链接地址下要有文件存在

Modificar 页面标签Busque src\settings.jsel archivo y modifique la línea 3.title

Insertar descripción de la imagen aquí

Una vez completada la modificación, la etiqueta del navegador cambiará.
Insertar descripción de la imagen aquí

Modificar barra de navegación

Haga clic aquí para ver la ventana de navegación.
Insertar descripción de la imagen aquí

Puede personalizar la modificación, buscar scr\layout\components\Navbar.vueel archivo y modificar el código en el cuadro rojo.
Insertar descripción de la imagen aquí
Insertar descripción de la imagen aquí

<el-dropdown-menu slot="dropdown" class="user-dropdown">
  <router-link to="/">
     <el-dropdown-item>
       个人信息
     </el-dropdown-item>
   </router-link>

   <a target="_blank" href="https://www.chinaums.com/">
     <el-dropdown-item>公司主页</el-dropdown-item>
   </a>
   <a target="_blank" href="https://www.hhu.edu.cn/">
     <el-dropdown-item>学校主页</el-dropdown-item>
   </a>
   <el-dropdown-item divided @click.native="logout">
     <span style="display:block;">退出登录</span>
   </el-dropdown-item>
 </el-dropdown-menu>

Menús y submenús personalizados

Insertar descripción de la imagen aquí

Primero , cree nuevas carpetas src\views\en sysy , y luego cree nuevos archivos ,,, y testen estas dos carpetas , como se muestra en la siguiente figura .role.vueuser.vuetest1.vuetest2.vuetest3.vue
Insertar descripción de la imagen aquí

Ingrese para role.vueescribir el código. Ingrese y aparecerán mensajes de código
automáticos (es necesario instalar un complemento). Simplemente presione Intro.VScodevueVScodevue
Insertar descripción de la imagen aquí

Las plantillas se generarán automáticamente.
Insertar descripción de la imagen aquí

Escribe algún código en este momento.
Insertar descripción de la imagen aquí

vueOtros archivos recién creados siguen el mismo procedimiento.

Luego vinculamos estos archivos src\router\index.jsrecién creados en la ruta.vue
Insertar descripción de la imagen aquí
Insertar descripción de la imagen aquí

Agregar código y comentarios

{
    
    
    path: '/sys',       // 浏览器访问路径
    component: Layout,
    redirect: '/sys',   // 本地views下的sys文件夹
    name: 'sysManage',  // 名字,唯一标识
    meta: {
    
     title: '系统管理', icon: '1' },   // 标题和图标
    children: [       // 子菜单   
      {
    
    
        path: 'user',   // 子菜单的浏览器访问路径,与父菜单结合 /sys/user 最终形成http://localhost:8888/#/sys/user
        name: 'user',   // 名字,唯一标识
        component: () => import('@/views/sys/user'),   // 新建views下的user.vue文件,该文件一定要存在
        meta: {
    
     title: '用户管理', icon: '个人中心'}    // 标题和图标
      },
      {
    
    
        path: 'role',   // 子菜单的浏览器访问路径,与父菜单结合 /sys/role
        name: 'role',
        component: () => import('@/views/sys/role'),  // 新建view下的user.vue界面,必须存在
        meta: {
    
     title: '角色管理', icon: '新增组织' }
      }
    ]
 },

Tenga en cuenta que en este código icon:'1', este es un ícono personalizado. Puede descargar su ícono favorito de la biblioteca de íconos vectoriales de Alibaba.

Insertar descripción de la imagen aquí

Haz clic en el ícono que te gusteSVG下载
Insertar descripción de la imagen aquí

El icono descargado cambia de nombre y se guarda en src\icons\svgla carpeta .
Insertar descripción de la imagen aquí

Luego puedes usar el ícono en el código sin escribir 路径y后缀名
Insertar descripción de la imagen aquí

El efecto del icono es el siguiente.
Insertar descripción de la imagen aquí

todo mi src\router\index.jscodigo

import Vue from 'vue'
import Router from 'vue-router'

Vue.use(Router)

/* Layout */
import Layout from '@/layout'

/**
 * Note: sub-menu only appear when route children.length >= 1
 * Detail see: https://panjiachen.github.io/vue-element-admin-site/guide/essentials/router-and-nav.html
 *
 * hidden: true                   if set true, item will not show in the sidebar(default is false)
 * alwaysShow: true               if set true, will always show the root menu
 *                                if not set alwaysShow, when item has more than one children route,
 *                                it will becomes nested mode, otherwise not show the root menu
 * redirect: noRedirect           if set noRedirect will no redirect in the breadcrumb
 * name:'router-name'             the name is used by <keep-alive> (must set!!!)
 * meta : {
    roles: ['admin','editor']    control the page roles (you can set multiple roles)
    title: 'title'               the name show in sidebar and breadcrumb (recommend set)
    icon: 'svg-name'/'el-icon-x' the icon show in the sidebar
    breadcrumb: false            if set false, the item will hidden in breadcrumb(default is true)
    activeMenu: '/example/list'  if set path, the sidebar will highlight the path you set
  }
 */

/**
 * constantRoutes
 * a base page that does not have permission requirements
 * all roles can be accessed
 */
export const constantRoutes = [
  {
    
    
    path: '/login',
    component: () => import('@/views/login/index'),
    hidden: true
  },

  {
    
    
    path: '/404',
    component: () => import('@/views/404'),
    hidden: true
  },

  {
    
    
    path: '/',
    component: Layout,
    redirect: '/dashboard',
    children: [{
    
    
      path: 'dashboard',
      name: 'Dashboard',
      component: () => import('@/views/dashboard/index'),
      meta: {
    
     title: '首页', icon: 'dashboard' , affix:true}
    }]
  },

  {
    
    
    path: '/sys',       // 浏览器访问路径
    component: Layout,
    redirect: '/sys',   // 本地views下的sys文件夹
    name: 'sysManage',  // 名字,唯一标识
    meta: {
    
     title: '系统管理', icon: '1' },   // 标题和图标
    children: [       // 子菜单,此子菜单   
      {
    
    
        path: 'user',   // 子菜单的浏览器访问路径,与父菜单结合 /sys/user 最终形成http://localhost:8888/#/sys/user
        name: 'user',   // 名字,唯一标识
        component: () => import('@/views/sys/user'),   // 新建views下的user.vue文件,该文件一定要存在
        meta: {
    
     title: '用户管理', icon: '个人中心'}    // 标题和图标
      },
      {
    
    
        path: 'role',   // 子菜单的浏览器访问路径,与父菜单结合 /sys/role
        name: 'role',
        component: () => import('@/views/sys/role'),  // 新建view下的user.vue界面,必须存在
        meta: {
    
     title: '角色管理', icon: '新增组织' }
      }
    ]
  },

  {
    
    
    path: '/test',
    component: Layout,
    redirect: '/test',
    name: 'test',
    meta: {
    
     title: '功能模块', icon: 'tree' },
    children: [   //子菜单
      {
    
    
        path: 'test1',
        name: 'test1',
        component: () => import('@/views/test/test1'),   // 新建view下的user.vue界面
        meta: {
    
     title: '功能1', icon: '维护管理' }
      },
      {
    
    
        path: 'test2',
        name: 'test2',
        component: () => import('@/views/test/test2'),  // 新建view下的user.vue界面,必须存在
        meta: {
    
     title: '功能2', icon: '维护管理' }
      },
      {
    
    
        path: 'test3',
        name: 'test3',
        component: () => import('@/views/test/test3'),  // 新建view下的user.vue界面,必须存在
        meta: {
    
     title: '功能3', icon: '维护管理' }
      }
    ]
  },



  // 404 page must be placed at the end !!!
  {
    
     path: '*', redirect: '/404', hidden: true }
]

const createRouter = () => new Router({
    
    
  // mode: 'history', // require service support
  scrollBehavior: () => ({
    
     y: 0 }),
  routes: constantRoutes
})

const router = createRouter()

// Detail see: https://github.com/vuejs/vue-router/issues/1234#issuecomment-357941465
export function resetRouter() {
    
    
  const newRouter = createRouter()
  router.matcher = newRouter.matcher // reset router
}

export default router

注意复制代码时,确认好自己的icon图标文件

Agregar función de etiqueta de navegación

Como se muestra en la siguiente figura, es necesario agregar una nueva función
Insertar descripción de la imagen aquí

El código para esta función está en el primer proyecto presentado anteriormente. Ahora necesitas transferir el copycódigo .
Insertar descripción de la imagen aquí

Después de descargar el último paquete comprimido, descomprímalo y busque los siguientes tres archivos. Tenga en cuenta 这些文件复制到正在开发的项目中对应的路径中去que la configuración de ruta de los dos proyectos es la misma.
src/layout/components/TagsView
src/store/modules/tagsView.js
src/store/modules/permission.js

Insertar descripción de la imagen aquí
Insertar descripción de la imagen aquí

Luego ingresa VScodey agrega el código:

  1. Introduce src/layout/components/AppMain.vueel archivo para modificar el código en el cuadro rojo.
    Insertar descripción de la imagen aquí

    <keep-alive :include="cachedViews">
        <router-view :key="key" />
    </keep-alive>
    
    
    export default {
          
          
      name: 'AppMain',
      computed: {
          
          
        key() {
          
          
          return this.$route.path
        },
        cachedViews() {
          
          
            return this.$store.state.tagsView.cachedViews
        }
      }
    }
    
  2. Modificar archivossrc/store/getters.js
    Insertar descripción de la imagen aquí

      visitedViews: state => state.tagsView.visitedViews,
      cachedViews: state => state.tagsView.cachedViews,   
      permission_routes: state => state.permission.routes
    
  3. Modificar archivossrc/store/index.js
    Insertar descripción de la imagen aquí

    import Vue from 'vue'
    import Vuex from 'vuex'
    import getters from './getters'
    import app from './modules/app'
    import settings from './modules/settings'
    import user from './modules/user'
    import tagsView from './modules/tagsView'
    
    Vue.use(Vuex)
    
    const store = new Vuex.Store({
          
          
      modules: {
          
          
        app,
        settings,
        user,
        tagsView
      },
      getters
    })
    
    export default store
    
  4. Modificar archivossrc\layout\index.vue
    Insertar descripción de la imagen aquí

  5. Modificar archivossrc\layout\components\index.js
    Insertar descripción de la imagen aquí

    export {
          
           default as TagsView } from './TagsView'
    

¡Ya terminaste! Reiniciar proyectonpm run dev

Si queremos establecer una etiqueta que no se puede cerrar, como 首页la etiqueta en la imagen a continuación, debemos src\router\index.jsbuscarla en el archivo 首页y agregar atributos.affix:true
Insertar descripción de la imagen aquí

Insertar descripción de la imagen aquí

Además, se puede hacer clic derecho en la navegación de la etiqueta, aquí cambié el inglés al chino.
Insertar descripción de la imagen aquí

Puede VScodebuscar el inglés que aparece en el navegador en China Global, luego buscarlo y luego modificarlo para que corresponda al chino. La ruta modificada aquí es la src\layout\components\TagsView\index.vuelínea media 20.
Insertar descripción de la imagen aquí

En este momento, la modificación de la página de inicio es casi la misma.

Formato de datos de front-end

jsonEl acoplamiento de front-end y back-end requiere conocer el formato de transferencia de datos del inicio de sesión de front-end.

Abra la interfaz del navegador y presione F12Seleccionar网络
Insertar descripción de la imagen aquí

Luego haga clic en 登录, el navegador registrará el estado.
Insertar descripción de la imagen aquí

Haga clic y loginaparecerá el formato de respuesta de datos, como se muestra en el cuadro rojo. Este formato se utilizará al escribir código en el backend.
Insertar descripción de la imagen aquí

{
    
    "code":20000,"data":{
    
    "token":"admin-token"}}

Supongo que te gusta

Origin blog.csdn.net/qq_56039091/article/details/131299419
Recomendado
Clasificación