国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

以太坊開發實戰學習-Web3.js(九)

luckyyulin / 3086人閱讀

摘要:首先我們需要要記住,以太坊是由共享同一份數據的相同拷貝的節點構成的。你可以運行你自己的以太坊節點來作為。在你部署智能合約以后,它將獲得一個以太坊上的永久地址。如果你還記得第二課,在以太坊上的地址是。

通過前邊的學習,DApp 的 Solidity 合約部分就完成了?,F在我們來做一個基本的網頁好讓你的用戶能玩它。 要做到這一點,我們將使用以太坊基金發布的 JavaScript 庫 —— Web3.js.
一、Web3.js簡介 什么是 Web3.js?

還記得么?以太坊網絡是由節點組成的,每一個節點都包含了區塊鏈的一份拷貝。當你想要調用一份智能合約的一個方法,你需要從其中一個節點中查找并告訴它:

1、智能合約的地址

2、你想調用的方法,以及

3、你想傳入那個方法的參數

以太坊節點只能識別一種叫做 JSON-RPC 的語言。這種語言直接讀起來并不好懂。當你你想調用一個合約的方法的時候,需要發送的查詢語句將會是這樣的:

// 哈……祝你寫所有這樣的函數調用的時候都一次通過
// 往右邊拉…… ==>
{"jsonrpc":"2.0","method":"eth_sendTransaction","params":[{"from":"0xb60e8dd61c5d32be8058bb8eb970870f07233155","to":"0xd46e8dd67c5d32be8058bb8eb970870f07244567","gas":"0x76c0","gasPrice":"0x9184e72a000","value":"0x9184e72a","data":"0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675"}],"id":1}

幸運的是 Web3.js 把這些令人討厭的查詢語句都隱藏起來了, 所以你只需要與方便易懂的 JavaScript 界面進行交互即可。

你不需要構建上面的查詢語句,在你的代碼中調用一個函數看起來將是這樣:

CryptoZombies.methods.createRandomZombie("Vitalik Nakamoto")
  .send({ from: "0xb60e8dd61c5d32be8058bb8eb970870f07233155", gas: "3000000" })

我們將在接下來的幾章詳細解釋這些語句,不過首先我們來把 Web3.js 環境搭建起來

準備工作

取決于你的項目工作流程和你的愛好,你可以用一些常用工具把 Web3.js 添加進來:

// 用 NPM
npm install web3

// 用 Yarn
yarn add web3

// 用 Bower
bower install web3

// ...或者其他。

甚至,你可以從 github直接下載壓縮后的 .js 文件 然后包含到你的項目文件中:


    
    
  
  

  

二、Web3提供者

現在我們的項目中有了Web3.js, 來初始化它然后和區塊鏈對話吧。

首先我們需要 Web3 Provider.

要記住,以太坊是由共享同一份數據的相同拷貝的 節點 構成的。 在 Web3.js 里設置 Web3 的 Provider(提供者) 告訴我們的代碼應該和 哪個節點 交互來處理我們的讀寫。這就好像在傳統的 Web 應用程序中為你的 API 調用設置遠程 Web 服務器的網址。

你可以運行你自己的以太坊節點來作為 Provider。 不過,有一個第三方的服務,可以讓你的生活變得輕松點,讓你不必為了給你的用戶提供DApp而維護一個以太坊節點— Infura.

Infura

Infura 是一個服務,它維護了很多以太坊節點并提供了一個緩存層來實現高速讀取。你可以用他們的 API 來免費訪問這個服務。 用 Infura 作為節點提供者,你可以不用自己運營節點就能很可靠地向以太坊發送、接收信息。

你可以通過這樣把 Infura 作為你的 Web3 節點提供者:

var web3 = new Web3(new Web3.providers.WebsocketProvider("wss://mainnet.infura.io/ws"));

不過,因為我們的 DApp 將被很多人使用,這些用戶不單會從區塊鏈讀取信息,還會向區塊鏈 入信息,我們需要用一個方法讓用戶可以用他們的私鑰給事務簽名。

