2.IHRM人力资源 - 登录

news2024/11/16 23:40:15

一、登录页结构与表单开发

我们要实现的登录界面

image-20240109112142005

目前的登录界面

image-20240109112337473

1.1 登录页结构

复制下面的代码到views/login/index.vue页面下

image-20240109113326105

<template>
  <div class="login-container">
    <div class="logo"/>
    <div class="form">
      <h1>登录</h1>
      <el-card shadow="never" class="login-card">
        <!--登录表单-->
      </el-card>
    </div>
  </div>
</template>
<script>
export default {
  name: 'Login'
}
</script>
<style lang="scss">
.login-container {
  display: flex;
  align-items: stretch;
  height: 100vh;

  .logo {
    flex: 3;
    background: rgba(38, 72, 176) url(../../assets/common/login_back.png) no-repeat center / cover;
    border-top-right-radius: 60px;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    justify-content: center;
    padding: 0 100px;

    .icon {
      background: url(../../assets/common/logo.png) no-repeat 70px center /
        contain;
      width: 300px;
      height: 50px;
      margin-bottom: 50px;
    }

    p {
      color: #fff;
      font-size: 18px;
      margin-top: 20px;
      width: 300px;
      text-align: center;
    }
  }

  .form {
    flex: 2;
    display: flex;
    flex-direction: column;
    justify-content: center;
    padding-left: 176px;

    .el-card {
      border: none;
      padding: 0;
    }

    h1 {
      padding-left: 20px;
      font-size: 24px;
    }

    .el-input {
      width: 350px;
      height: 44px;

      .el-input__inner {
        background: #f4f5fb;
      }
    }

    .el-checkbox {
      color: #606266;
    }
  }
}
</style>

保存并看一下页面结构,并没有登录表单,然后下面写一下登录表单

image-20240109113238985

1.2 登录表单结构

<template>
  <div class="login-container">
    <div class="logo"/>
    <div class="form">
      <h1>登录</h1>
      <el-card shadow="never" class="login-card">
        <!--登录表单-->
        <!--el-form element-ui的表单-->
        <!--el-form-item 表单中的一项-->
        <!--el-input 输入框-->
        <el-form>
          <el-form-item>
            <el-input placeholder="请输入手机号"></el-input>
          </el-form-item>

          <el-form-item>
            <el-input placeholder="请输入密码"></el-input>
          </el-form-item>
          <!--勾选框-->
          <el-form-item>
            <el-checkbox>用户平台使用协议</el-checkbox>
          </el-form-item>
          <!--登录按钮
          设置一下宽度 style="width: 350px"
          -->
          <el-form-item>
            <el-button type="primary" style="width: 350px">登录</el-button>
          </el-form-item>
        </el-form>
      </el-card>
    </div>
  </div>
</template>
<script>
export default {
  name: 'Login'
}
</script>
<style lang="scss">
.login-container {
  display: flex;
  align-items: stretch;
  height: 100vh;

  .logo {
    flex: 3;
    background: rgba(38, 72, 176) url(../../assets/common/login_back.png) no-repeat center / cover;
    border-top-right-radius: 60px;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    justify-content: center;
    padding: 0 100px;

    .icon {
      background: url(../../assets/common/logo.png) no-repeat 70px center /
        contain;
      width: 300px;
      height: 50px;
      margin-bottom: 50px;
    }

    p {
      color: #fff;
      font-size: 18px;
      margin-top: 20px;
      width: 300px;
      text-align: center;
    }
  }

  .form {
    flex: 2;
    display: flex;
    flex-direction: column;
    justify-content: center;
    padding-left: 176px;

    .el-card {
      border: none;
      padding: 0;
    }

    h1 {
      padding-left: 20px;
      font-size: 24px;
    }

    .el-input {
      width: 350px;
      height: 44px;

      .el-input__inner {
        background: #f4f5fb;
      }
    }

    .el-checkbox {
      color: #606266;
    }
  }
}
</style>

二、登录

我们使用了很多Element-ui的组件

官网:Element-ui组件官网

接下来我们的登录流程将会按照下图进行设计

2.1 登录表单校验

比如校验手机号的格式是否正确,密码是否符合位数

13.Vue - ref属性、props配置、mixin混入、插件、scoped样式

在element-ui中其实就是如下所示的组件,进行表单验证

我们可以通过el-form标签的ref属性获取form表单的整体实例,进而进行整体的校验

