[譯] 使用 Web3 和 Vue.js 來建立你的第一個以太坊去中心化應用程式(第三部分)

sakila發表於2019-03-01

使用 Web3 和 Vue.js 來建立你的第一個以太坊去中心化應用程式(第三部分)

大家好,歡迎來到本系列的最後一部分。如果你還沒進入狀況,那麼我告訴你,我們將為以太坊區塊鏈建立一個簡單的去中心化應用程式。您可以隨時檢視第 1 和第 2 部分!

接著第二部分的結尾開始

到目前為止,我們的應用程式能夠從 metamask 獲取並顯示帳戶資料。但是,在更改帳戶時,如果不重新載入頁面,則不會更新資料。這並不是最優的,我們希望能夠確保響應式地更新資料。

我們的方法與簡單地初始化 web3 例項略有不同。Metamask 還不支援 websockets,因此我們將不得不每隔一段時間就去輪詢資料是否有修改。我們不希望在沒有更改的情況下排程操作,因此只有在滿足某個條件(特定更改)時,我們的操作才會與它們各自的有效負載一起被排程。

也許上述方法並不是諸多解決方案中的最優解,但是它在嚴格模式的約束下工作,所以還算不錯。在 util 資料夾中建立一個名為 pollWeb3.js 的新檔案。下面是我們要做的:

  • 匯入 web3,這樣我們就不依賴於 Metamask 例項
  • 匯入我們的 store,這樣我們就可以進行資料對比和分發操作
  • 建立 web3 例項
  • 設定一個間隔來檢查地址是否發生了變化,如果沒有,檢查餘額是否發生了變化
  • 如果地址或餘額有變化,我們將更新我們的 store。因為我們的 hello-metamask 元件具有一個 Computed 屬性,這個改變是響應式的

import Web3 from 'web3'
import {store} from '../store/'

let pollWeb3 = function (state) {
  let web3 = window.web3
  web3 = new Web3(web3.currentProvider)

  setInterval(() => {
    if (web3 && store.state.web3.web3Instance) {
      if (web3.eth.coinbase !== store.state.web3.coinbase) {
        let newCoinbase = web3.eth.coinbase
        web3.eth.getBalance(web3.eth.coinbase, function (err, newBalance) {
          if (err) {
            console.log(err)
          } else {
            store.dispatch('pollWeb3', {
              coinbase: newCoinbase,
              balance: parseInt(newBalance, 10)
            })
          }
        })
      } else {
        web3.eth.getBalance(store.state.web3.coinbase, (err, polledBalance) => {
          if (err) {
            console.log(err)
          } else if (parseInt(polledBalance, 10) !== store.state.web3.balance) {
            store.dispatch('pollWeb3', {
              coinbase: store.state.web3.coinbase,
              balance: polledBalance
            })
          }
        })
      }
    }
  }, 500)
}

export default pollWeb3
複製程式碼

現在,一旦我們的 web3 例項被初始化,我們就要開始輪詢更新。所以,開啟 Store/index.js ,匯入 pollWeb3.js 檔案,並將其新增到我們的 regierWeb3Instance() 方法的底部,以便在狀態更改後執行。

import pollWeb3 from '../util/pollWeb3'

registerWeb3Instance (state, payload) {
 console.log('registerWeb3instance Mutation being executed', payload)
 let result = payload
 let web3Copy = state.web3
 web3Copy.coinbase = result.coinbase
 web3Copy.networkId = result.networkId
 web3Copy.balance = parseInt(result.balance, 10)
 web3Copy.isInjected = result.injectedWeb3
 web3Copy.web3Instance = result.web3
 state.web3 = web3Copy
 pollWeb3()
 }
複製程式碼

由於我們正在排程操作,所以需要將其新增到 store 中,並進行變異以提交更改。我們可以直接提交更改,但為了保持模式一致性,我們不這麼做。我們將新增一些控制檯日誌,以便您可以在控制檯中觀看精彩的過程。在 actions 物件中新增:

pollWeb3 ({commit}, payload) {
 console.log('pollWeb3 action being executed')
 commit('pollWeb3Instance', payload)
 }
複製程式碼

現在我們只需要對傳入的兩個變數進行更改

pollWeb3Instance (state, payload) {
 console.log('pollWeb3Instance mutation being executed', payload)
 state.web3.coinbase = payload.coinbase
 state.web3.balance = parseInt(payload.balance, 10)
 }
複製程式碼

搞定了!如果我們現在改變 Metamask 的地址,或者餘額發生變化,我們將看到在我們的應用程式無需重新載入頁面更新。當我們更改網路時,頁面將重新載入,我們將重新註冊一個新例項。但是,在生產中,我們希望顯示一個警告,要求更改到部署協約的正確網路。

