第7章:Web3.0 前端开发:连接钱包与交互(2025年10月最新版)
声明:仅供学习参考,不构成投资建议
国外可访问:rainweb3知识库
国内可访问:rainweb3知识库
⚠️ 免责声明:本文档旨在提供教育性、参考性的技术指导,基于当前(2025年)社区广泛认可的最佳实践。它不构成任何形式的投资、法律或专业建议。智能合约开发风险极高,任何部署前都应进行严格的自我审查、自动化扫描和第三方审计。
本章系统讲解现代Web3.0前端开发的核心技术栈 ,涵盖钱包连接、交易发送、事件监听等关键操作。所有内容基于当前(2025年10月)行业最佳实践,采用生产级、无过时信息、可直接部署的技术方案,确保开发者掌握真实可用的技能。
1. Web3.js vs Ethers.js:推荐 Ethers.js
| 对比项 | Ethers.js(推荐) | Web3.js | 
|---|---|---|
| 体积与性能 | 更轻量(~80KB),Tree-shaking 友好 | 较大(~400KB),包体积大 | 
| API 设计 | 现代、简洁、TypeScript 优先 | 旧式 API,回调风格遗留 | 
| 维护状态 | 活跃维护,v6 是当前稳定版(2023--2025) | 维护减缓,社区转向 Ethers | 
| 安全性 | 内置地址校验、ABI 解析更安全 | 需额外处理边界情况 | 
| 多链支持 | 原生支持以太坊及所有 EVM 链(Polygon、Arbitrum 等) | 支持但配置复杂 | 
✅ 结论(2025年) :Ethers.js v6 是当前和未来 Web3 前端开发的事实标准,强烈推荐用于新项目。
2. 钱包连接:使用 window.ethereum 检测 MetaMask
现代 DApp 通过浏览器注入的 window.ethereum 对象与钱包通信(遵循 EIP-1193 标准)。
(1)检测钱包存在
            
            
              ts
              
              
            
          
          function detectWallet() {
  if (typeof window.ethereum !== 'undefined') {
    console.log('MetaMask is installed!');
    return true;
  } else {
    alert('Please install MetaMask to use this DApp.');
    return false;
  }
}(2)请求用户授权(eth_requestAccounts)
        
            
            
              ts
              
              
            
          
          async function connectWallet() {
  if (!detectWallet()) return;
  try {
    // 请求用户授权连接
    const accounts = await window.ethereum.request({
      method: 'eth_requestAccounts',
    });
    const account = accounts[0];
    console.log('Connected account:', account);
    return account;
  } catch (error) {
    console.error('User rejected request or error:', error);
    throw error;
  }
}🔐 安全提示:
eth_requestAccounts是标准方法,不会自动连接。- 用户必须主动点击"连接"按钮才能触发。
3. 获取用户地址、余额、网络
(1)获取用户地址
            
            
              ts
              
              
            
          
          const account = await provider.getSigner().getAddress();(2)获取余额
            
            
              ts
              
              
            
          
          async function getBalance(account: string, provider: ethers.Provider) {
  const balanceWei = await provider.getBalance(account);
  const balanceEth = ethers.formatEther(balanceWei); // 转换为 ETH
  console.log(`Balance: ${balanceEth} ETH`);
  return balanceEth;
}(3)获取当前网络
            
            
              ts
              
              
            
          
          async function getNetwork(provider: ethers.Provider) {
  const network = await provider.getNetwork();
  console.log(`Chain ID: ${network.chainId}, Name: ${network.name}`);
  return network;
}🌐 常见 Chain ID(2025年):
- Ethereum Mainnet:
1- Polygon PoS:
137- Arbitrum One:
42161- Optimism:
10- Base:
8453
4. 发送交易:调用合约方法
以调用 NFT 合约的 mint 方法为例。
(1)初始化合约实例
            
            
              ts
              
              
            
          
          const contractAddress = "0xYourContractAddress";
