:2026-03-24 17:03 点击:7
区块链技术的浪潮中,去中心化应用(DApp)正逐渐从概念走向现实,以太坊,作为最具影响力的智能合约平台,为DApp的开发提供了强大的基础设施,本文将通过一个简单但完整的实例,带你一步步了解以太坊DApp的开发流程,从智能合约编写到前端交互,让你对DApp开发有一个直观的认识。
DApp概述与核心组成部分
一个典型的以太坊DApp通常由以下几个核心部分组成:
开发环境准备
在开始之前,我们需要准备以下开发工具和环境:
安装步骤相对简单,请访问各工具的官方网站下载并安装相应版本。
DApp开发实例:一个简单的“任务清单”(Todo List)DApp
我们将开发一个简单的Todo List DApp,用户可以添加任务、标记任务完成和查看所有任务。
步骤1:创建项目并初始化
ethereum-dapp-tutorial。truffle init
contracts/:存放智能合约文件。migrations/:存放部署脚本文件。test/:存放测试文件。truffle-config.js:Truffle配置文件。步骤2:编写智能合约
在contracts目录下,创建一个新的Solidity文件,命名为TodoList.sol。
编写智能合约代码:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract TodoList {
// 定义一个结构体来表示任务
struct Task {
uint id;
string content;
bool completed;
}
// 任务数组
Task[] public tasks;
// 任务计数器
uint public taskCount = 0;
// 添加任务的函数
function createTask(string memory _content) public {
taskCount++;
tasks.push(Task(taskCount, _content, false));
}
// 切换任务完成状态的函数
function toggleCompleted(uint _id) public {
Task storage task = tasks[_id - 1]; // 数组索引从0开始
task.completed = !task.completed;
}
// 可选:获取任务数量
function getTaskCount() public view returns (uint) {
return taskCount;
}
}
这个合约定义了任务的结构,提供了创建任务和切换任务完成状态的方法。
步骤3:编译智能合约
truffle compile
build/contracts目录下生成对应的ABI(Application Binary Interface)和字节码文件,ABI是前端与智能合约交互的桥梁。步骤4:编写部署脚本
在migrations目录下,创建一个新的迁移脚本文件,命名为2_deploy_contracts.js(数字前缀表示部署顺序)。
编写部署脚本:
const TodoList = artifacts.require("TodoList");
module.exports = function (deployer) {
deployer.deploy(TodoList);
};
步骤5:部署到本地测试网络(Ganache)
truffle-config.js中配置本地网络:module.exports = {
networks: {
development: {
host: "127.0.0.1",
port: 7545, // Ganache默认端口
network_id: "*", // 匹配任何network_id
},
},
compilers: {
solc: {
version: "0.8.0", // 指定Solidity编译器版本
},
},
};
truffle migrate --network development
步骤6:构建前端界面
在项目根目录下创建一个src目录(或public目录),用于存放前端文件。
在src目录下创建以下文件:
index.html:主页面style.css:样式文件(可选,用于美化界面)app.js:前端逻辑<

index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>以太坊Todo List DApp</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="container">
<h1>以太坊Todo List</h1>
<div class="form">
<input type="text" id="taskInput" placeholder="输入新任务...">
<button id="addTaskBtn">添加任务</button>
</div>
<ul id="taskList">
<!-- 任务列表将在这里动态生成 -->
</ul>
</div>
<script src="https://cdn.ethers.io/lib/ethers-5.2.umd.min.js" type="application/javascript"></script>
<script src="app.js"></script>
</body>
</html>
app.js 内容(核心交互逻辑):
// 声明变量
let todoList;
const todoListAddress = "0x..."; // 替换为你的合约部署地址
const todoListABI = [/* 这里粘贴你的TodoList合约的ABI */]; // 从build/contracts/TodoList.json中获取
// 初始化函数
async function init() {
// 连接到以太坊网络(通过MetaMask)
if (typeof window.ethereum !== 'undefined') {
console.log('MetaMask is installed!');
try {
// 请求账户访问
await window.ethereum.request({ method: 'eth_requestAccounts' });
const provider = new ethers.providers.Web3Provider(window.ethereum);
const signer = provider.getSigner();
todoList = new ethers.Contract(todoListAddress, todoListABI, signer);
// 监听事件并刷新任务列表
todoList.on('TaskCreated', (id, content, completed) => {
console.log('Task created:', id, content, completed);
loadTasks();
});
todoList.on('TaskCompleted', (id, completed) => {
console.log('Task completed:', id, completed);
loadTasks();
});
loadTasks();
} catch (error) {
console.error('User denied account access', error);
}
} else {
console.error('MetaMask is not installed. Please install it to use this DApp.');
alert('请安装MetaMask钱包!');
}
}
// 加载任务列表
async function loadTasks() {
const taskCount = await todoList.getTaskCount();
const taskListElement = document.getElementById('taskList');
taskListElement.innerHTML = ''; // 清空现有列表
for (let i = 1; i <= taskCount; i++) {
const task = await todoList.tasks(i - 1); // 数组索引从0开始
const li = document.createElement('li');
li.innerHTML = `
<span class="${task.completed ? 'completed' : ''}">${task.content}</span>
<button onclick="toggleTaskCompleted(${task.id})">${task.completed ? '未完成' : '完成'}</button>
`;
taskListElement.appendChild(li);
}
}
本文由用户投稿上传,若侵权请提供版权资料并联系删除!