客户端服务:PC端,小程序,移动web,移动app;
管理员端服务:PC后台管理端;
PC后台管理端功能:管理用户账号(登录,退出,用户管理,权限管理),商品管理(商品分类,分类参数,商品信息,订单),数据统计;
采用前后端分离的开发模式;前端项目是基于 Vue的SPA(单页应用程序)项目
前端技术栈:Vue, Vue-Router, Element-UI, Axios, Echarts
后端技术栈:Node.js, Express, Jwt(模拟session), Mysql, Sequelize(操作数据库的框架)
MySQL管理器 -->MySQL导入导出 -->MySQL默认密码:root -->要还原的文件:mydb.sql -->还原到数据库名:与数据名称保持一致(mydb) -->导入
打开后台项目 vue_api_server文件夹;
安装项目依赖包(node_modules文件夹): npm install;
启动服务器:node ./app.js;
使用 postman 测试登录接口;
1) 登录 — token原理分析
vue ui 打开ui界面,运行app 查看当前项目效果;
现在是一个默认页面,需要进行更改,打开src --> main.js(项目入口文件)
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import './plugins/element.js'
Vue.config.productionTip = false
new Vue({
router,
render: h => h(App)
}).$mount('#app')
再打开App.vue(根组件),将根组件的内容,进行删除,留下根节点;
再打开router.js(路由),将routes数组中的路由规则清除,
然后将views中的组件、及 helloword 组件删除;
3) 创建 login登录组件
1.创建login组件;
2.router.js -> 导入login组件,并设置路由规则;
import Login from '../components/login'
const router = new Router({
routes: [
{ path: '/', redirect: '/login' },
{ path: '/login', component: Login }
]
})
3.APP.vue 根组件:
添加路由占位符<router-view> (通过路由,匹配到的组件,都会被渲染到这里)
style样式中,添加背景色'2b4b6b',此时会报错 “缺少less-loader”;
依赖 -->安装依赖 -->开发依赖 less-loader less -->重新启动项目,生效;
背景色没有占满屏幕 -->assets文件夹 -->css文件夹,创建全局样式 global.css
main.js入口文件中引入: import "./assets/css/global.css"
/* Login.vue 中的根元素,设置撑满全屏(height:100%)
盒子居中:(450*300px)
position: absolute;
left:50%;
top:50%;
transform: translate(-50%,-50%); x,y轴 移动盒子自身的50%
头像:(130*130px)
阴影:box-shadow: 0 0 10px #ddd;
div 和 图片同时圆角:border-radius: 50%;
图片和边框的间隙,内padding */
登录页面布局:
复制 element-ui组件 -->element.js 中按需导入并注册;
import { Input } from 'element-ui'
Vue.use(Input) //注册为全局组件
button按钮 右对齐:
display:flex; //父元素开启flex
ustify-content: flex-end; //右对齐
表单移动到底部:
position:absolute; 定位到底部
bottom:0;
width: 100%;
padding: 0 20px;
/*左侧距离20px,右侧直接超出了表单区域,相当于input框整个右移了20px
因为默认from表单box-sizing:content*/
box-sizing:border-box; //解决input输入框,超出表单区域
引入第三方字体图标 (阿里图标库)
1.element-ui 以prefix-icon="属性的方式",添加字体图标:
//用class会出现,字体图标,在input框外的情况;
<el-input prefix-icon="iconfont icon-3702mima">
2.引入阿里字体图标库:
把fonts字体图标文件夹,放到assets文件夹中
入口文件 main.js中导入: import './assets/fonts/iconfont.css'
添加类名: <el-input prefix-icon="iconfont icon-user">
//prefix-icon="iconfont icon-xxx" iconfont基础类,每个都加;.icon-xxx 不加'.'
//form表单 -->:model表单的数据绑定,loginform 数据对象;rules表单的验证规则;
<el-form ref="loginref" :model ='loginform' :rules="loginrules">
<el-form-item prop='username'>
<el-input v-model='loginform.username' prefix-icon="iconfont icon-user">
</el-form-item>
<el-input v-model='loginform.password' type='password'>
</el-form>
//prop属性='具体的验证规则名字';和表单的 item项绑定,加给父元素,不是加给 input框
-------------------------------- data(){ return {}} -----------------------------------
loginform: {
username: '',
password: ''
},
loginrules: {
username: [ //数组中的每一个对象,都是验证规则;true 必填项;错误消息;失去焦点触发;
{ required: true, message: '请输入登录名称', trigger: 'blur' },
{ min: 3, max: 10, message: '长度在 3 到 10 个字符', trigger: 'blur' }
],
password: [
{ required: true, message: '请输入密码', trigger: 'blur' },
{ min: 6, max: 15, message: '长度在 6 到 15 个字符', trigger: 'blur' }
]
}
//验证规则中的登录名username[]、密码password[],必须和数据中名字一致;否则,验证长度规则,不生效;
获得表单的实例对象,调用resetField()函数,重置整个表单,为初始值;
用ref引用,获得表单的实例对象;loginref 就是表单的实例对象;
form 表单 -->ref="loginref"(名字自定义);
methods: {
resetform () {
this.$refs.loginref.resetFields()
}
}
//Vue 直接操作 DOM: 在DOM元素上,通过ref属性标注;(属性名称自定义)
<div ref="info">hello</div>
//通过Vue实例的 $refs获取,标记 ref属性的元素;
let info = this.$refs.info.innerHTML
console.log(info) // hello
/*点击"登录"按钮,发起请求之前,先对表单的数据,进行预验证;
*拿到表单的实例对象,调用实例对象的 validate()函数;validate 接收一个回调函数,对表单进行校验
*resetFields() validate() element-ui 组件的方法*/
// 发送请求前,找到 main.js 入口文件,对axios进行全局配置:
import axios from 'axios' //先导入axios包;用于发送 ajax请求;
axios.defaults.baseURL='接口文档请求基准地址' //设置请求根路径;
Vue.prototype.$http = axios
/*把这个包,挂载到vue的,原型对象上;这样每一个vue组件,
都可以通过this,访问到原型上的 $http,从而发起 ajax请求
*js必须挂在原型上 prototype.$http; html、css挂在 Vue.use()上
//点击登录时,先调用 validate方法,验证表单内容是否有错误;valid 表单验证的结果,布尔值
//先启动 mysql 数据库;启动接口服务器 node ./app.js
login() {
this.$refs.loginref.validate(async valid=>{
if(!valid) return; //return结束,不发送请求;
//const result = this.$http.post("login",this.loginform)
//this访问原型上的$http成员,发起 ajax请求;post(请求地址,this.loginform 请求参数)
//result返回结果是promise,所以用async/await;
//const result = await this.$http.post("login",this.loginform)
//async 加在最近的一个函数上;result对象,包含了6个属性,都是axios封装的,只用data属性,把它结构赋值出来;解构赋值:const { age, gender } = user user是一个对象;
const {data:res}=await this.$http.post("login",this.loginform)
if(res.meta.status !==200) return this.$message.error('登录失败');
this.$message.success('登录成功')
window.sessionStorage.setItem('token', res.data.token)
//调用API 保存session;('token 键',值是 res.data 中保存的 token)
this.$router.push('/home') //编程式导航,跳转到 '/home' 页面;
}
# element.js -->配置弹框提示
//import {Message} from 'element-ui' 按需导入弹框提示组件
//Vue.prototype.$message=Message 进行全局挂载 $message自定义属性,Message是组件;把弹框组件,挂载到了vue的原型对象上,这样,每一个组件,都可以通过this,访问到$message,进行弹窗提示;
# 登录成功后的页面跳转 -->localStorage(持久化的存储机制)
/*1.除登录外的其他 API接口,必须在登录之后,才能访问;
2.将登录成功后的 token,保存到客户端的 sessionStorage中;
3.sessionStorage:会话期间的存储机制;token 只在当前网站,打开期间生效;*/
----------------------------------------------------------------------------------------
//创建 home.vue 组件
//路由规则:import Home from './components/home.vue'
{path:'/home',component:Home}
day05 编程式导航:
this.$router.push('hash地址') # hash和url地址的区别
this.$router.go(n) // 1前进一步;-1后退一步;
setItem 将value存储到key字段 .setItem( key, value)
sessionStorage.setItem("key", "value"); storage.setItem(keyName, keyValue);
localStorage.setItem("site", "js8.in");
getItem 获取指定key本地存储的值 .getItem(key)
var value = sessionStorage.getItem("key");
var site = localStorage.getItem("site");
// router.js: 通过 url地址访问,没有token,没有登录,不能访问,强制跳转到登录页面
const router = new Router({
... ...
})
// 为路由对象,挂载路由导航守卫
router.beforeEach((to,from,next)=>{
if(to.path === '/login') return next();
const tokenStr = window.sessionStorage.getItem('token'); //获取保存的token值
if(!tokenStr) return next('/login'); //token 值为空,没有登录,强制跳转到登录页
next(); //token存在,直接放行;
})
//to 将要访问的页面路径;from 从那个路径跳转过来;
//next()放行函数: 1.next()放行; 2.next('/login')强制跳转到的路径;
export default router
基于 token 的方式,实现退出功能:销毁本地 token,后续请求,就不会携带 token;必须重新登录,才能访问;
Home.vue -->点击退出按钮
methods:{
logout(){
window.sessionStorage.clear(); //清空token
this.$router.push('/login'); //编程式导航,跳转到登录页
}
}
git status 查看修改与新增的文件
将所有文件添加到暂存区:git add .
提交到本地仓库:git commit -m "登录功能"
查看当前分支: git branch
将login分支代码,合并到 master主分支,先切换到主分支: git checkout master
再进行代码合并:git merge login
将本地的 master分支,推送到码云:git push
推送本地的子分支到码云,先切换到子分支:git checkout login
然后推送:git push -u origin login
/*根目录添加,格式化工具配置文件 .prettierrc(json格式的文件),
解决 ESLint 与 vscode 格式化时,的冲突 */
{
"semi":false, //格式化代码时,结尾不加';'
"singleQuote":true // ''替代" " 启用单引号,格式化方式;
}
.eslintrc.js文件
rules: {
'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
'space-before-function-paren' : 0 //禁用 ()之前需要空格;
}
ESLint 规则
不能有';'
"双引号" 换成 '单引号'
()之前需要空格
行与行之间最多空一行
no-trailing-spaces 不要-拖拉-空格:多了一个空格
object-curly-newline 目标-卷曲-换行
eol-last 文件最后空一行
{ 前后距离都要有一个空格 }
标签后不允许有空格 <div>
关键字后,要有空格 class ='';if (to.path === '/login') {}