注意: 以太坊 (以及通常意義上的 blockchains )使用一個公鑰/私鑰對來對給事務做數字簽名。把它想成一個數字簽名的異常安全的密碼。這樣當我修改區塊鏈上的數據的時候,我可以用我的公鑰來 證明 我就是簽名的那個。但是因為沒人知道我的私鑰,所以沒人能偽造我的事務。

加密學非常復雜,所以除非你是個專家并且的確知道自己在做什么,你最好不要在你應用的前端中管理你用戶的私鑰。

不過幸運的是,你并不需要,已經有可以幫你處理這件事的服務了: Metamask.

Metamask

Metamask 是 Chrome 和 Firefox 的瀏覽器擴展, 它能讓用戶安全地維護他們的以太坊賬戶和私鑰, 并用他們的賬戶和使用 Web3.js 的網站互動(如果你還沒用過它,你肯定會想去安裝的——這樣你的瀏覽器就能使用 Web3.js 了,然后你就可以和任何與以太坊區塊鏈通信的網站交互了)

作為開發者,如果你想讓用戶從他們的瀏覽器里通過網站和你的DApp交互(就像我們在 CryptoZombies 游戲里一樣),你肯定會想要兼容 Metamask 的。

注意: Metamask 默認使用 Infura 的服務器做為 web3 提供者。 就像我們上面做的那樣。不過它還為用戶提供了選擇他們自己 Web3 提供者的選項。所以使用 Metamask 的 web3 提供者,你就給了用戶選擇權,而自己無需操心這一塊。
使用Metamask的web3提供者

Metamask 把它的 web3 提供者注入到瀏覽器的全局 JavaScript對象web3中。所以你的應用可以檢查 web3 是否存在。若存在就使用 web3.currentProvider 作為它的提供者。

這里是一些 Metamask 提供的示例代碼,用來檢查用戶是否安裝了MetaMask,如果沒有安裝就告訴用戶需要安裝MetaMask來使用我們的應用。

window.addEventListener("load", function() {

  // 檢查web3是否已經注入到(Mist/MetaMask)
  if (typeof web3 !== "undefined") {
    // 使用 Mist/MetaMask 的提供者
    web3js = new Web3(web3.currentProvider);
  } else {
    // 處理用戶沒安裝的情況, 比如顯示一個消息
    // 告訴他們要安裝 MetaMask 來使用我們的應用
  }

  // 現在你可以啟動你的應用并自由訪問 Web3.js:
  startApp()

})

你可以在你所有的應用中使用這段樣板代碼,好檢查用戶是否安裝以及告訴用戶安裝 MetaMask。

注意: 除了MetaMask,你的用戶也可能在使用其他他的私鑰管理應用,比如 Mist 瀏覽器。不過,它們都實現了相同的模式來注入 web3 變量。所以我這里描述的方法對兩者是通用的。
實戰演練

我們在HTML文件中的 標簽前面放置了一個空的 script 標簽??梢园堰@節課的 JavaScript 代碼寫在里面。

把上面用來檢測 MetaMask 是否安裝的模板代碼粘貼進來。請粘貼到以 window.addEventListener 開頭的代碼塊中。

index.html



  
    
    CryptoZombies front-end
    
    
  
  

    
  

三、和合約對話

現在,我們已經用 MetaMask 的 Web3 提供者初始化了 Web3.js。接下來就讓它和我們的智能合約對話吧。

Web3.js 需要兩個東西來和你的合約對話: 它的 地址 和它的 ABI

合約地址

在你寫完了你的智能合約后,你需要編譯它并把它部署到以太坊。我們將在下一課中詳述部署,因為它和寫代碼是截然不同的過程,所以我們決定打亂順序,先來講 Web3.js。

在你部署智能合約以后,它將獲得一個以太坊上的永久地址。如果你還記得第二課,CryptoKitties 在以太坊上的地址是 YOUR_CONTRACT_ADDRESS

你需要在部署后復制這個地址以來和你的智能合約對話。

合約ABI

另一個 Web3.js 為了要和你的智能合約對話而需要的東西是 ABI。

