如何在Nuxt.js中从Onboard.js或Web3Modal.js设置OpenSea.js Provider并全局注入?解决$seaport未定义问题
问题分析与解决方案
你遇到的核心问题是Nuxt的inject方法仅在插件初始化阶段执行一次,后续在Onboard的异步wallet回调中调用inject时,已经无法将seaport挂载到已创建的Vue实例上,所以其他组件访问this.$seaport会返回undefined。
为什么当前代码不生效?
Nuxt的inject是在插件初始化(Vue实例创建前)把变量注入到Vue原型和Nuxt上下文里的一次性操作。当用户选择钱包触发回调时,页面的Vue实例早已创建完成,此时调用inject无法更新已存在的实例属性,自然无法在其他组件中访问到新的seaport实例。
解决方案:用全局状态管理共享seaport实例
我们需要把seaport实例存入全局响应式状态中,让所有组件能实时获取到它的最新值。下面提供两种适配不同Nuxt版本的方案:
方案1:Nuxt 2 + Vuex
- 创建Vuex状态模块
在store/seaport.js中创建专门管理seaport的模块:
export const state = () => ({ instance: null }) export const mutations = { SET_SEAPORT(state, seaportInstance) { state.instance = seaportInstance } } export const getters = { getSeaport: (state) => state.instance }
- 修改客户端插件
更新/plugins/onboardopensea.client.js,把seaport实例存入Vuex,并注入获取实例的方法:
import { OpenSeaPort, Network } from "opensea-js"; import Onboard from "bnc-onboard"; export default ({ app, store }, inject) => { const onboard = Onboard({ dappId: "...", networkId: 1, subscriptions: { wallet: (wallet) => { const seaport = new OpenSeaPort(wallet.provider, { networkName: Network.Main, apiKey: "...", }); // 将实例存入Vuex store.commit('seaport/SET_SEAPORT', seaport); }, }, walletSelect: { wallets: [...], // 你的钱包配置 }, }); inject("onboard", onboard); // 注入获取seaport的方法,或者直接注入getter inject("getSeaport", () => store.getters['seaport/getSeaport']); }
- 组件中使用
在组件里通过Vuex getter或注入的方法获取实例:
export default { computed: { seaport() { return this.$store.getters['seaport/getSeaport']; } }, watch: { // 监听seaport实例的变化,就绪后执行操作 seaport(newInstance) { if (newInstance) { console.log("Seaport实例已就绪", newInstance); // 调用seaport的方法,比如获取资产 // newInstance.api.getAssets(...); } } } }
方案2:Nuxt 3 + Pinia
如果是Nuxt 3项目,推荐用Pinia替代Vuex:
- 创建Pinia store
在stores/seaport.js中创建状态:
import { defineStore } from 'pinia' export const useSeaportStore = defineStore('seaport', { state: () => ({ instance: null }), actions: { setSeaport(instance) { this.instance = instance } } })
- 修改客户端插件
import { OpenSeaPort, Network } from "opensea-js"; import Onboard from "bnc-onboard"; import { useSeaportStore } from '~/stores/seaport' export default defineNuxtPlugin((nuxtApp) => { const seaportStore = useSeaportStore(nuxtApp.$pinia) const onboard = Onboard({ dappId: "...", networkId: 1, subscriptions: { wallet: (wallet) => { const seaport = new OpenSeaPort(wallet.provider, { networkName: Network.Main, apiKey: "...", }); seaportStore.setSeaport(seaport); }, }, walletSelect: { wallets: [...], }, }); return { provide: { onboard, seaportStore } } })
- 组件中使用
<script setup> const { $seaportStore } = useNuxtApp() // 监听实例变化 watch(() => $seaportStore.instance, (newInstance) => { if (newInstance) { // 执行操作 } }, { immediate: true }) </script>
额外提示
因为seaport实例依赖用户选择钱包后的provider,所以在组件中使用时一定要先判断实例是否存在,避免出现Cannot read properties of undefined的错误。
内容的提问来源于stack exchange,提问作者Alan Red
相关产品推荐
相关产品推荐

