最新版本的 web3.js 4.x 刚刚发布。在本指南中,我们将深入探讨如何将 web3.js 集成到 HTML 中以进行转账、铸造 NFT 以及查询区块链。web3.js v 1.10.0 文档中的一些功能即将被弃用,因此我们为本 web3.js 教程整理了最新的方法。我们将避免使用像 React js 这样的框架。在不使用任何框架的情况下,我们会迫使自己更深入地理解 Dapp 开发中涉及的基本概念。这种实践方法有助于为您构建区块链开发技能的坚实基础。只需按照分步说明进行操作,复制粘贴代码,并通读提供的代码片段即可。以下是本教程涵盖的内容:
- Web3.js 4.x 迁移亮点
- 入门指南:Web3.js
- 第 1 部分:连接到 MetaMask
- 第 2 部分:显示账户信息
- 第 2 部分:发送交易
- 第 3 部分:与智能合约交互
我们在整个教程中提供了示例和视觉效果,以说明所讨论的概念。
Web3.js 4.x 迁移亮点
本指南将引导您了解迁移到 Web3.js 4.x 的一些重大代码更改。
破坏性更改
1. 模块导入
// Web3.js 1.x import
const Web3 = require('web3');
// Web3.js 4.x import
const { Web3 } = require('web3');
在 Web3.js 4.x 中,我们切换到了解构语法来导入 Web3 对象。
2. 默认 Providers
在 Web3.js 4.x 中,web3.givenProvider 和 web3.currentProvider 的默认值为 undefined。以前,在没有 provider 的情况下实例化 web3 时,它们为 null。
// Defaults to undefined in Web3.js 4.x, previously null
console.log(web3.givenProvider);
console.log(web3.currentProvider);
如果您正在使用 MetaMask,建议直接将 window.ethereum 传递给 Web3 构造函数,而不是使用 Web3.givenProvider。
// Instantiate Web3 with MetaMask providerconst web3 = new Web3(window.ethereum);
3. 函数中的回调
除了事件监听器外,函数中不再支持回调。以下是 Web3.js 4.x 中回调的无效使用示例(这在版本 1 中是有效的):
// INVALID in Web3.js 4.x
web3.eth.getBalance("0x407d73d8a49eeb85d32cf465507dd71d507100c1", function(err, result) {
if (err) {
console.log(err);
} else {
console.log(result);
}
});
次要更改
1. 实例化合约
在 Web3.js 4.x 中,您必须使用 new 关键字来实例化 web3.eth.Contract() 对象。
// Web3.js 1.x
const contract = web3.eth.Contract(jsonInterface, address);
// Web3.js 4.x
const contract = new web3.eth.Contract(jsonInterface, address);
2. getBalance
在 Web3.js 4.x 中,getBalance 返回一个 BigInt 而不是 String。有关完整的迁移指南,请访问 web3.js docs:https://web3js.org/#/
入门指南:Web3.js
创建一个包含以下目录的文件夹:
├── directory/
│ ├── index.html
│ ├── main.js
│ ├── styles.css
在哪里下载 web3.js:
- CDN 链接:web3.js
在此处查找此项目:
- Github 项目链接:https://github.com/AymericRT/web3.js.git
第 1 部分:连接到 MetaMask
现在我们将创建一个用于建立与 MetaMask 连接的按钮。前端代码将放在 index.html 中,而 web3.js javascript 代码将放在 main.js 中。
Index.html
下面的代码包含以下内容:
- HTML 样板文件
- MetaMask 按钮
- web3.js CDN 包 Script 标签
- main.js Script 标签
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Web3.js Example</title>
<link rel="stylesheet" href="./styles.css" />
<script
src="https://cdnjs.cloudflare.com/ajax/libs/web3/4.0.1-alpha.5/web3.min.js"
integrity="sha512-NfffVWpEqu1nq+658gzlJQilRBOvjs+PhEKSjT9gkQXRy9OfxI2TOXr33zS7MgGyTpBa5qtC6mKJkQGd9dN/rw=="
crossorigin="anonymous"
referrerpolicy="no-referrer"
></script>
</head>
<body>
<main>
<p id="status1" class="status" style="color: red">disconnected</p>
<p id="status2" style="color: white"></p>
<div class="maincontainer">
<!-- Connect Wallet -->
<div class="container">
<div class="buttonswrapper">
<div class="buttonswrapperGrid">
<button id="metamask" class="button28">MetaMask</button>
</div>
</div>
</div>
<!-- Account Info Button -->
<!-- Send Transaction -->
<!-- Mint -->
</div>
</main>
<script src="./main.js"></script>
</body>
</html>
HTML 代码片段详述
<script src="https://cdnjs.cloudflare.com/ajax/libs/web3/4.0.1-alpha.5/web3.min.js"
integrity="sha512-NfffVWpEqu1nq+658gzlJQilRBOvjs+PhEKSjT9gkQXRy9OfxI2TOXr33zS7MgGyTpBa5qtC6mKJkQGd9dN/rw=="
crossorigin="anonymous" referrerpolicy="no-referrer">
<head> 部分中的此 script 标签用于加载 web3.js CDN 库。
这等效于 const { Web3 } = require(‘web3’);
<script src="./main.js"></script>
这会将我们的“main.js”函数加载到 HTML 中。最佳实践是将其放置在 body 底部,以避免在渲染之前访问 DOM 元素。
Styles.css
从 Github 复制并粘贴 css 代码:文件的 Github 链接:https://github.com/AymericRT/web3.js/blob/master/styles.css
Main.js 文件
在 main.js 文件中,我们将整合必要的 javascript 函数以激活 MetaMask 按钮。下面有三个主要函数:
- “metamask” 按钮的 Event Listener
- 发生点击事件时,它会检查 MetaMask 是否可用且已连接。
- 如果是,它将调用 ConnectWallet 函数。
- 否则,它会将错误消息记录到控制台,并更新网页上的状态以指示未找到 MetaMask。
- checkMetaMaskAvailability()
- 此函数用于确定是否存在并连接了 MetaMask 浏览器扩展。
- 它检查 window.ethereum 的存在,并尝试通过 ConnectMetaMask() 请求访问 MetaMask 账户。
- 如果授予了账户访问权限,该函数将返回 true,表示连接成功。否则,它会记录一条错误消息并返回 false。
- ConnectMetaMask();
- 此函数负责连接到 MetaMask。
- 它尝试使用 eth_requestAccounts 请求访问 MetaMask 账户。
将上述说明与下面的代码交叉对照。
const web3 = new Web3(window.ethereum);
// Function to check if MetaMask is available
async function checkMetaMaskAvailability() {
if (window.ethereum) {
try {
// Request access to MetaMask accounts
await window.ethereum.request({ method: "eth_requestAccounts" });
return true;
} catch (err) {
console.error("Failed to connect to MetaMask:", err);
return false;
}
} else {
console.error("MetaMask not found");
return false;
}
}
// Event listener for MetaMask button
document.getElementById("metamask").addEventListener("click", async () => {
const metaMaskAvailable = await checkMetaMaskAvailability();
if (metaMaskAvailable) {
await ConnectWallet();
} else {
// MetaMask not available
console.error("MetaMask not found");
// Update status
document.getElementById("status1").innerText = "MetaMask not found";
document.getElementById("status1").style.color = "red";
}
});
//Function to connect to MetaMask
async function ConnectWallet() {
try {
// Request access to MetaMask accounts
await window.ethereum.request({ method: "eth_requestAccounts" });
// Update status
document.getElementById("status1").innerText = "Connected to MetaMask";
document.getElementById("status1").style.color = "green";
} catch (err) {
// Handle error
console.error("Failed to connect to MetaMask:", err);
// Update status
document.getElementById("status1").innerText = "Failed to connect to MetaMask";
document.getElementById("status1").style.color = "red";
}
}
重要代码片段:连接到 MetaMask
web3.js window.ethereum
const web3 = new Web3(window.ethereum);
web3 是 Web3.js 库的一个新实例。
通过将 window.ethereum 分配给 Web3 构造函数,web3 变量会使用提供的 Ethereum provider 与 Ethereum 网络进行交互。
web3.js request Accounts
await window.ethereum.request({ method: "eth_requestAccounts" });
此代码使用 eth_requestAccounts 方法在 Web 应用程序中请求访问用户的 Ethereum 账户。
运行您的服务器
在您的终端中,导航到您的目录并运行此 Python 命令,它会自动在端口 8000 中部署您的服务器。
python -m SimpleHTTPServer 8000
这是您的网站在 localhost:8000 上的样子

