新增登录页面

.vuepress/components新增Login.vue

      <template>
  <div class="login-container">
   <div class="login-form">
	<Date />
	<div class="form-row">
		<div class="form-header">账号</div>
		<input type="text" class="form-control" v-model="username">
	</div>
	<div class="form-row">
		<div class="form-header">密码</div>
		<input type="password" class="form-control" v-model="password">
	</div>
	<div class="btn-row">
		<button class="btn" @click="login">
		登录
		</button>
	</div>
   </div>
  </div>
</template>

<script>
import { STORAGE_KEY } from '../login/helper'
import { DialogToast } from 'v-dialogs'

export default {
  data () {
	return {
	  username: '',
	  password: ''
	}
  },
  methods: {
	  login() {
		 let { time, token } = this.$themeConfig.loginInfo
	  if (this.username  && this.password ) {
		const data = JSON.stringify({
		  name: this.username,
		  time: Math.round(new Date().getTime()/1000),
		  expire: 86400 * time,
		  accesskey: token
		})
		window.localStorage.setItem(STORAGE_KEY, data)
		this.$router.push({ name: 'v-413f20b7' }, () => {
			DialogToast('登录成功', {
				messageType: 'success',
				position: 'topCenter',
				closeTime: 3
			})
		}, (error) => {
			DialogToast('系统错误', {
				messageType: 'error',
				position: 'topCenter',
				closeTime: 3
			})
		})		
	  } else {
		DialogToast('账号或密码错误!', {
			messageType: 'error',
			position: 'topCenter',
			closeTime: 3 
		})
	  }
	}
  }
}
</script>

<style lang="stylus">
.login-container {
  width: 100%;
  height: 100vh;
  background-color: #2d3a4b;
}
.form-row {
  display: flex;
  flex-direction: row;
  margin-top: 1rem;
}
.login-form {
  padding: 1rem;
  display: flex;
  flex-direction: column;
  box-sizing: border-box;
  background-color: #2d3a4b;
  width:50%;
  position:absolute;
  left:50%;    /* 定位父级的50% */
  top:50%;
  transform: translate(-50%,-50%); /*自己的50% */
}

.login-form .btn-row {
  margin: 2rem auto;
}

.login-form .btn {
  padding: 0.6rem 2rem;
  outline: none;
  background-color: #60C084;
  color: white;
  border: 0;
  width: 13rem;
}

.login-form .form-header {
  color: #f08d49;
  margin-bottom: 0.5rem;
  width: 3rem;
  padding-top: .5rem;
}

.login-form .form-control {
  padding: 0.6rem;
  border: 2px solid #ddd;
  margin-bottom: 0.5rem;
  box-sizing: border-box;
  outline: none;
  flex: 1;
  transition: border 0.2s ease;
}

.login-form .form-control:focus {
  border: 2px solid #aaa;
}
</style>
    

新增登录页面路由/login

      module.exports = {
  ...
  
   additionalPages: [
    {
      path: '/login/',
      frontmatter: {
        layout: 'Login', //.vuepress/components新增的页面,名称得同名
        article: false  // 设置为非文章页
      }
    }
  ],
  
   themeConfig: {
     ...
   }
  
}
    

添加登录验证逻辑helper.js

      export const STORAGE_KEY = 'employee-auth'

export function checkAuth() {
  // 通过 localStorage 对象从浏览器本地存储中获取指定键(STORAGE_KEY)对应的值
  // 使用 JSON.parse 将其转换为对象。
  const auth = JSON.parse(localStorage.getItem(STORAGE_KEY))
  // Object.keys(auth) 返回一个由对象的键组成的数组,而 .length 属性表示数组的长度,因此这个条件检查对象是否非空。
  // 返回值是一个布尔值。如果 auth 存在且至少包含一个键,那么表达式的结果为 true,否则为 false。
  return auth && Object.keys(auth).length 
}
    

添加路由守卫

安装v-dialogs模态对话框插件

:::: el-tabs

::: el-tab-pane label=yarn

      yarn add v-dialogs -D
    

::: ::: el-tab-pane label=npm

      npm i v-dialogs -D
    

::: ::::

然后在./vuepress/enhanceAPP.js执行路由守卫逻辑

      //引入登录验证逻辑helper.js
import { checkAuth, STORAGE_KEY } from './login/helper';
const whiteList = ['/login/', '/']

export default ({ Vue,router }) => {

  Vue.mixin({
    mounted() {

      //全局注册v-dialogs
      let dialog = require('v-dialogs')
      Vue.use(dialog)
     
      
      let { isLogin, token } = this.$themeConfig.loginInfo
       // 是否开启登录
      if (isLogin) {  
        router.beforeEach(async (to, from, next) => {
          if (checkAuth()) {
            if (to.path === '/login/') {
              // if is logged in, redirect to the home page
              next({ path: '/' })
            } else {
              //转成json对象
              let auth = JSON.parse(localStorage.getItem(STORAGE_KEY))
              // auth存在并且accesskey是config.js里的token的值
              if (auth && auth.accesskey === token) {
                // 存值时间戳 +  有效时间 = 过期时间戳
                // 如果当前时间戳大于过期时间戳说明过期了,删除值并返回提示
                if ((Date.now() / 1000) > (auth.time + auth.expire)) {
                  localStorage.removeItem(STORAGE_KEY)
                  //重定向到登录页,name通过vue.js devtools获取
                  next({ name: 'v-18a8437b' })
                } else {
                  next();
                }
              } else {
                dialog.DialogAlert('登录已过期,请重新登录!', function () {
                  localStorage.removeItem(STORAGE_KEY)
                   //重定向到登录页,name通过vue.js devtools获取
                  next({ name: 'v-18a8437b' })
                }, {
                  messageType: 'warning'
                })
              }
            }
          } else {
            /* has no token*/
            if (whiteList.indexOf(to.path) !== -1) {
              next()
            } else {
              //重定向到登录页,name通过vue.js devtools获取
              next({ name: 'v-18a8437b' })
            }
          }
        });
      } else {
        localStorage.removeItem(STORAGE_KEY)
      }  
    },
  });
};
    

完善路由守卫

enhanceAPP.js在页面刷新和直接在浏览器访问某个路由时并不会触发,所以需要注册一个全局组件LoginInfo,在没有token执行页面刷新和浏览器直接访问时重定向到登录页,弥补enhanceAPP.js缺失的功能

.vuepress/components中添加LoginInfo.vue,代码如下

      <template></template>

<script>
import { checkAuth, STORAGE_KEY } from '../login/helper';
export default {
    mounted() {
      // 是否开启登录
        let { isLogin } = this.$themeConfig.loginInfo
     
        if (!checkAuth() && this.$route.path !== '/login/' && isLogin) {
            this.$router.push('/login/')
        }
    },
};
</script>
    

config.js的themeConfig添加如下配置

      module.exports = {
  ...
 
   themeConfig: {
     loginInfo: {
      isLogin: false, // 是否开启登录
      token: Math.random().toString(32).slice(2),
      time: 1  // token过期时间,单位:天
    },
   }
  
  ...
  
}
    

声明

作者: liyao

版权:本博客所有文章除特别声明外,均采用CCBY-NC-SA4.O许可协议。转载请注明!

最后更新于 2026-02-18 18:15 history