el-form标签中的:rules="rulesFrom"属性其实就是我们的校验规则,并且校验规则都会写在rulesFrom里

el-form标签中的:model="ruleForm"属性其实就是我们所绑定的数据从ruleForm数据结构中来

el-form-item标签汇总的prop="test1"属性,并且test1字段是ruleForm数据结构中的一个属性

el-input标签做一个v-model双向绑定,这样的话就能做回显了

image-20240112112319251

<template>
  <div class="login-container">
    <div class="logo"/>
    <div class="form">
      <h1>登录</h1>
      <el-card shadow="never" class="login-card">
        <!--登录表单-->
        <!--el-form element-ui的表单-->
        <!--el-form-item 表单中的一项-->
        <!--el-input 输入框-->
        <el-form ref="loginFormRef" :model="loginFromModel" :rules="loginFromRules">
          <el-form-item prop="mobile">
            <el-input placeholder="请输入手机号" v-model="loginFromModel.mobile"></el-input>
          </el-form-item>

          <el-form-item prop="password">
            <!-- show-password是el-input属性,表示不展示input框中信息-->
            <el-input show-password placeholder="请输入密码" v-model="loginFromModel.password"></el-input>
          </el-form-item>
          <!--勾选框-->
          <el-form-item prop="isAgree">
            <el-checkbox v-model="loginFromModel.isAgree">用户平台使用协议</el-checkbox>
          </el-form-item>
          <!--登录按钮
          设置一下宽度 style="width: 350px"
          -->
          <el-form-item prop="isAgree">
            <el-button @click="login" type="primary" style="width: 350px">登录</el-button>
          </el-form-item>
        </el-form>
      </el-card>
    </div>
  </div>
</template>
export default {
  name: 'Login',
  data() {
    return {
      // 登录表单数据结构
      loginFromModel: {
        mobile: '',
        password: '',
        isAgree: false
      },
      // 登录表单规则,数据字段和loginFromModel一样,只不过值是数组的模式
      // 数组中的每一个对象值就是一个校验规则
      loginFromRules: {
        // 手机号校验规则
        mobile: [
          /**
           *  required: true 必填
           *  trigger触发模式
           *    change表示只要我们不断的写就会触发校验
           *    blur 失去焦点才会触发校验
           */
          { required: true, message: '请输入手机号信息', trigger: 'blur' },
          // 正则表达式检验规则
          { pattern: /^1[3-9]\d{9}$/, message: '手机号输入格式不合规范', trigger: 'blur' }
        ],
        password: [
          { required: true, message: '请输入密码', trigger: 'blur' },
          // 密码长度校验规则
          { min: 6, max: 16, message: '密码长度在 6 到 16 个字符', trigger: 'blur' }
        ],
        /**
         * 说明:required命令检测不了false,只能检测null/undefine/空字符串
         *  所以我们要自定义校验方式,其实是自定义校验方式是一个函数
         *    需要三个参数rule,value,callback
         *    rule:校验规则
         *    value:要校验的值
         *    callback: 一个必须要执行的函数(无论校验成功还是失败都要执行)
         *              如果校验成功的话直接执行callback()函数,如果失败的话执行callback(new Error(错误信息))
         */
        isAgree: [
          {
            validator: (rule, value, callback) => {
              value ? callback() : callback(new Error('您必须勾选用户平台使用协议'))
            }
          }
        ]
      }
    }
  },
  methods: {
    login() {
      /**
       * 通过表单的ref属性获取表单实例对象,并且执行此表单实例对象的validate方法校验一下
       * validate方法可以传入一个回调函数,并且会传入一个参数,我们可以命名为isOK
       */
      this.$refs.loginFormRef.validate((isOK) => {
        if (!isOK) {
          // 此时isOK为false,表示校验没有通过
          alert('校验没有通过,请检查您的登录信息')
          return
        }
        // 此时isOK为true,表示校验通过了
      })
    }
  }
}
</script>

效果展示

image-20240113133756705

2.2 Vuex 用户模块

我们在登录表单校验之后并不是直接调用请求到后台验证用户名和密码是否正确

而是前端又调用了VuexAction,之后会再去调用登录接口并返回一个token,我们要把此token进行缓存并使用vuex进行共享,共享之后相当于我们的登录成功了,然后跳转到主页

image-20240113134425480