第 2 部分:显示账户信息
现在我们的 MetaMask 已经连接,我们能够查询区块链以获取基本的账户详细信息,例如已连接的账户地址、余额以及当前的网络费用。我们将为此功能创建一个按钮并将其命名为“Account_Information”。
Index.html
在注释下方插入“account_Information”按钮。
<!-- Account Information Button -->
<div class="secondcontainer">
<button id="accountbutton" class="button49">
Account Information
</button>
</div>
Main.js
我们将编写一个从 MetaMask 获取数据的函数。该数据将显示以下内容:
- 账户地址
- 账户余额
- 当前的网络费用
所需的两个主要函数是:
- Account Information 按钮的 Event Listener
- 发生点击事件时,它会检查 MetaMask 是否可用且已连接。
- 如果是,它将调用 AccountInfo() 函数。
- 否则,它会记录错误并更新网页状态。
- AccountInformarion();
- 此函数负责从 Ethereum 钱包中获取数据。
- 它使用 web3.eth.getAccounts() 方法检索账户地址。
- 账户余额是通过 web3.eth.getBalance(from) 方法获取的。
- 此外,它通过调用 web3.eth.getGasPrice() 方法检索当前的 gas 价格。
// Event Listener for Account Information
document.getElementById("accountbutton").addEventListener("click", async () => {
const metaMaskAvailable = await checkMetaMaskAvailability();
if (metaMaskAvailable) {
await AccountInformation();
}
});
//Function to call the Account Information
async function AccountInformation() {
const account = await web3.eth.getAccounts();
const from = account[0];
const balanceInWei = await web3.eth.getBalance(from);
const balanceInEth = web3.utils.fromWei(balanceInWei, "ether");
const gasPrice = await web3.eth.getGasPrice();
const gasPriceInEth = web3.utils.fromWei(gasPrice, "ether");
// Display the account information
document.getElementById("status2").innerText ="Account Address: " + from + "\nBalance: " + balanceInEth + " ETH" +"\nGas Price: " + gasPriceInEth;
document.getElementById("status2").style.color = "white";
}
重要代码片段:显示账户信息
web3.js get Accounts
const account = await web3.eth.getAccounts() //returns list of account
const from = account[0]; // gets the first account in the list
getAccounts() 方法返回节点控制的账户列表。基本上,它返回已连接的 MetaMask 账户。
列表中的第一个元素将代表主要连接的账户。
web3.js get Balance
web3.eth.getBalance(from)
getBalance() 方法提取传递给参数的账户地址的余额(单位为 Wei)。请注意,1 Ether 相当于 10^18 Wei。
web3.js get Gas Price
web3.eth.getGasPrice()
getGasPrice() 方法检索 Ethereum 网络上交易的当前 gas 价格(单位为 Wei)。
web3.utils.fromWei(balanceInWei, "ether")
此方法将您的余额从 Wei 单位转换为 Ether。如果您想将其转换为 GWEI,只需将“ether”更改为“gwei”。