const contractABI = [ /* 从 artifacts 复制 ABI */ ];
// 使用 signer(有权限发送交易)
const signer = await provider.getSigner();
const contract = new ethers.Contract(contractAddress, contractABI, signer);(2)发送 Mint 交易
            
            
              ts
              
              
            
          
          async function mintNFT(amount: number) {
  if (!contract) throw new Error("Contract not initialized");
  try {
    const tx = await contract.publicMint(amount, {
      value: ethers.parseEther("0.01"), // 发送 0.01 ETH
      gasLimit: 300000, // 可选:设置 Gas 上限
    });
    console.log("Transaction sent:", tx.hash);
    // 等待交易确认
    const receipt = await tx.wait();
    console.log("Transaction confirmed in block:", receipt?.blockNumber);
    return receipt;
  } catch (error: any) {
    console.error("Transaction failed:", error.message);
    throw error;
  }
}💡 关键参数说明:
value: 发送 ETH(单位为 Wei,使用ethers.parseEther()转换)。
gasLimit: 手动设置 Gas 上限,避免意外消耗过多。
tx.wait(): 返回交易回执(Receipt),包含状态、日志、区块号等。
5. 事件监听:监听合约事件
监听 Transfer 事件,实时更新前端 UI。
(1)监听单个事件
            
            
              ts
              
              
            
          
          contract.on("Minted", (minter, tokenId) => {
  console.log(`New NFT minted! Owner: ${minter}, Token ID: ${tokenId.toString()}`);
  // 更新前端状态,如刷新 NFT 列表
});(2)监听所有事件(调试用)
            
            
              ts
              
              
            
          
          contract.on("Transfer", (from, to, tokenId) => {
  console.log(`NFT #${tokenId} transferred from ${from} to ${to}`);
});(3)移除监听器
            
            
              ts
              
              
            
          
          // 避免内存泄漏
contract.off("Minted", listenerFunction);⚠️ 生产建议:
- 在 React 中使用
useEffect清理监听器。- 对于高频事件,考虑使用 The Graph 或后端索引服务。
6. 前端框架集成:React + Ethers.js(推荐模式)
以 React + TypeScript + Vite 为例,展示最佳实践结构。
(1)安装依赖
            
            
              bash
              
              
            
          
          npm create vite@latest my-dapp -- --template react-ts
cd my-dapp
npm install ethers@6(2)创建 Web3 上下文(Web3Context.tsx)
        
            
            
              tsx
              
              
            
          
          import { createContext, useContext, useState, useEffect, ReactNode } from 'react';
import { ethers } from 'ethers';
interface Web3ContextType {
  account: string | null;
  balance: string;
  chainId: number | null;
  provider: ethers.Provider | null;
  connectWallet: () => Promise<void>;
}
const Web3Context = createContext<Web3ContextType | undefined>(undefined);
export function Web3Provider({ children }: { children: ReactNode }) {
  const [account, setAccount] = useState<string | null>(null);
  const [balance, setBalance] = useState("0");
  const [chainId, setChainId] = useState<number | null>(null);
  const [provider, setProvider] = useState<ethers.Provider | null>(null);
  useEffect(() => {
    if (typeof window.ethereum !== 'undefined') {
      const prov = new ethers.BrowserProvider(window.ethereum);
      setProvider(prov);
    }
  }, []);
  const connectWallet = async () => {
    if (!provider) return;
    try {
      const accounts = await provider.send("eth_requestAccounts", []);
      const acc = accounts[0];
      setAccount(acc);
      const bal = await provider.getBalance(acc);
      setBalance(ethers.formatEther(bal));
      const network = await provider.getNetwork();
      setChainId(network.chainId);
    } catch (err) {
      console.error("Failed to connect wallet", err);
    }
  };
  return (
    <Web3Context.Provider value={{ account, balance, chainId, provider, connectWallet }}>
      {children}
    </Web3Context.Provider>
  );
}
export const useWeb3 = () => {
  const context = useContext(Web3Context);
  if (!context) throw new Error("useWeb3 must be used within Web3Provider");
  return context;
};(3)在组件中使用
            
            
              tsx
              
              
            
          
          import { useWeb3 } from './Web3Context';
function App() {
  const { account, balance, connectWallet } = useWeb3();
  return (
    <div>
      <h1>My DApp</h1>
      {!account ? (
        <button onClick={connectWallet}>Connect Wallet</button>
      ) : (
        <div>
          <p>Account: {account}</p>
          <p>Balance: {balance} ETH</p>
        </div>
      )}
    </div>
  );
}本章小结
截至2025年10月,Web3.0前端开发已形成清晰的技术路径:
- 首选 Ethers.js v6,因其轻量、安全、现代化。
- 钱包连接 基于 window.ethereum和eth_requestAccounts。
- 交易发送 需正确处理 signer、gas、value和交易回执。
- 事件监听实现响应式UI更新。
- React + Context API 是管理 Web3 状态的推荐模式。