默认分类 2026-02-25 8:12 4 0

Vue3 与以太坊:打造去中心化应用的前端实践指南**


随着区块链技术的飞速发展,去中心化应用(DApps)正逐渐走进大众视野,Vue3 作为当前前端领域的主流框架之一,以其卓越的性能、灵活的组件化开发和友好的学习曲线,成为了构建 DApps 前端界面的理想选择,本文将详细介绍如何使用 Vue3 对接以太坊区块链,包括环境搭建、钱包连接、智能合约交互等核心步骤,助你快速入门 DApps 开发。

准备工作:环境与工具

在开始之前,我们需要确保以下环境和工具已准备就绪:

  1. Node.js 与 npm/yarn:Vue3 的运行基础,建议安装 LTS 版本。
  2. Vue3 项目:可以通过 npm create vue@latest 或 Vue CLI/Vite 快速创建一个新的 Vue3 项目。
  3. 代码编辑器:如 VS Code,并安装 Volar 等 Vue3 支持插件。
  4. 随机配图
i>浏览器钱包插件:如 MetaMask,这是与以太坊交互最常用的钱包,用户通过它管理私钥、进行交易和与 DApps 通信。
  • 以太坊节点服务(可选):在实际开发中,DApp 需要与以太坊网络交互,你可以:
    • 使用 InfuraAlchemy 等第三方服务提供商,它们提供可靠的 RPC 节点接入。
    • 本地运行以太坊客户端节点,如 Geth 或 Ganache(后者更适用于开发测试)。
  • 核心依赖:以太坊交互库

    在 Vue3 项目中,我们主要使用 ethers.js 库与以太坊进行交互。ethers.js 是一个功能强大且易于使用的 JavaScript 库,它提供了与以太坊区块链交互所需的所有功能,包括连接钱包、读取链上数据、发送交易等。

    安装 ethers.js

    npm install ethersyarn add ethers

    实现步骤:Vue3 对接以太坊全流程

    连接用户钱包(MetaMask)

    DApp 首先需要连接到用户的 MetaMask 钱包,以获取用户账户权限并进行后续操作。

    我们可以创建一个 Vue3 的 Composable(组合式函数)来管理钱包连接状态,useEthereum.ts

    // src/composables/useEthereum.ts
    import { ref, onMounted } from 'vue';
    import { ethers } from 'ethers';
    export const useEthereum = () => {
      const provider = ref<ethers.BrowserProvider | null>(null);
      const signer = ref<ethers.JsonRpcSigner | null>(null);
      const account = ref<string>('');
      // 连接钱包
      const connectWallet = async () => {
        if (typeof window.ethereum !== 'undefined') {
          try {
            // 请求连接钱包
            await window.ethereum.request({ method: 'eth_requestAccounts' });
            // 创建一个 BrowserProvider 实例
            provider.value = new ethers.BrowserProvider(window.ethereum);
            // 获取 signer(签名者,代表用户进行交易)
            signer.value = await provider.value.getSigner();
            // 获取当前账户地址
            account.value = await signer.value.getAddress();
            console.log('Connected account:', account.value);
          } catch (error) {
            console.error('Error connecting wallet:', error);
          }
        } else {
          alert('Please install MetaMask!');
        }
      };
      // 断开钱包(MetaMask 本身没有直接的断开 API,通常通过清除状态或用户手动断开)
      const disconnectWallet = () => {
        provider.value = null;
        signer.value = null;
        account.value = '';
      };
      // 监听账户变化
      onMounted(() => {
        if (typeof window.ethereum !== 'undefined') {
          window.ethereum.on('accountsChanged', (accounts: string[]) => {
            if (accounts.length > 0) {
              account.value = accounts[0];
              // 可以在这里重新获取 signer
              provider.value && provider.value.getSigner().then(newSigner => {
                signer.value = newSigner;
              });
            } else {
              disconnectWallet();
            }
          });
        }
      });
      return {
        provider,
        signer,
        account,
        connectWallet,
        disconnectWallet,
      };
    };

    在 Vue 组件中使用这个 Composable:

    <template>
      <div>
        <button v-if="!account" @click="connectWallet">Connect Wallet</button>
        <div v-else>
          <p>Connected Account: {{ account }}</p>
          <button @click="disconnectWallet">Disconnect</button>
        </div>
      </div>
    </template>
    <script setup lang="ts">
    import { useEthereum } from '@/composables/useEthereum';
    const { account, connectWallet, disconnectWallet } = useEthereum();
    </script>

    读取链上数据

    连接钱包后,我们可以使用 provider 来读取以太坊链上的公开数据,如区块高度、gas 价格、特定合约的状态变量等。

    假设我们有一个简单的智能合约,其 ABI(应用程序二进制接口)和地址已知:

    // 假设这是你的合约 ABI(简化版)
    const contractABI = [
      'function balanceOf(address owner) view returns (uint256)',
      'function symbol() view returns (string)',
    ];
    // 合约地址(测试网或主网)
    const contractAddress = '0x...YourContractAddress...';
    // 在组件中读取数据
    const { provider } = useEthereum();
    const tokenSymbol = ref('');
    const tokenBalance = ref('');
    const readContractData = async () => {
      if (!provider.value) {
        alert('Please connect wallet first!');
        return;
      }
      try {
        const contract = new ethers.Contract(contractAddress, contractABI, provider.value);
        // 读取代币符号
        const symbol = await contract.symbol();
        tokenSymbol.value = symbol;
        // 读取当前账户的代币余额
        const balance = await contract.balanceOf(account.value);
        tokenBalance.value = ethers.formatEther(balance); // 假设是 ERC20 代币,进行单位转换
        console.log('Token Symbol:', tokenSymbol.value);
        console.log('Token Balance:', tokenBalance.value);
      } catch (error) {
        console.error('Error reading contract data:', error);
      }
    };
    // 在适当的时候调用,例如连接钱包后或点击某个按钮时

    发送交易与调用合约写方法

    当需要修改链上状态时(如转账、调用合约的写入方法),我们需要使用 signer 发送交易,这通常会消耗 gas 费。

    const { signer, account } = useEthereum();
    const transferAmount = ref('1'); // 假设转账 1 个代币
    const transferTokens = async () => {
      if (!signer.value || !account.value) {
        alert('Please connect wallet first!');
        return;
      }
      try {
        const contract = new ethers.Contract(contractAddress, contractABI, signer.value);
        // 准备交易参数
        const amountToSend = ethers.parseEther(transferAmount.value); // 将字符串转换为 wei
        // 发送交易
        const tx = await contract.transfer('0x...RecipientAddress...', amountToSend);
        // 等待交易确认
        console.log('Transaction sent:', tx.hash);
        await tx.wait();
        console.log('Transaction confirmed!');
        // 可以在这里更新 UI 或重新读取数据
        alert(`Transfer ${transferAmount.value} tokens successfully!`);
      } catch (error) {
        console.error('Error transferring tokens:', error);
        alert('Transfer failed!');
      }
    };

    监听事件

    智能合约可以触发事件,我们可以使用 ethers.js 监听这些事件,以便在 DApp 中实时响应链上变化。

    const { provider } = useEthereum();
    const listenToEvents = async () => {
      if (!provider.value) return;
      const contract = new ethers.Contract(contractAddress, contractABI, provider.value);
      // 监听特定事件(假设合约有一个 Transfer 事件)
      contract.on('Transfer', (from, to, amount, event) => {
        console.log('Transfer event detected:', { from, to, amount: ethers.formatEther(amount) });
        // 更新 UI 或执行其他操作
        alert(`New transfer from ${from} to ${to} of ${ethers.formatEther(amount)} tokens!`);
      });
      // 注意:在组件卸载时,最好移除监听器以避免内存泄漏
      // onUnmounted(() => {
      //   contract.removeAllListeners('Transfer');
      // });
    };

    部署与测试

    1. 测试网部署:在开发阶段,强烈建议在以太坊测试网(如 Sepolia)上部署你的智能合约和 DApp,你可以从测试网水龙头获取免费的测试 ETH。
    2. **MetaMask 配置