比喻:前端 = 超市收银台,Web3.js/Ethers.js = 扫码枪,帮你读取区块链商品(数据)并结账(交易)。
功能 | Web3.js | Ethers.js |
---|---|---|
出身 | 以太坊官方团队 | 社区开发者维护 |
特点 | 功能全,但API较复杂 | 轻量、模块化,对新手友好 |
钱包支持 | 需要额外适配 | 内置钱包连接(如MetaMask) |
流行度 | 老牌,企业常用 | 新宠,个人项目首选 |
场景:从智能合约读取当前用户的ETH余额
// 使用Ethers.js(更简洁)
import { ethers } from "ethers";
// 连接MetaMask钱包
const provider = new ethers.providers.Web3Provider(window.ethereum);
const signer = provider.getSigner();
// 读取余额
const address = await signer.getAddress();
const balance = await provider.getBalance(address);
console.log("你的余额:", ethers.utils.formatEther(balance), "ETH");
// 使用Web3.js(传统写法)
import Web3 from "web3";
// 连接钱包
const web3 = new Web3(window.ethereum);
// 读取余额
const accounts = await web3.eth.getAccounts();
const balance = await web3.eth.getBalance(accounts[0]);
console.log("你的余额:", web3.utils.fromWei(balance), "ETH");
比喻:React组件 = 乐高积木,Web3功能 = 电动马达,拼在一起就能造出会动的机器人!
安装依赖
npm install ethers @web3-react/core
创建Web3上下文(让所有组件都能访问区块链数据)
// Web3Provider.js
import { Web3ReactProvider } from '@web3-react/core';
import { Web3Provider } from '@ethersproject/providers';
function getLibrary(provider) {
return new Web3Provider(provider);
}
export default ({ children }) => (
{children}
);
在组件中调用合约
// NFTGallery.js
import { useWeb3React } from '@web3-react/core';
import { Contract } from 'ethers';
function NFTGallery() {
const { library, account } = useWeb3React();
const [nfts, setNFTs] = useState([]);
// 加载用户的NFT
const loadNFTs = async () => {
const contract = new Contract(
'0x...合约地址...',
['function balanceOf(address) view returns (uint256)'],
library.getSigner()
);
const count = await contract.balanceOf(account);
setNFTs(Array(count).fill('')); // 模拟NFT数据
};
return (
{nfts.join(' ')}
);
}
比喻:钱包 = 你的区块链银行卡,前端需要教会用户刷卡、输密码、确认交易。
检测钱包
// 检查是否安装了MetaMask
if (!window.ethereum) {
alert('请先安装MetaMask!');
return;
}
请求账户权限
try {
const accounts = await window.ethereum.request({
method: 'eth_requestAccounts'
});
console.log('已连接账户:', accounts[0]);
} catch (error) {
console.error('用户拒绝了连接请求');
}
监听账户变化
window.ethereum.on('accountsChanged', (accounts) => {
if (accounts.length === 0) {
console.log('用户断开了钱包');
} else {
console.log('切换账户至:', accounts[0]);
}
});
const buyNFT = async () => {
// 1. 连接合约
const contract = new ethers.Contract(
NFT_ADDRESS,
NFT_ABI,
signer
);
// 2. 发送交易
try {
const tx = await contract.mintNFT({
value: ethers.utils.parseEther("0.1") // 支付0.1 ETH
});
console.log('交易已发送,哈希:', tx.hash);
// 3. 等待区块确认
await tx.wait();
alert('购买成功!');
} catch (error) {
console.error('交易失败:', error.message);
}
};
痛点:区块链数据加载慢、Gas费高,用户体验容易翻车。
缓存链上数据:
用SWR
或React Query
缓存合约读取结果,减少重复调用。
示例
const { data: balance } = useSWR('userBalance', async () => {
return await contract.balanceOf(account);
});
批量请求数据:
用Promise.all
合并多个合约调用
const [name, symbol, totalSupply] = await Promise.all([
contract.name(),
contract.symbol(),
contract.totalSupply()
]);
懒加载非关键数据:
先展示页面框架,再逐步加载NFT图片、交易历史等。
使用Intersection Observer
实现图片懒加载。
降低Gas费感知:
预估Gas费并显示进度条
const gasLimit = await contract.estimateGas.mintNFT();
showGasProgress(gasLimit);
使用索引服务(The Graph):
将链上数据索引到快速数据库,避免直接扫描区块链。
查询示例(类似SQL)
query {
users(where: { id: "0x..." }) {
nfts {
id
image
}
}
}
敏感操作二次确认:
大额转账前弹窗提示:“即将支付0.5 ETH,是否继续?”
自动检测网络:
防止用户在测试网误操作真钱
if (chainId !== 1) {
alert('请切换到以太坊主网!');
}
错误友好提示:
将区块链错误码转成人话
catch (error) {
if (error.code === 'INSUFFICIENT_FUNDS') {
alert('余额不足!');
}
}
Web3前端开发 ≈ 给区块链机器设计一个友好的收银台界面
钱包集成 ≈ 让用户安全刷卡付款
性能优化 ≈ 让收银台不卡顿、不排队
开发口诀:
先搞定钱包连接(用户进门的钥匙)
合约交互用Ethers.js更省心
缓存、懒加载、批量请求三件套必用
所有交易都要有加载状态和错误反馈
就像超市收银台的设计决定了顾客是否愿意再来,Web3前端的体验决定了DApp的生死——毕竟没人愿意用一个卡到怀疑人生的区块链应用!