第 3 部分:发送 Ether 交易
发送交易(Send Transaction)需要以下参数:
- 发送方地址
- 接收方地址
- 指定金额
我们的发送方地址将是默认的已连接账户。对于接收方地址和指定金额,我们将生成一个包含两个输入字段和一个“send”按钮的表单,该按钮将启动转账。
Index.html
在 <!— Send Transaction —> 注释下方插入表单。
<!-- Send Transaction -->
<form>
<div class="inputcontainer">
<input
id="addressinput"
class="myinput"
placeholder="Address 0x0..."
/>
<input
id="amountinput"
class="myinput"
placeholder="Amount ether..."
/>
</div>
<div class="buttoncontainer">
<button type="button" id="sendButton" class="button64">Send</button>
</div>
</form>
Main.js
要激活发送交易(Send Transaction)功能,我们需要创建两个主要函数。
- SendTransaction 按钮的 Event Listener
- 发生点击事件时,它会检查 MetaMask 是否可用且已连接。
- 如果是,它将调用 SendFunction() 函数。
- 否则,它会记录错误并更新网页状态。
- SendFunction()
- 此函数负责发送交易。
- 它通过 DOM 操作检索接收方地址和指定金额。
- 此外,在 transaction 中创建一个包含交易详细信息(from、to、amount)的 javascript 对象。
- 通过 web3.eth.sendTransaction(transaction) 在 Ethereum 网络上使用提供的交易详细信息 transaction 发送交易。
// Event Listener for Send Transaction
document.getElementById("sendButton").addEventListener("click", async () => {
const metaMaskAvailable = await checkMetaMaskAvailability();
if (metaMaskAvailable) {
await SendFunction();
}
});
//Function to call the Send Function
async function SendFunction() {
// Get input values
const to = document.getElementById("addressinput").value;
const amount = document.getElementById("amountinput").value;
// Check if both to and amount are provided
if (!to || !amount) {
console.error("To and amount are required");
return;
}
// Convert amount to wei (1 ether = 10^18 wei)
const amountWei = web3.utils.toWei(amount, "ether");
// Get the selected account from MetaMask
const accounts = await web3.eth.getAccounts();
const from = accounts[0];
// Create the transaction object
const transaction = {
from: from,
to: to,
value: amountWei,
};
// Send the transaction
try {
const result = await web3.eth.sendTransaction(transaction);
console.log("Transaction result:", result);
// Update status
document.getElementById("status2").innerText ="Transaction sent successfully";
document.getElementById("status2").style.color = "green";
} catch (err) {
// Handle error
console.error("Failed to send transaction:", err);// Update status
document.getElementById("status2").innerText = "Failed to send transaction";
document.getElementById("status2").style.color = "red";
}
}
重要代码片段:发送交易
web3.js Send Transaction
await web3.eth.sendTransaction(transaction)
sendTransaction 接受一个参数 transaction。如果交易不成功,则抛出错误。
transaction 是一个包含要发送的交易详细信息的对象。格式如下:
{
from: "Sender Address",
to: "Recepient Address",
value: "Amount to be sent in WEI",
};
您的网站应该如下所示:

第 4 部分:与智能合约交互
在最后一部分中,您将学习如何使用 web3.eth.Contract 对象与智能合约进行交互。这包括读取数据、写入数据和处理事件。
- 读取数据: 使用合约的读取方法从合约中获取数据,而不修改合约的状态,通常可以免费执行。
- 写入数据: 修改合约状态或通过向区块链发送交易(可能需要 gas 费用)来执行操作的方法。
- 处理事件: 智能合约在执行期间可以触发(emit)事件。我们可以监听这些事件,以便在合约中发生特定操作时收到通知。
这里有一个您将与之交互的合约:
// Rareskills contractpragma solidity ^0.8.0;contract RareSkills {
mapping(address => uint256) public balances;
uint256 public totalSupply;
event Mint(address indexed to, uint256 amount);
function mint(uint256 amount) public {
balances[msg.sender] += amount;
totalSupply += amount;
emit Mint(msg.sender, amount);
}
}
该合约部署在 Mumbai Polygon 网络上。您可以在以下链接中查看它:https://mumbai.polygonscan.com/
Index.html
首先在注释下方插入“mint”按钮。
<!-- Minting NFT -->
<div class="mintcontainer">
<button id="mintactual" class="button49">Mint</button>
<p id="demo3"></p>
</div>
Main.js
在 web3.js 中,我们必须首先实例化合约才能与之交互。实例化合约有两个核心元素:
- 合约地址 (contract address): 0x88d099496C1A493A36E678062f259FE9919B9150
- 合约 ABI (contract ABI): 在此处查找
我们的 javascript 将有两个主要函数:
- 我们的 Mint 按钮的 Event Listener
- 发生点击事件时,它会检查 MetaMask 是否可用且已连接。
- 如果是,它将调用 mintNFT() 函数。
- 否则,它会记录错误并更新网页状态。
- mintNFT()
- 此函数负责与 RareSkills contract 进行交互。
- 使用 web3.eth.Contract 对象创建合约的实例,并将 contractABI 和 contractAddress 作为其参数传递。
- 通过读取 totalSupply 函数来检索合约的总供应量 (total supply)。
- 通过执行 mint(uint256 amount) 函数来铸造合约数据。
- 监听“Mint event”(Mint 事件)的发生并处理它。
我们将深入探讨代码片段中的每个细节。
// Event Listener for Mint Button
document.getElementById("mintbutton").addEventListener("click", async () => {
const metaMaskAvailable = await checkMetaMaskAvailability();
if (metaMaskAvailable) {
await mintNFT();
}
});
// Contract Details
const contractAddress = "0x88d099496C1A493A36E678062f259FE9919B9150"; // Hardcoded contract address
const contractABI = [
// Hard coded ABI
{
anonymous: false,
inputs: [
{
indexed: true,
internalType: "address",
name: "to",
type: "address",
},
{
indexed: false,
internalType: "uint256",
name: "amount",
type: "uint256",
},
],
name: "Mint",
type: "event",
},
{
inputs: [
{
internalType: "address",
name: "",
type: "address",
},
],
name: "balances",
outputs: [
{
internalType: "uint256",
name: "",
type: "uint256",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [
{
internalType: "uint256",
name: "amount",
type: "uint256",
},],name: "mint",outputs: [],stateMutability: "nonpayable",type: "function",},{inputs: [],name: "totalSupply",outputs: [{internalType: "uint256",name: "",type: "uint256",},],stateMutability: "view",type: "function",},];
// Funciton to mint
async function mintNFT() {
// Get connected account
const accounts = await web3.eth.getAccounts();
const from = accounts[0];
// Instantiate a new Contract
const contract = new web3.eth.Contract(contractABI, contractAddress);
try {
// Invoke contract methods
const result = await contract.methods.mint(1).send({ from: from , value: 0});
const _totalSupply = await contract.methods.totalSupply().call();
document.getElementById("status2").innerText = "TotalSupply: " + _totalSupply;
document.getElementById("status2").style.color = "green";
document.getElementById("status3").innerText = "Minting successful";
document.getElementById("status3").style.color = "green";
// Event Listener
contract
.getPastEvents("Mint", {
fromBlock: "latest", // Start from the latest block
})
.then((results) => console.log(results));
} catch (err) {
console.error("Failed to mint:", err);
document.getElementById("status3").innerText = "Failed to mint";
document.getElementById("status3").style.color = "red";
}
}
重要代码片段
web3.js Contract
const contract = new web3.eth.Contract(contractABI, contractAddress);
我们使用 web3.eth.Contract 构造函数实例化了 RareSkills contract 的一个新实例,并传入 contractABI 和 contractAddress 作为其参数。此实例允许我们使用 contractABI 中定义的接口,直接与位于 contractAddress 的智能合约进行交互。与智能合约的交互需要我们调用 .send() 或 .call() 函数,具体取决于它是查看状态的函数还是更改状态的函数。
web3.js .send()
contract.methods.mint(1).send({ from: from , value: 0});
在执行改变合约状态的函数时使用 send() 方法。由于我们的 mint 函数增加了合约的 totalSupply,因此它是一个改变状态的函数。传递给 send() 方法的对象 { from: from, value: 0 } 指定了交易的详细信息。
- from: 指示发送交易的地址。
- value: 指示随交易一起发送的 Ether 数量。在这种情况下,没有发送任何 Ether。
web3.js .call()
contract.methods.totalSupply().call(); call() 合约方法用于执行不改变合约状态的函数。由于 totalSupplyl() 函数是一个“view”函数,因此它使用 call() 方法。
web.3.js event Listeners()
contract
.getPastEvents("Mint", {fromBlock: "latest",}).then((results) => console.log(results));
getPastEvents 是一个在 contract 对象上调用的事件处理程序方法,用于获取最新触发的事件。
-
第一个参数是事件名称,在我们的例子中是“Mint”事件。
-
第二个参数是一个选项对象。在这种情况下,fromBlock 设置为“latest”以从可用的最新区块中获取事件。更多信息在此处。
results 数组将记录到控制台,它应该如下所示:

最终网站结果:

恭喜您完成本 web3.js 教程!
首发于 2023 年 5 月 26 日