使用了vuex表示一定有数据要去做共享,在这里我们要共享用户的token,之后在每个页面我们都能拿到用户的token了

Vuex基础知识

vuex中的用户模块如下图所示:

image-20240113134628710

// State理解为数据源,像极了我们之前学的data,用来存放数据
const state = {
  token: null
}

// Mutations类似java中的数据层,只对数据进行操作,不对业务操作(比如数据加减乘除)
const mutations = {
  // 修改token
  setToken(state, token) {
    state.token = token
    // console.log(state.token)
  }
}

/**
 * actions似java中的业务逻辑层,对逻辑操作,然后向mutations发送数据,在这个业务逻辑中也可以互相调用
 * actions可以做异步操作
 */
const actions = {
  /**
   * 参数1: context上下文对象,有commit和dispatch方法
   * 参数2:我们要传入的参数
   */
  login(context, data) {
    console.log(context)
    console.log(data)
    // TODO 调用登录接口(代办)
    // 假设登录成功之后就会返回一个token,我们要将此token实现共享就要存储在state中
    // vuex中想修改state中数据必须通过mutations,不能直接修改state中属性
    context.commit('setToken', '123456')
  }
}

// 对三个变量进行一个默认的导出
export default {
  // 开启命名空间。表示之后调用state/mutations/actions时必须带上模块名称
  namespaced: true,
  state,
  mutations,
  actions
}

但是现在有一个问题,当我们刷新页面之后,state.token的值会消失,所以我们要实现vuex持久化

2.3 vuex 数据持久化

这样就算我们给state.token赋值之后,但刷新页面后仍然是null,所以此时永远不能取到我们缓存的token值

// State理解为数据源,像极了我们之前学的data,用来存放数据
const state = {
  token: null
}

所以我们要实现vuex的数据持久化,我们要从缓存中读取state.token的初始值

编写一个工具类

image-20240113145501980

// 我们使用了一个cookie的包,其实和localStorage都可以实现前端缓存数据
import Cookies from 'js-cookie'

const TokenKey = 'vue_admin_template_token'

// 按需导出了三个函数    
    
// 获取token
export function getToken() {
  return Cookies.get(TokenKey)
}

// 设置token
export function setToken(token) {
  return Cookies.set(TokenKey, token)
}

// 移除token
export function removeToken() {
  return Cookies.remove(TokenKey)
}

在vuex用户模块user.js中进行引用

// @符号表示根路径
import { getToken, setToken, removeToken } from '@/utils/auth'

const state = {
  // 这样就算我们给state.token赋值之后,但刷新页面后仍然是null,所以此时永远不能取到我们缓存的token值
  // token: null
  // 从缓存中读取初始值
  token: getToken()
}

const mutations = {
  // 修改token
  setToken(state, token) {
    state.token = token
    // console.log(state.token)
    // 将token值同步到缓存
    setToken(token)
  },
  removeToken() {
    // 删除vuex的token
    state.token = null
    // 删除缓存中的token
    removeToken()
  }
}

我们要在登录组件中进行调用vuex

methods: {
  login() {
    /**
     * 通过表单的ref属性获取表单实例对象,并且执行此表单实例对象的validate方法校验一下
     * validate方法可以传入一个回调函数,并且会传入一个参数,我们可以命名为isOK
     */
    this.$refs.loginFormRef.validate((isOK) => {
      if (!isOK) {
        // 此时isOK为false,表示校验没有通过
        alert('校验没有通过,请检查您的登录信息')
        return
      }
      /**
       * 此时isOK为true,表示校验通过了,调用vuex中的用户模块
       * 此时因为我们开启了命名空间,传参时要带上模块名,即模块名/actions中方法名
       * dispatch方法是调用vuex中的actions
       */
      this.$store.dispatch('user/login', this.loginFromModel)
    })
  }
}

效果如下图所示

image-20240113150404419

2.4 登录联调

image-20240113200709958

2.4.1 请求模块封装

编写登录接口

image-20240113200838635

// 引入封装的axios工具
import request from '@/utils/request'

// 按需暴露一个登录方法
export function login(Data) {
  // request发送登录请求,会得到一个promise结果并将其返回
  return request({
    // 请求地址
    url: '/sys/login',
    // 请求方式
    method: 'POST',
    // 请求参数
    data: Data
    // 在ES6中上面data: Data可以简写为 data
  })
}

2.4.2 登录表单 调用vuex

