小米商城系统(四)"/>
【Vue】仿小米商城系统(四)
【Vue】仿小米商城系统(四)
文章目录
- 【Vue】仿小米商城系统(四)
- 前言
- 🐶项目地址:
- 八、Element-UI使用
- 1.按需引入
- 一个🌰
- 2.插件引用
- 3.对于 babelrc文件 和 babel.config.js文件
- 方案一:
- 方案二:
- 在该项目中引入 --> 方法一,用import
- 在该项目中引入 --> 方法二,将该方法扩展到vue实例身上
- 九、订单支付页面
- 支付宝
- 微信支付
- 十、订单列表页 --> 分页功能
- elementUI: 分页器
- 加载更多按钮
- 滚动加载 --> 插件实现
- 原生实现加载更多
- 十一、项目优化
- 十二、总结
前言
本项目是基于Vue全家桶的仿小米商城系统,系列笔记(已完结)如下👇🏻
【Vue】仿小米商城系统(一)
【Vue】仿小米商城系统(二)
【Vue】仿小米商城系统(三)
【Vue】仿小米商城系统(四)
🐶项目地址:
点击这里👉仿小米商城系统mimall开发笔记及源码
这里是小飞侠Pan🥳,立志成为一名优秀的前端程序媛!!!
本篇博客收录于我的github前端笔记仓库中,持续更新中,欢迎star~
👉
八、Element-UI使用
1.按需引入
- 安装 babel-plugin-component
npm install babel-plugin-component -D
- 修改 babel.config.js:
官方文档是修改 .babelrc (现在已经找不到 .babelrc文件,而是 babel.config.js),
并且里面的"es2015"
好像有问题,这样好像会有bug
。
所以我们向babel.config.js文件
中追加,注意不是覆盖,最终代码如下图所示:
module.exports = {presets: ['@vue/cli-plugin-babel/preset',["@babel/preset-env", { "modules": false }]],"plugins": [["component",{"libraryName": "element-ui","styleLibraryName": "theme-chalk"}]]
}
//官方给的完整修改
{"presets": [["es2015", { "modules": false }]],"plugins": [["component",{"libraryName": "element-ui","styleLibraryName": "theme-chalk"}]]
}//尚硅谷的视频中的完整的修改:
{"presets": [["@babel/preset-env", { "modules": false }]],"plugins": [["component",{"libraryName": "element-ui","styleLibraryName": "theme-chalk"}]]
}
3.引入部分组件
import Vue from 'vue';
import { Button, Select } from 'element-ui';
import App from './App.vue';Vueponent(Button.name, Button);
Vueponent(Select.name, Select);
/* 或写为* Vue.use(Button)* Vue.use(Select)*/new Vue({el: '#app',render: h => h(App)
});
在Vueponent(Button.name, Button);
中,前面的参数是指自己给要用的组件起一个名字,如果不传,默认使用el-
。
一个🌰
<el-row><el-button>默认按钮</el-button><el-button type="primary">主要按钮</el-button><el-button type="success">成功按钮</el-button><el-button type="info">信息按钮</el-button><el-button type="warning">警告按钮</el-button><el-button type="danger">危险按钮</el-button>
</el-row>
2.插件引用
可以通过 element 插件快速集成 element-ui,在命令行中执行
vue add element
(对于一个新的项目,推荐使用插件引入)
3.对于 babelrc文件 和 babel.config.js文件
方案一:
官方文档是修改babelrc文件,那么我们可以建立一个babelrc文件
。
并在里面写入:
{// "presets": [["es2015", { "modules": false }]], 这个好像是有bug,改成下面那个"presets": [["@babel/preset-env", { "modules": false }]],"plugins": [["component",{"libraryName": "element-ui","styleLibraryName": "theme-chalk"}]]
}
方案二:
我们直接更改babel.config.js文件,
注意:这里是向
babel.config.js文件
中追加,而不是完全覆盖
我们打开babel.config.js
,如下面的代码所示
module.exports = {presets: ['@vue/cli-plugin-babel/preset']
}
然后和presets平级进行追加,
module.exports = {presets: ['@vue/cli-plugin-babel/preset',["@babel/preset-env", { "modules": false }]],"plugins": [["component",{"libraryName": "element-ui","styleLibraryName": "theme-chalk"}]]
}
在该项目中引入 --> 方法一,用import
//main.js
import { Message } from 'element-ui'Vue.use(Message)//注册//使用
Message.error(res.msg);
Message.success('注册成功');
注意:这里如果要在别的组件中使用,还需要再引入一遍,
即import { Message } from 'element-ui'
。
在该项目中引入 --> 方法二,将该方法扩展到vue实例身上
//main.js
import { Message } from 'element-ui'Vue.prototype.$message = Message;//将该方法扩展到vue实例身上//使用
this.$message.success("删除成功");
此时在别的组件中使用,并不需要再次引入
九、订单支付页面
微信支付:接口返回内容是支付链接,转换为二维码结扫码支付
支付宝支付:返回内容为form表单,我们将form表单提交后自动跳转到支付页面。
自己定义一个payType属性,来保存用户选择的是哪种支付方式,并且触发支付事件,
<div class="item-pay"><h3>选择以下支付方式付款</h3><div class="pay-way"><p>支付平台</p><div class="pay pay-ali" :class="{'checked':payType==1}" @click="paySubmit(1)"></div><div class="pay pay-wechat" :class="{'checked':payType==2}" @click="paySubmit(2)"></div></div></div>
在data中定义payType属性
data(){return {payType:''}}
实现支付:
paySubmit(payType){// @click="payType=1"if(payType==1){this.payType=1;window.open('/#/order/alipay?orderId=' + this.orderId,'_blank');}else{this.payType=2;this.axios.post('/pay',{orderId:this.orderId,orderName:'Vue高仿小米商城',amount:0.01,payType:2 //1.支付宝 2.微信}).then((res)=>{QRCode.toDataURL(res.content).then(url => {this.showPay = true;this.payImg = url;this.loopOrderState();}).catch(()=>{Message.error('微信二维码生成失败,请稍后重试');})})}}
支付宝
后端返回一个隐藏的form表单,然后我们插入前端,通过提交表单拉起支付宝支付
支付宝支付的逻辑比较简单。首先,请求之后,跳转至一个新的页面(alipay.vue),然后在这个页面上拿到返回的form表单,然后通过v-html="content"
,将表单嵌入到alipay页面上。在这里其实,alipay相当于一个中间页。
当我们点击支付宝支付按钮后,可以清楚的看到:页面跳转后,先进入的是我们自己定义的alipay页面,然后等待一会儿,才会进入支付宝的支付页面。
1.我们这里使用window.open来实现空白页面的打开,点击支付宝支付后,触发下面的方法:
window.open('/#/order/alipay?orderId='+this.orderId,'_blank')
跳转到的新的页面(alipay页面):
<template><div class="ali-pay"><loading></loading><div class="form" v-html="content"></div></div>
</template>
进入该页面后之后,触发提交的请求,后台会返回一个content,这是包含支付的一个支付宝支付表单的form表单,提交这段代码就会跳转到支付宝的支付页面。这里我们使用document.forms[0].submit()
来触发这个表单的提交:
alipay.vue
data() {return {orderId:this.$route.query.orderId,//获取我们的订单IDcontent:'' //用来将返回的form表单嵌入页面};},
methods: {paySubmit(){this.axios.post('/pay',{orderId:this.orderId,orderName:'Vue高仿小米商城',amount:0.01,payType:1 //1.支付宝 2.微信}).then((res)=>{this.content = res.content;//拿到form表单,将它嵌入页面setTimeout(() => {document.forms[0].submit();//提交表单,实现页面跳转}, 100);})}},mounted() {this.paySubmit();}
这里还使用了一个loading组件来作为从支付页面到支付宝的页面的过渡。
这两步完成之后,就可以跳到了支付宝支付页面,然后就可以进行支付操作了。
微信支付
微信支付相关文档 👉开发文档
该项目使用的是 Native支付
,用户打开“微信扫一扫”,扫描商户的二维码后完成支付。
后端会返回一个生成二维码的链接code_url,对应链接格式:weixin://wxpay/bizpayurl?sr=123456
当用户点击了微信支付的模块时,会将数据提交到后台,然后后台返回一个二维码链接,我们需要将这个链接转换成用户可以识别的二维码
.
而想要将链接转化为二维码,需要使用一个插件:qrcode,
- 安装:
npm install --save qrcode
- 引入:
import QRCode from 'qrcode'
<template><!-- 这里是我们引入的一个组件,这个组件在页面上显示的是一个模态框,当微信二维码返回后,会插入到这个组件中 --><scan-pay-code v-if="showPay" @close="closePayModal" :img="payImg"></scan-pay-code>
</template>paySubmit(payType){// @click="payType=1"if(payType==1){this.payType=1;window.open('/#/order/alipay?orderId=' + this.orderId,'_blank');}else{ //!!!微信支付this.payType=2;this.axios.post('/pay',{orderId:this.orderId,orderName:'Vue高仿小米商城',amount:0.01,payType:2 //1.支付宝 2.微信}).then((res)=>{QRCode.toDataURL(res.content)//转化成base64位的图片.then(url => {this.showPay = true;//展示图片this.payImg = url;//图片的URLthis.loopOrderState();}).catch(()=>{Message.error('微信二维码生成失败,请稍后重试');})})}}
另外我们需要定时轮询订单的支付状态,如果完成支付,自动跳转到订单列表页面。
接口文档中,对于订单状态的返回值:
0-已取消,10-未付款,20-已付款,40-已发货,50-交易成功,60-交易关闭
所以我们在这里判断当status===20时,表示已付款,跳转到订单列表页面。
//轮询当前订单支付状态
loopOrderState(){this.T = setInterval(()=>{this.axios.get(`/order/${this.orderId}`).then((res)=>{if(res.status == 20){clearInterval(this.T);//清除定时器this.goOrderList();//跳转到订单列表页面}})},1000);
},
goOrderList(){this.$router.push('/order/list');
}
十、订单列表页 --> 分页功能
elementUI: 分页器
在页面按需引入,并注册:
import {Pagination} from 'element-ui'// 由于我们引入的是Pagination,而使用时前面有一个el-,所以使用这种方式加载components:{[Pagination.name]: Pagination,}
<el-paginationclass="pagination"layout="prev, pager, next":pageSize="pageSize" :total="total"@current-change="handleChange"></el-pagination>
在handleChange事件中,我们要重新获取新的一页的数据进行渲染,
handleChange(pageNum){this.pageNum = pageNum;this.getOrderList();}
加载更多按钮
在最底部放一个“加载更多”的按钮,这里也使用element uI的button:
import { Button } from 'element-ui'components:{[Button.name]: Button,}
- 定义结构
这里定义一个数据showNextPage,默认为true,就是可以显示下一页
<div class="load-more" v-if="showNextPage"><el-button type="primary" :loading="loading" @click="loadMore">加载更多</el-button></div>
- 数据交互
这里需要注意,我们想要的是加载更多之后与前面加载的数据进行拼接,所以需要对订单的List进行改造:
getOrderList(){this.loading = truethis.axios.get('orders', {params:{pageNum: this.pageNum}}).then((res) => {this.loading = false;// 将数据与前一页进行拼接this.list = this.list.concat(res.list)this.total = res.total// 判断是否还有下一页,如果没有就会隐藏加载按钮this.showNextPage = res.hasNextPagethis.busy = false}).catch(() => {this.loading = false})}loadMore(){// 页数加一this.pageNum++// 重新刷新订单列表this.getOrderList()}
滚动加载 --> 插件实现
- 滚动加载需要使用到一个插件:vue-infinite-scroll,首先要安装并引入、注册插件:
// 安装
npm install vue-infinite-scroll --save
// 引入
import infiniteScroll from 'vue-infinite-scroll'
// 注册(与data同级)
directives:{infiniteScroll
}
- 定义结构
<div class="scroll-more"v-infinite-scroll="scrollMore" // 触发滚动infinite-scroll-disabled="busy" // 是否禁用infinite-scroll-distance="410"> // 距离底部多少像素的时候,进行加载<img src="/imgs/loading-svg/loading-spinning-bubbles.svg" alt="" v-show="loading"></div>
- 数据交互
//第三种方法:滚动加载,插件实现scrollMore(){this.busy = true;setTimeout(()=>{this.pageNum++;this.getOrderList();},500)},//专门给scrollMore使用getList(){this.loading = true;this.axios.get('/orders',{params:{pageSize:10,pageNum:this.pageNum}}).then((res)=>{this.loading = false;this.list = this.list.concat(res.list);if(res.hasNextPage){this.busy = false;}else{this.busy = true;}})}
busy:false; 滚动加载是否触发(true表示不触发)
原生实现加载更多
需要三个高度:scrollHeight(文档内容实际高度,包括超出视窗的溢出部分)、
scrollTop(滚动条滚动距离)、
clientHeight(窗口可视范围高度)。
当 clientHeight + scrollTop >= scrollHeight 时,表示已经抵达内容的底部了,可以加载更多内容。
// Js代码
window.onscroll= function(){//文档内容实际高度(包括超出视窗的溢出部分)var scrollHeight = Math.max(document.documentElement.scrollHeight, document.body.scrollHeight);//滚动条滚动距离var scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;//窗口可视范围高度var clientHeight = window.innerHeight || Math.min(document.documentElement.clientHeight,document.body.clientHeight);if(clientHeight + scrollTop >= scrollHeight){console.log("===加载更多内容……===");}
}
十一、项目优化
懒加载使用import的方式,由于import方式是ES7的语法,所以我们需要引入一个插件,来解析ES7的语法:@babel/plugin-syntax-dynamic-import
安装:npm install --save-dev @babel/plugin-syntax-dynamic-import
然后将路由改成按需加载的形式:
{path: 'confirm',name: 'order-confirm',component: () => import('./pages/orderConfirm.vue')}
十二、总结
-
对开发时请求后台数据设置跨域
-
对sessionStorage进行封装
-
对axios进行封装,设置拦截器,根据后端返回的不同状态码来进行不同响应设置
-
使用cookie管理
-
使用Vuex管理用户信息和购物车状态
-
封装Modal弹框组件
-
使用swiper轮播图组件
-
使用elementUI美化页面,如何按需引入
-
使用路由懒加载提高性能
-
使用Scss的mixin对公共样式抽离
-
使用图片懒加载
-
使用微信、支付宝支付
更多推荐
【Vue】仿小米商城系统(四)
发布评论