ABI 意為應用二進制接口(Application Binary Interface)。 基本上,它是以 JSON 格式表示合約的方法,告訴 Web3.js 如何以合同理解的方式格式化函數調用。

當你編譯你的合約向以太坊部署時(我們將后邊詳述), Solidity 編譯器會給你 ABI,所以除了合約地址,你還需要把這個也復制下來。

因為我們這一課不會講述部署,所以現在我們已經幫你編譯了 ABI 并放在了名為cryptozombies_abi.js,文件中,保存在一個名為 cryptozombiesABI 的變量中。

如果我們將cryptozombies_abi.js 包含進我們的項目,我們就能通過那個變量訪問 CryptoZombies ABI 。

cryptozombies_abi.js 文件:

var cryptozombiesABI = [
  {
    "constant": false,
    "inputs": [
      {
        "name": "_to",
        "type": "address"
      },
      {
        "name": "_tokenId",
        "type": "uint256"
      }
    ],
    "name": "approve",
    "outputs": [],
    "payable": false,
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "constant": false,
    "inputs": [
      {
        "name": "_zombieId",
        "type": "uint256"
      }
    ],
    "name": "levelUp",
    "outputs": [],
    "payable": true,
    "stateMutability": "payable",
    "type": "function"
  },
  {
    "constant": false,
    "inputs": [
      {
        "name": "_zombieId",
        "type": "uint256"
      },
      {
        "name": "_kittyId",
        "type": "uint256"
      }
    ],
    "name": "feedOnKitty",
    "outputs": [],
    "payable": false,
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "constant": true,
    "inputs": [
      {
        "name": "",
        "type": "uint256"
      }
    ],
    "name": "zombies",
    "outputs": [
      {
        "name": "name",
        "type": "string"
      },
      {
        "name": "dna",
        "type": "uint256"
      },
      {
        "name": "level",
        "type": "uint32"
      },
      {
        "name": "readyTime",
        "type": "uint32"
      },
      {
        "name": "winCount",
        "type": "uint16"
      },
      {
        "name": "lossCount",
        "type": "uint16"
      }
    ],
    "payable": false,
    "stateMutability": "view",
    "type": "function"
  },
  {
    "constant": false,
    "inputs": [],
    "name": "withdraw",
    "outputs": [],
    "payable": false,
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "constant": true,
    "inputs": [
      {
        "name": "_owner",
        "type": "address"
      }
    ],
    "name": "getZombiesByOwner",
    "outputs": [
      {
        "name": "",
        "type": "uint256[]"
      }
    ],
    "payable": false,
    "stateMutability": "view",
    "type": "function"
  },
  {
    "constant": true,
    "inputs": [
      {
        "name": "",
        "type": "uint256"
      }
    ],
    "name": "zombieToOwner",
    "outputs": [
      {
        "name": "",
        "type": "address"
      }
    ],
    "payable": false,
    "stateMutability": "view",
    "type": "function"
  },
  {
    "constant": false,
    "inputs": [
      {
        "name": "_address",
        "type": "address"
      }
    ],
    "name": "setKittyContractAddress",
    "outputs": [],
    "payable": false,
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "constant": false,
    "inputs": [
      {
        "name": "_zombieId",
        "type": "uint256"
      },
      {
        "name": "_newDna",
        "type": "uint256"
      }
    ],
    "name": "changeDna",
    "outputs": [],
    "payable": false,
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "constant": true,
    "inputs": [
      {
        "name": "_tokenId",
        "type": "uint256"
      }
    ],
    "name": "ownerOf",
    "outputs": [
      {
        "name": "_owner",
        "type": "address"
      }
    ],
    "payable": false,
    "stateMutability": "view",
    "type": "function"
  },
  {
    "constant": true,
    "inputs": [
      {
        "name": "_owner",
        "type": "address"
      }
    ],
    "name": "balanceOf",
    "outputs": [
      {
        "name": "_balance",
        "type": "uint256"
      }
    ],
    "payable": false,
    "stateMutability": "view",
    "type": "function"
  },
  {
    "constant": false,
    "inputs": [
      {
        "name": "_name",
        "type": "string"
      }
    ],
    "name": "createRandomZombie",
    "outputs": [],
    "payable": false,
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "constant": true,
    "inputs": [],
    "name": "owner",
    "outputs": [
      {
        "name": "",
        "type": "address"
      }
    ],
    "payable": false,
    "stateMutability": "view",
    "type": "function"
  },
  {
    "constant": false,
    "inputs": [
      {
        "name": "_to",
        "type": "address"
      },
      {
        "name": "_tokenId",
        "type": "uint256"
      }
    ],
    "name": "transfer",
    "outputs": [],
    "payable": false,
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "constant": true,
    "inputs": [],
    "name": "getAllZombies",
    "outputs": [
      {
        "name": "",
        "type": "uint256[]"
      }
    ],
    "payable": false,
    "stateMutability": "view",
    "type": "function"
  },
  {
    "constant": false,
    "inputs": [
      {
        "name": "_tokenId",
        "type": "uint256"
      }
    ],
    "name": "takeOwnership",
    "outputs": [],
    "payable": false,
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "constant": false,
    "inputs": [
      {
        "name": "_zombieId",
        "type": "uint256"
      },
      {
        "name": "_newName",
        "type": "string"
      }
    ],
    "name": "changeName",
    "outputs": [],
    "payable": false,
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "constant": false,
    "inputs": [
      {
        "name": "_fee",
        "type": "uint256"
      }
    ],
    "name": "setLevelUpFee",
    "outputs": [],
    "payable": false,
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "constant": false,
    "inputs": [
      {
        "name": "_zombieId",
        "type": "uint256"
      },
      {
        "name": "_targetId",
        "type": "uint256"
      }
    ],
    "name": "attack",
    "outputs": [],
    "payable": false,
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "constant": false,
    "inputs": [
      {
        "name": "newOwner",
        "type": "address"
      }
    ],
    "name": "transferOwnership",
    "outputs": [],
    "payable": false,
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "name": "_from",
        "type": "address"
      },
      {
        "indexed": true,
        "name": "_to",
        "type": "address"
      },
      {
        "indexed": false,
        "name": "_tokenId",
        "type": "uint256"
      }
    ],
    "name": "Transfer",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "name": "_owner",
        "type": "address"
      },
      {
        "indexed": true,
        "name": "_approved",
        "type": "address"
      },
      {
        "indexed": false,
        "name": "_tokenId",
        "type": "uint256"
      }
    ],
    "name": "Approval",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": false,
        "name": "attackResult",
        "type": "bool"
      },
      {
        "indexed": false,
        "name": "winCount",
        "type": "uint16"
      },
      {
        "indexed": false,
        "name": "lossCount",
        "type": "uint16"
      }
    ],
    "name": "AttackResult",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": false,
        "name": "zombieId",
        "type": "uint256"
      },
      {
        "indexed": false,
        "name": "name",
        "type": "string"
      },
      {
        "indexed": false,
        "name": "dna",
        "type": "uint256"
      }
    ],
    "name": "NewZombie",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "name": "previousOwner",
        "type": "address"
      },
      {
        "indexed": true,
        "name": "newOwner",
        "type": "address"
      }
    ],
    "name": "OwnershipTransferred",
    "type": "event"
  }
]
實例化Web3.js