image-20240113201636001

methods: {
  login() {
    /**
     * 通过表单的ref属性获取表单实例对象,并且执行此表单实例对象的validate方法校验一下
     * validate方法可以传入一个回调函数,并且会传入一个参数,我们可以命名为isOK
     */
    this.$refs.loginFormRef.validate((isOK) => {
      if (!isOK) {
        // 此时isOK为false,表示校验没有通过
        alert('校验没有通过,请检查您的登录信息')
        return
      }
      /**
       * 此时isOK为true,表示校验通过了,调用vuex中的用户模块
       * 此时因为我们开启了命名空间,传参时要带上模块名,即模块名/actions中方法名
       * dispatch方法是调用vuex中的actions
       */
      this.$store.dispatch('user/login', this.loginFromModel)
    })
  }
}

2.4.3 vux模块 调用登录接口

image-20240113201858115

2.4.4 登录测试

超级管理员电话号:138 0000 0002

超级管理员密码:hm#qd@23!

登录密码:网络安全需要,密码以由原来的123456 变更为hm#qd@23! , 管理员不可修改密码,新建用户的密码仍为123456

image-20240113202917035

点击登录接口

image-20240113205216951

请求信息

image-20240113205231956

响应信息

image-20240113205552222

成功存储了浏览器缓存:cookie

image-20240113205300039

image-20240113205459505

刷新之后进入了主页面

image-20240113205515377

补充:为了方便,登录表单的数据我们可以做出如下所示的修改

data() {
  return {
    // 登录表单数据结构
    loginFromModel: {
      mobile: process.env.NODE_ENV === 'development' ? '13800000002' : '',
      password: process.env.NODE_ENV === 'development' ? 'hm#qd@23!' : '',
      isAgree: isAgree: process.env.NODE_ENV === 'development'
    },
 }   

2.5 跳转主页面

当用户登录成功后直接跳转到主页面,而不是等到用户手动刷新之后才跳转到主页面

此功能是登录的最后一个功能

修改登录页面的代码

image-20240113211212413

methods: {
  login() {
    /**
     * 通过表单的ref属性获取表单实例对象,并且执行此表单实例对象的validate方法校验一下
     * validate方法可以传入一个回调函数,并且会传入一个参数,我们可以命名为isOK
     */
    this.$refs.loginFormRef.validate(async(isOK) => {
      if (!isOK) {
        // 此时isOK为false,表示校验没有通过
        alert('校验没有通过,请检查您的登录信息')
        return
      }
      /**
       * 此时isOK为true,表示校验通过了,调用vuex中的用户模块
       * 此时因为我们开启了命名空间,传参时要带上模块名,即模块名/actions中方法名
       * dispatch方法是调用vuex中的actions
       * Vuex中的action返回的是一个promise,说明是一个异步,我们必须等到promise执行成功才能继续跳转到主页
       * 只要是用了await表示下方的代码一定是promise执行成功了
       * await 一定要写,因为我们要等待登录成功,如果失败的话就走axios中的reject
       */
      await this.$store.dispatch('user/login', this.loginFromModel)
      // 登录成功后跳转到主页面
      //  this.$router获取到路由的实例对象,push表示我们要跳转到哪里,'/'表示我们的主页
      this.$router.push('/')
    })
  }
}

我们可以看一下路由的配置

image-20240113212644831

image-20240113212723553

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

Vue.use(Router)

/**
 *  Layout @/在vue中代表路径别名
 *  @ 符号表示当前目录的src
 *  @/ 表示src下的layout,而layout又是一个目录,所以会拉取index.vue文件
 *  即index.vue组件就是我们的路由组件,会实现二级路由
* */
import Layout from '@/layout'

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: 'Dashboard', icon: 'dashboard' }
    }]
  },

  {
    path: '/example',
    component: Layout,
    redirect: '/example/table',
    name: 'Example',
    meta: { title: 'Example', icon: 'el-icon-s-help' },
    children: [
      {
        path: 'table',
        name: 'Table',
        component: () => import('@/views/table/index'),
        meta: { title: 'Table', icon: 'table' }
      },
      {
        path: 'tree',
        name: 'Tree',
        component: () => import('@/views/tree/index'),
        meta: { title: 'Tree', icon: 'tree' }
      }
    ]
  },

  {
    path: '/form',
    component: Layout,
    children: [
      {
        path: 'index',
        name: 'Form',
        component: () => import('@/views/form/index'),
        meta: { title: 'Form', icon: 'form' }
      }
    ]
  },

  {
    path: '/nested',
    component: Layout,
    redirect: '/nested/menu1',
    name: 'Nested',
    meta: {
      title: 'Nested',
      icon: 'nested'
    },
    children: [
      {
        path: 'menu1',
        component: () => import('@/views/nested/menu1/index'), // Parent router-view
        name: 'Menu1',
        meta: { title: 'Menu1' },
        children: [
          {
            path: 'menu1-1',
            component: () => import('@/views/nested/menu1/menu1-1'),
            name: 'Menu1-1',
            meta: { title: 'Menu1-1' }
          },
          {
            path: 'menu1-2',
            component: () => import('@/views/nested/menu1/menu1-2'),
            name: 'Menu1-2',
            meta: { title: 'Menu1-2' },
            children: [
              {
                path: 'menu1-2-1',
                component: () => import('@/views/nested/menu1/menu1-2/menu1-2-1'),
                name: 'Menu1-2-1',
                meta: { title: 'Menu1-2-1' }
              },
              {
                path: 'menu1-2-2',
                component: () => import('@/views/nested/menu1/menu1-2/menu1-2-2'),
                name: 'Menu1-2-2',
                meta: { title: 'Menu1-2-2' }
              }
            ]
          },
          {
            path: 'menu1-3',
            component: () => import('@/views/nested/menu1/menu1-3'),
            name: 'Menu1-3',
            meta: { title: 'Menu1-3' }
          }
        ]
      },
      {
        path: 'menu2',
        component: () => import('@/views/nested/menu2/index'),
        name: 'Menu2',
        meta: { title: 'menu2' }
      }
    ]
  },

  {
    path: 'external-link',
    component: Layout,
    children: [
      {
        path: 'https://panjiachen.github.io/vue-element-admin-site/#/',
        meta: { title: 'External Link', icon: 'link' }
      }
    ]
  },

  // 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

