一、前言
欢迎来到本期的博客!在这篇文章中,我们将带您深入了解前端开发领域中的一个热门话题:
如何使用 Vue 3 和 Vite 构建前端项目。随着现代 Web 应用程序的需求不断演进,
选择适当的工具和技术变得至关重要。Vue 3 作为一种流行的前端框架,以其出色的性能和灵活的特性赢得了众多开发者的青睐。
而 Vite,则以其极速的开发体验和创新的构建方式在开发者中引起了极大的兴趣。`
重中之重本篇介绍如何装修我们的下单页面!!!!!
本次为前端知识点如果不懂前段可以去仓库直接copy出来使用,如果有什么问题可以在评论区留言,我会第一时间回复大家的.
在此之前已经更新了微信支付开篇、微信支付安全、微信实战基础框架搭建、本次更新为微信支付实战PC端接口搭建,实战篇分为几个章节因为代码量确实有点多哈.
注意: 如果不懂Vue语言没关系我会讲或直接Copy主要是学习如何实现的嘛
- 第一章从零玩转系列之微信支付开篇
- 第二章从零玩转系列之微信支付安全
- 第三章从零玩转系列之微信支付实战基础框架搭建
- 第四章从零玩转系列之微信支付实战PC端支付下单接口搭建
- 第五章从零玩转系列之微信支付实战PC端支付微信回调接口搭建
- 第五章从零玩转系列之微信支付实战PC端支付微信取消订单接口搭建
- 第六章从零玩转系列之微信支付实战PC端支付微信退款订单接口搭建
- 第七章从零玩转系列之微信支付实战PC端项目构建Vue3 Vite 页面基础搭建
- 第八章从零玩转系列之微信支付实战PC端装修下单页面
本次项目使用技术栈
后端: SpringBoot3.1.x、Mysql8.0、MybatisPlus
前端: Vue3、Vite、ElementPlus
小程序: Uniapp、Uview
演示地址查看 WEB端 小程序
二、介绍
1. 继续上一篇我们集成好了头部和内容区和底部
可以看到当前内容区域的样式 他其实是居中状态并且设置了固定的大小 1200px margin(边缘) 0 auto;的参数进行左右居中上下0不设置任何属性的操作
代码语言:html复制⚠️注意:
<router-
view /> 是一个在前端Web开发中常用的Vue.js框架中的标签。Vue.js是一个流行的JavaScript框架,用于构建用户界面和单页面应用程序(SPA)。 在Vue.js中,SPA的路由是通过Vue Router来管理的。路由是指根据不同的URL路径显示不同的内容,而不需要刷新整个页面。<router-v
iew /> 是Vue Router提供的一个组件,它的作用是在页面中渲染与当前路由匹配的组件。 具体来说,当你在Vue Router中定义了一组路由规则,每个规则对应一个URL路径和一个组件,当用户访问某个URL时,匹配的组件会被渲染到<router-v
iew /> 中,从而实现了页面内容的动态切换,而无需刷新整个页面。 例如,以下是一个简单的Vue Router的示例:
import Vue from 'vue';
import VueRouter from 'vue-router';
import Home from './components/Home.vue'; // 引入home页面
import About from './components/About.vue'; // 引入about页面
Vue.use(VueRouter); // 使用路由配置
// 编辑路由信息
const routes = [
{ path: '/', component: Home },// 如果访问 / 那么跳转到 home页面
{ path: '/about', component: About } // 如果访问 / about 即可跳转about页面
];
// 创建路由对象将我们自定义的路由引入即可
const router = new VueRouter({
routes
});
new Vue({
router,
el: '#app'
});
在这个例子中,当访问根路径
/
时,Home
组件会被渲染到<router-view />
中;当访问/about
路径时,About
组件会被渲染到<router-view />
中。 总之,<router-view />
是Vue Router中的一个占位符,用于动态渲染与当前路由匹配的组件内容,从而实现单页面应用程序中页面内容的切换。
2.使用开发工具调试 F12
使用快捷键
windows 快捷键 F12
或者 MacOS FN F12
出来后点击控制台的鼠标即可唤出调试工具 直接指哪里打哪里
可以看到我们自定义样式都生效的宽度也是我们自定义固定死的高度则后面使用内容支撑开来,那么我们已经知道咋玩了直接开始装修
三、装修
购买课程页面
看我们的设计图 外层有一个墙壁包裹则我们的一些家具 由于之前我们已经将家具的调料都买好了我们可以直接用了(说的是CSS文件、CSS文件、CSS文件、重要的事情说三遍‼️‼️‼️)
- 红色家具: 标题
- 粉色家具: 自定义一些介绍
- 蓝色家具: 选择对应的方块用来支付
- 绿色家具: 选择什么方式来支付
安装红色家具
编写最外层盒子、在编写一个墙壁盒子 container-wall
装修了墙壁 设置了背景颜色、墙壁周围的阴影、内边距 上下为30像素 左右 80像素
代码语言:html复制 <div class="app-container">
<div class="container-wall">
<header>
<h2>
<span>课程列表</span>
</h2>
</header>
</div>
</div>
代码语言:scss复制<style scoped lang="scss">
.container-wall {
background-color: var(--el-bg-color);
box-shadow: 0 0 60px 0 rgb(392 390 288 / 70%);
padding: 30px 80px;
}
</style>
安装粉色家具
看样子旁边有个扶手 后面跟着部分信息
我们就先把主体搞出来
代码语言:html复制 <div class="app-container">
<div class="container-wall">
<header>
<h2>
<span>课程列表</span>
</h2>
</header>
<!-- 墙壁的广告~ -->
<div class="container-wall-advertisement">
本案例使用Native模式拉取二维码用户进行微信扫码支付指定商品操作。
</div>
</div>
</div>
代码语言:scss复制<style scoped lang="scss">
.container-wall {
background-color: var(--el-bg-color);
box-shadow: 0 0 60px 0 rgb(392 390 288 / 70%);
padding: 30px 80px;
.container-wall-advertisement {
margin-top: 10px;
color: red;
margin-bottom: 10px;
font-size: 14px;
height: auto !important;
position: relative;
padding-left: 30px;
line-height: 25px;
font-weight: 500;
}
}
</style>
设置了头部外边距10像素 颜色红色 等
编写扶手 使用伪类直接造一个出来
设置子级设置绝对定位父元素设置相对 (子绝父相) position: relative / absolute;
代码语言:css复制 .container-wall-advertisement:before {
content: "";
display: block;
position: absolute;
left: 0;
top: calc(50% - 10px);
width: 4px;
height: 18px;
background: #fa8919;
border-radius: 0 4px 4px 0;
}
安装蓝色家具
可以看到蓝色家具当中都是一样的我们只需要搞好一个其他的直接复制即可
编写一个盒子用来包裹
盒子内部咱们使用有序标签来搞 ul标签 li 标签
同学们根据图片编写出来
效果就是这样子的
ok我们进行装修 把它 摆正 并且 有边框 包裹 有颜色 如下
给 container-wall-content
盒子 下面的 li 标签 进行装修
设置一个名为 .container-wall-content li
的选择器的样式,该选择器应用于HTML文档中的列表项元素(<li>
)在特定的容器(.container-wall-content
)内。以下是每个属性的中文解释:
border: 2px solid #f3e2c6;
- 解释:设置边框样式为2像素宽度的实线边框,边框颜色为淡色 #f3e2c6。
background-color: #ffffff;
- 解释:设置背景颜色为白色 #ffffff。
color: #f39800;
- 解释:设置文字颜色为橙色 #f39800。
border-radius: 5px;
- 解释:设置边框的圆角半径为5像素,使边框角变得圆润。
width: 170px;
- 解释:设置元素的宽度为170像素。
height: 60px;
- 解释:设置元素的高度为60像素。
line-height: 60px;
- 解释:设置行高为60像素,使文字在垂直方向上居中显示。
font-size: 20px;
- 解释:设置文字的字体大小为20像素。
text-align: center;
- 解释:设置文字在元素内水平居中对齐。
text-decoration: none;
- 解释:移除文字的下划线装饰。
cursor: pointer;
- 解释:将鼠标指针形状设置为手型,表示该元素是可点击的。
display: inline-block;
- 解释:将元素的显示类型设置为
inline-block
,使其既具有行内元素的特性(可以在同一行显示多个元素),又具有块级元素的特性(可以设置宽度、高度等属性)。
- 解释:将元素的显示类型设置为
margin: 10px 10px;
- 解释:设置元素的外边距(margin)为10像素上下和10像素左右,这会在元素周围创建一段空白区域,增加元素与其他元素之间的间距。
定义了一个具有边框、背景色、文字颜色和其他样式的列表项样式,用于在容器内的特定情境中显示。
查看效果 好看好看好看~
选中状态的差异
如图表示右边的是粉色(选中状态)
自定义一个样式
.container-wall-content li.current
定义了一个针对选中状态的样式,这个样式将应用于具有特定类名的<li>
元素,即带有current
类的<li>
元素。让我逐条解释其中的属性和值的含义:
border: 2px solid #f89898;
这行代码设置了一个2像素宽的边框,颜色为#f89898
,这是一种浅红色。这个边框将会围绕在被应用此样式的元素周围。background-color: #ffffff;
这行代码将背景颜色设置为白色,即#ffffff
。color: #f89898;
这行代码设置文本颜色为#f89898
,与上面边框的颜色相同,以保持颜色一致。font-weight: bold;
这行代码将文本字重设置为粗体,使文本在选中状态下更加显眼。
因此,这个样式的效果是,在选中状态下,带有current
类的<li>
元素将拥有一个红色的粗边框,白色的背景,红色的文本,并且文本会以粗体显示。这样的设计通常用于在用户界面中突出显示当前活动的或者被选中的项目。
使用方式
直接在 li 标签上面新增一个 样式名称
安装绿色家具
可以看到这里面的东西和上面差不多我呢直接写好了同学们直接打出来吧
同学们自己打出来哦 class 名称要一样因为css配置文件是定义的这些名称
查看效果 好看好看好看~
安装按钮
打开 ElementPlus文档 挑选觉得好看的直接安排
样式设置右边
代码语言:css复制 .container-wall-btn {
text-align: right;
}
最终装修效果
四、实现点击切换
目前我们的 我是盒子 不能点击切换选中状态
想要来回点击切换不同的选中样式
切换选中
要知道我们前面已经编写了选中的样式 给谁添加 current 那么就会有选中状态 那么我们可以利用 vue的动态样式来完成
具体的官方文档: https://cn.vuejs.org/guide/essentials/class-and-style.html
示例:
代码语言:html复制<div :class="{ active: isActive }"></div>
上面的语法表示 active
是否存在取决于数据属性 isActive
的真假值。
你可以在对象中写多个字段来操作多个 class。此外,:class
指令也可以和一般的 class
attribute 共存。举例来说,下面这样的状态:
const isActive = ref(true)
const hasError = ref(false)
配合以下模板:
代码语言:html复制<div
class="static"
:class="{ active: isActive, 'text-danger': hasError }"
></div>
渲染的结果会是:
代码语言:html复制<div class="static active"></div>
好那么我们了解了直接应用上去
上面的例子 isActive
他是布尔类型的那么就好办了我们整个点击事件拿到当前点击的 盒子 的唯一 ID 到时候直接判断是否是他就行啦
首先在 script标签当中定义响应式变量
代码语言:html复制<script setup>
// 定义多个盒子对象
let productList = ref([
{id: 1, "name": "我是盒子"},
{id: 2, "name": "我是盒子"},
{id: 3, "name": "我是盒子"},
{id: 4, "name": "我是盒子"},
{id: 5, "name": "我是盒子"},
])
</script>
使用 for 循环来生成每个li标签 同学们手动打一下
添加动态样式
给 li标签添加 :class="'container-wall-content-li', 'current'"
给 li 添加点击事件 实现切换
定义当前选中的盒子
代码语言:html复制// 定义当前选中的盒子
let payOrder = ref({
productId: 1
})
li 点击事件 将当前点击的id记录起来
代码语言:txt复制// li 点击事件 将当前点击的id记录起来
function clickLi(id) {
payOrder.value.productId = id
}
根据记录的ID来判断是否选中
课程列表最终效果
支付方式
也和上面的一样
同学们直接看图片打出来
支付方式最终效果
目前我们的页面搭建完毕~
五、对接
查看设计图
思路: 盒子的数据也是数据库里拿到的,我们也要进行发送请求获取到盒子的全部数据. 点击任意盒子进行支付发起请求到后端创建订单数据,调用微信下单接口返回URL使用前端插件生成二维码,在进行弹出层显示即可
查看表
编写后端商品列表接口
调试一波可以拿到
编写axios发送请求配置
axios
是一个流行的基于 JavaScript 的 HTTP 客户端库,用于在浏览器和 Node.js 环境中进行网络请求。它可以帮助开发者轻松地执行 HTTP 请求,处理响应数据,并在应用程序中管理异步操作。
主要功能包括:
- 支持多种请求方法:
axios
支持常见的 HTTP 请求方法,如 GET、POST、PUT、DELETE 等。 - Promise 风格的 API:
axios
使用 Promise 风格的 API,允许您通过.then()
和.catch()
处理成功和失败的响应。 - 请求和响应拦截器: 可以通过拦截器在请求发送之前和响应返回之后执行自定义逻辑。
- 请求取消:
axios
允许您创建一个取消令牌,以便在需要时取消正在进行的请求。 - 处理请求和响应数据:
axios
可以自动解析响应数据,例如将 JSON 数据解析为 JavaScript 对象。 - 浏览器和 Node.js 支持:
axios
可以在浏览器和 Node.js 环境中使用。
以下是一个简单的示例,展示如何使用 axios
发送一个 GET 请求:
const axios = require('axios');
axios.get('https://api.example.com/data')
.then(response => {
console.log('Response:', response.data);
})
.catch(error => {
console.error('Error:', error);
});
以上是对axios的介绍和使用
在src目录下创建utils文件夹 在里面创建 request.js
文件
import axios from "axios";
import {ElMessage} from "element-plus";
// 创建axios实例
const service = axios.create({
baseURL: "/wx-api", // 部署 api 的 base_url
timeout: 20000, // 请求超时时间
});
// request拦截器
service.interceptors.request.use(
(config) => {
return config;
},
(error) => {
// Do something with request error
Promise.reject(error);
}
);
// response 拦截器
service.interceptors.response.use(
(response) => {
const res = response.data;
// 201 表示请求成功自定义处理问题
if (res.code === 201 || res.code === 200) {
return response.data;
} else {
ElMessage({
message: res.message,
type: "error",
duration: 5 * 1000,
});
return Promise.reject("error");
}
},
(error) => {
ElMessage({
message: error.message,
type: "error",
duration: 5 * 1000,
});
return Promise.reject(error);
}
);
export default service;
搭建商品接口
在 src目录下创建api文件夹 在里面创建 product.js
文件
编写 API请求
定义加载层 文档: https://element-plus.gitee.io/zh-CN/component/loading.html
代码语言:html复制// 加载层
let loading = ref(false);
测试请求
修改 选择商品 前面我们定义的字段和数据库不一样导致渲染是空白的
查看页面效果
弹出二维码
使用组件库 dialog 弹出
官方文档: https://element-plus.gitee.io/zh-CN/component/dialog.html
定义弹出变量
代码语言:html复制// 弹出框宽度
let widthBox = ref("350px");
// 确认支付按钮是否禁用
let payBtnDisabled = ref(false);
// 微信支付二维码弹出
let codeDialogVisible = ref(true);
// 微信支付二维码地址
let codeUrl = ref("");
代码语言:html复制 <!-- 微信支付二维码 -->
<el-dialog v-model="codeDialogVisible" :width="widthBox" center>
<div style="display: flex">
<div>
<qrcode-vue :value="codeUrl" :size="300" level="H" />
<div class="line">请打开手机微信,扫一扫完成支付</div>
</div>
<div class="comp-wxpay-qrcode-tip">
<img
src="https://qiniu.staticfile.org/static/wxpay_tip-ac45fc3d17795a22330c.png"
title=""
style=""
/>
</div>
</div>
</el-dialog>
查看页面
没有二维码我们去后端下单一个获取一个二维码看看效果
将codeUrl复制到前端变量当中
代码语言:txt复制// 微信支付二维码地址
let codeUrl = ref("weixin://wxpay/bizpayurl?pr=INYxOERzz");
出来了可以进行扫码支付
六、Native下单
后台接口我们都已经编写完毕了,那么开始前端接口创建
在api文件夹当中创建 weChatPay.js
文件
// axios 发送ajax请求
import request from "@/utils/request";
export default {
/**
* NativeV3下单
* @param productId 商品ID
* @returns {*}
*/
nativePay(productId) {
return request({
url: "/api/wx-pay/native/v3/" productId,
method: "post",
});
},
/**
* 取消接口
* @param orderNo 订单号
* @returns {*}
*/
cancel(orderNo) {
return request({
url: "/api/wx-pay/cancel/v3/" orderNo,
method: "post",
});
},
/**
* 退款接口
* @param orderNo 订单号
* @param reason 退款理由
* @param refundNo 支付成功后的交易单号
* @returns {*}
*/
refunds(orderNo, reason, refundNo) {
return request({
url: "/api/wx-pay/refunds/v3/" orderNo "/" refundNo "/" reason,
method: "post",
});
},
};
⚠️注意: 对应的URL地址和后端保持一致.
调用Native接口
编写调用接口的方法 nativePayFun
框框的则是需要新增的代码
import WeChatPayApi from "@/api/weChatPay";
短轮询查询订单状态
保持唯一性后端支付成功后无法返回最新的支付状态给前端需要前端主动去数据库查询.
编写 orderInfo.js
代码语言:javascript复制import request from "@/utils/request";
export default {
queryOrderStatus(orderNo) {
return request({
url: "/api/orderInfo/queryOrderStatus/" orderNo,
method: "get",
});
},
};
编写请求函数 框框的则是新增代码
使用轮询查询订单状态
测试
先解决一个小bug 给异步请求增加 await 否则导致响应数据丢失
开启内网穿透 注意后端地址 和前端地址
可以看到我们的轮询已经启动
扫码支付后成功接收到支付回调请求
前端短轮询检查是否支付成功
最终视频显示
最后
本期结束咱们下次再见