Web3.js 实战:基于 Hardhat 的以太坊投票 DApp 开发全流程

本文以一个完整的投票 DApp 项目为例,带你从合约开发、部署到前端集成 Web3.js,体验 Web3 全栈开发流程。


一、项目结构与部署流程时序图

sequenceDiagram participant D as 开发者 participant H as Hardhat participant F as 前端 participant U as 用户 D->>H: 编写 Voting.sol 合约 D->>H: npx hardhat compile D->>H: npx hardhat node D->>H: npx hardhat ignition deploy H->>F: 生成 ABI/地址 (contractInfo.json) U->>F: 打开 vote.html F->>F: 读取 contractInfo.json F->>H: 通过 Web3.js 连接本地节点 U->>F: 投票/查询操作 F->>H: 调用合约方法 H-->>F: 返回结果 F-->>U: 展示投票结果
  • contracts/:Solidity 智能合约源码
  • ignition/modules/:合约部署脚本
  • artifacts/:合约 ABI、字节码等编译产物
  • frontend/:前端页面与合约信息

二、合约开发与部署

1. 编写 Voting 合约

solidity 复制代码
// contracts/Voting.sol
pragma solidity ^0.7.4;

contract Voting {
    struct Candidate { uint id; string name; uint voteCount; }
    mapping(uint => Candidate) public candidates;
    mapping(address => bool) public voters;
    uint public candidatesCount;
    event CandidateAdded(uint id, string name);
    event Voted(uint indexed candidateId);

    constructor() {
        addCandidate("Alice");
        addCandidate("Bob");
    }
    function addCandidate(string memory _name) private {
        candidatesCount++;
        candidates[candidatesCount] = Candidate(candidatesCount, _name, 0);
        emit CandidateAdded(candidatesCount, _name);
    }
    function vote(uint _candidateId) public {
        require(!voters[msg.sender], "You have already voted.");
        require(_candidateId > 0 && _candidateId <= candidatesCount, "Invalid candidate ID.");
        voters[msg.sender] = true;
        candidates[_candidateId].voteCount++;
        emit Voted(_candidateId);
    }
    function getResult() public view returns (string memory winnerName, uint winnerVoteCount) {
        uint winningVoteCount = 0;
        for (uint i = 1; i <= candidatesCount; i++) {
            if (candidates[i].voteCount > winningVoteCount) {
                winningVoteCount = candidates[i].voteCount;
                winnerName = candidates[i].name;
            }
        }
        winnerVoteCount = winningVoteCount;
    }
}

2. Hardhat 编译与本地链部署

bash 复制代码
npm install
npx hardhat compile
npx hardhat node

部署合约:

bash 复制代码
npx hardhat ignition deploy ./ignition/modules/Voting.js --network localhost

部署成功后,终端会输出合约地址:


三、前端集成 Web3.js

1. 前端页面结构

html 复制代码
<!-- frontend/vote.html -->
<script src="https://cdn.jsdelivr.net/npm/web3/dist/web3.min.js"></script>
<script>
  async function loadContractInfo() {
    const res = await fetch('contractInfo.json');
    return await res.json();
  }
  let contract, web3;
  loadContractInfo().then(({ abi, address }) => {
    web3 = new Web3(Web3.givenProvider || 'http://localhost:8545');
    contract = new web3.eth.Contract(abi, address);
    loadCandidates();
  });

  async function loadCandidates() {
    const candidatesCount = await contract.methods.candidatesCount().call();
    // ...渲染候选人
  }
  async function vote() {
    const candidateId = document.getElementById('candidateId').value;
    const accounts = await web3.eth.getAccounts();
    await contract.methods.vote(candidateId).send({ from: accounts[0] });
    alert('投票成功!');
    loadCandidates();
  }
  async function getResults() {
    const result = await contract.methods.getResult().call();
    // ...显示结果
  }
</script>

2. 合约 ABI 和地址自动同步 (这里需要手动修改json文件)

json 复制代码
// frontend/contractInfo.json
{
  "abi": [ ... ],
  "address": "0x1234567890abcdef..."
}

3. 启动本地前端服务

bash 复制代码
cd frontend
python3 -m http.server 8080

浏览器访问 http://localhost:8080/vote.html


四、Web3.js 交互流程图

sequenceDiagram participant U as 用户 participant F as 前端(vote.html) participant W as Web3.js participant C as 合约(Voting) U->>F: 输入候选人ID点击投票 F->>W: 调用 contract.methods.vote(id).send() W->>C: 发送交易到 Voting 合约 C-->>W: 交易回执/事件 W-->>F: 返回投票结果 F-->>U: 页面提示"投票成功"

五、常见问题与调试

  • web3.js 加载慢/超时:可切换为本地 web3.min.js 文件
  • 合约地址不对/前端报错:请确保 contractInfo.json 里的地址和最新部署一致
  • 投票失败:请确保钱包连接本地节点,或本地节点已启动

六、参考资料


建议:

在实际项目中,建议将合约 ABI/地址自动同步到前端,并用脚本化方式管理部署和前端集成,提升开发效率。

相关推荐
kjmkq21 小时前
区块链项目出海宣发,依托全球Web3垂直媒体快速建立行业背书
web3·区块链·媒体
梦帮科技2 天前
【3.0修订版】音乐权利 NFT:MusicRightsNFT 的确权思想与授权关联
网络协议·算法·web3·区块链·密码学·智能合约·零知识证明
怒放de生命20102 天前
2026年新加坡TOKEN2049大会:传统金融与加密世界的深度融合与现实叩问
人工智能·web3·去中心化·区块链·以太坊·分布式账本
怒放de生命20107 天前
【web3基础】区块链演化逻辑:从分布式账本到可编程世界
web3·区块链·分布式账本
DcMedia元宇宙12 天前
谁能登上「数字化」的「诺亚方舟」
web3·数字化
木西12 天前
从 “跑鞋” 到实体卡牌藏品:户外 AR 互动游戏 GoCollect,产品架构全景解析
web3·智能合约·solidity
重明链迹实验室13 天前
重明链迹丨每周区块链安全要闻(0921-0927)
安全·web3·区块链
木西21 天前
把 NEAR 的 “链抽象与 AI 智能体” 搬进以太坊:用 Solidity 0.8.28 打造元交易意图结算核心底座
智能合约·solidity·以太坊
木西23 天前
链上再保险怎么落地?Re Protocol RWA 分层合约架构深度拆解
web3·智能合约·solidity
Web3李李25 天前
Meme 币绑定美股:Robinhood Chain 掀起链上传统市场新实验
web3·区块链·软件开发·dapp·robinhood chain·meme 币