跳转后如下如图所示

image-20240113213017032

三、vue-cli 代理解决跨域

下面仅仅是解决开发环境中的跨域问题,生产环境的跨域问题后面会详细解析

image-20240113151249028

如果跨域问题不解决的话,我们的请求是发送不过去的

Vue - 前端代理服务器解决跨域问题

image-20240113152849778

image-20240113152925711

我们前端页面的地址是http://localhost:9528,后端项目的地址是https://heimahr.itheima.net/,一眼可以看出前后端地址不同源

浏览器同源策略:协议、主机、端口三者一致。目前来说都不一致,如果后端不开启cors的话,前端是请求不到后端去的

解决方案:配置vue-cli代理服务器

如果是node向后端接口服务发送请求的话不会发生跨域问题,因为同源策略是浏览器的策略,并不是node的策略

相当于前端向后端请求的中间新加了一个vue-cli(node)

image-20240113153125683

修改vue.config.js文件,并且修改后记得重启项目

module.exports = {
    .....
  // 此属性中存放项目的一些配置,可以在这个位置写代理的一些属性
  devServer: {
    port: port,
    open: true,
    overlay: {
      warnings: false,
      errors: true
    },
    // before: require('./mock/mock-server.js'), 基础模板做的模拟数据
    // 代理属性
    proxy: {
      // path:目标服务器,想要代理到哪里
      '/api': {
        // 要代理到的目标服务器
        target: 'https://heimahr.itheima.net/'
      }
    }
  },     
    ....    
    
}

四、axios 封装

image-20240113194132188

image-20240113154412346

基地址:axios中有一个baseurl的属性,表示我痛序偶axios设置了一个基础的地址,剩下的所有请求都不要再拼接这个地址了

超时时间:请求超时时间,比如设置为10s,但是我们前端发起请求而服务器10s内没有做出响应,则表示请求失败

axios中还有两个比较重要的拦截器:请求拦截器与响应拦截器

一般来说我们的请求拦截器是往请求中注入一个token,后面的请求就不用一个一个的往请求数据中添加token数据了

响应拦截器一般是负责解析一些数据结构及处理异常

拦截器的基础知识

axios——难点语法使用、拦截器的使用、取消请求功能演示

image-20240113154949071

4.1 配置axios基础信息

配置一下axios的基地址和超时时间

image-20240113170125447

我们补充一下其他文件的内容

