注册组件
注意:
assets文件夹---放置全部组件的共用静态资源
在样式当中也可以使用@符号【src】别名,切记要在前面加上~
由于登录组件需要先注册,所以我们先完善注册组件
第一步:注册组件(路由组件)之前已经写好了的。
最后一步:表单验证(暂时不做,最后再处理)
-
静态页面
静态页面已经写好
-
绑定参数
因为用户输入的数据都是我们需要的,因此分别绑定参数v-model。
data() { return { //收集表达数据--手机号 phone:'', //验证码 code:'' , //密码 password:'', //确认密码 password1:'', //是否同意 agree:true }; }, -
获取验证码
正常来说是将验证码发送到用户手机上,但是为了省钱。我们将用户手机号传递给服务器后,服务器把用户验证码当成数据发送给我们。
-
绑定点击函数
-
点击函数,发送请求
getCode(){ //解构复制 const {phone} = this phone && this.$store.dispatch('user/getCode',phone) 。。。。。。 }, -
api
//获取验证码 // URL:/api/user/passport/sendCode/{phone} method GET export const reqGetCode = (phone) =>requests({ url:`/user/passport/sendCode/${phone}`, method:"get" }) -
Vuex
//获取验证码 action async getCode({commit},phone){ //获取验证码的接口:把验证码返回,但是正常情况,后台把验证码发到用户手机上【省钱】 let result = await reqGetCode(phone) if(result.code==200){ commit('GETCODE',result.data) }else{ return Promise.reject(new Error('faile')) } },
-
-
组件获取验证码
//获取验证码 async getCode(){ //简单判断---至少有数据 try { //如果获取验证码 const {phone} = this phone && await this.$store.dispatch('user/getCode',phone) //将仓库中的code复制给组件的code[验证码自己填写] this.code = this.$store.state.user.code } catch (error) { console.log(error.message); } }, -
完成注册
完成注册分为几步:收集数据信息,编写API,vuex发送请求,收到vuex注册成功后组件跳转到登录页面
-
收集数据,绑定点击函数
//用户注册 userRegister(){ const {phone,code,password,password1} = this if(phone&&code&&password==password1) { this.$store.dispatch('user/userRegister',{phone,password,code}) ...... } }, -
API
//注册接口 // URL: /api/user/passport/register method :post phone code password export const reqUserRegister = (data) =>requests({ url:`/user/passport/register`, data, method:"post", }) -
Vuex
注册成功无需返回数据,所以只需要actions
//用户注册 async userRegister({commit},user){ let result = await reqUserRegister(user) if(result.code==200){ return 'ok' }else{ return Promise.reject(new Error('fail')) } } -
组件实例
//用户注册 async userRegister(){ const {phone,code,password,password1} = this if(phone&&code&&password==password1) { try { //如果成功,路由跳转 await this.$store.dispatch('user/userRegister',{phone,password,code}) alert('账号注册成功') //路由跳转 this.$router.push("/login") } catch (error) { console.log(error.message); } } },
-
登录组件
登录成功的时候,后台为了区分你这个用户是谁-服务器下发token【令牌:唯一标识符】
注意:vuex存储数据是非持久化的,刷新就没
-
静态组件
静态组件已经给出
-
绑定函数、传递参数
async userLogin(){ const {phone,password} = this this.$store.dispatch('user/userLogin',{phone,password}) } -
API
//登录接口 // URL:/api/user/passport/login method:post phone password export const reqUserLogin = (data) =>requests({ url:`/user/passport/login`, data, method:"post", }) -
Vuex(发送请求、保存token)
const actions ={ ...... //登录业务 async userLogin({commit},data){ let result = await reqUserLogin(data) //服务器下发token,用户唯一标识符(UUID) //将来通过带token找服务器要用户信息展示 if(result.code==200){ commit("USERLOGIN",result.data.token) return 'ok' }else{ return Promise.reject(new Error('fail')) } } } const mutations ={ ...... USERLOGIN(state,token){ state.token=token } } const state ={ ...... token:'' } -
组件使用、路由跳转
//登录业务 async userLogin({commit},data){ let result = await reqUserLogin(data) //服务器下发token,用户唯一标识符(UUID) //将来通过带token找服务器要用户信息展示 if(result.code==200){ commit("USERLOGIN",result.data.token) return 'ok' }else{ return Promise.reject(new Error('fail')) } }
token问题
上一节中我们拿到了用户的token。我们需要根据token拿到用户信息
跳转到home组件之后,需要修改header组件的登录|注册 部分。
也就是说,跳转到home组件时,我们需要拿到用户的信息
-
home组件发起请求(也就是跳转到home组件的时候,vuex会拿到用户信息)
src\pages\Home\index.vuemounted() { ...... //获取用户信息在首页展示 this.$store.dispatch('user/getUserInfo') }, -
API
//获取用户信息【需要带着用户token找服务器要信息】 // URL:api/user/passport/auth/getUserInfo GET export const reqUserInfo = () =>requests({ url:`user/passport/auth/getUserInfo`, method:"get", })需要在请求头添加TOKEN信息
//请求拦截器:在请求发出去之前可以做一些事情 requests.interceptors.request.use((config)=>{ //config:配置对象,对象里面有一个属性很重要,headers请求头 ...... //需要token带给服务器 if(store.state.user.token){ config.headers.token = store.state.user.token } return config }); -
Vuex
//获取用户信息 actions async getUserInfo({commit}){ let result = await reqUserInfo() if(result.code==200){ //提交用户信息 commit("GETUSERINFO",result.data) return 'ok' }else{ return Promise.reject(new Error('fail')) } } //mutation const mutations ={ GETUSERINFO(state,userInfo){ state.userInfo = userInfo } } //state const state ={ code:'', token:'', userInfo:{} } -
header组件根据用户信息改变
userName根据计算属性得到
computed: { //用户名信息 userName(){ return this.$store.state.user.userInfo.name } },
刷新问题
此时会出现一个问题,那就是当你刷新页面的时候,由于vuex存储数据是非持久化的,刷新就没。又因为你的vuex中的token是通过登录按钮得到。所以刷新后home页面会因为发送给服务器的token是空的,所以会变成没有登陆的状态。
解决方式:将登录时得到的token保存在本地存储中。
-
重新包装一下(localStorage)非常的简单,也可以不包装
src\utils\token.js//对外暴露一个函数 export const setToken = (token)=>{ localStorage.setItem('TOKEN',token) } -
登陆的时候保存
//引入 import { setToken } from "@/utils/token"; //登录业务 async userLogin({commit},data){ let result = await reqUserLogin(data) //服务器下发token,用户唯一标识符(UUID) //将来通过带token找服务器要用户信息展示 if(result.code==200){ commit("USERLOGIN",result.data.token) //持久化存储token setToken(result.data.token) return 'ok' }else{ return Promise.reject(new Error('fail')) } }, //state const state ={ code:'', token:localStorage.getItem('TOKEN'), userInfo:{} }
退出登录
退出登录要做的事情:
1:需要发请求,通知服务器退出登陆【清楚一些数据:token】
2:清除项目当中的数据【userInfo,token】
-
绑定点击函数、发送请求
//退出登陆 logout(){ //退出登录需要做的事 // 1:需要发请求,通知服务器退出登陆【清楚一些数据:token】 //2:清除项目当中的数据【userInfo,token】 this.$store.dispatch("user/userLogout") } -
API
//退出登录 // URL:/api/user/passport/logout GET export const reqLogout = () =>requests({ url:`/user/passport/logout`, method:"get", }) -
Vuex
//退出登录action async userLogout({commit}){ //向服务器发起请求,通知服务器清除token let result = await reqLogout() if(result.code==200){ commit('CLEAR') return 'ok' }else{ return Promise.reject(new Error('fail')) } } //mutations //清除本地数据 CLEAR(){ //把仓库中的相关的用户信息清空, state.token='' state.userInfo='' //本地存储数据清空 removeToken() } -
mutation使用到的函数:removeToken(包装的函数)。
src\utils\token.js//清除本地存储的token export const removeToken = ()=>{ localStorage.removeItem('TOKEN') } -
跳转页面(跳转到首页)
//退出登陆 logout(){ //退出登录需要做的事 // 1:需要发请求,通知服务器退出登陆【清楚一些数据:token】 //2:清除项目当中的数据【userInfo,token】 try { //如果退出成功 this.$store.dispatch("user/userLogout") //回到首页 this.$router.push('/home') } catch (error) { console.log(error.message); } } },
导航守卫
在此主要是解决2个问题。
1:当登录之后再地址栏输入login不能返回登陆界面
2:除home组件外,其他组件登陆后再刷新(导致仓库的用户数据没了)会导致header显示问题。
对于问题1:增加一个判断,如果登陆后路要跳转到登陆界面,此时组织这个行为。
对于问题2:主要问题在于发起用户信息的请求在home组件中,我们把它拿出来,发到路由跳转之前。也就是说,如果你登陆了,然后你在刷新之前,再发起一次请求(注意,判断是否保留用户信息通过看能不能拿到name)
src\router\index.js
......
//引入store
import store from "@/store";
......
//全局路由守卫
router.beforeEach(async (to, from, next) => {
//to:可以获取你要跳转到哪个路由信息
//from:可以获取你从哪个路由而来的信息
//next:放行函数
//1:next()直接放行
//2:next('path') 放行到指定路由
//3:next(false) 中断此次导航。
//用户登陆了,才会有token
let token = store.state.user.token;
//用户信息
let name = store.state.user.userInfo.name;
//用户已经登陆了
if (token) {
//用户已经登陆了就别想去login[给它停在首页]
if (to.path == "/login") {
next("/home");
} else {
//未登录或者登录刷新
//登录刷新去的是【home|search|detail|shopcart】
//如果用户名已有
if (name) {
next();
} else {
//没有用户信息,派发actions让仓库存储用户信息
try {
//获取用户信息成功
await store.dispatch("user/getUserInfo");
next();
} catch (error) {
//token失效了 获取不到用户信息
//清除token
await store.dispatch('user/userLogout')
next('login')
}
}
}
} else {
//未登录暂时未处理
next();
}
});
export default router;
Trade组件
trade组件就是购物车之后的结算页面。
-
静态页面
已经给出
-
shopcart兄弟组件点击跳转
-
编写路由
import AppTrade from '@/pages/Trade' { path:"/trade", component:AppTrade, meta:{show:true} }, -
发起actions请求
因为在组件一开始就需要用户地址信息和商品清单俩个数据,因此需要想服务器发起请求
mounted() { this.$store.dispatch('trade/getUserAddress') this.$store.dispatch('trade/getOrderInfo') }, -
API
//获取用户地址信息 // URL:/api/user/userAddress/auth/findUserAddressList get export const reqAddress = () =>requests({ url:`/user/userAddress/auth/findUserAddressList`, method:"get", }) //获取商品清单 // URL:/api/order/auth/trade GET export const reqOrderInfo = () =>requests({ url:`/order/auth/trade`, method:"get", }) -
Vuex
注意:先在大仓库中引入和注册一下,此处省略
const state ={ address:[], orderInfo:{} } const mutations ={ GETUSERADDRESS(state,address){ state.address = address }, GETORDERINFO(state,orderInfo){ state.orderInfo= orderInfo } } const actions ={ //获取用户地址信息 async getUserAddress({commit}){ let result = await reqAddress() if(result.code==200){ commit('GETUSERADDRESS',result.data) }else{ return Promise.reject(new Error('fail')) } }, //获取商品清单数据 async getOrderInfo({commit}){ let result = await reqOrderInfo() if(result.code==200){ commit('GETORDERINFO',result.data) }else{ return Promise.reject(new Error('fail')) } } } -
组件计算属性得到数据
...mapState({ addressInfo:state=>state.trade.address, orderInfo:state=>state.trade.orderInfo }), -
将数据填入模板中
-
修改默认地址(排他性)
注意:绑定点击事件要给父组件绑定
methods: { //修改默认地址 changeDefault(address,addressInfo){ //全部的isDefault变为0 addressInfo.forEach(item => { item.isDefault=0 }); address.isDefault=1 } }, -
买家留言部分
因为此部分是要收集的之后提交订单的,因此单独给一个数据
data() { return { //收集买家留言信息 msg: '', }; }, -
将来提交订单最终选中地址(数组find方法)
注意:赋值一个空对象,放置假报错(页面刷新时数据还没得到)
computed: { ...... //将来提交订单最终选中地址 userDefaultAddress(){ //find查找数组当中符合条件的第一个结果返回。 return this.addressInfo.find(item=>{ return item.isDefault==1 })||{} } },
提交订单
提交订单这个部分我们要做一些其他的事情。对Vuex的使用要变更:为后面做准备,这里我们不再使用Vuex,因此要对API进行一些改动
API:
-
将API定义为全局属性
src\main.js类似于全局总线$bus,放在vue原型对象上面
//统一接口API文件夹里面全部请求函数 //统一引入 import * as API from "@/api" new Vue({ render: h => h(App), //全局事件总线$bus配置 beforeCreate(){ Vue.prototype.$bus = this Vue.prototype.$API = API }, //注册路由 //注册路由信息:当这里书写router的时候,组件身上都拥有$route,$router属性 router, //注册仓库:组件实例的身上会多一个属性:&store store }).$mount('#app') -
使用
this.$API.reqSubmitOrder(tradeNo,data);
提交订单按钮功能
-
绑定点击函数
-
函数功能实现
在这里要注意,因为我们不使用Vuex,所以我们将返回的数据(orderId)存储于data中
data() { return { //收集买家留言信息 msg: "", orderId:'' }; },//提交订单 async submitOrder() { //交易编码 let { tradeNo } = this.orderInfo; //其余的六个参数 let data = { consignee:this.userDefaultAddress.consignee,//名字 consigneeTel: this.userDefaultAddress.phoneNum,//手机号 deliveryAddress: this.userDefaultAddress.fullAddress,//地址 paymentWay: "ONLINE",//支付方式 orderComment: this.msg,//留言信息 orderDetailList: this.orderInfo.detailArrayList//商品清单 }; //需要参数:tradeNo, let result = await this.$API.reqSubmitOrder(tradeNo,data); //提交订单成功 if(result.code==200){ this.orderId = result.data //路由跳转 + 路由传参 this.$router.push('/pay?orderId='+this.orderId) }else{ //提交订单失败 console.log(result.data); } console.log(result); },
立即支付组件(pay)
-
静态组件
-
配置路由
src\router\routes.jsimport AppPay from '@/pages/Pay' { path:"/pay", component:AppPay, meta:{show:true} }, -
获取订单编号以及支付信息
获取订单编号(路由传参)
computed: { orderId(){ return this.$route.query.orderId } },获取支付信息:
API:
//获取支付信息 // URL:/api/payment/weixin/createNative/{orderId} GET export const reqPayInfo = (orderId) =>requests({ url:`/payment/weixin/createNative/${orderId}`, method:"get", })组件内发送请求及获取数据
//不建议在生命周期函数中async|await mounted() { this.getPayInfo() }, methods:{ //获取支付信息 async getPayInfo(){ let result = await this.$API.reqPayInfo(this.orderId) //如果成功:组件当中存储支付信息 if(result.code==200){ this.payInfo=result.data } }, } -
填写模板
使用elmentUI生成支付弹窗
-
安装elmentUI
npm i element-ui -S -
按需引入以及注册
注意:主要使用MessageBox 弹框
src\main.jsimport { Button,MessageBox} from 'element-ui'; //注册按钮的全局组件 Vue.component(Button.name,Button) //ElmentUI注册组件的另外一种写法:挂在原型上 Vue.prototype.$msgbox = MessageBox; Vue.prototype.$alert = MessageBox.alert; -
绑定点击函数
src\pages\Pay\index.vue -
使用MessageBox 弹框
this.$alert(`输入文本`, '标题', { confirmButtonText: '已支付成功', dangerouslyUseHTMLString:true, //取消按钮的文本内容 cancelButtonText:'支付遇见问题', //显示取消按钮 showCancelButton:true, //居中 center:true, //右上角的X showClose:false, }); -
使用QRCODE生成二维码地址
-
安装
npm i qrcode -
引入
import QRCode from 'qrcode' -
生成二维码地址
payInfo的数据中有codeUrl,可以使用这个连接生成二维码
//生成二维码(地址) let url = await QRCode.toDataURL(this.payInfo.codeUrl)
-
-
展示二维码界面
this.$alert(`<img src=${url} />`, '微信支付', { confirmButtonText: '已支付成功', dangerouslyUseHTMLString:true, //取消按钮的文本内容 cancelButtonText:'支付遇见问题', //显示取消按钮 showCancelButton:true, //居中 center:true, //右上角的X showClose:false, }); -
支付成功的操作
注意:要不断向后台发请求来确认是否成功,因此使用定时器。data数据timer保存定时器
data() { return { payInfo: {}, timer:null, //支付成功的状态码 code:'' }; },//弹出框 async open(){ //生成二维码(地址) let url = await QRCode.toDataURL(this.payInfo.codeUrl) this.$alert(`<img src=${url} />`, '微信支付', { confirmButtonText: '已支付成功', dangerouslyUseHTMLString:true, //取消按钮的文本内容 cancelButtonText:'支付遇见问题', //显示取消按钮 showCancelButton:true, //居中 center:true, //右上角的X showClose:false, //关闭弹出框前的回调 }); //需要知道支付成功|失败 //支付成功,路由跳转。支付失败,提示信息 //定时器 if(!this.timer){ this.timer = setInterval(async ()=>{ //发请求获取用户支付状态 let result = await this.$API.reqPayStatus(this.orderId) //如果支付成功 if(result.code==200){ //第一步:清除定时器 clearInterval(this.timer) this.time=null //第二步:保存支付成功返回的code this.code =result.code //第三步:关闭弹出框 this.$msgbox.close() //第四步:跳转到下一路由 this.$router.push('/paysuccess') } },1000) } }
8. 按钮的回调(关闭弹出框前)
```js
//弹出框
async open(){
//生成二维码(地址)
let url = await QRCode.toDataURL(this.payInfo.codeUrl)
this.$alert(`<img src=${url} />`, '微信支付', {
confirmButtonText: '已支付成功',
dangerouslyUseHTMLString:true,
//取消按钮的文本内容
cancelButtonText:'支付遇见问题',
//显示取消按钮
showCancelButton:true,
//居中
center:true,
//右上角的X
showClose:false,
//关闭弹出框前的回调
beforeClose:(type,instance,down)=>{
//type:区分取消|确定按钮
//instance 为 MessageBox 实例,可以通过它访问实例上的属性和方法
//done 用于关闭 MessageBox 实例
if(type=='cancel'){
alert('请联系飞大帅')
//清除定时器
clearInterval(this.timer)
this.time=null
//关闭弹出框
down()
}else{
//判断是否真的支付成功
//为了方便
/* if(this.code==200){ */
//清除定时器
clearInterval(this.timer)
this.time=null
//关闭弹出框
down()
this.$router.push('/paysuccess')
/* } */
}
}
});
//需要知道支付成功|失败
//支付成功,路由跳转。支付失败,提示信息
//定时器
if(!this.timer){
this.timer = setInterval(async ()=>{
//发请求获取用户支付状态
let result = await this.$API.reqPayStatus(this.orderId)
//如果支付成功
if(result.code==200){
//第一步:清除定时器
clearInterval(this.timer)
this.time=null
//第二步:保存支付成功返回的code
this.code =result.code
//第三步:关闭弹出框
this.$msgbox.close()
//第四步:跳转到下一路由
this.$router.push('/paysuccess')
}
},1000)
}
}
个人中心组件(center)
知识点:二级路由,行合并
基础功能实现
-
静态页面,已经给出
我们将
我的订单以及团购订单的模板拆出来,作为子组件。分别放到src\pages\Center\myOrder\index.vue和src\pages\Center\groupOrder\index.vue中 -
组件内容
二级路由搭建
注意:二级路由路径写法以及重定向
src\router\routes.js
import Center from '@/pages/Center'
//引入二级路由组件
import myOrder from '@/pages/Center/myOrder'
import groupOrder from '@/pages/Center/groupOrder'
{
path:"/center",
component:Center,
meta:{show:true},
//二级路由组件
children:[
{
path:'myorder',
component:myOrder
},
{
path:'grouporder',
component:groupOrder
},
/* 重定向 */
{
path:'/center',
redirect:'/center/myorder'
}
]
},
子组件(myOrder)
由于另一个子组件没有详情页面,主要介绍myOrder子组件
-
获取我的订单数据
同样的,mouted钩子不建议放promise函数,因此将getData()函数放在method里面,然后通过调用实现。数据放在data中
data() { return { //初始化参数 //当前第几页 page: 1, //每页展示数据个数 limit:3, //存储我的订单的数据 myOrder:{} }; }, mounted() { //获取我的订单数据的方法 this.getData() }, methods: { async getData(){ //解构出参数 const {page,limit} = this let result = await this.$API.reqMyOrderList(page,limit) if(result.code==200){ this.myOrder = result.data } }, }, -
API
//获取个人中心的数据 // URL:/api/order/auth/{page}/{limit} get export const reqMyOrderList = (page,limit) =>requests({ url:`/order/auth/${page}/${limit}`, method:"get", }) -
模板呈现数据
注意查看数据结构
-
行合并
:rowspan="order.orderDetailList.length"根据元素个数合并行
v-if="index==0"只显示一行就够
分页器
我们之前写过分页器,并且将它注册为全局组件,因此在这里使用的时候只需要将它引入且传递参数就可
<!-- 分页器 -->
<AppPagination
:pageNo="page"
:pageSize="limit"
:total="myOrder.total"
:continues="5"
@getPageNo="getPageNo"
></AppPagination>
未登录的导航守卫判断
在之前的全局路由守卫中,我们对于用户未登录就进行路由跳转的行为没有做任何处理,直接放行next(),在这部分,要对未登录的路由跳转做处理
未登录应该有的限制
未登录:不能去交易相关、不能去支付相关【pay|paysuccess】、不能去个人中心
//用户已经登陆了
if (token) {
。。。。。。
} else {
//未登录:不能去交易相关、不能去支付相关【pay|paysuccess】、不能去个人中心
//未登录去上面这些路由-----登陆页面
if(to.path =='/trade'|| to.path.indexOf('/pay')!=-1 ||to.path.indexOf('/center')!=-1){
next(`/login`)
}
//去的不是上面这个
next();
}
存储路由信息
把未登录的时候想去而没有去成的信息,存储于地址栏中【路由】(也就是先点击例如“我的订单”,会跳转到登陆页面,但是登陆后应该立即跳转到“我的订单”)
处理方法:把点击的路由信息放在query参数中,传递给登录组件。登录组件点击登录按钮时对query参数进行判断
-
全局路由守卫
if (token) { 。。。。。。 } else { //未登录:不能去交易相关、不能去支付相关【pay|paysuccess】、不能去个人中心 //未登录去上面这些路由-----登陆页面 if(to.path =='/trade'|| to.path.indexOf('/pay')!=-1 ||to.path.indexOf('/center')!=-1){ //把未登录的时候想去而没有去成的信息,存储于地址栏中【路由】 next(`/login?redirect=`+to.path) } //去的不是上面这个 next(); } -
登陆组件
登录的路由:看路由当中是否包含query参数,由:跳到query参数指定路由,没有:跳转到home首页
async userLogin(){ try { const {phone,password} = this if(phone&&password){ await this.$store.dispatch('user/userLogin',{phone,password}) //登录的路由:看路由当中是否包含query参数,由:跳到query参数指定路由,没有:跳转到home首页 let toPath = this.$route.query.redirect||'/home' this.$router.push(toPath) } } catch (error) { console.log(error.message); } }
路由守卫的应用
全局路由守卫
src\router\index.js
//全局路由守卫
router.beforeEach(async (to, from, next) => {
//to:可以获取你要跳转到哪个路由信息
//from:可以获取你从哪个路由而来的信息
//next:放行函数
//1:next()直接放行
//2:next('path') 放行到指定路由
//3:next(false) 中断此次导航。
//用户登陆了,才会有token
let token = store.state.user.token;
//用户信息
let name = store.state.user.userInfo.name;
//用户已经登陆了
if (token) {
//用户已经登陆了就别想去login[给它停在首页]
if (to.path == "/login"||to.path == "/register") {
next("/home");
} else {
//未登录或者登录刷新
//登录刷新去的是【home|search|detail|shopcart】
//如果用户名已有
if (name) {
next();
} else {
//没有用户信息,派发actions让仓库存储用户信息
try {
//获取用户信息成功
await store.dispatch("user/getUserInfo");
next();
} catch (error) {
//token失效了 获取不到用户信息
//清除token
await store.dispatch('user/userLogout')
next('login')
}
}
}
} else {
//未登录:不能去交易相关、不能去支付相关【pay|paysuccess】、不能去个人中心
//未登录去上面这些路由-----登陆页面
if(to.path =='/trade'|| to.path.indexOf('/pay')!=-1 ||to.path.indexOf('/center')!=-1){
//把未登录的时候想去而没有去成的信息,存储于地址栏中【路由】
next(`/login?redirect=`+to.path)
}
//去的不是上面这个
next();
}
});
路由独享守卫
src\router\routes.js
export default [
......
{
path:"/paysuccess",
component:PaySuccess,
meta:{show:true}
},
{
path:"/pay",
component:AppPay,
meta:{show:true},
beforeEnter: (to, from, next) => {
if(from.path=='/trade'){
next()
}else{
next(false)
}
}
},
{
path:"/trade",
component:AppTrade,
meta:{show:true},
//路由独享守卫
beforeEnter: (to, from, next) => {
//去交易页,必须是从购物车而来
if(from.path=='/shopcart'){
next()
}else{
next(false)
}
}
},
......
]
路由内守卫
src\pages\PaySuccess\index.vue
export default {
name: 'PaySuccess',
//组件内守卫
beforeRouteEnter (to, from, next) {
// 在渲染该组件的对应路由被验证前调用
// 不能获取组件实例 `this` !
// 因为当守卫执行时,组件实例还没被创建!
if(from.path=='/pay'){
next()
}
else{
next(false)
}
},
/* beforeRouteUpdate(to, from) {
// 在当前路由改变,但是该组件被复用时调用
// 举例来说,对于一个带有动态参数的路径 `/users/:id`,在 `/users/1` 和 `/users/2` 之间跳转的时候,
// 由于会渲染同样的 `UserDetails` 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
// 因为在这种情况发生的时候,组件已经挂载好了,导航守卫可以访问组件实例 `this`
}, */
/* beforeRouteLeave(to, from) {
// 在导航离开渲染该组件的对应路由时调用
// 与 `beforeRouteUpdate` 一样,它可以访问组件实例 `this`
},
*/
}
图片懒加载
图片懒加载:在我们的图片加载出来之前先展示一个其他的图片(gif)
方法:使用插件Vue-Lazyload
-
安装Vue-Lazyload
使用这个版本不会bug
npm i vue-lazyload@1.3.3 -S -
注册插件
src\main.js注:atm是我们放在assets文件夹下的gif
//引入插件 import VueLazyload from 'vue-lazyload' import atm from '@/assets/1.gif' //注册插件 Vue.use(VueLazyload,{ //懒加载默认图片 loading: atm }) -
使用
src\pages\Search\index.vue放在搜索页面下的图片
原来是:
img :src="good.defaultImg"
自定义插件
我们定义一个自定义插件,里面用到了[自定义指令](Vue.js 自定义指令 | 菜鸟教程)
-
创建文件并且定义插件
src\plugins\maPlugins.js
注意:传递的参数
Vue:Vue实例,方便我们在这上面进行操作,比如注册自定义指令。或者将一些东西挂载到vue原型上去
options:一个对象,在我们注册的时候传入
//Vue插件一定暴露一个对象 let myPlugins = {} myPlugins.install = function(Vue,options){ //Vue.prototype.$bus:任何组件都可以使用 //Vue.directive:注册自定义指令 } export default myPlugins -
引入注册插件
注意:Vue.use执行的时候,其实就是调用myPlugins的install方法
//引入自定义插件 import myPlugins from '@/plugins/maPlugins' //注册插件 Vue.use(myPlugins,{ name:'upper' }) -
vue自定义指令
我们要使用自定义插件,为了掩饰可以通过vue实例做一些事情,通过调用Vue自定义指令来做一个示例。
myPlugins.install = function(Vue,options){ //Vue.prototype.$bus:任何组件都可以使用 //Vue.directive:注册自定义指令 Vue.directive(options.name,(element,params)=>{ element.innerHTML = params.value.toUpperCase() } ); }注解:此时的optings是我们在main.js注册时传递过来的{name:'upper'}。
调用的Vue.directive传递的参数可参照:[Vue.js 自定义指令](Vue.js 自定义指令 | 菜鸟教程)
-
使用
<h1 v-upper="msg"></h1> data() { return { msg: 'ABC', }; },
总结:其实我们使用VUE插件,就是调用插件的install方法,这个方法可以接受Vue实例以及注册时传递的参数。我们可以做一些操作。
上述的使用过程可以总结为:引入注册插件(调用)==>插件调用函数(编写了一个自定义指令)===》使用自定义指令
路由懒加载
当打包构建应用时,JavaScript 包会变得非常大,影响页面加载。如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就会更加高效。
src\router\routes.js
-
开头不用引入
-
直接写在路由配置里面
箭头函数简写形式
{ path:"/home", component:()=>import('@/pages/Home'), meta:{show:true} },
打包上限
打包:npm run build
打包后js文件夹中会出现.map文件,它是我们源文件代码的映射,体积大,打包上线后作用不大,可通过配置来选择打包不生成.map文件
vue.config.js
module.exports = defineConfig({
//打包不生成map文件
productionSourceMap:false,
//新创建vue项目后,会出现第一行代码爆红的现象,解决它的方法
transpileDependencies: true,
//关闭ESLINT校验工具
lintOnSave:false,
//代理跨域
devServer: {
proxy: {
'/api': {
target:'http://gmall-h5-api.atguigu.cn',
}
},
},
})