主题
订单支付与问诊室通知(一)
本页对应 订单支付与问诊室通知,共 7 段视频,约 1 小时 10 分。
学习目标
- 能够将全局支付组件应用到问诊订单页面,并在点击“立即支付”且待付款订单创建成功后调用组件实例的
open方法显示支付弹层。 - 能够通过
ref获取支付组件实例,并在组件外部调用其通过defineExpose暴露的open、close方法完成弹层打开与关闭。 - 能够为支付组件定义并接收
orderId、amount两个自定义属性,在页面使用组件时传入订单 ID 与实际支付金额,并在组件内正确渲染金额。 - 能够使用
defineEmits定义change、close、confirm三个自定义事件,并在支付方式切换、关闭图标点击、确认支付按钮点击时触发对应事件。 - 能够监听支付组件的
change事件,接收切换后的索引值并更新组件内选中状态,实现微信支付与支付宝支付方式的切换。 - 能够监听支付组件的
close事件,在用户关闭支付弹层时弹出挽留确认框,并根据用户选择执行“继续支付”或调用close方法关闭支付组件。
知识点
在问诊订单页接入支付组件
为什么需要:支付弹层不只在当前页面用,所以前面把它封装成全局组件;页面里只要拿到组件实例,就能在“立即支付”后打开它。怎么想:先确认组件已全局注册,页面不用再 import,直接用 ref 拿实例。怎么做:在问诊订单页面放组件,并定义 paymentRef:
html
<custom-payment ref="paymentRef" />js
const paymentRef = ref(null)易错点:ref 名称要和模板一致;不要直接操作 DOM,拿组件实例后调用它暴露的方法。转写里调试时先看“立即支付”有没有进入 onPaymentButtonClick,再确认 createOrder 成功后有没有调用 paymentRef.value.open()。
点击立即支付后打开弹层并传金额
为什么需要:用户点“立即支付”时,要先创建待付款订单,再显示支付方式。怎么想:在 onPaymentButtonClick 里,订单创建成功后打开组件;金额从订单信息里的实付款取。怎么做:
js
async function onPaymentButtonClick() {
const orderId = await createOrder()
paymentRef.value.open()
}模板传金额和订单 ID:
html
<custom-payment
ref="paymentRef"
:amount="orderInfo.actualPayment"
:order-id="orderId"
/>易错点:用了 await 就要给函数加 async;金额字段别写错,转写里调试发现弹层出来了但金额没显示,就是 amount 没传进去。
监听 close 做关闭挽留
为什么需要:用户点叉号可能误关,需要提醒“取消支付后将无法获得医生回复”。怎么想:组件点叉会触发 close 事件,外部监听后弹 uni.showModal。怎么做:
html
<custom-payment ref="paymentRef" @close="onPaymentClose" />js
function onPaymentClose() {
uni.showModal({
title: '关闭支付',
content: '取消支付后将无法获得医生回复,医生接诊名额有限,今日是否要关闭?',
cancelText: '仍要关闭',
confirmText: '继续支付',
success(res) {
if (!res.confirm) paymentRef.value.close()
}
})
}易错点:confirm 为 true 是“继续支付”,不做关闭;只有用户选“仍要关闭”时才调 paymentRef.value.close(),别把逻辑写反。
用 defineExpose 暴露 open/close
为什么需要:弹层组件内部用 uni-popup,外部不能直接点内部按钮,所以要暴露方法。怎么想:组件内部拿 popupRef,把 open/close 映射出去。怎么做:
js
const popupRef = ref(null)
const open = () => popupRef.value.open()
const close = () => popupRef.value.close()
defineExpose({ open, close })html
<uni-popup ref="popupRef" :is-mask-click="false">
...
</uni-popup>易错点:defineExpose 给的是对象,键是外部调用名,值是内部真实函数;外部必须先拿到组件实例再调 paymentRef.value.open()。
用 props 接收 orderId 与 amount
为什么需要:不同订单的 ID 和金额不同。怎么想:用 defineProps 定义两个属性,金额允许数字或字符串。怎么做:
js
defineProps({
orderId: { type: String, default: '' },
amount: { type: [Number, String], default: 0 }
})模板里显示 amount。易错点:外部传参用 kebab-case,如 :order-id;金额类型别只写 Number,避免字符串金额报错。
用 change 事件同步支付方式切换
为什么需要:微信/支付宝只能选中一个,切换结果要告诉外部。怎么想:用 channelIndex 控制选中,点击列表项时修改索引并 emit('change', index)。怎么做:
js
const emit = defineEmits(['change', 'close', 'confirm'])
const channelIndex = ref(0)
function onChannelChange(index) {
channelIndex.value = index
emit('change', index)
}html
<uni-list-item
v-for="(channel, index) in channels"
:key="channel.title"
clickable
@click="onChannelChange(index)"
>易错点:uni-list-item 默认不可点击,必须加 clickable;转写里切换没反应就是漏了它。事件名和外部监听名要一致。
用 close/confirm 事件收口交互
为什么需要:叉号要关闭,立即支付要真正确认支付。怎么想:在组件模板里触发 close,大按钮触发 confirm 并带当前渠道索引。怎么做:
html
<uni-icons type="closeempty" @click="$emit('close')" />
<button @click="$emit('confirm', channelIndex)">立即支付</button>外部监听:
html
<custom-payment
ref="paymentRef"
@close="onPaymentClose"
@confirm="onPaymentConfirm"
/>易错点:模板里 $emit 不要漏引号;confirm 要传 channelIndex,否则外部不知道用户选了微信还是支付宝。
在问诊订单页接入支付组件
为什么需要:支付弹层不只在一个页面用,所以把它封装成全局组件 custom-payment,问诊订单页只负责“什么时候打开、传什么数据”。
怎么想:先在页面拿到组件实例,再在“立即支付”创建待付款订单成功后调用 open()。
怎么做:页面中放组件并绑定 ref、金额、订单号和事件;onPaymentButtonClick 里 await createOrder() 后打开弹层。
易错点:ref 名要和脚本一致;组件是全局注册的,不需要重复 import;订单号要在创建订单成功后接收,金额取 orderInfo.actualPayment,漏传会出现金额空白。
vue
<custom-payment
ref="paymentRef"
:amount="orderInfo.actualPayment"
:order-id="orderId"
@close="onPaymentClose"
@change="onChannelChange"
@confirm="onPaymentConfirm"
/>
<script setup>
import { ref } from 'vue'
const paymentRef = ref(null)
const orderId = ref('')
async function onPaymentButtonClick() {
// 创建待付款订单
await createOrder()
paymentRef.value.open()
}
</script>调试时先看网络请求:点“立即支付”后订单创建成功,再确认弹层是否出现;若不出现,先查 paymentRef.value 是否为空、open 是否已暴露。
关闭支付时的挽留提示
为什么需要:用户点关闭叉号时,要提醒“取消支付后将无法获得医生回复”,避免误关。
怎么想:组件内部点叉号触发 close 事件,页面监听后弹 uni.showModal;点“继续支付”不处理,点“仍要关闭”才调组件 close()。
怎么做:页面监听 @close="onPaymentClose",在方法里用 uni.showModal,根据 res.cancel 关闭弹层。
易错点:uni.showModal 的确认/取消文字要对应“继续支付/仍要关闭”;只有用户仍要关闭时才 paymentRef.value.close(),不要一弹提示就关。
js
function onPaymentClose() {
uni.showModal({
title: '关闭支付',
content: '取消支付后将无法获得医生回复。医生接诊名额有限。',
cancelText: '仍要关闭',
confirmText: '继续支付',
success(res) {
if (res.cancel) paymentRef.value.close()
}
})
}用 defineExpose 开放 open/close 方法
为什么需要:弹层开关由页面控制,组件必须把内部方法暴露给外部。
怎么想:defineExpose 的 key 是外部调用名,value 是组件内部真实函数;内部再调 popupRef.value.open()/close()。
怎么做:组件内定义 open、close,最后 defineExpose({ open, close })。
易错点:不要直接操作弹层实例;外部必须通过组件实例调用;组件未挂载时调用会拿不到实例,通常放在按钮点击后调用。
js
const popupRef = ref(null)
function open() { popupRef.value.open() }
function close() { popupRef.value.close() }
defineExpose({ open, close })用 defineProps 接收订单号和金额
为什么需要:不同订单的订单号、支付金额不同,必须由外部传入。
怎么想:订单号用 String,金额兼容数字和字符串并给默认值 0。
怎么做:defineProps 定义 orderId、amount,模板中显示 {{ amount }}。
易错点:金额没传会显示空;模板里可直接用 amount,脚本里用 props.amount;属性名要和页面传参一致。
js
const props = defineProps({
orderId: String,
amount: { type: [Number, String], default: 0 }
})用 defineEmits 定义 change/close/confirm 事件
为什么需要:组件内部切换支付方式、点关闭、点确认,都要把结果交给页面。
怎么想:先 defineEmits(['change','close','confirm']),再在对应点击处 emit;change 传索引,confirm 传当前渠道索引。
怎么做:列表项加 clickable 和 @click,关闭图标触发 close,支付按钮触发 confirm。
易错点:uni-list-item 默认不可点击,漏加 clickable 会导致点击无反应;调试时用 console.log 验证 emit('change', index) 的 0/1 是否传到页面。
js
const emit = defineEmits(['change', 'close', 'confirm'])
const channelIndex = ref(0)
function onChannelChange(index) {
channelIndex.value = index
emit('change', index)
}
function onClose() { emit('close') }
function onConfirm() { emit('confirm', channelIndex.value) }模板关键处:
vue
<uni-list-item
clickable
v-for="(item, index) in channelList"
:key="item.title"
@click="onChannelChange(index)"
/>
<text @click="onClose">×</text>
<button @click="onConfirm">立即支付</button>调试过程中还遇到:await 所在函数漏写 async 会报语法错误;演示时订单只能用一次,需要重新创建订单再测。
先明确:支付组件为什么要“开放方法”
支付弹层不是在组件内部自己弹出来的,而是用户在问诊订单页点击“立即支付”后才显示。
为什么需要:组件内部只负责弹层外观和交互,真正触发时机在父页面。
怎么想:父页面要拿到组件实例,再调用组件暴露出来的 open、close。
怎么做:组件内用 defineExpose 暴露方法,父页面用 ref 获取实例。
易错点:不要直接操作组件内部 popupRef;父页面调用前要确保组件已挂载,通常在按钮点击事件里调用。
vue
<!-- 支付组件内部:开放 open / close -->
<script setup>
import { ref } from 'vue'
const popupRef = ref(null)
function open() {
popupRef.value?.open()
}
function close() {
popupRef.value?.close()
}
defineExpose({ open, close })
</script>defineExpose 的语法是“外部调用的方法名:组件内部真实函数”。如果名字一样,可以简写为 defineExpose({ open, close })。父页面中组件若是全局注册,无需单独导入:
vue
<template>
<payment-popup
ref="paymentRef"
:order-id="orderId"
:amount="actualPayment"
@change="onPaymentChange"
@close="onPaymentClose"
@confirm="onPaymentConfirm"
/>
</template>
<script setup>
import { ref } from 'vue'
const paymentRef = ref(null)
const orderId = ref('')
const actualPayment = ref(0)
async function onPaymentButtonClick() {
// 创建待付款订单后,再打开支付组件
// const res = await createOrder()
// orderId.value = res.orderId
paymentRef.value?.open()
}
</script>组件基础用法:先理解 uni-popup 的蒙层
转写中先临时加按钮验证组件:点按钮调用 open 显示弹层。
为什么需要:支付弹层要能打开、关闭,还要控制点击蒙层是否关闭。
怎么想:isMaskClick 控制蒙层点击后是否关闭;@maskClick 监听蒙层点击。
怎么做:先设 isMaskClick=false,点击蒙层事件会触发但弹层不消失;设为 true 时点击蒙层会关闭。
易错点:测试按钮只是临时验证,正式使用时删掉;不要把它当成业务入口。
vue
<payment-popup :is-mask-click="false" @mask-click="onMaskClick" />定义属性:订单号和金额必须由外部传入
为什么需要:不同订单支付不同金额,组件不能写死。
怎么想:父向子传数据用自定义属性。
怎么做:用 defineProps 定义 orderId 和 amount,金额允许数值或字符串,默认 0。
易错点:父组件传金额时注意是否加冒号;amount 是变量要写 :amount="actualPayment",纯数字可写 amount="39.9"。
vue
<script setup>
const props = defineProps({
orderId: {
type: String,
default: ''
},
amount: {
type: [Number, String],
default: 0
}
})
</script>模板中显示金额:
vue
<text>{{ amount }}</text>父页面从订单信息中取实付款,例如 orderInfo.actualPayment,并传给组件。
定义事件:change、close、confirm
为什么需要:组件内部切换支付方式、点击关闭、点击确认支付,父页面都要知道。
怎么想:子向父传结果用自定义事件。
怎么做:defineEmits 定义事件;点击时 emit 触发;父页面用 @change、@close、@confirm 监听。
易错点:事件名必须一致;emit 第二个参数才是传给父页面的数据。
vue
<script setup>
import { ref } from 'vue'
const emit = defineEmits(['change', 'close', 'confirm'])
const channelIndex = ref(0)
const channelList = [
{ title: '微信支付', thumb: '/static/pay-wechat.png' },
{ title: '支付宝支付', thumb: '/static/pay-alipay.png' }
]
function onChannelChange(index) {
channelIndex.value = index
emit('change', index)
}
</script>渠道列表关键结构示意,注意 uni-list-item 默认不可点击,要加 clickable:
vue
<uni-list>
<uni-list-item
v-for="(channel, index) in channelList"
:key="channel.title"
clickable
@click="onChannelChange(index)"
>
<image :src="channel.thumb" alt="支付渠道图标" />
<text>{{ channel.title }}</text>
<uni-icons v-if="channelIndex === index" type="checkmarkempty" />
<uni-icons v-else type="circle" />
</uni-list-item>
</uni-list>小叉叉触发关闭,确认支付按钮触发确认:
vue
<uni-icons type="closeempty" @click="emit('close')" />
<button type="primary" @click="emit('confirm', channelIndex)">立即支付</button>调试时如果点击渠道没有反应,先检查是否忘记加 clickable;如果父页面没收到事件,检查 defineEmits、emit 名称和父组件监听名称是否一致。
父页面监听 close:做关闭支付挽留
为什么需要:用户点关闭时,要提醒“取消支付后将无法获得医生回复”。
怎么想:父页面监听 @close,弹 uni.showModal;只有用户点“仍要关闭”才调用组件 close。
怎么做:confirm 为 true 表示继续支付,不关闭;否则调用 paymentRef.value?.close()。
易错点:不要一收到 close 就直接关弹层,否则没有挽留机会。
vue
function onPaymentClose() {
uni.showModal({
title: '关闭支付',
content: '取消支付后将无法获得医生回复,医生接诊名额有限,确定要关闭吗?',
cancelText: '仍要关闭',
confirmText: '继续支付',
success(res) {
if (!res.confirm) {
paymentRef.value?.close()
}
}
})
}
function onPaymentChange(index) {
console.log('当前支付渠道索引:', index)
}
function onPaymentConfirm(index) {
console.log('确认支付,渠道索引:', index)
}这一节的完整流程
先在支付组件内用 uni-popup 做弹层,用 defineExpose 开放 open、close;用 defineProps 接收 orderId、amount;用 defineEmits 定义 change、close、confirm。父页面在“立即支付”回调里创建订单后,通过 paymentRef.value?.open() 打开组件,并监听三个事件。关闭时先弹挽留框,用户坚持关闭才调用组件 close。这样支付组件就能被问诊订单页复用了。
代码示例
代码1:支付弹层组件 payment-popup.vue(组件内部:props / emits / expose)
vue
<!-- components/payment-popup/payment-popup.vue -->
<template>
<uni-popup ref="popupRef" type="bottom" :is-mask-click="false" @mask-click="onMaskClick">
<view class="payment-container">
<view class="payment-header">
<text class="title">选择支付方式</text>
<uni-icons type="closeempty" size="20" @click="emit('close')" />
</view>
<view class="payment-amount">
<text class="label">支付金额</text>
<text class="value">¥{{ amount }}</text>
</view>
<uni-list>
<uni-list-item
v-for="(item, index) in channelList"
:key="item.title"
clickable
@click="onChannelChange(index)"
>
<template #body>
<view class="channel-item">
<image class="thumb" :src="item.thumb" />
<text class="channel-title">{{ item.title }}</text>
<uni-icons
:type="channelIndex === index ? 'checkbox-filled' : 'circle'"
size="20"
:color="channelIndex === index ? '#16a085' : '#999'"
/>
</view>
</template>
</uni-list-item>
</uni-list>
<button class="pay-btn" type="primary" @click="emit('confirm', channelIndex)">
立即支付
</button>
</view>
</uni-popup>
</template>
<script setup>
import { ref } from 'vue'
// 1. 定义属性:订单ID + 金额
const props = defineProps({
orderId: {
type: String,
default: ''
},
amount: {
type: [Number, String],
default: 0
}
})
// 2. 定义事件:切换 / 关闭 / 确认支付
const emit = defineEmits(['change', 'close', 'confirm'])
const popupRef = ref(null)
// 3. 支付渠道数据(微信 / 支付宝)
const channelList = ref([
{ title: '微信支付', thumb: '/static/weixin.png' },
{ title: '支付宝支付', thumb: '/static/zhifubao.png' }
])
// 当前选中的支付方式索引
const channelIndex = ref(0)
// 切换支付方式:改内部选中状态 + 通知外部
const onChannelChange = (index) => {
channelIndex.value = index
emit('change', index)
}
// 蒙层点击:is-mask-click 为 false 时事件仍会触发,但弹层不消失
const onMaskClick = () => {
// 此处按需处理,讲义中此处未做额外操作
}
// 4. 开放给组件外部调用的方法
const open = () => {
popupRef.value.open()
}
const close = () => {
popupRef.value.close()
}
defineExpose({ open, close })
</script>
<style lang="scss" scoped>
.payment-container {
padding: 20px;
background-color: #fff;
border-radius: 12px 12px 0 0;
.payment-header {
display: flex;
justify-content: space-between;
align-items: center;
.title {
font-size: 16px;
font-weight: 600;
}
}
.payment-amount {
margin: 20px 0;
text-align: center;
.label {
color: #999;
font-size: 12px;
}
.value {
display: block;
margin-top: 6px;
font-size: 26px;
font-weight: 600;
}
}
.channel-item {
display: flex;
align-items: center;
.thumb {
width: 24px;
height: 24px;
margin-right: 8px;
}
.channel-title {
flex: 1;
}
}
.pay-btn {
margin-top: 20px;
}
}
</style>关键行 / 易错点
defineExpose({ open, close }):key是外部调用名,value是组件内部真实函数;组件外部必须先通过ref拿到组件实例,才能.open()/.close()。open内部是popupRef.value.open(),不要漏.value,否则调的是 ref 对象本身。uni-list-item默认点击事件是被禁用的,必须加clickable,否则@click不生效(转写稿里就是漏了这个导致切换没反应)。is-mask-click="false"时,点蒙层事件仍触发,只是弹层不消失,所以关闭要由外部显式调close()。amount类型用[Number, String],因为后端返回的金额可能是字符串,写死Number会警告。:key="item.title"保证不重复即可。
代码2:问诊订单页面使用组件(立即支付 → 打开弹层 → 关闭挽留)
vue
<!-- pages/consult/order.vue(节选) -->
<template>
<view class="page">
<!-- 订单信息等省略 -->
<view class="footer">
<text class="pay-amount">实付款:¥{{ orderInfo.actualPayment }}</text>
<button type="primary" @click="onPaymentButtonClick">立即支付</button>
</view>
<!-- 支付组件:全局注册,无需单独 import -->
<custom-payment
ref="paymentRef"
:order-id="orderId"
:amount="orderInfo.actualPayment"
@close="onPaymentClose"
@change="onPaymentChange"
@confirm="onPaymentConfirm"
/>
</view>
</template>
<script setup>
import { ref } from 'vue'
// 组件实例(后缀 REF 表示组件实例)
const paymentRef = ref(null)
// 创建订单后拿到的订单ID
const orderId = ref('')
// 上一步生成的待付款订单信息
const orderInfo = ref({ actualPayment: 0 })
// 点击“立即支付”
const onPaymentButtonClick = async () => {
// await createOrder() —— 生成待付款订单,拿到 orderId 与实付金额
orderId.value = 'order_123456'
orderInfo.value = { actualPayment: 39.9 }
// 打开支付弹层(单标签写法,后面可省结束标签)
paymentRef.value.open()
}
// 用户点“×”关闭:先挽留
const onPaymentClose = async () => {
const res = await uni.showModal({
title: '关闭支付',
content: '取消支付后将无法获得医生回复,医生接诊名额有限。',
cancelText: '仍要关闭',
cancelColor: '#999999',
confirmText: '继续支付',
confirmColor: '#16a085'
})
// 点“继续支付”时 res.confirm 为 true,什么都不做
// 点“仍要关闭”时 res.confirm 为 false,才真正关闭弹层
if (!res.confirm) {
paymentRef.value.close()
}
}
// 支付方式切换
const onPaymentChange = (index) => {
console.log('内部切换了支付方式,当前索引:', index)
}
// 点击“立即支付”大按钮
const onPaymentConfirm = (index) => {
console.log('确认支付,支付渠道索引:', index, '订单:', orderId.value)
}
</script>关键行 / 易错点
- 组件已全局注册,页面里不用 import,直接
<custom-payment ref="paymentRef" ... />。 onPaymentButtonClick里有await,函数必须声明为async,否则报语法错误(转写稿里就踩了这个坑)。- 属性名用中划线
:order-id、:amount,金额来自上一步的orderInfo.actualPayment。 uni.showModal的“仍要关闭”是取消按钮(cancelText),所以判断是if (!res.confirm)才close(),写成res.confirm逻辑就反了。- 订单只能用一次,测试时要重新走一遍创建订单流程,别拿旧订单反复点。
代码3:最小验证示例(defineExpose 开放方法 → 父组件 ref 调用)
vue
<!-- pages/test/test.vue -->
<template>
<view>
<!-- 组件外部按钮:打开弹层 -->
<button type="primary" @click="openPayment">组件外部打开弹层</button>
<custom-payment ref="paymentRef" order-id="test_001" :amount="39.9" />
</view>
</template>
<script setup>
import { ref } from 'vue'
// 获取组件实例
const paymentRef = ref(null)
// 点击时调用组件内部通过 defineExpose 开放的 open 方法
const openPayment = () => {
paymentRef.value.open()
}
</script>关键行 / 易错点
- 流程:外部拿组件实例(
ref)→ 调open()→ 组件内部执行popupRef.value.open()→ 弹层显示。 - 不要在
onMounted之前/组件还没挂载时调open(),所以演示里放在按钮点击里调,此时组件一定已挂载完。 - 名字要对应:
defineExpose里叫什么,外部就.什么(),改名两处都要改(讲义里组件名也统一成了payment-popup)。 - 组件内部自带的测试按钮和测试
@mask-click监听可以删掉,只保留对外开放的方法,避免干扰。
常见错误
现象:点击“立即支付”后报错
Cannot read properties of null (reading 'open')→ 原因:父组件ref尚未绑定到已挂载的组件实例,或调用时机早于组件挂载 → 修法:确认模板中已写ref="paymentRef",并在按钮点击等挂载后时机再调用paymentRef.value.open()。现象:子组件点击支付方式无反应,
change事件不触发 → 原因:uni-list-item默认不可点击,或点击事件未绑定到实际可点击项 → 修法:给列表项加clickable,并在对应项上绑定点击回调后触发自定义事件。现象:父组件监听了
close/confirm/change,但回调不执行 → 原因:子组件defineEmits声明名、emit触发名、父组件监听名三者不一致,或只声明未触发 → 修法:统一事件命名,逐项核对声明、触发、监听位置。现象:支付弹层金额或订单号显示为空/不正确 → 原因:父组件未传
amount、orderId,或属性名大小写、拼写不一致 → 修法:核对defineProps与父组件模板传参名称,确认数据来源字段正确。现象:点关闭叉号后直接关闭,没有“继续支付/仍要关闭”挽留逻辑 → 原因:只监听了
close,未在父组件区分确认结果,或判断分支写反 → 修法:在关闭回调中弹出确认框,仅在用户选择“仍要关闭”时调用组件close(),选择“继续支付”则不关闭。
练习
- 在问诊订单页面点击“立即支付”后打开支付组件,并传入当前订单
orderId与实付金额amount,验证弹层展示正确。 - 在支付组件内实现微信/支付宝切换:点击某项后更新选中态,并向父组件传出当前索引。
- 父组件监听支付组件的
close事件,实现“继续支付 / 仍要关闭”挽留流程,并验证两个分支行为。 - 排查并修复一个场景:
uni-list-item已绑定点击事件但控制台无输出,要求说明检查点与修复步骤。 - 父组件分别监听
change、confirm、close三个事件,打印或处理对应数据,验证事件传参是否符合预期。
课堂画面






原视频对照
| # | 视频 | 时长 |
|---|---|---|
| 1 | 优医咨询-问诊订单支付-1 | 09:20 |
| 2 | 优医咨询-问诊订单支付-2 | 05:45 |
| 3 | 优医咨询-支付组件开放方法 | 17:14 |
| 4 | 优医咨询-支付组件定义属性 | 08:24 |
| 5 | 优医咨询-支付组件定义事件-1 | 09:29 |
| 6 | 优医咨询-支付组件change事件 | 14:24 |
| 7 | 优医咨询-支付组件close和confirm事件 | 06:19 |
小结
- 组件联调先查三件事:属性是否传对、事件是否对齐、方法是否在挂载后调用。
ref调用组件方法前,必须确认模板绑定存在且实例已可用。- 支付组件的关键契约是:数据向内传、事件向外抛、方法供外部调用。
- 支付方式切换应由索引状态驱动,事件负责把切换结果同步给父组件。
- 关闭挽留逻辑必须区分“继续支付”和“仍要关闭”,不能把确认框结果当成关闭指令直接执行。
- 列表项点击无效时,优先检查组件是否显式开启可点击能力。
- 页面联调顺序建议:先验
props,再验事件,再验方法,最后走完整支付流程。