一旦你有了合約的地址和 ABI,你可以像這樣來實例化 Web3.js。

// 實例化 myContract
var myContract = new web3js.eth.Contract(myABI, myContractAddress);
實戰演練

1、在文件的 標簽塊中,用 script 標簽引入cryptozombies_abi.js,好把 ABI 的定義引入項目。

2、在 里的 四、調用和合約函數

我們的合約配置好了!現在來用 Web3.js 和它對話。

Web3.js 有兩個方法來調用我們合約的函數: call and send.

call

call 用來調用 viewpure 函數。它只運行在本地節點,不會在區塊鏈上創建事務。

復習: viewpure 函數是只讀的并不會改變區塊鏈的狀態。它們也不會消耗任何gas。用戶也不會被要求用MetaMask對事務簽名。

使用 Web3.js,你可以如下 call 一個名為myMethod的方法并傳入一個 123 作為參數:

myContract.methods.myMethod(123).call()
Send

send創建一個事務并改變區塊鏈上的數據。你需要用 send 來調用任何非 view 或者 pure 的函數。

注意: send 一個事務將要求用戶支付gas,并會要求彈出對話框請求用戶使用 Metamask 對事務簽名。在我們使用 Metamask 作為我們的 web3 提供者的時候,所有這一切都會在我們調用 send() 的時候自動發生。而我們自己無需在代碼中操心這一切,挺爽的吧。

