1,问题
需要在页面上显示支付宝付款码。后端对接后,前端请求后端获取数据,通过 form
表单提交数据最终会得到一个 url
。但这个 url
不是图片链接而是一个 html
,其中二维码以 canvas
的形式展示。
问题,如何在 dialog 弹窗中显示这个付款码?因为 form 表单请求后会刷新页面。
2,思路
既然是一个 html
,那可以使用 iframe
来显示这个图片,这样即便触发刷新也不影响当前页面。于是有2个思路:
- 在
iframe
中发起form
表单请求。 - 将
form
表单的响应信息放到iframe
中。
查阅资料,发现 form
表单有一个属性 target ,可以指定响应信息的显示位置。所以第2种更简单一点。
在 mdn 中,
form.target
有 4 个可选值,但也可指定为iframe.name
。这样就能用iframe
来显示form
表单提交的响应信息。
3,实现
1,核心逻辑
需要一个 form
表单和 iframe
<form target="iframe">
<input type="hidden" />
</form>
<iframe name="iframe"></iframe>
2,具体实现
<template>
<div style="width: 200px; height: 200px">
<!-- frameborder="0" 不显示边框 -->
<iframe name="iframe" frameborder="0" class="alipay-iframe"></iframe>
</div>
<form target="iframe" ref="_formALIPAY" method="post" :action="info.submitUrl">
<input v-for="(value, key) in info.formInputs" :key="key" :name="key" :value="value" type="hidden" />
</form>
</template>
<script setup>
import { ref, watch, nextTick } from 'vue'
// { submitUrl: '', formInputs: {} }
const props = defineProps(['info'])
const _formALIPAY = ref(null)
watch(
() => props.info,
async (nv) => {
if (nv) {
await nextTick()
_formALIPAY.value.submit()
}
}
)
</script>
<style>
.alipay-iframe {
width: 305px;
height: 305px;
transform-origin: 40px 40px; // 缩放原点
transform: scale(0.52459); // (200 - 40)/305
}
</style>
3,其他问题
网路问题导致请求慢时,iframe
是一个空白的区域,需要加一个 loading
动画。
1,通过 v-if
或 v-show
的方式来判断展示 loading
不行,因为无法得知 form 请求完成的时间。
2,一开始展示 loading,当 iframe 有内容时,自动覆盖掉 loading
不行,因为 iframe 一开始就有宽高和背景,如果一开始置为空得到请求后再设置,那又回到了第一个方式。
3,背景图!(使用的方案)
给 iframe
加一个 gif 的背景图,这样图片展示后自动覆盖。
<style>
.alipay-iframe {
// ...
background-image: url('./loading.gif');
background-repeat: no-repeat;
background-size: 150px 150px;
background-position: center;
}
</style>
以上。