我知道這是一個漫長的道路。但在下一節,我們將最終深入到我們的智慧協議連線到我們的應用程式。與我們已經做過的相比,這實際上相當容易了。

例項化我們的協議

首先,我們將編寫程式碼,然後部署協議並將 ABI 和 Address 插入到應用程式中。為了建立我們期待已久的 casino 元件,需要執行以下操作:

  • 需要一個輸入欄位,以便使用者可以輸入下注金額
  • 需要代表下注數字的按鈕,當使用者點選某個數字時,它將把輸入的金額押在該數字上
  • onClick 函式將呼叫 smart 協議上的 bet() 函式
  • 顯示一個載入旋轉器,以顯示事務正在進行中
  • 交易完成後,我們會顯示使用者是否中獎以及中獎金額

但是,首先,我們需要我們的應用程式能夠與我們的智慧協議互動。我們將用已經做過的同樣的方法來處理該問題。在 util 資料夾中建立一個名為 getContract.js 的新檔案。

import Web3 from ‘web3’
import {address, ABI} from ‘./constants/casinoContract’

let getContract = new Promise(function (resolve, reject) {
 let web3 = new Web3(window.web3.currentProvider)
 let casinoContract = web3.eth.contract(ABI)
 let casinoContractInstance = casinoContract.at(address)
 // casinoContractInstance = () => casinoContractInstance
 resolve(casinoContractInstance)
})

export default getContract
複製程式碼

首先要注意的是,我們正在匯入一個尚不存在的檔案,稍後我們將在部署協議時修復該檔案。

首先,我們通過將 ABI(我們將回到)傳遞到 web3.eth.Contact() 方法中,為穩固性協議建立一個協議物件。然後,我們可以在一地址上初始化該物件。在這個例項中,我們可以呼叫我們的方法和事件。

然而,如果沒有 action 和變體,這將是不完整的。因此,在 casino-component.vue 的指令碼標記中新增以下內容。

export default {
 name: ‘casino’,
 mounted () {
 console.log(‘dispatching getContractInstance’)
 this.$store.dispatch(‘getContractInstance’)
 }
}
複製程式碼

現在 action 和變體在 store 中。首先匯入 getContract.js 檔案,我相信您現在已經知道如何做到這一點了。然後在我們建立的過程中,呼叫它:

getContractInstance ({commit}) {
 getContract.then(result => {
 commit(‘registerContractInstance’, result)
 }).catch(e => console.log(e))
 }
複製程式碼

把結果傳給我們的變體:

registerContractInstance (state, payload) {
 console.log(‘Casino contract instance: ‘, payload)
 state.contractInstance = () => payload
 }
複製程式碼

這將把我們的協議例項儲存在 store 中,以便我們在元件中使用。

與我們的協議互動

首先,我們將新增一個資料屬性(在匯出中)到我們的 casino 元件中,這樣我們就可以擁有具有響應式屬性的變數。這些值將是 winEvent、amount 和 Pending。

data () {
 return {
 amount: null,
 pending: false,
 winEvent: null
 }
 }
複製程式碼

我們將建立一個 onclick 函式來監聽使用者點選數字事件。這將觸發協議上的 bet() 函式,顯示微調器,當它接收到事件時,隱藏微調器並顯示事件引數。在 data 屬性下,新增一個名為 methods 的屬性,該屬性接收一個物件,我們將在其中放置我們的函式。

methods: {
    clickNumber (event) {
      console.log(event.target.innerHTML, this.amount)
      this.winEvent = null
      this.pending = true
      this.$store.state.contractInstance().bet(event.target.innerHTML, {
        gas: 300000,
        value: this.$store.state.web3.web3Instance().toWei(this.amount, 'ether'),
        from: this.$store.state.web3.coinbase
      }, (err, result) => {
        if (err) {
          console.log(err)
          this.pending = false
        } else {
          let Won = this.$store.state.contractInstance().Won()
          Won.watch((err, result) => {
            if (err) {
              console.log('could not get event Won()')
            } else {
              this.winEvent = result.args
              this.pending = false
            }
          })
        }
      })
    }
  }
複製程式碼

bet() 函式的第一個引數是在協議中定義的引數 u Number.Event.Target.innerHTML ,接下來,引用我們將在列表標記中建立的數字。然後是一個定義事務引數的物件,這是我們輸入使用者下注金額的地方。第三個引數是回撥函式。完成後,我們將監聽這一事件。

現在,我們將為元件建立 html 和 CSS。只是複製貼上它,我認為它已經很淺顯了。在此之後,我們將部署協議,並獲得 ABI 和 Address。

