登录注册
注册:向服务器post账号和密码
登录:向服务器post账号和密码,后端进行匹配,成功则返回token存入本地的localstorage中
form表单验证
注册用的是element-ui的表单组件 配置验证validator
前后端认证方式
目的:为了跟踪会话信息,标记访问者的身份。(http是无状态协议,会话结束后,不保存会话信息,每次打开新页面都要重新登录)
1.session cookie
2.token验证
令牌,访问资源接口(API)所需要的凭证
客户端post用户名和密码给服务端,服务端验证后返回一个token
客户端将token保存在本地如localstorage 然后写在请求头的authorization字段里
服务端验证token后返回相应资源。
token相比cookie来说 不受同源的限制
JWT (json web token)
JWT是token的一种 包括header payload和signature 中间用.隔开 header是元数据 payload 是实际数据 signature是对前两个的加密 三个JSON对象会使用 Base64URL 算法转成字符串
www.ruanyifeng.com/blog/2018/0…
自动刷新token
refresh token是用来请求新的token的
token的有效时间短,refresh token的有效时间长(7-14天)
1.后端返回一个refresh token和token 用户存储在本地
2.携带token发请求,如果http状态吗401(没有访问权限)说明token过期,携带fresh token发请求新的token
3.如果refresh token有效 返回新的token 如果refreshtoken也过期了 就重新登录 www.ay1.cc/article/302…
function refreshTokenRequst(){
return axios.request({
baseURL: BASE_URL,
url:'/app/renewal',
method: 'POST',
data:{
refreshToken:localStorage.getItem('refreshToken')
},
})
}
//响应拦截器
// 添加响应拦截器
service.interceptors.response.use((response) => {
NProgress.done()
return response.data
}, (error) => {
NProgress.done()
//解析出状态码和请求配置
const {config,status} = error
if(status === 401){
try{
const refreshTokenResult = refreshTokenRequst()
if(refreshTokenResult.data && refreshTokenResult.code === 200){
//存入新的token
localStorage.setItem('token',refreshTokenResult.data)
//重新发请求 请求拦截器会带上新的token
const newRes = service(config)
return newRes.data
}
}catch(e){
return Promise.reject(e)
}
}
}
alert( `请求出错: ${error.message||'未知错误'}`)
// 后面可以选择不处理或处理
return Promise.reject(error)
})
cookie sessionStorage localstorage
都是浏览器本地存储
cookie、localStorage 以及 sessionStorage 的异同点:
cookie:
用于浏览器和服务器通信的,由服务器生成,存储在浏览器中。
服务器发给浏览器的一小块数据(4kb以内)(响应头里的set-cookie),下次发送给同一个域名时请求头中带上cookie,服务器就可以判断请求来自同一浏览器。
cookie不支持跨域,每个cookie绑定给指定域名。
使用:记住密码免登录;记录用户偏好进行个性化推荐
localStorage和sessionStorage:
不参与和服务器的通信
| 分类 | 生命周期 | 存储容量 | 存储位置 | 操作 |
|---|---|---|---|---|
| cookie | 通过设置过期时间控制 | 4KB | 保存在客户端,每次请求时都会带上 | document.cookie |
| localStorage | 理论上永久有效的,除非主动清除。 | 约5MB | 保存在客户端,不与服务端交互。 | localStorage.getItem()/setItem() |
| sessionStorage | 仅在当前网页会话下有效,关闭页面或浏览器后会被清除。 | 约5MB | 保存在客户端,不与服务端交互。 | sessionStorage.getItem()/setItem() |
localStorage 适合持久化缓存数据,如token、用户偏好;
sessionStorage 适合保存一次性数据,适合单页页面,关闭之后不需要但刷新前仍需要的,比如存表单信息。
axios二次封装
二次封装axios 添加请求和响应拦截器
const service = axios.create({
baseURL: "/api", // 基础路径
timeout: 15000 // 连接请求超时时间
})
// 添加请求拦截器
service.interceptors.request.use((config) => {
// 显示请求中的水平进度条
NProgress.start()
/* 每次请求总是携带用户临时ID(不管是否登陆) */
config.headers['userTempId'] = store.state.user.userTempId
// 有token的话 请求头要加上token
if(store.state.user.userInfo.token){
config.headers['token'] = store.state.user.userInfo.token
}
// 必须返回配置对象
return config
})
//响应拦截器
service.interceptors.response.use((response) => {
//返回状态码为2xx的进入成功回调
// 隐藏进度条
NProgress.done()
// 返回响应体数据
return response.data
}, (error) => {
//响应状态码为2xx以外的进入失败回调
// 隐藏进度条
NProgress.done()
// 统一处理一下错误
alert( `请求出错: ${error.message||'未知错误'}`)
// 后面可以选择不处理或处理
return Promise.reject(error)
})
配置代理服务器解决跨域
vue.config.js里 配置代理服务器,对请求路由以'/api'开头的请求转发到目标服务器url
代理服务器和我们同源,这样我们可以去代理服务器取数据。
服务器与服务器之间不用ajax请求,没有跨域问题。
devServer: {
proxy: {
'/api': { // 只对请求路由以/api开头的请求进行代理转发
target: 'http://gmall-h5-api.atguigu.cn', // 转发的目标url
changeOrigin: true // 支持跨域
}
}
},
引:ajax跨域 JSONP等等
轮播图 nextTick
nextTick 数据更新后 dom的渲染是异步的 nextTick用来写操作更新后的dom的
用swiper插件做
watch banners监听banners数据 然后在watch里写一个this.$nextTick()
遇到的问题 直接写肯定是操作不到dom数据也生成不了swiper
search
search通过操作面包屑导航 来实时修改search页的展示数据
向后台发post请求
配置options 搜索请求
面包屑每次修改之后 修改options的内容 都重新发请求this.dispatch('..',options) 然后存到vuex的state里
selector 遍历prop属性展示
options初始化: 通过路由 解构赋值 this.options = {...this.options,}或者用object.assign合并
如果修改了路由里的东西 要改路由 然后用replace 重跳一下 还要重新发一次请求 这逻辑都好简单。。
删对象属性 delete obj[key]
路由相关
params 要占位 /search/:ID? (?代表可传可不传) 在url里是 /search/123 这样 要配合name传参
query 不占位 在url是/search?id=123这样
放大镜zoom 和 imagelist
两者之间传值 用全局事件总线
因为是zoom接受数据 所以在zoom里on绑定事件和回调
在imagelist里不断触发事件 来传当前的图片
图片懒加载
juejin.cn/post/710073… 图片懒加载 按需加载 原理是把img图片的真实请求url写到自定义属性data-src里 src属性都统一请求一个很小的透明图片 然后监听滚动事件 判断图片在视口时再把真实url赋值给src去发请求。
实现方法:
1.getCliendBoundingRect()
判断是否在视口内函数:用getCliendBoundingRect()方法 返回一个对象有top left width height等属性
获取图片相对视口左上角的top left值 和自身的宽高 width height 和视口的宽高 window.innerHeight window.innerHeightWidth
在视口内:top+height >=0 && top<= window.innerHeight &&...
懒加载函数:获取所有lazy类的图片存入数组(Array.from从类数组生成数组) 遍历数组 逐个判断是否在视口内 如果是视口内就把data-src的真实url赋值给src属性 并移除lazy类和data-src
监听scroll事件,绑定节流处理的懒加载函数:document.addEventListener('scroll',throttle(lazyload,1000))
弊端:引起重绘和回流 需要自己手动计算+绑定事件
- IntersectionObserver API 可以返回一个观察器 自动观察元素是否可见
function lazyLoadWithObserver() {
// 推荐使用IntersectionObserver
let observer = new IntersectionObserver((entries, observe) => {
entries.forEach(item => {
// 获取当前正在观察的元素
let target = item.target
// 在视口内
if(item.isIntersecting && target.dataset.src) {
target.src = target.dataset.src
// 删除data-src属性
target.removeAttribute('data-src')
// 取消观察
observe.unobserve(item.target)
}
})
})
let imgs = document.querySelectorAll('.lazy')
imgs.forEach(item => {
// 遍历观察元素
observer.observe(item)
})
}
lazyLoadWithObserver()
路由懒加载
简单说:把路由对应组件分开打包成代码块 访问该路由的时候再加载组件
原理是传一个import函数给路由component属性
vue是单页面应用,直接用import from 的话 运用webpack打包后,一般会放在一个单独的js文件中,不用懒加载的话会变得非常大。路由懒加载是把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件。
原理:import(路径)webpack会单独打包 import函数
常用:箭头函数+ES6的import()函数实现:component: ()=>import(...) 传一个函数给component
路由守卫
全局: 全局前置beforeEach 全局解析 beforeResolve 全局后置afterEach 路由专属 beforeEnter 组件专属 beforeRouteEnter Update Leave
遇到的问题
1.swiper创建 配合nexttick 2.三级导航的卡顿现象 防抖节流 + 用了事件委托来优化 3.当从页面跳转到新路由时,滚动条保持原有位置
难点:
不说难点说我遇到的问题
//配置路由
export default new VueRouter({
routes,
scrollBehavior (to, from, savedPosition) {
return {x:0,y:0} //每次路由切换时的滚动条位置
}
})