使用
在我们想要保存项目的目录下打开终端运行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>
< input
type= "text"
id= "title"
placeholder= "Enter image title"
value= { title}
onChange= { ( e ) => setTitle ( e. target. value) }
required
/ >
< label htmlFor= "description" > Description< / label>
< textarea
id= "description"
placeholder= "Describe your image"
value= { description}
onChange= { ( e ) => setDescription ( e. target. value) }
/ >
< label htmlFor= "file" > Image * < / label>
< input
type= "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
命令,即可出现以下界面,但是目前我们还没有连接到合约那些,因此还不能实现其它功能哈,后续会实现滴。 😊未完待续~