在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
开源软件名称:0xthreebody/Dapp-IPFS-Image开源软件地址:https://github.com/0xthreebody/Dapp-IPFS-Image开源编程语言:JavaScript 92.3%开源软件介绍:Dapp-IPFS-Image基于IPFS去中心化相册以太坊Dapp
安装IPFS官网(访问不了时,需要科学上网) https://ipfs.io 创建IPFS节点
启动服务器
跨域资源共享 CORS配置
验证启动IPFS服务器
项目开发新建项目文件夹 下载unbox react 框架 安装ipfs-api
验证框架和环境:编译合约 开启前端 看见 项目页面, ok 修改项目框架代码:Atom编辑器打开项目: 编写智能合约修改 pragma solidity ^0.4.19;
contract SimpleStorage {
string[] public photoArr; //定义一个 装图片hash值的字符串数组
function storePhoto(string hash) public { //定义添加新图片hash方法
photoArr.push(hash); //往字符串数组末尾 添加 新图片的 hash
}
function getPhoto(uint index) public view returns (uint, string){ //定义函数:传入图片序列号,获取图片hash数组长度 和 对应序列号的 装图片hash值的字符串数组
return (photoArr.length, photoArr[index]);
}
} 修改 src/app.jsimport React, {Component} from 'react'
import SimpleStorageContract from '../build/contracts/SimpleStorage.json'
import getWeb3 from './utils/getWeb3'
import './css/oswald.css'
import './css/open-sans.css'
import './css/pure-min.css'
import './App.css'
import ipfsAPI from 'ipfs-api'
const ipfs = ipfsAPI({host: 'localhost', port: '5001', protocal: 'http'})
const contractAddress = "0xd7d25cd0f1ab028a43576b93380c52992716a0d1"
let simpleStorageInstance
let saveImageOnIpfs = (reader) => {
return new Promise(function (resolve, reject) {
const buffer = Buffer.from(reader.result);
ipfs.add(buffer).then((response) => {
console.log(response)
resolve(response[0].hash);
})
.catch((err) => {
console.error(err)
reject(err);
})
})
}
class App extends Component {
constructor(props) {
super(props)
this.state = {
photos: [],
count: 0,
web3: null
}
}
componentWillMount() {
// Get network provider and web3 instance. See utils/getWeb3 for more info.
getWeb3.then(results => {
this.setState({web3: results.web3})
this.instantiateContract()
}).catch(() => {
console.log('Error finding web3.')
})
}
instantiateContract() {
const that = this
const contract = require('truffle-contract')
const simpleStorage = contract(SimpleStorageContract)
simpleStorage.setProvider(this.state.web3.currentProvider)
this.state.web3.eth.getAccounts((error, accounts) => {
simpleStorage.at(contractAddress).then((instance) => {
simpleStorageInstance = instance
})
.then(result => {
return simpleStorageInstance.getPhoto(0)
})
.then(result => {
console.log(result)
let imgNum = result[0].c[0]
if(imgNum===0){
return
}
if(imgNum===1){
this.setState({
count: imgNum,
photos: this.state.photos.concat([result[1]])
})
}
if(imgNum>1){
for(let i=0;i<imgNum;i++){
(function(i){
simpleStorageInstance.getPhoto(i)
.then(result => {
that.setState({
photos: that.state.photos.concat([result[1]])
})
})
})(i)
}
}
})
})
}
render() {
let doms = [],
photos = this.state.photos
for(let i=0; i<photos.length;i++){
doms.push(<div key={i}><img src={"http://localhost:8080/ipfs/" + photos[i]}/></div>)
}
return (
<div className="App">
<header>上传图片至ipfs,并保存信息至以太坊区块</header>
<div className="upload-container">
<label id="file">选择图片</label>
<input type="file" ref="file" id="file" name="file" multiple="multiple" onChange={e => this.change(e)}/>
<button onClick={() => this.upload()}>上传</button>
</div>
<div className="img-container">
{doms}
</div>
</div>
);
}
upload() {
var file = this.refs.file.files[0];
console.log(file)
var reader = new FileReader();
// reader.readAsDataURL(file);
reader.readAsArrayBuffer(file)
reader.onloadend = (e) => {
//console.log(reader);
saveImageOnIpfs(reader).then((hash) => {
console.log(hash);
this.setState({imgSrc: hash})
simpleStorageInstance.storePhoto(hash, {from: this.state.web3.eth.accounts[0]})
.then(() => {
console.log("写入区块成功")
this.setState({
photos: this.state.photos.concat([hash])
})
})
});
}
}
change(e){
console.log(e.target.value)
}
}
export default App 修改src/app.css 前端 UI CSS/* PAGE */
* {
margin: 0;
padding: 0;
}
html, body, #root, .App{
width: 100%;
height: 100%;
}
.App{
display: flex;
flex-direction: column;
}
header{
height: 60px;
line-height: 60px;
padding: 0 20px;
background: #cfd8dc;
border-bottom: 1px solid #eee;
font-size: 24px;
color: #fff;
}
.upload-container {
height: 100px;
display: flex;
justify-content: center;
align-items: center;
background: #cfd8dc;
color: #666;
}
.img-container {
flex: 1;
display: flex;
flex-wrap: wrap;
justify-content: center;
/* align-items: center; */
height: 80px;
background: #eceff1;
}
.img-container div{
width: 200px;
height: 200px;
margin: 20px;
box-shadow: 0 0 10px #ccc;
border-radius: 3px;
}
.img-container div{
display: flex;
justify-content: center;
align-items: center;
}
.img-container div img{
max-width: 200px;
max-height: 200px;
}
.upload-container input{
font-size: 14px;
display: flex;
align-items: center;
margin-left: 10px;
}
.upload-container button{
height: 30px;
width: 80px;
line-height: 30px;
font-size: 14px;
color: #fff;
border: 0;
outline: none;
cursor: pointer;
border-radius: 3px;
background: cadetblue
}
.upload-container button:hover{
opacity: 0.7;
} 本地测试:
(Mnemonic:后面 就是本地 以太坊测试框架区块链 钱包的助记词,可用于直接导入 Metamask钱包中)
如果消耗gas出错, 可以导入truffle 助记词到MetaMask钱包,重试.
http://jiangfuyao.comBlock DEV Blog 区块链开发博客:
|
2023-10-27
2022-08-15
2022-08-17
2022-09-23
2022-08-13
请发表评论