p93-112
5.1 trade结算页面
<div class="address clearFix" v-for="(address,index) in addressInfo" :key="index">
<span class="username " :class="{selected:address.isDefault==1}">{{address.consignee}}</span>
<p @click="changeDefault(address,addressInfo)">
<span class="s1">{{address.fullAddress}}</span>
<span class="s2">{{address.phoneNum}}</span>
<span class="s3" v-show="address.isDefault==1">默认地址</span>
</p>
</div>
index.vue
<script>
import {mapState} from 'vuex'
export default {
name: 'Trade',
data () {
return {
msg:''
}
},
// 生命周期挂载完毕
mounted(){
this.$store.dispatch('getUserAddress'),
this.$store.dispatch('getOrderInfo')
},
computed:{
...mapState({
addressInfo:state=>state.trade.address,
orderInfo:state=>state.trade.orderInfo
}),
// 提交订单的地址
userDefaultAddress(){
// find查找数组中符合条件的元素,为最终结果
return this.addressInfo.find(item=>item.isDefault==1)
}
},
methods:{
// 修改默认地址
changeDefault(address,addressInfo){
// 全部isDefault为0
addressInfo.forEach(item =>item.isDefault=0);
address.isDefault=1
}
}
}
</script>
5.2 提交订单
当用户点击提交订单按钮的时候,需要发请求的
13700000000
111111
注:不能在生命周期函数(mounted)中写async
export default {
name: "Pay",
data () {
return {
payInfo:{}
}
},
mounted() {
this.getPayInfo()
},
computed: {
orderId() {
return this.$route.query.orderId;
},
},
methods:{
async getPayInfo(){
let res=await this.$API.reqPayInfo(this.orderId);
if(res.code==200){
this.payInfo=res.data
}
}
}
};
5.3 ElementUI及按需引入
react框架:
UI组件库antd【蚂蚁金服旗下PC端UI组件库】
antd-mobile【蚂蚁金服旗下的移动端UI组件库】
Vue框架:
element-UI【饿了吗旗下的UI组件库,官方承认的PC组件库插件】
vant【Vue官方提供移动端UI组件库】
第一步:项目中安装element-ui组件库 [2.15.6版本:Vue2]
第二步:在入口文件引入elementUI组件库
第一种:全部引入【不采用:因为项目中只是用到一个组件,没必要全都引入进来】
第二种:按需引入【按照开发需求引入相应的组件,并非全部组件引入】
第三步:按需引入,安装相应的插件
cnpm install babel-plugin-component -D
文档中说的.babelrc文件,即为babel.config.js文件
修改完babel.config.js配置文件以后,项目重启
第四部:按照需求引入相应的组件即可
Vue.component();
Vue.prototype.$xxx = xxx;
main.js
import {Button,MessageBox} from 'element-ui'
// 1.注册全局组件
Vue.component(Button.name,Button);
// 2.ElementUI注册组件时,还有种写法挂载到原型上
Vue.prototype.$msgbox = MessageBox;
Vue.prototype.$alert = MessageBox.alert;
index.vue
//弹出框
open() {
this.$alert("<strong>这是 <i>HTML</i> 片段</strong>", "HTML 片段", {
dangerouslyUseHTMLString: true,
//中间布局
center: true,
//是否显示取消按钮
showCancelButton: true,
//取消按钮的文本内容
cancelButtonText: "支付遇见问题",
//确定按钮的文本
confirmButtonText: "已支付成功",
//右上角的叉子没了
showClose: false,
});
5.4 微信支付业务
展示二维码----qrcode插件
通过qrCode.toDataUrl方法,将字符串转换为加密的在线二维码链接,通过图片进行展示。
moment.js
swiper.js
nprogress.js
qrcode.js
async open() {
//生成二维(地址)
let url = await QRCode.toDataURL(this.payInfo.codeUrl);
// console.log(url);
this.$alert(`<img src=${url} />`, "微信支付", {
dangerouslyUseHTMLString: true,
//中间布局
center: true,
//是否显示取消按钮
showCancelButton: true,
//取消按钮的文本内容
cancelButtonText: "支付遇见问题",
//确定按钮的文本
confirmButtonText: "已支付成功",
//右上角的叉子没了
showClose: false,
//关闭弹出框的配置值
beforeClose: (type, instance, done) => {
//type:区分取消|确定按钮
//instance:当前组件实例
//done:关闭弹出框的方法
if (type == "cancel") {
alert("阿巴巴巴");
//清除定时器
clearInterval(this.timer);
this.timer = null;
//关闭弹出框
done();
} else {
//判断是否真的支付了
//开发人员:为了自己方便,这里判断先不要了
// if (this.code == 200) {
clearInterval(this.timer);
this.timer = null;
done();
this.$router.push("/paysuccess");
// }
}
},
});
//你需要知道支付成功|失败
//支付成功,路由的跳转,如果支付失败,提示信息
//定时器没有,开启一个新的定时器
if (!this.timer) {
this.timer=setInterval(async ()=>{
// 发请求获取用户支付状态
let res=await this.$API.reqPayStatus(this.orderId)
if(res.code==205){
//第一步:清除定时器
clearInterval(this.timer);
this.timer = null;
//保存支付成功返回的code
this.code = res.code;
//关闭弹出框
this.$msgbox.close();
//跳转到下一路由
this.$router.push("/paysuccess");
}
},1000)
}
},
5.5 我的订单
center下的二级路由myOrder
<div class="orders">
<!-- 每笔订单 -->
<table
class="order-item"
v-for="(order, index) in myOrder.records"
:key="index"
>
<thead>
<tr>
<th colspan="5">
<span class="ordertitle"
>{{ order.createTime }} 订单编号:{{ order.outTradeNo }}
<span class="pull-right delete"
><img src="../images/delete.png" /></span
></span>
</th>
</tr>
</thead>
<tbody>
<tr v-for="(cart, index) in order.orderDetailList" :key="index">
<td width="60%">
<div class="typographic">
<img :src="cart.imgUrl" style="height: 100px; width: 100px" />
<a class="block-text">{{ cart.skuName }}</a>
<span>x{{ cart.skuNum }}</span>
<a href="#" class="service">售后申请</a>
</div>
</td>
<td
:rowspan="order.orderDetailList.length"
v-if="index == 0"
width="8%"
class="center"
>
{{ order.consignee }}
</td>
<td
:rowspan="order.orderDetailList.length"
v-if="index == 0"
width="13%"
class="center"
>
<ul class="unstyled">
<li>总金额¥{{ order.totalAmount }}</li>
<li>在线支付</li>
</ul>
</td>
<td
:rowspan="order.orderDetailList.length"
v-if="index == 0"
width="8%"
class="center"
>
<a href="#" class="btn">{{ order.orderStatusName }}</a>
</td>
<td
:rowspan="order.orderDetailList.length"
v-if="index == 0"
width="13%"
class="center"
>
<ul class="unstyled">
<li>
<a href="mycomment.html" target="_blank">评价|晒单</a>
</li>
</ul>
</td>
</tr>
</tbody>
</table>
</div>
<div class="choose-order">
<!-- 分页器 -->
<!-- total:一共的数据 pageNo:当前多少页 continues:中间连续几页 pageSize:一页展示多少数据-->
<Pagination
:total="myOrder.total"
:pageSize="limit"
:pageNo="page"
:continues="9"
@getPageNo="getPageNo"
/>
</div>
export default {
data() {
return {
//初始化参数
//当前第几页
page: 1,
//每一页展示数据个数
limit: 3,
//存储我的订单的数据
myOrder: {},
};
},
mounted() {
this.getData();
},
methods: {
// 获取我的订单的方法
async getData() {
const { page, limit } = this;
let res = await this.$API.reqMyOrderList(page, limit);
if (res.code == 200) {
this.myOrder = res.data;
}
},
//获取当前点击那一页
getPageNo(page){
//修改组件响应式数据page
this.page=page
this.getData()
}
},
};
5.6 未登录的导航守卫判断
//未登录:不能去交易(trade)相关、不能去支付相关【pay|paysuccess】、不能去个人中心(center)//未登录去上面这些路由-----登录let toPath=to.pathif(toPath.indexOf('/trade')!=-1||toPath.indexOf('/pay')!=-1||toPath.indexOf('/center')!=-1){ //把未登录的时候向去而没有去成的信息,存储于地址栏中【路由】 next('/login?redirect='+toPath)}else{ //去的不是上面这些路由(home|search|shopCart)---放行 next()}
5.7 用户登录(路由独享与组件内守卫)
3)路由独享守卫
路由独享守卫:需要在配置路由的地方使用
导航守卫:全局守卫->项目当中有任何路由变化【a->b,b->d】触发。
路由独享守卫:专门负责某一个路由
用户登陆了:
去交易页面:从购物车才能跳转到交易页面。
next():你本来想去哪里,我就放行,你就去完事了。
next(’/login’):执行守卫放行到执行的路由。
next(false):路由跳转的时候,从哪里来回那里去。
{ path: "/pay", name: 'pay', component: Pay, meta: { show: true }, beforeEnter:(to,from,next)=>{ // 去支付页,从交易页来的 if(from.path=='/trade'){ next() }else{ // 其他的路由组件而来,停留在当前 next(false) } } },
4)组件内守卫---->一般很少用【全局 + 路由独享守卫】
组件内守卫:也是专门负责某一个路由【并非负责全部路由】,写法和路由独享守卫有区别?
组件内守卫需要书写在组件内部
beforeRouteEnter
beforeRouteUpdate (2.2 新增)
beforeRouteLeave
// 组件内守卫beforeRouteEnter(to, from, next) { // 在渲染该组件的对应路由被 confirm 前调用 // 不!能!获取组件实例 `this` // 因为当守卫执行前,组件实例还没被创建 if(from.path=='/pay'){ next() }else{ next(false) }},
5.8 图片懒加载
面试【高频的面试】:项目的性能优化手段有哪些?
v-if|v-show:尽可能采用v-show
按需引入【lodash、elementUI】
防抖与节流
路由懒加载:当用户访问的时候,加载对应组件进行展示。
7)图片懒加载
vue-lazyload:图片懒加载
图片:比用用户网络不好,服务器的数据没有回来,
总不可能让用户看白色,至少有一个默认图片在展示。
main.js// 引入Vue-lazyloadimport VueLazyLoad from 'vue-lazyload'import mwzi from '@/assets/1.jpg'// 注册插件Vue.use(VueLazyLoad,{ // 懒加载默认的图片 loading:mwzi})
5.9 vee-validate表单验证使用
8)表单验证【后台管理系统:大量使用elementUI】
以后工作的时候经常会进行表单验证【element-ui】进行表单验证,so 简单。
项目当中表单验证功能比较常见的。
8.1vee-validate插件:Vue官方提供的一个表单验证的插件【老师接下来的操作能大概看懂即可】
这个插件很难用:如果你翻看它的文档(看一个月:不保证能看懂),依赖文件很多(文档书写的很难理解)
花大量时间学习,很难搞懂。
8.2哪怕将来工作了,真的使用vee-valadiate【老师项目搞出来:改老师代码即可】
使用步骤:
1:安装vee-valadite,别安装最新版本@2
2:在plugins文件夹中创建一个validate.js[专门注册vee-valadite]
3:注册插件
4:注册插件的时候,用中文,以及需要验证的字段【用中文显示提示形式】
5:在入口文件需要引入执行一次
6:使用vee-valadiate插件
8)vee-validate 基本使用
第一步:插件安装与引入
cnpm i vee-validate@2 --save 安装的插件安装2版本的
import VeeValidate from ‘vee-validate’
import zh_CN from ‘vee-validate/dist/locale/zh_CN’ // 引入中文 message
Vue.use(VeeValidate)
第二步:提示信息
VeeValidate.Validator.localize(‘zh_CN’, {
messages: {
…zh_CN.messages,
is: (field) => ${field}必须与密码相同
// 修改内置规则的 message,让确认密码和密码相同
},
attributes: { // 给校验的 field 属性名映射中文名称
phone: ‘手机号’,
code: ‘验证码’,
password:‘密码’,
password1:‘确认密码’,
isCheck:‘协议’
}
})
第三步:基本使用
{{ errors.first(“phone”) }}
const success = await this.$validator.validateAll(); //全部表单验证
//自定义校验规则
//定义协议必须打勾同意
VeeValidate.Validator.extend(‘agree’, {
validate: value => {
return value
},
getMessage: field => field + ‘必须同意’
})
5.10 路由懒加载
引入组件方式 箭头函数
{ path: "/home", component: ()=>import('@/pages/Home'), meta: { show: true } },
5.11 打包上线
打包npm run build
项目打包后,代码都是经过压缩加密的,如果运行时报错,输出的错误信息无法准确得知是哪里的代码报错。有了map就可以像未加密的代码一样,准确的输出是哪一行哪一列有错。
所以该文件如果项目不需要是可以去除掉
vue.config.js 配置
productionSourceMap:false