本地服务器配置apache安装学习参考网址:(官网下载apache包的时候可能会疯狂断开链接)教程里没说,但是要管理员身份操作cmd。
https://blog.csdn.net/qqhruchen/article/details/127457889?spm=1001.2101.3001.6661.1&utm_medium=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1-127457889-blog-126964130.235%5Ev38%5Epc_relevant_anti_t3_base&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1-127457889-blog-126964130.235%5Ev38%5Epc_relevant_anti_t3_base&utm_relevant_index=1
公司大佬说想直接在浏览器输入ip地址和端口访问自己做的前端项目,可以 npm run build 生成dist文件夹,然后把文件夹里面的内容扔到服务器上。但是只有局域网的机子能访问,外网不可以。我的扫雷看来是没法给闺蜜玩了,悲。
具体的以后再问,打个标记码住。
公司前端项目的继续学习。前些天研究扫雷,打了一下基础,好歹能分辨各个文件夹是干嘛的。今天通过现成的代码学一下网页布局怎么布置的。
目录大概说明:
<!-- build --> <!-- config --> <!-- generate --> <!-- node_modules --> <!-- public --> <!-- src --> <!-- static --> <!-- config --> 不少内容看起来是新建项目后没动过,连vue图标都还在。
对于公司主页面布局,项目根目录下的index.html文件:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <!-- 以下句子↓几乎都能在网上找到一模一样的 --> <!-- 意为没有缩放,最大缩放1倍 --> <meta name="viewport" content="width=device-width, initial-scale=1,maximum-scale=1, user-scalable=no"> <title>公司平台名字</title> <!-- 设置标签页标签前图标 --> <link rel="shortcut icon" href="./favicon.ico" type="image/x-icon"> <!-- 用于初始化css,需要自行新建static/css/reset.css文件 --> <!-- 重置样式表,去除浏览器默认样式 --> <link rel="stylesheet" type="text/css" href="static/css/reset.css"> <!-- 查了一下,应该是服务器给客户端推消息的方法 --> <!-- signalr.js 据说可以直接百度下载 --> <!-- 真百度了,摸到微软官网教程 https://learn.microsoft.com/zh-cn/aspnet/core/signalr/javascript-client?view=aspnetcore-7.0&tabs=visual-studio --> <script src="static/js/signalr.js"></script> </head> <body> <div id="app"></div> </body> </html>
基本涉及到项目根目录下的static文件夹,但是我看网上资料好像这里一般装的都是图片和字体,不知道为什么佬要把signalr.js搁这。static下面还有一个ueditor文件夹.我搜了一下,里面基本都是网上下载的文件,由于是下载的关系,系统无法排版的长句非常多,格式看起来非常恶心。不,这根本没有格式。截个屏分享一下此刻的恶心感。
这个ueditor文件夹大概包括:处理HTML事件的jQuery、开源富文本编辑器ueditor文件。这个ueditor我查了一下,能做出编辑图文、多种样式排版的效果。
有机会可以小做一个网页文本编辑器练练手,打个标记码住坑。
总的来说,static就放了signalr.js和ueditor资源。
再看index.html的body部分,跳转根目录的src/App.vue查看详情(忽略style):
<template> <div id="app"> <!-- <keep-alive> <router-view v-if="$route.meta.keepAlive" /> </keep-alive> <router-view v-if="!$route.meta.keepAlive" /> --> <router-view /> </div> </template> <script> export default { mounted() { // 手机屏幕适应【自动缩放】 // const t = window.devicePixelRatio // const allWidth = window.document.body.offsetWidth // if (t !== 1) { // document.body.style.zoom = 1 / t // } else { // if (allWidth < 1920) { // document.body.style.zoom = allWidth / 1920 // } // } // 固定pt 65 // pt与px转换 px = pt / 72 * 96 } } </script>
不知道为什么注释掉了这么多,看起来是能用的。如果是我的话,那个被注释掉的两个v-if,我会把其中一个直接用v-else代替。后面那一串写着多累啊。
查了一下,注释段中keep-alive用于保活组件
1 <keep-alive> 2 <router-view> 3 <!-- 所有路径匹配到的视图组件都会被缓存! --> 4 </router-view> 5 </keep-alive> 6 <!-- 可参考的详细教程网址: --> 7 <!-- https://juejin.cn/post/6844903918313406472 -->
看一下路由src/router,包括src/router/index.js和src/router/methods/router-view.vue
(为什么router也要vue啊……)因为涉及到公司功能,大概归类一下:
//找到一个靠谱的动静态路由设置教程: //https://blog.csdn.net/m0_37787662/article/details/111887288 //其实人家是教怎么实现:前端每次刷新时根据用户角色,获取后台的菜单数据,添加到动态路由中,格式化成菜单数据 // 隐藏路由 export const constantRouterMap = [ //第一个大花括号 { path: "/", //目录和router同级,在src下 component: Layout, //组件为src/Layout文件夹内容 redirect: "dashboard", //重定向(?)到路径src/view/dashboard(首页) //很神奇,接下来的children路由路径,变成以dashboard为基准的了 hidden: true, //隐藏该组件 meta: { title: "功能菜单", //组件名字 icon: "maintenance-management",//组件图标 power: [1] //查不到power。可能和安卓开发的layout-weight一个性质? //项目中基本都是power:[1] }, children: [ { //第一种:设dashboard=d,D为dashboard同级文件夹,x为文件夹名字 path: "/x", //路径:@/view/D/x path: "d", //路径:@/view/d path: "/x/:k", //路径:@/view/D name: "x", //基本就是path不带'/' component: () => import("注释所写的路径/index"), meta: { title: "显示时候的标题", power: [1], code: codeID //有的会没有code } }, //{......},...... ] }, //第二个大花括号 { path: "/login", component: () => import("@/view/login/index"), hidden: true },
{......} //据说生成view会有的路由:(我之前生成的时候没有,可能编译器不同) { path: "/404", component: () => import("@/view/404"), hidden: true }, { path: "*", redirect: "/404", hidden: true }, { path: "/401", redirect: "/401", component: () => import("@/view/401"), hidden: true } ];
//其他路由 const router = new Router({ mode: "hash", //mode: "history", //后端支持可开 scrollBehavior: () => ({ y: 0 }), routes: constantRouterMap }); // 解决重复点击路由报错的BUG const originalPush = Router.prototype.push; Router.prototype.push = function push(location) { return originalPush.call(this, location).catch(err => err); }; export default router;
router/methods/router-view.vue:
<template> <div class="router-view"> <router-view /> </div> </template> <script> export default { name: 'Blank' } </script> <style lang="stylus" rel="stylesheet/stylus" scoped> .router-view { width: 100%; height: 100%; } </style> <!-- 看起来只是为了设置name --> <!-- stylus学习参考网址:https://stylus.bootcss.com/ -->
进入公司项目页面的时候,首先是登录界面,但是在router里,login界面是隐藏的。所以必然有一个处理是否登录、是否需要跳转登录、验证用户身份的文件。文件执行发生在页面跳转之前。在src找了找,目录有一个permission.js文件应该就是实现这个功能的。
const whiteList = ["/login", "/change-password"]; // 不重定向白名单
当点击登录和改密的时候路由不重定向,试了一下,前往登录或者改密的话,只要进入页面,就会默认退出登录。应该是和首页分开的。
点开这个文件首先就是router.beforeEach()函数:
1 router.beforeEach((to, from, next) => { 2 //from 没有在函数内用到,可能只是增加代码易读性,或者辅助其他函数使用 3 NProgress.start(); 4 //加载进度条,前有import引入,在node_modules里 5 handleKeepAlive(to); 6 //permission.js的其他函数,辅助上文App.vue中提到的keep-alive缓存路由(也就是说注释掉后应该是能删掉的?) 7 if (updateDate() === true) { 8 //如果登录没过期 9 if (whiteList.indexOf(to.path) !== -1) { 10 next(); 11 return false; 12 } 13 //点击空白列表无反应 14 if (to.path === "/login") { 15 next({ path: "/" }); 16 return false; 17 NProgress.done(); //放在return之后的神奇代码 18 } else { 19 if (to.path !== "/") { 20 // outLiveRouter(to) 21 /*重定向到收藏页的代码,但是没用过 22 //可能这个permission.js里面的代码是从什么地方copy过来的。这个项目功能不全,可能是公司已上线网站上搬过来一部分代码做的。 23 function outLiveRouter(to) { 24 console.log("outLiveRouter"); 25 let collection = { 26 path: "/collection-live", 27 component: Layout, 28 meta: { 29 icon: "warehouse-management", 30 title: "收藏", 31 power: [1] 32 }, 33 children: [] 34 }; 35 outRouterConfig(constantRouterMap, to); 36 collection.children.push(obj); 37 if (obj) { 38 router.addRoute(collection); 39 } 40 } 41 */ 42 } 43 // 通知详情 44 if (to.name === "flow-details") { 45 to.meta.title = to.params.title; 46 } 47 if (store.getters.roles.length === 0) { 48 store 49 .dispatch("GetInfo") 50 .then(res => { 51 loadMenus(next, to); 52 }) 53 .catch(err => { 54 store.dispatch("FedLogOut").then(() => { 55 Message.error(err || "Verification failed, please login again"); 56 next({ path: "/" }); 57 return false; 58 }); 59 }); 60 } else if (store.getters.loadMenus) { 61 store.dispatch("updateLoadMenus"); 62 loadMenus(next, to); 63 } else { 64 getPowerIs(to, next); 65 } 66 } 67 } else { 68 if (whiteList.indexOf(to.path) !== -1) { 69 next(); 70 return false; 71 } else {//上面三行可以不写的,开头已经有了if (whiteList.indexOf(to.path) !== -1) 72 next(`/login?redirect=${to.path}`); // 否则全部重定向到登录页 73 NProgress.done(); 74 return false; 75 } 76 } 77 });router.beforeEach((to, from, next) => {}
1 function getPowerIs(to, next) { 2 if (to.meta) { 3 let arr = to.meta.power; 4 //arr=[[1]...] ,大概是获取功能菜单meta的children 5 if (arr) { 6 for (let i = 0; i < arr.length; i++) { 7 if (isPower(arr[i])) { 8 next(); 9 NProgress.done(); 10 return false; 11 } 12 } 13 //非[1]:网页错误 14 next({ path: "/401" }); 15 NProgress.done(); 16 } else { 17 next({ path: "/" }); 18 NProgress.done(); 19 } 20 } else { 21 next({ path: "/" }); 22 NProgress.done(); 23 }//其实,两个else{next({ path: "/" });NProgress.done();}可以删掉的吧 24 }function getPowerIs(to, next)
1 function isPower(key) {//用于验证权限的,没权限不给看 2 if (getRoleIds()) { 3 if (getRoleIds().indexOf(key) > -1) { 4 return true; 5 } else { 6 return false; 7 } 8 }//import { getUser, getRoleIds } from "@/utils/auth"; 9 return false; 10 }function isPower(key)
1 function updateDate() { 2 //获取当前系统时间 3 let date = new Date().getTime(); 4 //24小时x60分钟每小时x60秒每分钟x1000毫秒 5 //其实就是获取前一天的时间 6 date = date - 24 * 60 * 60 * 1000; 7 //如果能获取到用户?就解析用户的JS对象转化日期,不能就是登陆超时 8 //如果解析用户的JS对象但是缺少日期信息,也是登陆超时 9 if (getUser()) { 10 if (JSON.parse(getUser()).date) { 11 date = JSON.parse(getUser()).date; 12 } else { 13 return false; 14 } 15 } else { 16 return false; 17 } 18 //提取型日期,看用户登陆时间更早那么登录成功,用户登陆时间晚了就登录失败。不明白为什么要加这一道判定,可能跟系统延时有关? 19 let d1 = new Date(); 20 if (d1 > date) { 21 return false; 22 } else { 23 return true; 24 } 25 }function updateDate()
1 export const loadMenus = (next, to) => {//侧边栏菜单? 2 //import httpRequest from "@/api"; 3 httpRequest.systemmanagement.MenuButtons.getmenuauth({ enable: 1 }).then( 4 res => { 5 const sdata = JSON.parse(JSON.stringify(res.data)); 6 const rdata = JSON.parse(JSON.stringify(res.data)); 7 //import { filterAsyncRouter } from "@/store/modules/permission"; 8 const sidebarRoutes = filterAsyncRouter(sdata); 9 const rewriteRoutes = filterAsyncRouter(rdata, false, true); 10 // rewriteRoutes.push({ path: "*", redirect: "/404", hidden: true }); 11 store.dispatch("GenerateRoutes", rewriteRoutes).then(() => { 12 // 存储路由 13 rewriteRoutes.forEach(item => { 14 // 动态添加可访问路由表 15 router.addRoute(item); 16 }); 17 next({ ...to, replace: true }); 18 }); 19 store.dispatch("SetSidebarRouters", sidebarRoutes); 20 } 21 ); 22 };export const loadMenus = (next, to) => {}
router.afterEach(() => { NProgress.done();});
大概浏览了一下文件内所有的函数,但是不知道在哪里调用这个permission.js文件。百度了一下,发现它是vue-element-admin的登录逻辑。
参考博客:(博客里面的目录都有一点点出入,但不影响阅读。)
1 https://www.cnblogs.com/huayang1995/p/13818828.html 2 https://www.cnblogs.com/huayang1995/p/13818732.html 3 https://segmentfault.com/a/1190000009275424
总的来说permission像是负责路由监控和登录判断的角色。
一直到目前为止,大部分文件都像是网上找的略修改后的文件,我以后也能抄。
通过router和permission.js大概能知道公司各个页面设置在哪些文件或者文件夹内。
对于公司的登录界面:文件在src/view/login下,包含index.vue和informationDialog.vue
1 <template> 2 <!--资源文件地址我直接用urls代替,文件都存在src/assets文件夹下--> 3 <div class="login-container"> 4 <img src="<!--urls-->" class="bg-content" /><!--页面全屏背景--> 5 <div class="login-body"> 6 <img src="<!--urls-->" class="bg-body" /><!--页面中间表单左侧背景图--> 7 <div class="body-right"> 8 <!-- 此处是一个左图右大小标题的布局块 --> 9 <div class="body-form-title"> 10 <img src="<!--urls-->" class="icon" /> 11 <div class="content"> 12 <div class="form-title">大标题</div> 13 <div class="label">小标题</div> 14 </div> 15 </div><!-- 小布局块写完了,挺好看的 --> 16 <!-- 下面是两个填写框,带图标,密码栏可操作密码是否可视 --> 17 <el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form" auto-complete="on" label-position="left"> 18 <el-form-item prop="username"> 19 <el-input v-model="loginForm.username" name="username" type="text" auto-complete="on" placeholder="用户名" @blur="loginForm.username = $event.target.value"> 20 <span slot="prefix" class="svg-container"><svg-icon icon-class="user" /></span> 21 </el-input> 22 </el-form-item> 23 <el-form-item prop="password"> 24 <el-input :type="pwdType" v-model="loginForm.password" name="password" auto-complete="on" placeholder="密码" @keyup.enter.native="handleLogin"> 25 <span slot="prefix" class="svg-container"><svg-icon icon-class="password" /></span> 26 <span slot="suffix" class="show-pwd" @click="showPwd"><svg-icon :icon-class="eye" /></span> 27 </el-input> 28 </el-form-item> 29 <!-- 下面是记住密码功能键,原本有忘记密码的,注释掉了我就删了 --> 30 <el-form-item style="text-align: right"> 31 <el-checkbox v-model="loginForm.remember">记住密码</el-checkbox> 32 </el-form-item> 33 <el-form-item> 34 <el-button round :loading="loading" type="primary" style="width: 100%" @click.native.prevent="handleLogin" >登录</el-button> 35 </el-form-item> 36 </el-form> 37 </div> 38 </div> 39 <div><!-- informationDialogShow用处 --> 40 <information-dialog ref="informationDialog" :dialogBool.sync="informationDialogShow"></information-dialog> 41 </div> 42 </div> 43 </template>index.vue template
1 <script> 2 import { isvalidUsername } from '@/utils/validate' 3 import informationDialog from './InformationDialog' 4 import { getRemember } from '@/utils/auth' 5 6 export default { 7 components: { 8 informationDialog 9 }, 10 data() { 11 const validateUsername = (rule, value, callback) => { 12 if (!isvalidUsername(value)) { 13 callback(new Error('请输入正确的用户名')) 14 } else { 15 callback() 16 } 17 } 18 const validatePass = (rule, value, callback) => { 19 if (value.length < 1) { 20 callback(new Error('密码不能为空')) 21 } else { 22 callback() 23 } 24 } 25 return { 26 loginForm: { 27 username: '', password: '', remember: false 28 }, 29 loginRules: { 30 username: [ 31 { required: true, trigger: 'blur', validator: validateUsername } 32 ], 33 password: [{ required: true, trigger: 'blur', validator: validatePass }] 34 }, 35 eye: 'eye', 36 loading: false, 37 pwdType: 'password', 38 redirect: undefined, 39 informationDialogShow: false 40 } 41 }, 42 created() { 43 // 是否记住密码 44 let rememberInfo = JSON.parse(getRemember()) 45 // 如果存在,赋值给表单,并且将记住密码勾选 46 if (rememberInfo.remember) { 47 // 在页面加载时从cookie获取登录信息 48 this.loginForm.username = rememberInfo.account 49 this.loginForm.password = rememberInfo.pwd 50 this.loginForm.remember = rememberInfo.remember 51 } else { 52 this.loginForm.username = '' 53 this.loginForm.password = '' 54 this.loginForm.remember = false 55 } 56 }, 57 watch: { 58 $route: { 59 handler: function (route) { 60 this.redirect = route.query && route.query.redirect 61 }, 62 immediate: true 63 } 64 }, 65 methods: { 66 showPwd() { 67 if (this.pwdType === 'password') { 68 this.pwdType = '' 69 this.eye = 'open-eye' 70 } else { 71 this.eye = 'eye' 72 this.pwdType = 'password' 73 } 74 }, 75 handleLogin() { 76 this.$refs.loginForm.validate((valid) => { 77 if (valid) { 78 this.$store 79 .dispatch('Login', this.loginForm) 80 .then((req) => { 81 this.loading = false 82 let context = req.data 83 if (context.reset_pwd) { 84 this.informationDialogShow = true 85 } else { 86 setTimeout(() => { 87 this.$store.dispatch('ToggleSideBar') 88 if (!this.$store.getters.sidebar.opened) { 89 setTimeout(() => { 90 this.$store.dispatch('ToggleSideBar') 91 }, 100) 92 } 93 }, 100) 94 } 95 // this.$router.push({ path: '/' }) 96 if (process.env.NODE_ENV == 'development') { 97 this.$router.push({ path: '/' }) 98 } 99 }) 100 .catch((err) => { 101 this.loading = false 102 this.$message({ type: 'error', message: err }) 103 }) 104 } else { 105 return false 106 } 107 }) 108 } 109 } 110 } 111 </script>index.vue script
关于ToggleSideBar侧边栏找了个资料,留着学习:
https://blog.csdn.net/u012258564/article/details/79474973
informationDialog是用来在输入初始密码的时候邀请改密的,只有70行。
关于公司的首页:文件在src/view/dashboard下,包含index.vue、文件夹image和文件夹component;component文件夹下有7个组件:
1 commonly-function.vue //根本没用到的文件 2 ListBox.vue //页面信息小模块内嵌的列表,提供部分事件 3 NoticeBox.vue //页面公告信息小模块的布局,会调用ListBox.vue内容 4 PendingApproval.vue //页面审批信息小模块的布局,会调用ListBox.vue内容 5 ShareDocuments.vue //页面共享文档小模块的布局,会调用ListBox.vue内容 6 title-tool.vue //没用到的文件,像是TitleBox的练手作,含页面顶部功能卡片,包括待审批公文卡片、待处理事项卡片、未读消息卡片、提醒事项卡片 7 TitleBox.vue //设置页面顶部功能卡片、顶部导航栏
实现后有页内标签栏,就很妙。看代码的时候发现用到了这个文件夹src/settings
import settings from '@/settings'
里面只有一个index.js,就是单纯存常量用的。
当初为什么要给layout重定向也有了答案……因为layout!完全用不到!但是据说是系统主题文件删不了(刚刚和大佬核验思路,大佬说他能删的都删光了,这个删不了哈哈哈哈哈)。
这个项目应该是搬了别人的表单和框架(原来的好像是车库管理系统),删删改改搭完的……而NoticeBox.vue有不少是src/layout/Navbar.vue复制黏贴过来的。
不过还有一处布局没找到位置。页面顶部导航栏最左侧有个图标,点开能看到左侧导航栏。前面src/view/login/index.vue里面确实有提到过ToggleSideBar,但是导航导航,总得有插菜单项和跳转链接的地方,我还没找到。
现在倒回去看文档,提及的代码行:
this.$store.dispatch('ToggleSideBar')
说明这是个传参,我扫雷的时候用过但是我用的都是$emit('xxxxx')这种,这个store可能是差不多的功能,而src里正好有个store文件夹……经验告诉我,肯定又是大佬copy的,直接无脑百度!
vuex?我还在学vue2啊,啊这……
store参考博客:
https://blog.csdn.net/weixin_44582045/article/details/121852631
同步操作:
【存】this.$store.commit('方法名',值) 【取】this.$store.state.方法名
异步操作:
【存】this.$store.dispatch('方法名',值) 【取】this.$store.getters.方法名
所以这行代码的意思是:异步存入ToggleSiderBar函数。而和当初看文件理解的不一样,这很可能不是组件,而是一个捏组件的函数或者是组件的事件函数。
正好查store的时候博客下面就有侧边导航栏的指导博客:
https://blog.csdn.net/u010559460/article/details/105235469
根据博客所讲的子组件提取父组件的方法,只需要定位 @click="toggleClick" 即可,目标是子组件。
1 import { isvalidUsername } from '@/utils/validate' 2 import informationDialog from './InformationDialog' 3 import { getRemember } from '@/utils/auth'
那么定位这三文件看看。坏消息,一个都没有……
得扩大范围看看了。博客里路径落到 src/layout/components/Navbar.vue ,大佬删不了文件,可能功能还在沿用。
找到了!
1 <hamburger 2 :toggle-click="toggleSideBar" 3 :is-active="sidebar.opened" 4 class="hamburger-container" 5 />
toggleSideBar() { this.$store.dispatch('ToggleSideBar') },
这个文件的布局看着就是顶部导航栏和左侧导航栏的功能图标。考虑到之前某个文件和这个重复率很高,再看了一眼整个dashboard文件夹都没有toggleSideBar,可能跟store文件夹配置有关,不得不设置在layout里。但是既然要写在layout,为什么要复制一份出来呢?
问了大佬,大佬说忘了。
标签:vue,记录,next,学习,router,path,else,store From: https://www.cnblogs.com/yyn20230517/p/17480864.html