区块链技术正以惊人的速度重塑互联网交互方式,而Dapp(去中心化应用)作为这一变革的核心载体,已成为开发者必须掌握的技能。与传统的Web2应用不同,Dapp将数据控制权真正交还给用户——没有中心服务器,没有单点故障,所有操作都通过智能合约在区块链上公开透明地执行。本文将带你用最简化的方式,通过一个存储个人信息的完整案例,体验从智能合约编写到前端交互的全流程。
在开始编码前,我们需要准备三个关键工具:
提示:本教程使用Rinkeby测试网,避免消耗真实资金。实际产品开发时可切换至主网。
访问MetaMask官网安装浏览器插件,创建新钱包后:
javascript复制// 检查MetaMask注入的web3对象
if (typeof window.ethereum !== 'undefined') {
console.log('MetaMask已安装!')
} else {
alert('请先安装MetaMask扩展')
}
在钱包网络下拉菜单中选择"Rinkeby测试网络",然后通过官方水龙头获取测试ETH(需Twitter或Facebook验证)。
打开Remix IDE,新建UserProfile.sol文件:
solidity复制// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract UserProfile {
struct Profile {
string name;
uint age;
uint lastUpdate;
}
mapping(address => Profile) public profiles;
event ProfileUpdated(address user, uint timestamp);
function setProfile(string memory _name, uint _age) external {
profiles[msg.sender] = Profile(_name, _age, block.timestamp);
emit ProfileUpdated(msg.sender, block.timestamp);
}
function getProfile() external view returns (string memory, uint, uint) {
Profile memory p = profiles[msg.sender];
return (p.name, p.age, p.lastUpdate);
}
}
关键组件解析:
mapping:实现地址到用户资料的键值存储event:记录资料更新日志,可供前端监听view函数:声明该操作不会修改链上状态在Remix的"Solidity Compiler"标签页:
切换到"Deploy & Run Transactions"标签:
部署成功后,复制合约地址(格式如0x3F...85f1),这是后续前端交互的关键标识。
创建index.html文件:
html复制<!DOCTYPE html>
<html>
<head>
<title>我的首个Dapp</title>
<script src="https://cdn.jsdelivr.net/npm/web3@1.5.2/dist/web3.min.js"></script>
<style>
body { font-family: Arial; max-width: 600px; margin: 0 auto; }
.profile-card {
background: #f5f5f5;
padding: 20px;
margin: 20px 0;
border-radius: 8px;
}
input, button { padding: 8px; margin: 5px 0; }
</style>
</head>
<body>
<h1>个人资料管理器</h1>
<div class="profile-card">
<h3>当前资料</h3>
<p>姓名: <span id="nameDisplay">未设置</span></p>
<p>年龄: <span id="ageDisplay">0</span></p>
<p>最后更新: <span id="timeDisplay">从未</span></p>
</div>
<h3>更新资料</h3>
<input type="text" id="nameInput" placeholder="输入姓名">
<input type="number" id="ageInput" placeholder="输入年龄">
<button id="updateBtn">提交更新</button>
<script src="app.js"></script>
</body>
</html>
创建app.js文件处理区块链交互:
javascript复制// 初始化Web3
let web3;
if (window.ethereum) {
web3 = new Web3(window.ethereum);
try {
await window.ethereum.enable();
} catch (error) {
console.error("用户拒绝访问账户");
}
} else {
alert('请安装MetaMask!');
}
// 合约ABI和地址
const contractABI = [/* 从Remix复制的完整ABI */];
const contractAddress = "0x3F...85f1"; // 替换为你的合约地址
// 初始化合约实例
const profileContract = new web3.eth.Contract(contractABI, contractAddress);
// 获取并显示当前资料
async function loadProfile() {
const accounts = await web3.eth.getAccounts();
const result = await profileContract.methods.getProfile().call({ from: accounts[0] });
document.getElementById('nameDisplay').textContent = result[0] || '未设置';
document.getElementById('ageDisplay').textContent = result[1] || '0';
document.getElementById('timeDisplay').textContent =
result[2] ? new Date(result[2]*1000).toLocaleString() : '从未';
}
// 更新资料
document.getElementById('updateBtn').addEventListener('click', async () => {
const name = document.getElementById('nameInput').value;
const age = document.getElementById('ageInput').value;
const accounts = await web3.eth.getAccounts();
try {
await profileContract.methods.setProfile(name, age)
.send({ from: accounts[0] });
alert('资料更新成功!');
loadProfile();
} catch (error) {
console.error("交易失败:", error);
}
});
// 监听资料更新事件
profileContract.events.ProfileUpdated({
fromBlock: 'latest'
}, (error, event) => {
if (!error) {
console.log('事件触发:', event);
loadProfile();
}
});
// 页面加载时执行
window.addEventListener('load', loadProfile);
当交易长时间未确认时:
典型排查步骤:
javascript复制// 诊断代码示例
console.log('当前账户:', await web3.eth.getAccounts());
console.log('网络ID:', await web3.eth.net.getId());
console.log('合约代码:', await web3.eth.getCode(contractAddress));
只需三步迁移:
注意:主网交易不可逆,务必先在小额测试环境中验证所有功能
完成基础功能后,可以考虑添加:
solidity复制// 进阶合约示例:添加权限控制
modifier onlyOwner() {
require(msg.sender == owner, "Not authorized");
_;
}
function clearProfile(address user) external onlyOwner {
delete profiles[user];
}
开发过程中遇到任何问题,建议查阅Solidity官方文档或加入Ethereum StackExchange社区讨论。记住,每个成功的Dapp都是从第一个"Hello World"开始的——你现在已经迈出了最关键的一步。