在本文中,我们将使用 WalletConnect 将钱包应用链接到我们使用Vue.js开发的去中心化应用。
去中心化应用程序 (DApps) 的主要功能之一是能够连接钱包,这反过来又允许用户与 DApp 上的交易进行交互。它抽象了诸如交换网络、 提供签名者和其他为用户提供身份验证形式的功能等功能。连接钱包还充当网关,允许用户通过 DApp 使用他们的钱包地址作为授权身份在 区块链上进行和读取操作。
WalletConnect是一个免费的开源协议,可以将我们的 DApp 连接到多个钱包,包括MetaMask、Trust Wallet、Rainbow 等。 该协议通过在 DApp 和钱包之间建立连接来抽象这个过程,使它们在整个会话期间保持同步。
你可以在此处下载本教程的源代码,应用程序的演示请访问这里。

用熟悉的语言学习 Web3.0开发 : Java | Php | Python | .Net / C# | Golang | Node.JS | Flutter / Dart
1、Vue.js 应用程序开发
首先,让我们使用 Vue CLI 启动项目。如果你的系统上已经安装了 Vue CLI,可以继续直接创建 Vue 项目。
可以使用以下命令全局安装它:
1
| npm install -g @vue / cli
|
我们现在可以使用 Vue CLI 来创建我们的项目。使用以下命令创建一个新项目:
1
| vue create vue-wallet-connect
|
你将需要选择一个预设。选择,然后选择如下所示的选项:Manually select features。

创建项目后,导航到新的项目文件夹:
我们将在Vue 应用程序中使用Ethers.js在连接钱包时直接与区块链交互:
在这里,我们将 WalletConnect 库安装到项目中:
1
| npm install --save web3 @walletconnect/web3-provider
|
接下来,要直接在 Vue 3 中使用 WalletConnect 库,我们需要安装node-polyfill-webpack-plugin:
1
| npm i node-polyfill-webpack-plugin
|
我们安装这个插件是因为项目使用 webpack v5,其中删除了 polyfill Node 核心模块。因此,需要安装它以访问项目中的这些模块。
现在,打开vue.config.js文件并将其替换为以下代码块:
12345678910111213
| const { defineConfig } = require("@vue/cli-service");const NodePolyfillPlugin = require("node-polyfill-webpack-plugin");module.exports = defineConfig({ transpileDependencies: true, configureWebpack: { plugins: [new NodePolyfillPlugin()], optimization: { splitChunks: { chunks: "all", }, }, },});
|
完成后,现在可以启动服务器:
2、构建用户界面
让我们进入 components 文件夹并创建一个名为StatusContainer.vue的文件, 该组件包含我们的主页。
这个文件包含了欢迎信息、帮助我们连接的Connect Wallet按钮以及用于断开我们与钱包的连接的Disconnect按钮。最后,当我们成功连接到钱包时, 会显示Connected按钮:
12345678910111213141516
| Welcome to Your Vue.js Dapp
|
完成后,打开App.vue文件并导入StatusContainer组件,如下所示:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748
|
|
在样式标签中,现在为之前创建的按钮添加样式:.button和.disconnect。 此外,我们从 Google Fonts 导入 Sora Custom Font 并在.__buttonfont-family样式中使用该字体。
3、实例化 WalletConnect
我们将需要一个 RPC 提供程序来实例化 WalletConnect 库。对于此示例,我们将使用Infura。 打开 Infura,创建一个新项目,然后获取项目 ID。

