以太坊–智能合约前端页面



以太坊(Ethereum) – 智能合约前端页面

现在我们来开发智能合约的前端页面,让用户可以通过前端页面与智能合约交互。这个页面的主要功能是:

显示当前连接的帐户
读取智能合约中存储的value值
更新智能合约中存储的value值

页面大概的样子:
以太坊–智能合约前端页面_https://bianchenghao6.com_【Ethereum 以太坊教程】_第1张
为开发前端页面,需要完成下面几项工作:

配置web服务器,用来部署页面
创建前端的h5、js文件

配置web服务器

首先,让我们来配置web服务器。服务器使用lite-server,安装lite-server:
$ npm install lite-server--save-dev

项目根目录下,创建lite-server的配置文件
bs-config.json,内容如下:
{
  "server": {
    "baseDir": [
      "./src",
      "./build/contracts"
    ],
    "routes": {
      "/vendor": "./node_modules"
    }
  }
}

baseDir配置告诉lite-server将./src./build/contracts目录作为web服务器的根目录,所有文件都可以被访问
routes./node_modules映射为/vendor,在引用文件时,可以使用/vendor

创建前端页面

项目根目录下,创建
src目录,用于存放前端页面。
前端页面包含2个文件:
src/index.html
src/app.js

index.html

添加
index.html页面,内容如下:
<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>以太坊 DApp Demo</title>
    <!--HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries-->
    <!--WARNING: Respond.js doesn't work if you view the page via file://-->
    <!--[if lt IE 9]>
      <script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script>
      <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
    <![endif]-->
  </head>
  <body>
      <h1>账号: <span id="account"></span></h1>
      <hr>
      <div id="content">
          <h2>智能合约:MyContract</b></h2>
          <p>获取智能合约中的value值: <span id="value"></span></p>
            <h5>设置value值</h5>
            <form onSubmit="App.set(); return false;" role="form">
            <div >
                <input id="newValue"  type="text"></input>
            </div>
            <button type="submit" >设置</button>
            </form>
      </div>
      <div id="loader">正在加载...</div>
    </div>
    <!--jQuery (necessary for Bootstrap's JavaScript plugins)-->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
    <!--Include all compiled plugins (below), or include individual files as needed-->
    <script src="https://etherscan.io/jss/web3.min.js"></script>
    <script src="vendor/@truffle/contract/dist/truffle-contract.js"></script>
    <script src="app.js"></script>
  </body>
</html>

这个文件的重点是引入了几个js文件:

web3.min.js – web3.js库文件,直接从https://etherscan.io/引入
truffle-contract.js – truffle提供的处理智能合约的库文件

安装
@truffle/contract
$ npm install @truffle/contract--save-dev

app.js

添加javascript脚本文件:
app.js
App = {
    web3Provider: null,
    contracts: {},
    account: '0x0',
    loading: false,
    contractInstance: null,
    init: async () => {
        // 加载web3
        await App.loadWeb3()
        // 加载智能合约
        await App.loadContract()
        // 网页刷新
        await App.render()
    },
    // https://medium.com/metamask/https-medium-com-metamask-breaking-change-injecting-web3-7722797916a8
    loadWeb3: async () => {
        if (typeof web3 !== 'undefined') {
            App.web3Provider = web3.currentProvider
            web3 = new Web3(web3.currentProvider)
        } else {
            window.alert("Please connect to Metamask.")
        }
        // MetaMask新版本…
        if (window.ethereum) {
            window.web3 = new Web3(ethereum)
            try {
                // 向用户请求帐户访问
                await ethereum.enable()
                // 用户允许使用账户
                web3.eth.sendTransaction({/* ... */ })
            } catch (error) {
                // 用户拒绝使用账户
            }
        }
        // MetaMask老版本…
        else if (window.web3) {
            App.web3Provider = web3.currentProvider
            window.web3 = new Web3(web3.currentProvider)
            // 无需向用户请求,可以直接使用账号
            web3.eth.sendTransaction({/* ... */ })
        }
        // 没有安装以太坊钱包插件(MetaMask)...
        else {
            console.log('需要安装以太坊钱包插件(例如MetaMask)才能使用!')
        }
    },
    loadContract: async () => {
        const contract = await $.getJSON('MyContract.json')
        App.contracts.MyContract = TruffleContract(contract)
        App.contracts.MyContract.setProvider(App.web3Provider)
    },
    render: async () => {
        // 如果正在加载,直接返回,避免重复操作
        if (App.loading) {
            return
        }
        // 更新app加载状态
        App.setLoading(true)
        // 设置当前区块链帐户
        const accounts = await ethereum.enable()
        App.account = accounts[0]
        $('#account').html(App.account)
        // 加载智能合约
        const contract = await App.contracts.MyContract.deployed()
        App.contractInstance = contract
        const value = await App.contractInstance.get()
        $('#value').html(value)
        App.setLoading(false)
    },
    set: async () => {
        App.setLoading(true)
        const newValue = $('#newValue').val()
        await App.contractInstance.set(newValue, {from: App.account})
        window.alert('更新成功,页面值不会马上更新,等待几秒后多刷新几次。')
        App.setLoading(false)
    },
    setLoading: (boolean) => {
        App.loading = boolean
        const loader = $('#loader')
        const content = $('#content')
        if (boolean) {
            loader.show()
            content.hide()
        } else {
            loader.hide()
            content.show()
        }
    }
}
$(document).ready(function () {
    App.init()
});

在上面的代码中:

loadWeb3()函数添加了用Metamask将web浏览器连接到区块链所需的配置。这是直接从Metamask的配置规范中复制粘贴的,如函数上面代码注释中的url所示。
loadContract()函数使用TruffleContract库创建智能合约的javascript对象,可以用于调用智能合约中的函数。
render()函数设置页面内容,包括帐户及智能合约的value值。

现在启动服务器:
$ npm run dev

然后使用安装了MetaMask插件的Chrome浏览器,打开网址:http://localhost:3000,就可以查看前端页面,与区块链上的智能合约进行交互。