用 Web3.js 开发你的第一个去中心化应用(DApp)

·

本文带你从 0 到 1,动手写出、部署并运行一个完全运行在以太坊区块链上的“问候”示例;你会看到如何使用 Web3.js、Truffle、Ganache 让前端与智能合约无缝交互。通过实践学习 DApp 开发流程、Web3.js API、Solidity 合约迁移部署 等核心知识,快速迈入 Web3 世界。


1. 基础术语与概念速览


2. Web3.js 如何工作

Web3.js 本质上是把 JavaScript 调用翻译成 JSON-RPC 请求:

前端 ↔ Web3.js ↔ Provider ↔ 以太坊节点

常见 Provider:HttpProviderWebsocketProviderIpcProvider
Web3.js 提供了五大包:

👉 一次性掌握所有 Web3 核心生态知识点,点击直达完整资料页!


3. 环境搭建(macOS、Windows、Linux 通杀)

工具作用安装命令
Node.js运行 JavaScript、构建前端brew install node
Truffle以太坊开发框架,合约编译与部署npm install -g truffle
Ganache本地区块链,一键启动多个测试账户官网安装 GUI 版 或 npm install -g ganache-cli
solcSolidity 编译器npm install -g solc

说明:Ganache GUI 适合可视化调试,CLI 更轻量,二选一即可。


4. 初始化项目

mkdir dapp-demo && cd dapp-demo
truffle init

运行后,Truffle 会生成:


5. 编写智能合约 Greeting.sol

保存为 contracts/Greeting.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Greeting {
    string public greeting = "hello";

    function sayHello() external view returns (string memory) {
        return greeting;
    }

    function updateGreeting(string calldata _greeting) external {
        greeting = _greeting;
    }
}

6. 编写迁移脚本

创建 migrations/2_greeting_migration.js

const Greeting = artifacts.require("Greeting");
module.exports = deployer => deployer.deploy(Greeting);

7. 编译 & 部署到本地链

  1. 启动 Ganache(快速启动即可)。
  2. 取消 truffle-config.jsdevelopment 网络的注释,并确保端口对应 Ganache 的 RPC Server(默认 7545)。
  3. 命令行执行:

    truffle compile
    truffle migrate --network development

    控制台会返回合约地址:如 0x123...,记住它!


8. 前端联调:让页面直接与链对话

8.1 新建前端文件夹并安装依赖

mkdir client && cd client
npm init -y
npm install web3@latest jquery lite-server --save-dev
mkdir src contracts

8.2 复制合约 ABI


8.3 封装工具函数 src/utils.js

// 获取 Web3 实例
const getWeb3 = () =>
  new Promise((resolve, reject) => {
    window.addEventListener("load", async () => {
      try {
        const web3 = new Web3("http://127.0.0.1:7545"); // Ganache RPC端口
        resolve(web3);
      } catch (error) {
        reject(error);
      }
    });
  });

// 获取合约对象
const getContract = async (web3) => {
  const data = await $.getJSON("./contracts/Greeting.json");
  const netId = await web3.eth.net.getId();
  const deployedNetwork = data.networks[netId];
  return new web3.eth.Contract(
    data.abi,
    deployedNetwork && deployedNetwork.address
  );
};

8.4 页面入口 client/index.html

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="utf-8"/>
  <title>DApp Demo</title>
</head>
<body>
  <h2 id="greeting-text">加载中 …</h2>
  <form id="form">
    <input id="input" type="text" placeholder="输入新问候语"/>
    <button type="submit">更新</button>
  </form>

  <script src="node_modules/jquery/dist/jquery.min.js"></script>
  <script src="node_modules/web3/dist/web3.min.js"></script>
  <script type="module" src="src/index.js"></script>
</body>
</html>

8.5 交互逻辑 src/index.js

import { getWeb3, getContract } from "./utils.js";

const displayGreeting = async (contract) => {
  const text = await contract.methods.sayHello().call();
  $("#greeting-text").text(text);
};

const updateGreeting = async (inputText, contract, accounts) => {
  await contract.methods
    .updateGreeting(inputText)
    .send({ from: accounts[0], gas: 40000 });
  await displayGreeting(contract);
};

const greetingApp = async () => {
  const web3 = await getWeb3();
  const accounts = await web3.eth.getAccounts();
  const contract = await getContract(web3);

  displayGreeting(contract);
  $("#form").on("submit", async (e) => {
    e.preventDefault();
    const inputText = $("#input").val();
    updateGreeting(inputText, contract, accounts);
  });
};

greetingApp();

Tip: ⚡ 记得在 client\package.json 中添加脚本:

"scripts": {
  "start": "lite-server"
}

9. 启动 DApp

  1. 在项目根目录另开一个终端:cd client && npm start
  2. 浏览器自动打开 http://localhost:3000
  3. 页面先读取链上默认问候语 “hello”,输入新词点击“更新”即可上链。每笔交易都能同步到 Ganache 的区块里。

👉 想进一步部署到主网或测试网?这里提供一站式区块链部署攻略!


常见问题 FAQ

Q1:为什么刷新页面后交易更新马上生效?
A:Web3.js 通过轮询节点,会立即读取最新区块状态,因此几乎实时可见。

Q2:报错 connection not open on send 如何解决?
A:大多数情况是 Ganache 没启动或端口被占用。确认 http://127.0.0.1:7545 正常返回 JSON:{"jsonrpc":"2.0","id":1,"result":"0x539"}。

Q3:如何切换 MetaMask 网络?
A:关闭本示例中的 Web3.js 实例,把页面 Provider 替换为 window.ethereum 即可让 MetaMask 接管权限;更新仅对用户签名的账户生效。

Q4:Gas Limit 选多少合适?
A:简单读写 40,000 Wei 足够。复杂逻辑先用 Remix 估算,再上调 10–20% 作为缓冲区。

Q5:我想把币值单位换算为 ETH,而不是 Wei?
A:使用 web3.utils.fromWei(ethValue) 一行搞定数值转换。

Q6:怎样让合约开源以便社区验证?
A:把源码与编译参数上传到 Etherscan、Blockscout 等区块浏览器的 Verify & Publish 通道,自动生成 ABI 及校验代码。


结语

恭喜,你已经完成了第一个 基于 Web3.js 的以太坊 DApp 的完整端到端体验:从合约编写、Truffle 部署,到前端联调。掌握了这些核心技能后,下一步可以挑战更复杂的 DeFi、NFT、DAO 项目。持续迭代、参与线上黑客松,让代码与创意在链上闪光!