vuex中的index.js文件

image-20240113171642993

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'

Vue.use(Vuex)

const store = new Vuex.Store({
  // 模块
  modules: {
    app,
    settings,
    user
  },
  // Vuex中的计算属性
  getters
})

export default store

vuex中的getters.js文件

image-20240113171719736

const getters = {
  sidebar: state => state.app.sidebar,
  device: state => state.app.device,
  token: state => state.user.token,
  avatar: state => state.user.avatar,
  name: state => state.user.name
}
export default getters

4.2 请求拦截器

如下所示的代码我们配置了基地址、超时时间、请求拦截器

// 引入axios
import axios from 'axios'
// 引入vuex可以获取vuex实例对象,
// 我们在vuex实例对象找那个又添加了一个getters.js,其实是为了获取token数据
import store from '@/store/index.js'

// 创建一个axios实例
// 根据指定配置创建一个新的axios,也就是每个新的axios都有自己的配置
var service = axios.create({
  // 基地址。因为后端的所有地址都有一个共同路径/api
  baseURL: '/api',
  // 超时时间,单位为毫秒,10000毫秒为10秒
  timeout: 10000
})

// 创建请求拦截器,并且两个参数都是回调函数
// 请求成功的时候执行第一个成功回调函数
// 请求失败的时候执行第二个失败回调函数,error就是错误对象
service.interceptors.request.use(
  // 成功时执行
  (config) => {
    // 将vuex中的token值放入到请求头里面
    if (store.getters.token) {
      // 存在token,才放入请求头中
      config.headers.Authorization = `Bearer ${store.getters.token}`
    }
    return config
  },
  // 失败时执行
  (error) => {
    // 默认支持promise的,下面语句相当于终止了当前promise的执行
    return Promise.reject(error)
  })

// 默认导出axios实例对象
export default service

4.3 响应拦截器

仍然是修改如下所示文件

image-20240113193909930

image-20240113192714709

// 创建响应拦截器,并且两个参数都是回调函数
service.interceptors.response.use(
  // 请求成功时响应,此时的响应默认包裹了一层data,即response.data才是后台服务返回的内容
  (response) => {
    // 一次性解析出response.data中的三个属性
    const { data, message, success } = response.data
    if (success) {
      // 此时响应正常
      return data
    } else {
      Message({ type: 'error', message: message })
      return Promise.reject(new Error(message))
    }
  },
  // 请求失败时响应
  (error) => {
    // this.$message.warning 不能这么使用,因为此时的this不是组件实例对象
    Message({ type: 'error', message: error.message })
    // 默认支持promise的,下面语句相当于终止了当前promise的执行
    return Promise.reject(error)
  }
)

4.4 axios 区分不同环境

4.4.1 介绍

开发环境:开发人员开发代码、测试的代码环境。此环境对代码的要求不是很高,可以随意更改,因为还不是面向真正的用户

生产环境:也叫做正式环境,面向真实的用户

image-20240113194614759

下面我们就要实现下图流程中的“区分环境”模块

image-20240113194259285

怎么区分不同的环境

使用环境变量,有如下两个位置

  • .env.development中设置开发环境变量 默认 NODE_ENV 值为 development

  • .env.production中设置生产环境变量默认 NODE_ENV 值为 production

image-20240113200035069

执行不同的命令,NODE_ENV的值是不同的,我们需要node命令来取出NODE_ENV的值

process.env.属性的方式获取

process.env是我们node.js的全局变量,可以通过它来取到环境变量的名称

测试一下

开发环境下:在登录界面写一个created钩子函数

created(){
    alert(process.env.NODE_ENV)
}

image-20240113195347418

生产环境下:

image-20240113195433408

4.4.2 区分不同环境

所以为什么要区分环境

开发环境下我们的数据随意更改,但是生产环境下数据是不能随意更改的,并且开发环境下和生产环境下的请求路径也是有所差别的

比如开发环境下请求/api路径,生产环境下走/prod-api路径

image-20240113195841574

vue-cli给我们做了一个变量规范

Vue代码中NODE_ENV之外,所有的变量必须以VUE_APP_开头

image-20240113200155923

所以接下来我们要在axios中区分不同的环境,将VUE_APP_BASE_API的值赋值给axios的基地址

image-20240113200427220