<template>
 <div class=”casino”>
   <h1>Welcome to the Casino</h1>
   <h4>Please pick a number between 1 and 10</h4>
   Amount to bet: <input v-model=”amount” placeholder=”0 Ether”>
   <ul>
     <li v-on:click=”clickNumber”>1</li>
     <li v-on:click=”clickNumber”>2</li>
     <li v-on:click=”clickNumber”>3</li>
     <li v-on:click=”clickNumber”>4</li>
     <li v-on:click=”clickNumber”>5</li>
     <li v-on:click=”clickNumber”>6</li>
     <li v-on:click=”clickNumber”>7</li>
     <li v-on:click=”clickNumber”>8</li>
     <li v-on:click=”clickNumber”>9</li>
     <li v-on:click=”clickNumber”>10</li>
  </ul>
  <img v-if=”pending” id=”loader” src=”https://loading.io/spinners/double-ring/lg.double-ring-spinner.gif”>
  <div class=”event” v-if=”winEvent”>
    Won: {{ winEvent._status }}
    Amount: {{ winEvent._amount }} Wei
  </div>
 </div>
</template>

<style scoped>
.casino {
 margin-top: 50px;
 text-align:center;
}
#loader {
 width:150px;
}
ul {
 margin: 25px;
 list-style-type: none;
 display: grid;
 grid-template-columns: repeat(5, 1fr);
 grid-column-gap:25px;
 grid-row-gap:25px;
}
li{
 padding: 20px;
 margin-right: 5px;
 border-radius: 50%;
 cursor: pointer;
 background-color:#fff;
 border: -2px solid #bf0d9b;
 color: #bf0d9b;
 box-shadow:3px 5px #bf0d9b;
}
li:hover{
 background-color:#bf0d9b;
 color:white;
 box-shadow:0px 0px #bf0d9b;
}
li:active{
 opacity: 0.7;
}
*{
 color: #444444;
}
</style>
複製程式碼

Ropsten 網路和 Metamask(面向第一次使用者)

如果您不熟悉 metamask 或以太坊網路,請不要擔心。

  1. 開啟瀏覽器和 metamask 外掛。接受使用條款並建立密碼。
  2. 將種子短語存放在安全的地方(這是為了在丟失錢包時將其恢復原狀)。
  3. 點選「以太坊主網」並切換到 Ropsten 測試網。
  4. 單擊「購買」,然後單擊「Ropsten Testnet Fucet」。在這裡我們可以得到一些免費的測試-以太坊。
  5. 在 faucet 網站上,點選「從 faucet 請求 1 ether」幾次。

當所有的事情都熟悉了並做完之後,您的 Metamask 應該如下所示:

[譯] 使用 Web3 和 Vue.js 來建立你的第一個以太坊去中心化應用程式(第三部分)

部署和連線

再開啟 remix,我們的協議應該還在。如果不是,請轉到此要點並複製貼上。在 ReMix 的 rop 右邊,確保我們的環境被設定為「InsistedWeb 3(Ropsten)」,並且選擇了我們的地址。

部署與第1部分中的部署相同。我們在 Value 欄位中輸入幾個引數來預裝協議,輸入建構函式引數,然後單擊 Create。這一次,metamask 將提示接受/拒絕事務(約定部署)。單擊「接受」並等待事務完成。

當 TX 完成後點選它,這將帶你到那個 TX 的萎縮塊鏈瀏覽器。我們可以在「to」欄位下找到協議的地址。你的協議雖然不同,但看起來很相似。

[譯] 使用 Web3 和 Vue.js 來建立你的第一個以太坊去中心化應用程式(第三部分)

我們的協議地址在「to」欄位中。

這就給了我們地址,現在是 ABI。回到 remix 並切換到「編譯」選項卡(右上角)。在協議名稱旁邊,我們將看到一個名為「Details」的按鈕,單擊它。第四個領域是我們的 ABI。

[譯] 使用 Web3 和 Vue.js 來建立你的第一個以太坊去中心化應用程式(第三部分)

不錯,現在我們只需要建立前一節還不存在的一個檔案。因此,在 util/constents 資料夾中建立一個名為 casinoContract.js 的新檔案。建立兩個變數,貼上必要的內容並匯出變數,這樣我們從上面匯入的內容就可以訪問它們。

const address = ‘0x…………..’
const ABI = […]
export {address, ABI}
複製程式碼

幹得好!

現在,我們可以通過在終端中執行 npm start ,並在瀏覽器中執行 localhost:8080 來測試我們的應用程式。輸入金額並單擊一個數字。Metamask 將提示您接受事務,旋轉器將啟動。在 30 秒到 1 分鐘之後,我們得到第一次確認,因此也得到了事件的確認。我們的餘額發生了變化,所以 pollweb 3 觸發它的 action 來更新餘額:

[譯] 使用 Web3 和 Vue.js 來建立你的第一個以太坊去中心化應用程式(第三部分)

最終結果(左)和生命週期(右)。

如果你能在這個系列中走到這一步,我會為您鼓掌。我不是一個專業的作家,所以有時閱讀起來並不容易。我們的應用程式在主幹網上已經設定好了,我們只需要讓它更漂亮一些,更友好一些。我們將在下一節中這樣做,儘管這是可選的。

關注需要它的部分

我們很快就會講完的。它將只是一些 html、css 和 vue 條件語句,帶有 v-if/v-Else。

**在 App.vue **中,將容器類新增到我們的 div 元素中,在 CSS 中定義該類:

.container {
 padding-right: 15px;
 padding-left: 15px;
 margin-right: auto;
 margin-left: auto;
}
@media (min-width: 768px) {
 .container {
 width: 750px;
 }
}
複製程式碼

**在 main.js 中,**匯入我們已經安裝的 font-awesome 的庫(我知道,這不是我們需要的兩個圖示的最佳方式):

import ‘font-awesome/css/font-awesome.css’
複製程式碼

在 Hello-metanask.vue 中,我們將做一些更改。我們將在我們的 Computed 屬性中使用 mapState 助手,而不是當前函式。我們還將使用 v-if 檢查 isInjected ,並在此基礎上顯示不同的 HTML。最後的元件如下所示:

<template>
  <div class='metamask-info'>
    <p v-if="isInjected" id="has-metamask"><i aria-hidden="true" class="fa fa-check"></i> Metamask installed</p>
    <p v-else id="no-metamask"><i aria-hidden="true" class="fa fa-times"></i> Metamask not found</p>
    <p>Network: {{ network }}</p>
    <p>Account: {{ coinbase }}</p>
    <p>Balance: {{ balance }} Wei </p>
  </div>
</template>

<script>
import {NETWORKS} from '../util/constants/networks'
import {mapState} from 'vuex'
export default {
  name: 'hello-metamask',
  computed: mapState({
    isInjected: state => state.web3.isInjected,
    network: state => NETWORKS[state.web3.networkId],
    coinbase: state => state.web3.coinbase,
    balance: state => state.web3.balance
  })
}
</script>

<style scoped>
#has-metamask {
  color: green;
}
#no-metamask {
  color:red;
}</style>
複製程式碼

我們將執行相同的 v-if/v-else 方法來設計我們的事件,該事件將在賭場內部返回 -Component.vue

<div class=”event” v-if=”winEvent”>
 <p v-if=”winEvent._status” id=”has-won”><i aria-hidden=”true” class=”fa fa-check”></i> Congragulations, you have won {{winEvent._amount}} wei</p>
 <p v-else id=”has-lost”><i aria-hidden=”true” class=”fa fa-check”></i> Sorry you lost, please try again.</p>
 </div>

#has-won {
  color: green;
}
#has-lost {
  color:red;
}
複製程式碼

最後,在我們的 clickNumber() 函式中,在 this.winEvent=Result.args :下面新增一行:

this.winEvent._amount = parseInt(result.args._amount, 10)
複製程式碼

恭喜,你已經完成了!

首先,專案的完整程式碼可以在主分支下獲得:https://github.com/kyriediculous/dapp-tutorial/tree/master !

[譯] 使用 Web3 和 Vue.js 來建立你的第一個以太坊去中心化應用程式(第三部分)

輸掉賭注後的最後申請:

在我們的應用程式中仍然有一些警告。我們沒有在任何地方正確地處理錯誤,我們不需要所有的控制檯日誌語句,它不是一個非常完美的應用程式(我不是一個設計人員),等等。然而,這款應用程式做得很好。

希望本教程系列能夠幫助您構建更多、更好的去中心化應用程式。我真誠地希望你和我一樣喜歡讀這篇文章。

我不是一個有 20 多年經驗的軟體工程師。因此,如果您有任何建議或改進,請隨時發表意見。我喜歡學習新事物,在力所能及的範圍內提高自己。謝謝。

更新:增加以太坊平衡顯示

歡迎在Twitter上關注我們,訪問我們的網站,如果您喜歡本教程,請留下提示!

TIPJAR: ETH — 0x6d31cb338b5590adafec46462a1b095ebdc37d50


掘金翻譯計劃 是一個翻譯優質網際網路技術文章的社群,文章來源為 掘金 上的英文分享文章。內容覆蓋 AndroidiOS前端後端區塊鏈產品設計人工智慧等領域,想要檢視更多優質譯文請持續關注 掘金翻譯計劃官方微博知乎專欄

相關文章