Vue集成Stripe支付刷新报reading 'elements' undefined错误
报错原因
- 触发
Cannot read properties of undefined (reading 'elements')的直接原因是,组件mounted钩子执行时,全局Stripe构造函数还未加载完成,调用Stripe("pk_test_xxx")返回了undefined,后续对undefined调用elements()方法就抛出了类型错误。 - Nuxt项目下逻辑正常是因为Nuxt的插件/头部脚本加载机制会保证第三方SDK在页面生命周期钩子执行前完成挂载,普通Vue项目如果直接在HTML中引入Stripe脚本,默认的脚本加载时序不做特殊处理的话,刷新页面时很容易出现SDK加载晚于
mounted执行的时序问题。 - 原代码还存在两个会引发后续报错的隐藏问题:
onPurchase方法中调用stripe.createToken时未加this.前缀,会引用不存在的全局变量stripe.createToken、axios.post都是异步方法,原代码未加await关键字,无法拿到真实的返回结果,且axios返回的业务数据默认存放在response.data字段中,直接判断response.success永远不会命中逻辑。
修复方案
方案1:保留全局脚本引入,修复加载时序问题
如果已经在public/index.html中通过script标签引入了Stripe SDK,只需要在初始化前判断SDK是否加载完成,同时修复代码中的语法问题即可:
export default { data() { return { error: "", stripe: null, card: null }; }, computed: { ...mapGetters([ "getCart", "getCartTotalPriceWithShipping", "getEstimatedDelivery" ]) }, mounted() { // 轮询判断Stripe SDK是否加载完成 const initStripe = () => { if (!window.Stripe) { return setTimeout(initStripe, 80); } this.stripe = window.Stripe("pk_test_51KGqWkHC"); if (!this.stripe) return; const elements = this.stripe.elements(); this.card = elements.create("card"); this.card.mount(this.$refs.card); }; initStripe(); }, methods: { async onPurchase() { try { // 补全this前缀,加await等待异步结果,解构token和错误信息 const { token, error: stripeError } = await this.stripe.createToken(this.card); if (stripeError) { this.error = stripeError.message; return; } // 加await等待接口响应,从data字段取业务返回值 const response = await axios.post("http://localhost:5000/api/pay", { token: token, totalPrice: this.getCartTotalPriceWithShipping, cart: this.getCart, estimatedDelivery: this.getEstimatedDelivery }); if (response.data.success) { this.$store.commit("clearCart"); this.$router.push("/"); } } catch (err) { console.log(err); this.error = err.message || "支付发起失败,请重试"; } } } };
方案2:NPM包引入(推荐,彻底规避时序问题)
普通Vue项目更推荐通过官方NPM包引入Stripe,完全不需要依赖全局变量,从根源避免加载时序问题:
- 先安装依赖:
npm install @stripe/stripe-js
- 组件中直接导入使用,修改初始化逻辑:
import { loadStripe } from '@stripe/stripe-js'; export default { // 其余data、computed、methods配置和方案1中修复后的逻辑一致,仅修改mounted逻辑 async mounted() { // 等待Stripe实例加载完成再执行后续初始化 this.stripe = await loadStripe("pk_test_51KGqWkHC"); const elements = this.stripe.elements(); this.card = elements.create("card"); this.card.mount(this.$refs.card); } }
内容的提问来源于stack exchange,提问作者xander
相关产品推荐
相关产品推荐