使用 Web3.js, 你可以像這樣 send 一個事務調用myMethod 并傳入 123 作為參數:

myContract.methods.myMethod(123).send()

語法幾乎 call()一模一樣。

獲取僵尸數據

來看一個使用 call 讀取我們合約數據的真實例子

回憶一下,我們定義我們的僵尸數組為 公開(public):

Zombie[] public zombies;

在 Solidity 里,當你定義一個 public變量的時候, 它將自動定義一個公開的 "getter" 同名方法, 所以如果你像要查看 id 為 15 的僵尸,你可以像一個函數一樣調用它: zombies(15).

這是如何在外面的前端界面中寫一個 JavaScript 方法來傳入一個僵尸 id,在我們的合同中查詢那個僵尸并返回結果

注意: 本課中所有的示例代碼都使用 Web3.js 的 1.0 版,此版本使用的是 Promises 而不是回調函數。你在線上看到的其他教程可能還在使用老版的 Web3.js。在1.0版中,語法改變了不少。如果你從其他教程中復制代碼,先確保你們使用的是相同版本的Web3.js。
function getZombieDetails(id) {
  return cryptoZombies.methods.zombies(id).call()
}

// 調用函數并做一些其他事情
getZombieDetails(15)
.then(function(result) {
  console.log("Zombie 15: " + JSON.stringify(result));
});

我們來看看這里都做了什么
cryptoZombies.methods.zombies(id).call() 將和 Web3 提供者節點通信,告訴它返回從我們的合約中的 Zombie[] public zombies,id為傳入參數的僵尸信息。

注意這是 異步的,就像從外部服務器中調用API。所以 Web3 在這里返回了一個 Promises. (如果你對 JavaScript的 Promises 不了解,最好先去學習一下這方面知識再繼續)。

一旦那個 promiseresolve, (意味著我們從 Web3 提供者那里獲得了響應),我們的例子代碼將執行 then 語句中的代碼,在控制臺打出 result。

result 是一個像這樣的 JavaScript 對象:

{
  "name": "H4XF13LD MORRIS"S COOLER OLDER BROTHER",
  "dna": "1337133713371337",
  "level": "9999",
  "readyTime": "1522498671",
  "winCount": "999999999",
  "lossCount": "0" // Obviously.
}

我們可以用一些前端邏輯代碼來解析這個對象并在前端界面友好展示。

實戰演練

我們已經把 getZombieDetails 復制進了代碼。

1、先為zombieToOwner 創建一個類似的函數。如果你還記得 ZombieFactory.sol,我們有一個長這樣的映射:

`mapping (uint => address) public zombieToOwner;

定義一個 JavaScript 方法,起名為 zombieToOwner。和上面的 getZombieDetails 類似, 它將接收一個id 作為參數,并返回一個 Web3.js call 我們合約里的zombieToOwner 。

2、之后在下面,為 getZombiesByOwner 定義一個方法。如果你還能記起 ZombieHelper.sol,這個方法定義像這樣:

function getZombiesByOwner(address _owner)

我們的 getZombiesByOwner 方法將接收 owner 作為參數,并返回一個對我們函數 getZombiesByOwner的 Web3.js call

index.html



  
    
    CryptoZombies front-end
    
    
    
  
  

    
  

Promise學習

promise異步編程的一種解決方案,比傳統的解決方案–回調函數和事件--更合理和更強大。它由社區最早提出和實現,ES6將其寫進了語言標準,統一了語法,原生提供了Promise

所謂Promise ,簡單說就是一個容器,里面保存著某個未來才回結束的事件(通常是一個異步操作)的結果。從語法上說,Promise是一個對象,從它可以獲取異步操作的消息。
Promise 對象的狀態不受外界影響

三種狀態:

pending:進行中

fulfilled :已經成功

rejected 已經失敗

狀態改變:
Promise對象的狀態改變,只有兩種可能:

從pending變為fulfilled

從pending變為rejected。

這兩種情況只要發生,狀態就凝固了,不會再變了,這時就稱為resolved(已定型)

基本用法

ES6規定,Promise對象是一個構造函數,用來生成Promise實例:

const promist = new Promise(function(resolve,reject){
    if(/*異步操作成功*/){
        resolve(value);
    }else{
        reject(error);
    }
})

resolve函數的作用是,將Promise對象的狀態從“未完成”變為“成功”(即從 pending 變為 resolved),在異步操作成功時調用,并將異步操作的結果,作為參數傳遞出去;

reject函數的作用是,將Promise對象的狀態從“未完成”變為“失敗”(即從 pending 變為 rejected),在異步操作失敗時調用,并將異步操作報出的錯誤,作為參數傳遞出去。

Promise 實例生成以后,可以用then 方法分別指定resolved狀態和rejected狀態的回調函數。

promise.then(function(value){
//success
},function(error){
//failure
});

示例:

function timeout(ms){
    return new Promise((resolve,reject)=>{
        setTimeout(resolve,ms,"done");
    });
}
timeout(100).then((value)=>{
    console.log(value);
});
let promise = new Promise(function(resolve,reject){
    console.log("Promise");
    resolve();
});
promise.then(function(){
    console.log("resolved");
});
console.log("Hi!");

//Promise
//Hi!
//resolved
//異步加載圖片
function loadImageAsync(url){
    return new Promise(function(resolve,reject){
        const image = new Image();
        image.onload = function(){
            resolve(image);
        };
        image.onerror = function(){
            reject(new Error("error");
        };
        image.src = url;
    });
}

下面是一個用Promise對象實現的 Ajax 操作的例子。

const getJSON = function(url) {
  const promise = new Promise(function(resolve, reject){
    const handler = function() {
      if (this.readyState !== 4) {
        return;
      }
      if (this.status === 200) {
        resolve(this.response);
      } else {
        reject(new Error(this.statusText));
      }
    };
    const client = new XMLHttpRequest();
    client.open("GET", url);
    client.onreadystatechange = handler;
    client.responseType = "json";
    client.setRequestHeader("Accept", "application/json");
    client.send();

  });

  return promise;
};

getJSON("/posts.json").then(function(json) {
  console.log("Contents: " + json);
}, function(error) {
  console.error("出錯了", error);
});
五、MetaMask和賬戶

接下來我們綜合一下——比如我們想讓我們應用的首頁顯示用戶的整個僵尸大軍。

毫無疑問我們首先需要用 getZombiesByOwner(owner) 來查詢當前用戶的所有僵尸ID。

但是我們的 Solidity 合約需要 owner 作為 Solidity address。我們如何能知道應用用戶的地址呢?

獲得MetaMask中的用戶賬戶

MetaMask 允許用戶在擴展中管理多個賬戶。

我們可以通過這樣來獲取 web3 變量中激活的當前賬戶:

var userAccount = web3.eth.accounts[0]

因為用戶可以隨時在 MetaMask 中切換賬戶,我們的應用需要監控這個變量,一旦改變就要相應更新界面。例如,若用戶的首頁展示它們的僵尸大軍,當他們在 MetaMask 中切換了賬號,我們就需要更新頁面來展示新選擇的賬戶的僵尸大軍。

我們可以通過 setInterval 方法來做:

var accountInterval = setInterval(function() {
  // 檢查賬戶是否切換
  if (web3.eth.accounts[0] !== userAccount) {
    userAccount = web3.eth.accounts[0];
    // 調用一些方法來更新界面
    updateInterface();
  }
}, 100);

這段代碼做的是,每100毫秒檢查一次 userAccount 是否還等于 web3.eth.accounts[0] (比如:用戶是否還激活了那個賬戶)。若不等,則將 當前激活用戶賦值給 userAccount,然后調用一個函數來更新界面。

實戰演練

我們來讓應用在頁面第一次加載的時候顯示用戶的僵尸大軍,監控當前 MetaMask 中的激活賬戶,并在賬戶發生改變的時候刷新顯示。

1、定義一個名為userAccount的變量,不給任何初始值。

2、在 startApp()函數的最后,復制粘貼上面樣板代碼中的 accountInterval 方法進去。

3、將 updateInterface();替換成一個 getZombiesByOwnercall 函數,并傳入 userAccount

4、在 getZombiesByOwner 后面鏈式調用then 語句,并將返回的結果傳入名為 displayZombies 的函數。 (語句像這樣: .then(displayZombies);).

我們還沒有 displayZombies 函數,將于下一章實現。



  
    
    CryptoZombies front-end
    
    
    
  
  

    
  

六、顯示合約數據

如果我們不向你展示如何顯示你從合約獲取的數據,那這個教程就太不完整了。

在實際應用中,你肯定想要在應用中使用諸如 React 或 Vue.js 這樣的前端框架來讓你的前端開發變得輕松一些。不過要教授 React 或者 Vue.js 知識的話,就大大超出了本教程的范疇——它們本身就需要幾節課甚至一整個教程來教學。

所以為了讓 CryptoZombies.io 專注于以太坊和智能合約,我們將使用 JQuery 來做一個快速示例,展示如何解析和展示從智能合約中拿到的數據。

顯示僵尸數據

我們已經在代碼中添加了一個空的代碼塊

, 在 displayZombies 方法中也同樣有一個。

回憶一下在之前章節中我們在 startApp() 方法內部調用了 displayZombies 并傳入了 call getZombiesByOwner 獲得的結果,它將被傳入一個僵尸ID數組,像這樣:

[0, 13, 47]

因為我們想讓我們的 displayZombies 方法做這些事:

1、首先清除 #zombies 的內容以防里面已經有什么內容(這樣當用戶切換賬號的時候,之前賬號的僵尸大軍數據就會被清除)

2、循環遍歷 id,對每一個id調用 getZombieDetails(id), 從我們的合約中獲得這個僵尸的數據。

3、將獲得的僵尸數據放進一個HTML模板中以格式化顯示,追加進 #zombies 里面。

再次聲明,我們只用了 JQuery,沒有任何模板引擎,所以會非常丑。不過這只是一個如何展示僵尸數據的示例而已。

// 在合約中查找僵尸數據,返回一個對象
getZombieDetails(id)
.then(function(zombie) {
  // 用 ES6 的模板語法來向HTML中注入變量
  // 把每一個都追加進 #zombies div
  $("#zombies").append(`
  • Name: ${zombie.name}
  • DNA: ${zombie.dna}
  • Level: ${zombie.level}
  • Wins: ${zombie.winCount}
  • Losses: ${zombie.lossCount}
  • Ready Time: ${zombie.readyTime}