// 创建一个axios实例
// 根据指定配置创建一个新的axios,也就是每个新的axios都有自己的配置
var service = axios.create({
  // 基地址。因为后端的所有地址都有一个共同路径/api
  // 并且这个地方不能写死,否则生产环境和开发环境都走的一个地址
  baseURL: process.env.VUE_APP_BASE_API,
  // 超时时间,单位为毫秒,10000毫秒为10秒
  timeout: 10000
})

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【计算机二级考试C语言】C常量

C 常量 常量是固定值&#xff0c;在程序执行期间不会改变。这些固定的值&#xff0c;又叫做字面量。 常量可以是任何的基本数据类型&#xff0c;比如整数常量、浮点常量、字符常量&#xff0c;或字符串字面值&#xff0c;也有枚举常量。 常量就像是常规的变量&#xff0c;只…

反序列化提升刷题

例题&#xff1a; <?php //flag is in flag.php highlight_file(__FILE__); error_reporting(0); class Modifier { private $var; public function append($value) { include($value); echo $flag; } public function __invoke(){ …

Vue中keep-alive缓存的详解(深度理解)

文章目录 一、Keep-alive 是什么二、使用场景三、原理分析四、思考题&#xff1a;缓存后如何获取数据beforeRouteEnteractived 参考文献 一、Keep-alive 是什么 keep-alive是vue中的内置组件&#xff0c;能在组件切换过程中将状态保留在内存中&#xff0c;防止重复渲染DOM ke…

吉祥物如何解锁虚拟主持人身份,赋能品牌营销?

在互联网突破时空的整体语境下&#xff0c;一个吉祥物可以解锁虚拟主持人身份&#xff0c;结合动作捕捉技术&#xff0c;活跃于品牌线上线下营销活动场景&#xff0c;让吉祥物虚拟主持人凭借其“萌”、的特征&#xff0c;带给用户亲近感&#xff0c;快速拉近品牌与用户的距离&a…

对Transformer的理解。

要理解Transformer&#xff0c;需要先理解注意力机制&#xff0c;下面大部分内容来自台大教授李宏毅老师讲课资料。 注意力机制 之前使用的MLP&#xff0c;CNN&#xff0c;RNN模型可以解决一些简单序列问题&#xff0c;但当序列长度太长容易失去效果&#xff0c;原因是看了新…

怎样获取power shell 的全部可用命令?2/5(篇幅有点长,分成5份)

在power shell 窗口中&#xff0c;有一个获取全部可用命令的命令&#xff1a;get-command&#xff0c;获取到的命令有1640多个&#xff0c;够学习了吧&#xff1f;那么&#xff0c;power shell 命令有哪些类别呢&#xff1f; PowerShell命令可以分为以下几类&#xff1a; Cmdl…

统一存储双控NAS同步备份应用方案

随着业务量的增加&#xff0c;企业必须找到一种有效的解决方案保护数据安全&#xff0c;防止不可预测的存储系统故障。传统的数据备份往往是专用的数据格式&#xff0c;不能保留完整的用户目录信息。因此&#xff0c;IT 人员必须在数据恢复后重新配置才可重新恢复业务。为了解决…

Java零基础教学文档servlet(1)

【Web开发和HTTP协议】 1. Web开发概述 1.1 web概述 万维网&#xff08;英语&#xff1a;World Wide Web&#xff09;亦作WWW、Web、全球广域网&#xff0c;是一个透过互联网访问的&#xff0c;由许多互相链接的超文本组成的信息系统。英国科学家蒂姆伯纳斯-李于1989年发明了…

推荐一款通过ssh连接linux服务的开源工具WindTerm

文章目录 前言WindTerm介绍WindTerm使用主密码和锁屏总结 前言 工作一入门便是游戏服务器开发&#xff0c;所以常常有连接Linux服务器的需求&#xff0c;之前用的最多的是Xshell&#xff0c;最近这个软件个人版只能免费使用一个月了&#xff0c;超过时间会提示更新无法正常使用…

FX110网:保加利亚外汇牌照FSC,进入欧盟市场的另一扇大门

汇市经纪商们对欧盟金融工具市场法规&#xff08;MiFID&#xff09;都不会陌生。通过MiFID体系&#xff0c;欧盟所有国家的监管机构连成了一张网络。因此&#xff0c;任何想要进入欧洲市场的汇商&#xff0c;都希望获得加入MiFID监管机构的牌照&#xff0c;其中最受欢迎的莫过于…