现在,在 src/walletConnect 文件夹下创建一个新文件夹walletConnect, 在这个文件夹中,让我们创建一个文件provider.js。在这里,我们导入WalletConnect 库,并使用 我们的 Infura ID 对其进行实例化,然后将其导出以用于其他文件。
src/walletConnect/provider.js看起来像这样:
1234
| import WalletConnectProvider from "@walletconnect/web3-provider";export const provider = new WalletConnectProvider({ infuraId: process.env.VUE_APP_INFURA_ID,});
|
Infura ID 应当设置为环境变量。因此,将以下内容添加到你的.env文件中:
1
| VUE_APP_INFURA_ID={{INFURA__ID}}
|
4、创建Composables
在创建接口并成功实例化我们的库之后,下一步是实现功能。为此,我们将使用 Vue composables,因为它允许我们在应用程序的任何组件中使用 我们的状态和操作,类似于Pinia和 Vuex。
在src文件夹内,添加src/composables/connect,在connect文件夹中,让我们创建一个index.js文件。
在这里,我们导入reactive 和 watch,我们将在这个文件中使用它。让我们创建状态对象defaultState:
123456789
| import { reactive, watch } from "vue";const defaultState = { address: "", chainId: "", status: false,};const state = defaultState
|
为了保持状态一致,我们将状态与本地存储中的项目同步。让我们命名这个条目为userState并将其分配给一个名为STATE_NAME 的变量。 这样做是为了避免userState在多个地方重复时出错:
1
| const STATE_NAME = "userState";
|
我们使用watch来监听状态的任何变化,以便及时更新本地存储:
1234567
| watch( () => state, () => { localStorage.setItem(STATE_NAME, JSON.stringify(state)); }, { deep: true });
|
接下来,我们创建一个getDefaultState函数来检查本地存储中的STATE_NAME项是否存在,并将本地存储项赋给状态。如果本地存储项不存在, 它会将defaultState赋给state。
现在,我们可以删除const state = defaultState并使用reactive来赋值:
1234567
| const getDefaultState = () => { if (localStorage.getItem(STATE_NAME) !== null) { return JSON.parse(localStorage.getItem(STATE_NAME)); } return defaultState;};const state = reactive(getDefaultState());
|
最后,我们导出状态。我们还添加了一条if语句来检查本地存储项是否不存在。如果没有,它会创建项目并分配state给本地存储:
12345678
| export default () => { if (localStorage.getItem(STATE_NAME) === null) { localStorage.setItem(STATE_NAME, JSON.stringify(state)); } return { state, };};
|
现在,我们的状态总是与本地存储同步,确保一致性。
让我们看看src/composables/connect/index.js:
1234567891011121314151617181920212223242526272829303132
| import { reactive, watch } from "vue";const defaultState = { address: "", chainId: "", status: false,};const STATE_NAME = "userState";const getDefaultState = () => { if (localStorage.getItem(STATE_NAME) !== null) { return JSON.parse(localStorage.getItem(STATE_NAME)); } return defaultState;};const state = reactive(getDefaultState());watch( () => state, () => { localStorage.setItem(STATE_NAME, JSON.stringify(state)); }, { deep: true });export default () => { if (localStorage.getItem(STATE_NAME) === null) { localStorage.setItem(STATE_NAME, JSON.stringify(state)); } return { state, };};
|
5、创建Actions
Actions由将在程序中使用的功能组成。我们将创建三个函数:
- connectWalletConnect,这会触发 WalletConnect 与钱包连接
- autoConnect,它在 DApp 连接后处理我们 WalletConnect 会话中的一致性,因此当 DApp 连接并且刷新页面后,用户的会话仍然处于活动状态
- disconnectWallet,这会断开 DApp 与钱包的连接并结束用户的会话
让我们直接进入代码!
仍在我们的src/composables/connect文件夹中,创建connectWalletConnect文件。首先,我们导入index文件等:
1234567891011121314151617181920212223242526272829303132333435363738
| import { providers } from "ethers";import connect from "./index";import { provider } from "../../walletConnect/provider";const connectWalletConnect = async () => { try { const { state } = connect(); // Enable session (triggers QR Code modal) await provider.enable(); const web3Provider = new providers.Web3Provider(provider); const signer = await web3Provider.getSigner(); const address = await signer.getAddress(); state.status = true; state.address = address; state.chainId = await provider.request({ method: "eth_chainId" }); provider.on("disconnect", (code, reason) => { console.log(code, reason); console.log("disconnected"); state.status = false; state.address = ""; localStorage.removeItem("userState"); }); provider.on("accountsChanged", (accounts) => { if (accounts.length > 0) { state.address = accounts[0]; } }); provider.on("chainChanged", (chainId) => { state.chainId = chainId }); } catch (error) { console.log(error); }};export default connectWalletConnect;
|
然后我们用provider监听三个事件: disconnect、accountsChanged和chainChainged。
- disconnect:一旦用户直接从他们的钱包断开连接就会触发
- accountsChanged:如果用户在其钱包中切换帐户,则会触发。如果account数组的长度大于零,我们将state.address设置为数组第一个地址,也就是当前地址
- chainChainged:如果用户切换其链/网络,则会触发。例如,如果从以太坊主网切换到 rinkeby 测试网,我们的应用程序会将state.chainId从1更改为4。
然后,我们的catch语句只是将任何错误记录到控制台。
返回到connect文件夹中的index.js文件并导入connectWalletConnect动作。在这里,我们创建一个actions对象并使用state导出:
1234567891011121314151617181920212223242526272829303132333435
| import { reactive, watch } from "vue";import connectWalletConnect from "./connectWalletConnect";const STATE_NAME = "userState";const defaultState = { address: "", chainId: "", status: false,};const getDefaultState = () => { if (localStorage.getItem(STATE_NAME) !== null) { return JSON.parse(localStorage.getItem(STATE_NAME)); } return defaultState;};const state = reactive(getDefaultState());const actions = { connectWalletConnect,};watch( () => state, () => { localStorage.setItem(STATE_NAME, JSON.stringify(state)); }, { deep: true });export default () => { if (localStorage.getItem(STATE_NAME) === null) { localStorage.setItem(STATE_NAME, JSON.stringify(state)); } return { state, ...actions, };};
|
6、实现组件逻辑
让我们打开StatusContainer组件并将composables中的逻辑连接到接口。像往常一样,导入文件并对其进行解构以获取动作和状态:
123456789101112131415161718192021
|
|
然后返回函数 ( disconnectUser, connectUserWallet) 和state以便在模板中使用:
12345678910111213
| Welcome to Your Vue.js Dapp Address: {{state.address}} ChainId: {{state.chainId}}
|
首先,我们用v-if来有条件地显示事物,使用state.status。 如果已连接并且state.status为真, 我们将显示Connected按钮、用户address和chainId。此外,我们将显示一个触发disconnectUser功能的断开连接按钮。

如果用户没有连接并且state.status是false,我们只显示触发connectUserWallet功能的连接钱包按钮。

7、结束语
在本文中,我们介绍了在 Vue DApp 中集成 WalletConnect 的详细步骤。内容涵盖项目配置、界面构建、逻辑编写、状态同步 等环节,以确保我们的应用程序始终与钱包同步。
原文链接:http://blog.hubwiz.com/2022/08/14/vue-walletconnect-integration/