使用
在我们想要保存项目的目录下打开终端运行npx create-react-app test2
命令初始化,test2是我们的项目名字,可以自己去更改。 初始化完成后,我们目录下就会多出一个test2文件夹 ,然后我们在vscode中打开该文件夹 然后我们打开javascript终端,在终端输入npm run start
命令打开一个网页,这就是初始化项目后它原始的一个界面。 到目前为止我们需要五个界面,ipfs节点启动界面,连接remix界面,react前端启动界面,后端启动界面,hardhat节点启动界面。 新建一个Navbar.js
文件来新建组件,代码如下
function Navbar ( ) { return ( < nav className= "navbar" > < div className= "navbar-brand" > NFT Marketplace< / div> < div className= "navbar-menu" > < button className= "connect-wallet-button" > Connect Wallet< / button> < / div> < / nav> )
} export default Navbar;
import './App.css' ;
import Navbar from './Navbar.js' ;
import { useEffect, useState } from 'react' ; function App ( ) { const [ walletAddress, setWalletAddress] = useState ( "" ) ; useEffect ( ( ) => { getWalletAddress ( ) ; } , [ ] ) ; async function getWalletAddress ( ) { if ( window. ethereum) { const accounts = await window. ethereum. request ( { method : 'eth_requestAccounts' } ) ; const account = accounts[ 0 ] ; setWalletAddress ( account) ; } else { alert ( "Please install MetsMask" ) ; } } return ( < div className= "container" > < Navbar / > < p> { walletAddress} < / p> < / div> ) ;
} export default App;
.App { text-align : center;
} #container { min-height : 160px; padding : 32px; position : relative; border-radius : 16px; -webkit-box-align : center; align-items : center; -webkit-box-pack : center; justify-content : center; flex-direction : column; text-align : left; word-break : break-word;
} .upload-container { max-width : 600px; margin : 0 auto; margin-top : 50px; padding : 20px; background : #fff; border-radius : 8px; box-shadow : 0 0 10px rgba ( 0, 0, 0, 0.1) ;
} .upload-form { display : flex; flex-direction : column;
} .upload-form label { margin-top : 10px;
} .upload-form input,
.upload-form textarea { padding : 10px; margin-top : 5px; border : 1px solid #ddd; border-radius : 4px;
} .upload-form .buttons { display : flex; justify-content : space-between; margin-top : 20px;
} .cancel-button,
.upload-button { padding : 10px 20px; border : none; border-radius : 4px; cursor : pointer;
} .cancel-button { background : #ccc;
} .upload-button { background : #007bff; color : white;
} .navbar { display : flex; justify-content : space-between; align-items : center; padding : 1rem; background-color : #333; color : white;
} .navbar-brand { font-size : 1.5rem;
} .navbar-menu { display : flex; align-items : center;
} .connect-wallet-button { padding : 0.5rem 1rem; border : none; border-radius : 4px; cursor : pointer; background-color : #007bff; color : white;
} input#title::placeholder { font-family : sans-serif; font-size : 16px; color : #a9a9a9;
}
textarea#description::placeholder { font-family : sans-serif; font-size : 16px; color : #a9a9a9;
} .nft-grid { display : grid; grid-template-columns : repeat ( auto-fit, minmax ( 250px, 1fr) ) ; gap : 1rem; padding : 1rem;
} .nft-card { border : 1px solid #e1e1e1; border-radius : 10px; overflow : hidden;
} .nft-image img { width : 100%; height : auto; display : block;
} .nft-info { padding : 0.5rem; text-align : center;
} .nft-detail { display : flex; max-width : 600px; margin : 0 auto; margin-top : 50px; padding : 20px; background : #fff; border-radius : 8px; box-shadow : 0 0 10px rgba ( 0, 0, 0, 0.1) ;
} .nft-image { flex : 1;
} .nft-info { flex : 1; text-align : left;
} .navbar a { color : white;
}
然后我们来测试下,看看能不能返回账户地址,运行后返回网页,然后连接到我们的MetaMask,就能得到返回的地址 新建一个组件名为UploadSuccess.js
新建一个名为UploadImage.js
的文件 npm install react-router-dom
命令安装库npm install axios
库安装
以下是前端开发一修改完后的代码
function Navbar ( { onConnectWallet, address } ) { return ( < nav className= "navbar" > < div className= "navbar-brand" > NFT Marketplace< / div> < div className= "navbar-menu" > { } < button className= "connect-wallet-button" onClick= { onConnectWallet} > { address. slice ( 0 , 8 ) || "Connect Wallet" } < / button> < / div> < / nav> )
} export default Navbar;
import { useEffect, useState } from 'react' ;
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom' ;
import './App.css' ; import UploadImage from './UploadImage.js' ;
import Navbar from './Navbar.js' ;
import UploadSuccess from './UploadSuccess.js' ; function App ( ) { const [ walletAddress, setWallet] = useState ( "" ) ; useEffect ( ( ) => { addWalletListener ( ) ; ; } , [ ] ) ; function addWalletListener ( ) { if ( window. ethereum) { window. ethereum. on ( "accountsChanged" , ( accounts ) => { if ( accounts. length > 0 ) { setWallet ( accounts[ 0 ] ) ; } else { setWallet ( "" ) ; } } ) ; } } const getWalletAddress = async ( ) => { if ( window. ethereum) { try { const accounts = await window. ethereum. request ( { method : 'eth_requestAccounts' } ) ; setWallet ( accounts[ 0 ] ) ; } catch ( error) { console. error ( 'Error connecting to wallet' , error) ; } } } ; return ( < div id= "container" > { } < Router> < Navbar onConnectWallet= { getWalletAddress} address= { walletAddress} / > { } < Routes> { } < Route path= "/" exact element= { < UploadImage address= { walletAddress} / > } / > < Route path= "/success" element= { < UploadSuccess / > } / > < / Routes> < / Router> < / div> ) ;
} ; export default App;
const UploadSuccess = ( ) => { return ( < div> < h1> Upload Successfully< / h1> < p> Your image has been uploaded to IPFS successfully! < / p> < / div> ) ;
} ; export default UploadSuccess;
import React, { useState, useRef } from 'react' ;
import { useNavigate } from 'react-router-dom' ;
import axios from 'axios' ;
import './App.css' ; function UploadImage ( { address } ) { const [ title, setTitle] = useState ( '' ) ; const [ description, setDescription] = useState ( '' ) ; const fileInputRef = useRef ( null ) ; const navigate = useNavigate ( ) ; const handleCancel = ( ) => { setTitle ( '' ) ; setDescription ( '' ) ; if ( fileInputRef. current) { fileInputRef. current. value = "" ; } } ; const handleUpload = async ( event ) => { event. preventDefault ( ) ; if ( fileInputRef. current. files. length === 0 ) { alert ( 'Please select a file to upload.' ) ; return ; } const formData = new FormData ( ) ; formData. append ( 'title' , title) ; formData. append ( 'description' , description) ; formData. append ( 'file' , fileInputRef. current. files[ 0 ] ) ; formData. append ( 'address' , address) ; try { const response = await axios. post ( 'http://127.0.0.1:3000/upload' , formData, { headers : { 'Content-Type' : 'multipart/form-data' } } ) ; console. log ( 'File uploaded successfully' , response. data) ; navigate ( '/success' ) ; } catch ( error) { console. error ( 'Error uploading file:' , error) ; } } ; return ( < div className= "upload-container" > < h1> Upload Image to IPFS and Mint NFT < / h1> { } < form className= "upload-form" onSubmit= { handleUpload} > < label htmlFor= "title" > Title * < / label> < inputtype= "text" id= "title" placeholder= "Enter image title" value= { title} onChange= { ( e ) => setTitle ( e. target. value) } required/ > < label htmlFor= "description" > Description< / label> < textareaid= "description" placeholder= "Describe your image" value= { description} onChange= { ( e ) => setDescription ( e. target. value) } / > < label htmlFor= "file" > Image * < / label> < inputtype= "file" id= "file" ref= { fileInputRef} required/ > < div className= "buttons" > < button type= "button" className= "cancel-button" onClick= { handleCancel} > Cancel< / button> < button type= "submit" className= "upload-button" > Upload< / button> < / div> < / form> < / div> ) ;
} export default UploadImage;
然后我们在终端运行npm run start
命令,即可出现以下界面,但是目前我们还没有连接到合约那些,因此还不能实现其它功能哈,后续会实现滴。 😊未完待续~