什么是充放电振子理论?

CHAT回复&#xff1a;充放电振子模型&#xff08;Charging-Reversal Oscillator Model&#xff09;是一种解释ENSO现象的理论模型&#xff0c;这个模型把ENSO现象比喻成一个“热力学振荡系统”。 在这个模型中&#xff0c;ENSO现象由三个组成部分&#xff1a;充电&#xff08;C…

web开发学习笔记(2.js)

1.引入 2.js的两种引入方式 3.输出语句 4.全等运算符 5.定义函数 6.数组 7.数组属性 8.字符串对象的对应方法 9.自定义对象 10.json对象 11.bom属性 12.window属性 13.定时刷新时间 14.跳转网址 15.DOM文档对象模型 16.获取DOM对象&#xff0c;根据DOM对象来操作网页 如下图…

JavaScript采集各大电商平台关于预制菜酸菜鱼销售量

因为我喜欢吃酸菜鱼&#xff0c;但是自己弄又弄不来&#xff0c;想从网上找找看看&#xff0c;但是种类多&#xff0c;自己逐个选择又太浪费时间。索性利用自己专业爬虫知识&#xff0c;一边检验我最近代码水平&#xff0c;另一方面还能选择到满意的年货。过去写个各大平台预制…

YOLOv8 Ultralytics:使用Ultralytics框架进行FastSAM图像分割

YOLOv8 Ultralytics&#xff1a;使用Ultralytics框架进行FastSAM图像分割 前言相关介绍前提条件实验环境安装环境项目地址LinuxWindows 使用Ultralytics框架进行FastSAM图像分割参考文献 前言 由于本人水平有限&#xff0c;难免出现错漏&#xff0c;敬请批评改正。更多精彩内容…

射频天线信号防雷器的行业应用解决方案

射频天线信号防雷器&#xff08;信号SPD防雷浪涌保护器&#xff09;是一种用于保护射频信号系统免受雷电和电涌干扰的装置&#xff0c;它可以有效地吸收和分散过电压&#xff0c;保证信号的稳定传输和设备的安全运行。射频天线信号防雷器广泛应用于无线通信、广播电视、卫星导航…

一篇搞明白微信的基本授权功能

一、介绍 由于部分接口需要经过用户授权同意才能调用。我们把这些接口按使用范围分成多个 scope , 用户选择对 scope 来进行授权&#xff0c;当授权给一个 scope 之后&#xff0c;其对应的所有接口都可以直接使用。 此类接口调用时&#xff1a; 如果用户未接受或拒绝过此权限…

elasticsearch[二]-DSL查询语法:全文检索、精准查询(term/range)、地理坐标查询(矩阵、范围)、复合查询(相关性算法)、布尔查询

ES-DSL查询语法&#xff08;全文检索、精准查询、地理坐标查询&#xff09; 1.DSL查询文档 elasticsearch 的查询依然是基于 JSON 风格的 DSL 来实现的。 1.1.DSL 查询分类 Elasticsearch 提供了基于 JSON 的 DSL&#xff08;Domain Specific Language&#xff09;来定义查…

基于WebRTC技术的EasyRTC视频云服务系统在线视频客服解决方案

一、需求分析 随着互联网技术的发展&#xff0c;视频客服也成为服务行业的标配体验&#xff0c;基于WebRTC实时通信技术&#xff0c;客服人员与用户可以建立实时双向的视频交互与沟通。借助视频客服功能可以更加直观地了解用户的需求&#xff0c;提高沟通效率&#xff0c;并帮…

三种连接因特网的方式

拨号上网dial-up Internet Access 是用Modern接电话线&#xff0c;拔一个特定号码&#xff0c;才能接入到因特网&#xff0c;此时电话处于占线状态&#xff0c;网速56Kbps左右 基于PPPoE协议的ADSL(虚拟拨号) ADSL(非对称数字用户环路):是线路传输技术(硬件),是基于电话线上…

基于Java SSM框架实现摄影器材租赁系统项目【项目源码+论文说明】

基于java的SSM框架实现摄影器材租赁系统演示 摘要 21世纪的今天&#xff0c;随着社会的不断发展与进步&#xff0c;人们对于信息科学化的认识&#xff0c;已由低层次向高层次发展&#xff0c;由原来的感性认识向理性认识提高&#xff0c;管理工作的重要性已逐渐被人们所认识&a…