前端部分:
Vue项目的入口文件main.js:
//引入Vue
import Vue from 'vue'
//引入App
import App from './App.vue'
//引入VueRouter
import VueRouter from 'vue-router'
import router from './router/index'
import Vuex from 'vuex'
import store from './store'
//完整引入
//引入ElementUI组件库
import ElementUI from 'element-ui';
//引入ElementUI全部样式
import 'element-ui/lib/theme-chalk/index.css';
import './assets/css/reset.css'
import api from './api/index'
import * as echarts from 'echarts'
// 引入图标库
import './assets/icon/icon.css'
import './assets/fonts/iconfont.css'
//引入mavon-editor
import mavonEditor from 'mavon-editor'
import 'mavon-editor/dist/css/index.css'
// //引入动画
// import animate from 'animate.css'//代码高亮
// import '../src/plugins/hljs.js'
//引入Swiper
// import 'swiper/css/swiper.css'
import hljs from 'highlight.js';Vue.directive('highlight', function (el) {let blocks = el.querySelectorAll('pre code');blocks.forEach((block) => {hljs.highlightBlock(block)})
})import 'highlight.js/styles/atom-one-dark.css'
//引入音频插件
import APlayer from 'vue-aplayer';Vue.use(APlayer, {defaultCover: 'https://github.com/u3u.png',productionTip: true,
});import 'swiper/swiper-bundle.css'
// 引入插件
import plugins from '../src/plugins/plugins'
Vue.use(plugins)
//引入瀑布流插件
import waterfall from 'vue-waterfall2'
Vue.use(waterfall)
Vue.prototype.$echarts = echarts
// import { json } from 'express'
Vue.prototype.$api = api
Vue.use(ElementUI)
Vue.use(VueRouter)
Vue.use(Vuex)
Vue.use(mavonEditor)//关闭Vue的生产提示
Vue.config.productionTip = false
//登录持久化
//用户信息
let username = localStorage.getItem('username')
if (username) {username = JSON.parse(username)store.commit('loginModule/setUser', username)
}
//管理员信息
let adminname = localStorage.getItem('lwandzxl')
if (adminname){adminname = JSON.parse(adminname)store.commit('AdminLogin/setAdmin', adminname)
}
//管理员登录ip
let adminaddress = localStorage.getItem('lwandzxladdress')
if (adminaddress) {adminaddress = JSON.parse(adminaddress)store.commit('AdminLoginAddress/setAddress', adminaddress)
}
// let bgzxl = localStorage.getItem('bgzxl')
// if (bgzxl) {
// bgzxl = JSON.parse(bgzxl)
// store.commit('loginModule/setAdmin', bgzxl)
// }
//判断token是否失效
import axios from 'axios' // 引入axios
Vue.prototype.$axios = axios
import Storage from '@/assets/js/storage.js'
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded'
/* 请求拦截器 */axios.interceptors.request.use(function (config) { // 每次请求时会从localStorage中获取tokenlet token = Storage.localGet('token')if (token) {token = 'bearer' + ' ' + token.replace(/'|"/g, '') // 把token加入到默认请求参数中config.headers.common['Authorization'] = token}return config
}, function (error) {return Promise.reject(error)
})/* 响应拦截器 */axios.interceptors.response.use(function (response) { // ①10010 token过期(30天) ②10011 token无效if (response.data.code === 10010 || response.data.code === 10011) {Storage.localRemove('token') // 删除已经失效或过期的token(不删除也可以,因为登录后覆盖)router.replace({path: '/login' // 到登录页重新获取token})} else if (response.data.token) { // 判断token是否存在,如果存在说明需要更新tokenStorage.localSet('token', response.data.token) // 覆盖原来的token(默认一天刷新一次)}return response
}, function (error) {return Promise.reject(error)
})new Vue({el: '#app',render: h => h(App),router: router,store,beforeCreate() {Vue.prototype.$bus = this}
})
路由文件router.js
import Vue from 'vue'
import VueRouter from 'vue-router'
/*
在原始的 Vue Router 中,当使用 this.$router.push(location) 导航到一个新路由时,如果目标路由不存在,则会抛出错误。
这个代码块可以解决这个问题
*/
const originalPush = VueRouter.prototype.push
VueRouter.prototype.push = function push(location) {return originalPush.call(this, location).catch(err => err)
}Vue.use(VueRouter)
const router = new VueRouter({routes: [{path: '',//redirect: '/home',name: 'index', 把/home设置为首页redirect: '/home',name: 'index',component: () => import('../views/Layout/index'),children: [{path: '/home',name: 'home',component: () => import('../views/components/Home/Home')},{path: 'todos',name: 'todos',component: () => import('../components/Todos/Todos')},{path: 'tools',name: 'tools',component: () => import('../components/Tools/index'),children: [{path: 'fanyi',name: 'fanyi',component: () => import('../components/Tools/Fanyi')},{path: 'weather',name: 'weather',component: () => import('../components/Tools/Weather')},{path: 'photos',name: 'photos',component: () => import('../components/Tools/Photo')}, {path: 'word',name: 'word',component: () => import('../components/Tools/Word')},]},{path: 'usercenter',name: 'usercenter',meta: { isLogin: true },component: () => import('../../src/views/components/Usercenter/Usercenter'),},{name: 'userinfoedit',path: 'userinfoedit',component: () => import('../components/Userinfoedit/Userinfoedit')},{name: 'photo',path: 'photo',component: () => import('../views/components/Photo/Photo')},{name: 'video',path: 'video',component: () => import('../views/components/Video/Video')},{name: 'article',path: 'article',component: () => import('../../src/views/components/Article/Article')},{name: 'articleinfo',path: 'articleinfo',component: () => import('../../src/components/ArticleInfo/ArticleInfo')},{name: 'search',path: 'search',component: () => import('../../src/components/Search/Search')},{name: 'messageinfo',path: 'messageinfo',component: () => import('../../src/components/Message/MessageInfo')},]},{path: '/login',name: 'login',component: () => import('../views/components/Login/Login')},{path: '/register',name: 'register',component: () => import('../views/components/Register/Register')},{path: '/adminlogin',name: 'adminlogin',component: () => import('../Admin/AdminLogin/AdminLogin')},{path: '/admin',name: 'admin',meta: { isAdminLogin: true },component: () => import('../Admin/Layout/index'),children: [{path: 'userlist',name: 'userlist',component: () => import('../Admin/User/UserList')},{path: 'adduser',name: 'adduser',component: () => import('../Admin/User/AddUser')},{path: 'updateuser',name: 'updateuser',component: () => import('../Admin/User/UpdateUser')},{path: 'addphoto',name: 'addphoto',component: () => import('../Admin/Photo/AddPhoto')},{path: 'photolist',name: 'photolist',component: () => import('../Admin/Photo/PhotoList')},{path: 'home',name: '/admin/home',component: () => import('../Admin/Home/Home')},{path: 'articlelist',name: 'articlelist',component: () => import('../Admin/Article/ArticleList')},{path: 'huishouzhan',name: 'huishouzhan',component: () => import('../Admin/Article/Huishouzhan')},{path: 'addarticle',name: 'addarticle',component: () => import('../Admin/Article/Add')},{path: 'editarticle',name: 'editarticle',component: () => import('../Admin/Article/Edit')},{path: 'comment',name: 'comment',component: () => import('../Admin/Article/Comment')},{path: 'system',name: 'system',component: () => import('../Admin/System/System')},{path: 'videolist',name: 'videolist',component: () => import('../Admin/Video/VideoList')},{path: 'addvideo',name: 'addvideo',component: () => import('../Admin/Video/AddVideo')},{path: 'message',name: 'message',component: () => import('../Admin/Message/Message')},{path: 'category',name: 'category',component: () => import('../Admin/Category/Category')},]}]
})
//获取vuex数据
import store from '../store/index'
//用户路由拦截
router.beforeEach((to, from, next) => {// to and from are both route objects. must call `next`.//需要登录if (to.meta.isLogin) {let token = store.state.loginModule.userinfo.tokenif (token) {next()} else if (confirm('您还没有登录,确定登录吗?')) {next('/login')this.$router.go(-1)}} else {//不需要登录next()}
})export default router
登录页面:
<template><div class="login"><h3 class="title">登录界面</h3><el-form:model="loginForm"status-icon:rules="rules"ref="loginForm"label-width="60px"class="demo-loginForm"><el-form-item label="账号" prop="username"><el-inputtype="text"v-model="loginForm.username"autocomplete="off"></el-input></el-form-item><el-form-item label="密码" prop="password"><el-inputtype="password"v-model="loginForm.password"autocomplete="off"></el-input></el-form-item><el-form-item><el-button type="primary" @click="submitForm('loginForm')">登录</el-button><el-button @click="resetForm('loginForm')">重置</el-button><span class="zhuce" @click="register">没有账户?去注册</span><span class="youke" @click="zhuye">我是游客</span></el-form-item></el-form></div>
</template><script>
import jwt from "jwt-decode";
import { mapMutations } from "vuex";
export default {name: "Login",data() {var validateLname = (rule, value, callback) => {if (value === "") {callback(new Error("请输入账户😊"));} else {callback();}};var validatePass = (rule, value, callback) => {if (value === "") {callback(new Error("请输入密码😊"));} else {callback();}};return {bodyImg: "url(" + require("../../../assets/img/loginbg.jpg") + ")",loginForm: {username: "",password: "",},rules: {username: [{ validator: validateLname, trigger: "blur" }],password: [{ validator: validatePass, trigger: "blur" }],},};},//设置背景图片mounted() {document.body.style.backgroundImage = this.bodyImg;document.body.style.backgroundSize = "100%";//注册成功后,跳转登录界面,通过读取localStorage里的数据,使得登录的账户,密码就是注册的账户,密码let register = localStorage.getItem("register");if (register) {register = JSON.parse(register);this.loginForm.username = register.username;this.loginForm.password = register.password;}},beforeMount() {document.body.style.backgroundImage = "";},beforeDestroy() {this.$bus.$off("zxl");},methods: {//游客身份跳转主页zhuye() {this.$router.push("/");},register() {this.$router.push("/register");},...mapMutations("loginModule", ["setUser"]),submitForm(formName) {this.$refs[formName].validate((valid) => {if (valid) {console.log("校验通过", this.loginForm);let { username, password } = this.loginForm;// 请求登录接口this.$api.getLogin({username,password,}).then((res) => {console.log("解析前", res.data);if (res.data.status === 200) {console.log("解析后", jwt(res.data.data));//登录成功后:1. 存储登录信息 2. 跳转网页 3. 顶部区域显示用户信息 4. 持久化let obj = {username: jwt(res.data.data).username,token: res.data.data,avatar: res.data.avatar,email: res.data.email,};console.log("obj", obj);this.setUser(obj);//存储本地localStorage.setItem("loginStatus", true);localStorage.setItem("username", JSON.stringify(obj));//跳转this.$router.push("/home");this.$message({message: "恭喜您,登录成功😊",type: "success",});//清除注册成功的用户数据localStorage.removeItem("register");} else {//账户或密码错误this.$message({message: "警告哦,账户或密码错误😊",type: "warning",});}});} else {console.log("error submit!!");return false;}});},resetForm(formName) {this.$refs[formName].resetFields();},},
};
</script>
项目主页:
<template><div class="main"><!-- 顶部区域 --><div class="header"><!-- <div class="logo"><div class="zxl"><img src="../../assets/img/logo3.png" alt="" /></div><div class="lw"><img src="../../assets/img/logo2.png" alt="" /></div></div> --><div class="search"><el-inputplaceholder="请输入内容"v-model="val"@keydown.native.enter="goSearch(val.trim())"><i slot="prefix" class="el-input__icon el-icon-search"></i></el-input><button class="hhh" @click="goSearch(val.trim())">搜索</button></div><div class="login"><i v-show="userinfo.username === 'admin'">欢迎超级管理员:</i><i v-show="userinfo.username !== 'admin'">欢迎:</i>{{ userinfo.username || " 游客" }}<span v-show="userinfo.username" @click="loginout"><i class="el-icon-loading"></i> 退出登录</span><span v-show="userinfo.username === ''" @click="login"><i class="el-icon-loading"></i> 登录</span><span v-show="userinfo.username === ''" @click="register"> 注册</span><!-- <span @click="loginout"> 退出登录</span> --></div><!-- <div class="light"><Light @changeBackground="changeBG"></Light></div> --></div><!-- 内容区域 --><div class="layout"><Leftmenu class="leftmenu"></Leftmenu><Rightmenu class="rightmenu"></Rightmenu><Content class="content"></Content></div><transitionappearname="animate__animated animate__bounce"enter-active-class="animate__backInUp"leave-active-class="animate__backOutDown"><div class="gotop" v-if="istop" @click="gotop"><img src="../../assets/img/gotop.png" alt="" /></div></transition></div>
</template><script>
import "animate.css";
import { mapState } from "vuex";
import { mapMutations } from "vuex";
import Fengche from "../../components/Fengche/Fengche";
import Content from "./Content";
import Leftmenu from "./Leftmenu";
import Rightmenu from "./Rightmenu";
import Light from "../../components/Light/Light";
export default {name: "index",data() {return {istop: false,val: "",bodyImg: "url(" + require("../../assets/img/bg111.jpg") + ")",bodyImg1: "url(" + require("../../assets/img/night.gif") + ")",isclick: true,};},components: {Content,Leftmenu,Rightmenu,Light,Fengche,},computed: {...mapState("loginModule", ["userinfo"]),},watch: {isclick(val) {console.log("变化", val);if (val === true) {document.body.style.backgroundImage = this.bodyImg;document.body.style.backgroundSize = "100%";document.body.style.backgroundAttachment = "fixed";} else {document.body.style.backgroundImage = this.bodyImg1;document.body.style.backgroundSize = "100%";document.body.style.backgroundAttachment = "fixed";}},},// watch: {// val(val, oldval) {// console.log("新", val);// console.log("旧", oldval);// if (val !== oldval) {// this.val = val;// }// },// },methods: {//搜索goSearch(val) {if (val == "") {return this.$message.error("错了哦,输入不能为空");}this.$router.push(`/search?content=${val}`);},changeBG() {this.isclick = !this.isclick;// console.log(this.isclick);// document.body.style.backgroundImage = `${// this.click ? this.bodyImg : this.bodyImg1// } `;// document.body.style.backgroundSize = "100%";// document.body.style.backgroundAttachment = "fixed";},...mapMutations("loginModule", ["clearUser"]),//退出登录loginout() {//清空vuex数据this.clearUser();//清空本地数据localStorage.removeItem("username");localStorage.removeItem("loginStatus");//返回登录this.$router.push("/login");},login() {this.$router.push("/login");},register() {this.$router.push("/register");},handleScroll(e) {let scrollTop =document.body.scrollTop || document.documentElement.scrollTop;if (scrollTop >= 480) {this.istop = true;}if (scrollTop < 480) {this.istop = false;}// if (e.target.scrollTop > 700) this.istop = true;},gotop() {let top = document.documentElement.scrollTop || document.body.scrollTop;const timeTop = setInterval(() => {document.body.scrollTop =document.documentElement.scrollTop =top -=50;if (top < 0) {clearInterval(timeTop);}}, 10);},},mounted() {document.body.style.backgroundImage = this.bodyImg;document.body.style.backgroundSize = "100%";document.body.style.backgroundAttachment = "fixed";window.addEventListener("scroll", this.handleScroll);},beforeMount() {document.body.style.backgroundImage = "";},beforeDestroy() {window.removeEventListener("scroll", this.handleScroll);},
};
</script>
left:
<template><el-menu:default-active="$route.path"class="el-menu-vertical-demo"@open="handleOpen"@close="handleClose"background-color="rgba(0,0,0,0.5)"text-color="#fff"active-text-color="#ffd04b"@select="handleSelect"><el-menu-item index="/home"><i class="iconfont icon-shouye"></i><span slot="title"><router-link to="/home"> 首页</router-link></span></el-menu-item><el-menu-item index="/article"><i class="iconfont icon-16"></i><span slot="title"><router-link to="/article"> 文章</router-link></span></el-menu-item><el-menu-item index="/todos"><i class="iconfont icon-zuozhe2"></i><span slot="title"><router-link to="/todos"> 记事本</router-link></span></el-menu-item><el-menu-item index="/photo"><i class="iconfont icon-tupian"></i><span slot="title"><router-link to="/photo"> 相册</router-link></span></el-menu-item><el-menu-item index="/video"><i class="iconfont iconfont icon-shipin"></i><span slot="title"><router-link to="/video"> 视频</router-link></span></el-menu-item><el-menu-item index="/messageinfo"><i class="iconfont icon-liuyanban"></i><span slot="title"><router-link to="/messageinfo"> 留言板</router-link></span></el-menu-item><el-menu-item index="/usercenter"><i class="iconfont icon-yonghuxinxi-"></i><span slot="title"><router-link to="/usercenter"> 个人中心</router-link></span></el-menu-item><el-menu-item index="/tools"><i class="iconfont icon-gongjuxiang1"></i><span slot="title"><router-link to="/tools"> 实用工具</router-link></span></el-menu-item><el-menu-item index="/admin/home" v-show="userinfo.username === 'admin'"><i class="iconfont icon-yonghu"></i><span slot="title"><router-link to="/admin/home"> 后台登录</router-link></span></el-menu-item></el-menu>
</template><script>
import { mapState } from "vuex";
export default {name: "Leftmenu",computed: {...mapState("loginModule", ["userinfo"]),},// mounted() {// console.log(this.userinfo.username);// },methods: {handleOpen(key, keyPath) {console.log(key, keyPath);},handleClose(key, keyPath) {console.log(key, keyPath);},//element-ui导航菜单使用刷新后高亮显示不一致完美解决办法handleSelect(key, keyPath) {this.$router.push(key);},},
};
</script>