`); });
如何來展示僵尸元素呢?

在上面的例子中,我們只是簡單地用字符串來顯示 DNA。不過在你的 DApp 中,你將需要把 DNA 轉換成圖片來顯示你的僵尸。

我們通過把 DNA 字符串分割成小的字符串來做到這一點,每2位數字代表一個圖片,類似這樣:

// 得到一個 1-7 的數字來表示僵尸的頭:
var head = parseInt(zombie.dna.substring(0, 2)) % 7 + 1

// 我們有7張頭部圖片:
var headSrc = "../assets/zombieparts/head-" + i + ".png"

每一個模塊都用 CSS 絕對定位來顯示,在一個上面疊加另外一個。

如果你想看我們的具體實現,我們將用來展示僵尸形象的 Vue.js 模塊開源了: 點擊這里.

不過,因為那個文件中有太多行代碼, 超出了本教程的討論范圍。我們依然還是使用上面超級簡單的 JQuery 實現,把美化僵尸的工作作為家庭作業留給你了

實戰演練

我們為你創建了一個空的 displayZombies 方法。來一起實現它。

1、首先我們需要清空 #zombies 的內容。 用JQuery,你可以這樣做: $("#zombies").empty();。

2、接下來,我們要循環遍歷所有的 id,循環這樣用: for (id of ids) {

3、在循環內部,復制粘貼上面的代碼,對每一個id調用 getZombieDetails(id),然后用 $("#zombies").append(...) 把內容追加進我們的 HTML 里面。



  
    
    CryptoZombies front-end
    
    
    
  
  
    

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/24154.html

相關文章

  • 以太開發實戰學習-Web3.js(十)

    摘要:如果當前在以太坊上有大量掛起事務或者用戶發送了過低的價格,我們的事務可能需要等待數個區塊才能被包含進去,往往可能花費數分鐘。 接上篇 Web3.js,這節課繼續學習Web3.js 的相關知識。 一、發送事務 這下我們的界面能檢測用戶的 MetaMask 賬戶,并自動在首頁顯示它們的僵尸大軍了,有沒有很棒? 現在我們來看看用 send 函數來修改我們智能合約里面的數據。 相對 call...

    Scott 評論0 收藏0
  • 以太web3.js文檔翻譯及說明

    摘要:這些天,為了錄制以太坊開發實戰課程,我準備把文檔全部翻譯一下并做適當的補充,目前版本已經翻譯完成,歡迎大家前往查閱。 這些天,為了錄制以太坊DAPP開發實戰課程,我準備把web3文檔全部翻譯一下(并做適當的補充),目前web3.js 0.20.x 版本 已經翻譯完成,歡迎大家前往查閱。 這里還幾個實用DEMO,供大家參考: 使用web3.js API在頁面中轉賬 web3.js 0....

    趙春朋 評論0 收藏0
  • 以太web3.js文檔翻譯及說明

    摘要:這些天,為了錄制以太坊開發實戰課程,我準備把文檔全部翻譯一下并做適當的補充,目前版本已經翻譯完成,歡迎大家前往查閱。 這些天,為了錄制以太坊DAPP開發實戰課程,我準備把web3文檔全部翻譯一下(并做適當的補充),目前web3.js 0.20.x 版本 已經翻譯完成,歡迎大家前往查閱。 這里還幾個實用DEMO,供大家參考: 使用web3.js API在頁面中轉賬 web3.js 0....

    makeFoxPlay 評論0 收藏0
  • Web3與智能合約交互實戰

    摘要:本文首發于深入淺出區塊鏈社區原文鏈接與智能合約交互實戰原文已更新,請讀者前往原文閱讀寫在前面在最初學習以太坊的時候,很多人都是自己創建以太坊節點后,使用與之交互。 本文首發于深入淺出區塊鏈社區原文鏈接:Web3與智能合約交互實戰原文已更新,請讀者前往原文閱讀 寫在前面 在最初學習以太坊的時候,很多人都是自己創建以太坊節點后,使用geth與之交互。這種使用命令行交互的方法雖然讓很多程序員...

    liaoyg8023 評論0 收藏0
  • Geth控制臺使用及 Web3.js 使用實戰

    摘要:本文首發于深入淺出區塊鏈社區原文鏈接控制臺使用及使用實戰原文已更新,請讀者前往原文閱讀在開發以太坊去中心化應用,免不了和以太坊進行交互,那就離不開。 本文首發于深入淺出區塊鏈社區原文鏈接:Geth控制臺使用及 Web3.js 使用實戰原文已更新,請讀者前往原文閱讀 在開發以太坊去中心化應用,免不了和以太坊進行交互,那就離不開Web3。Geth 控制臺(REPL)實現了所有的web3 A...

    hlcc 評論0 收藏0

發表評論

0條評論

luckyyulin

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<