使用vue和web3建立你的第一個以太坊APP

歡迎回到這個很牛的教程系列的第2部分,在教程中咱們親手構建咱們的第一個分佈式應用程序。 在第二部分中,咱們將介紹VueJS和Vuex的核心概念,並引入web3js以與metamask進行交互。javascript

若是你錯過了第一部分,你能夠在下面找到它。前端

正事: VueJS
VueJS是一個用於構建UI的javascript框架。乍一看,它看起來與經典的moustache模板相似,但在底層爲了使Vue變得響應式發生了不少事情。vue

{{ message }}

var app = new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
}
})
這將是一個很是基礎的Vue應用程序的結構。數據對象中的消息屬性將渲染到id爲'app'的元素的屏幕區域,當咱們更改此消息時,它將在屏幕上更新並沒有需刷新。你能夠在這個jsfiddle中查看它(須打開自動運行):https://jsfiddle.net/tn1mfxwr/2/ 。java

VueJS的另外一個重要特性是組件。組件是小規模的、可重用的和自包含的代碼片段。本質上,Web應用程序能夠抽象爲一顆更小的組件樹。當咱們開始編寫咱們的前端應用程序時,這將會變得更加清晰。web

將網頁抽象成組件的示例。該網頁由三部分組成。其中兩個組件具備子組件。vue-router

狀態的聯合:Vuex
咱們將使用Vuex來管理咱們的應用程序的狀態。與redux相似,Vuex實現了一個倉庫,做爲咱們app相關數據的「惟一真實數據源」。Vuex容許咱們以可預測的方式操做和提供咱們的應用程序所使用的數據。vuex

它的工做方式很是簡單。組件在渲染時是須要數據的,它會派發一個動做(action)來獲取它所須要的數據。獲取數據的API調用發生在action的async中。 一旦數據被提取完成,action就會將這些數據提交給mutation。 以後mutation會改變咱們倉庫中的狀態。當該組件所使用的數據在倉庫中發生更改時,它將從新渲染。vue-cli

Vuex 的狀態管理模式npm

在繼續以前…
在第一部分中,咱們使用 vue-cli 生成了 Vue 應用程序,同時還安裝了須要的依賴項。 若是你尚未完成這一部分,請點擊的頂部的連接。redux

若是你正確地完成了一切,目錄結構應該以下所示:

新生成的 vue 應用

注意: 若是你打算從這裏複製粘貼代碼,添加/src/ 到 .eslintignore 文件中,避免縮進錯誤。

你能夠在終端輸入‘npm start’來啓動這個App。這個App會包含默認的vue應用,所以咱們能夠將它放出來。
注意:咱們正在使用vue Router儘管只有一個route,咱們不須要它,可是由於它太簡單了,我認爲將它放到教程裏挺好的。
提示:在.vue文件將你的atom語法(例如 bottom right)添加到HTML。
如今來清理一下這個新項目:

在app.vue中刪除img-tag,同時刪除在style-tags之間的全部東西。

刪除components/HelloWorld.vue,新建兩個文件分別名爲casino-dapp.vue(咱們的主模塊)和hello-metamask.vue(會包括咱們的metamask數據)

在咱們的新文件hello-metamask.vue中粘貼如下代碼,這些代碼如今只是在一個p-tag中顯示文字‘Hello’。

Hello





經過引入文件,咱們如今要加載hello-metamask模塊到咱們的主模塊casino-dapp模塊中,而後在咱們的vue實例中關聯這個模塊,所以咱們能夠將它做爲一個tag加到咱們的模板中。將下面代碼粘貼到casino-dapp.vue文件中:




如今若是你打開了router/index.js,你就會看到咱們根目錄下只有一個route,它仍然指向咱們已經刪掉的HelloWorld.vue模塊。咱們須要將它改成指向咱們的casino-dapp.vue模塊。

import Vue from 'vue'
import Router from 'vue-router'
import CasinoDapp from '@/components/casino-dapp'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
name: 'casino-dapp',
component: CasinoDapp
}
]
})
關於Vue Router:你能夠添加其餘的路徑以及綁定模塊,當你訪問定義的路徑他們會進行渲染。由於咱們App.vue文件中有route-view tag,正確的模塊會被渲染。

在src中建立一個名爲util的新文件夾。在這個文件夾中建立另外一個文件夾名爲constants。建立一個名爲network.js的新文件,而後將下面代碼粘貼進去。當咱們代碼在清理的時候,這會讓咱們顯示Ethereum 網絡名稱而不是它的id。

export const NETWORKS = {
'1': 'Main Net',
'2': 'Deprecated Morden test network',
'3': 'Ropsten test network',
'4': 'Rinkeby test network',
'42': 'Kovan test network',
'4447': 'Truffle Develop Network',
'5777': 'Ganache Blockchain'
}
最後但一樣重要的是(如今其實並不重要),在src中建立一個名爲store的新文件夾。在下一章咱們再來談論這個。

若是你在終端運行‘npm start’,而後在瀏覽器訪問localhost:8080,你應該就能在屏幕上看到‘Hello’。若是是這樣的,你就能夠準備繼續了。

設置咱們的 Vuex store
在這一章咱們要設置咱們的store。如今開始在咱們的全新的store目錄(上一章的最後一部分)建立兩個文件:index.js和state.js;咱們由state.js開始,這個文件將會做爲一個新的咱們檢索數據的表明。

let state = {
web3: {
isInjected: false,
web3Instance: null,
networkId: null,
coinbase: null,
balance: null,
error: null
},
contractInstance: null
}
export default state
好的,如今咱們開始在index.js中配置咱們的store。咱們要引入vuex庫供vueJS使用。咱們還要引入state,而後也加入咱們的store中。

import Vue from 'vue'
import Vuex from 'vuex'
import state from './state'
Vue.use(Vuex)
export const store = new Vuex.Store({
strict: true,
state,
mutations: {},
actions: {}
})
最後一步來編輯main.js來包含咱們的store:

import Vue from 'vue'
import App from './App'
import router from './router'
import { store } from './store/'
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
store,
components: { App },
template: ' '
})
作得不錯,完成了這麼多的配置,給本身一點表揚。如今咱們準備好了開始經過web3 API獲取咱們的metamask數據,而後讓他爲咱們的應用服務。就要實現了!

從Web3和Metamask開始
就像以前提到的,爲了將數據獲取到咱們的Vue app,咱們須要發送一個action來作異步API調用。咱們使用promises將一些調用鏈接到一塊兒,而後將其抽象成一個文件。所以在util文件夾中建立一個名爲getWeb.js的新文件。將下面的代碼粘貼到裏面,這些代碼包含了你要遵循的至關多的註解。咱們在代碼塊下面也會提到。

import Web3 from 'web3'

/*

    1. Check for injected web3 (mist/metamask)
    1. If metamask/mist create a new web3 instance and pass on result
    1. Get networkId - Now we can check the user is connected to the right network to use our dApp
    1. Get user account from metamask
    1. Get user balance
      */

let getWeb3 = new Promise(function (resolve, reject) {
// Check for injected web3 (mist/metamask)
var web3js = window.web3
if (typeof web3js !== 'undefined') {
var web3 = new Web3(web3js.currentProvider)
resolve({
injectedWeb3: web3.isConnected(),
web3 () {
return web3
}
})
} else {
// web3 = new Web3(new Web3.providers.HttpProvider('http://localhost:7545')) GANACHE FALLBACK
reject(new Error('Unable to connect to Metamask'))
}
})
.then(result => {
return new Promise(function (resolve, reject) {
// Retrieve network ID
result.web3().version.getNetwork((err, networkId) => {
if (err) {
// If we can't find a networkId keep result the same and reject the promise
reject(new Error('Unable to retrieve network ID'))
} else {
// Assign the networkId property to our result and resolve promise
result = Object.assign({}, result, {networkId})
resolve(result)
}
})
})
})
.then(result => {
return new Promise(function (resolve, reject) {
// Retrieve coinbase
result.web3().eth.getCoinbase((err, coinbase) => {
if (err) {
reject(new Error('Unable to retrieve coinbase'))
} else {
result = Object.assign({}, result, { coinbase })
resolve(result)
}
})
})
})
.then(result => {
return new Promise(function (resolve, reject) {
// Retrieve balance for coinbase
result.web3().eth.getBalance(result.coinbase, (err, balance) => {
if (err) {
reject(new Error('Unable to retrieve balance for address: ' + result.coinbase))
} else {
result = Object.assign({}, result, { balance })
resolve(result)
}
})
})
})

export default getWeb3
首先要注意的是咱們使用promises來鏈接回調,若是你不知道promises,查看相關連接。下一步咱們檢查用戶是否有Metamask(或者 Mist)在運行。Metamase注入他本身的web3的實例,咱們所以確認window.web3(被注入的實例)已經定義了。若是沒有定義的話,咱們要使用Metamask建立一個web3實例做爲當前provider,所以咱們不依賴被注入的實例的版本。咱們將咱們新建立的實例傳給下一個promises,在這裏咱們作幾個API調用:

web3.version.getNetwork() 會返回咱們鏈接的網絡ID。

web3.eth.coinbase() 返回咱們節點屬於的地址,當使用Metamask的時候這會是咱們選擇的帳戶。

web3.eth.getBalance(

) 返回咱們做爲參數傳過去的地址的balance。

還記得咱們說的在咱們的Vuex store中須要在一個action產生異步API調用嗎?咱們如今會把它hook出來,以後從咱們的組件dispatch出去。在store/index.js中咱們會引入咱們的getWeb3.js文件,調用它而後將它commit給一個mutation,而後在咱們的store中保存。
在你的引用語句中添加

import getWeb3 from '../util/getWeb3'
而後在action對象(在你的sotre中)中咱們會調用getWeb3而後commit結果。咱們在邏輯中添加了大量的console.logs,所以咱們能夠看到進程的步驟,這會讓咱們對徹底的dispatch-action-commit-mutation-statechange流程瞭解的更加透徹。

registerWeb3 ({commit}) {
console.log('registerWeb3 Action being executed')
getWeb3.then(result => {
console.log('committing result to registerWeb3Instance mutation')
commit('registerWeb3Instance', result)
}).catch(e => {
console.log('error in action registerWeb3', e)
})
}
如今開始建立咱們的mutation,它會在咱們的store中將數據保存到state。經過訪問第二個參數,咱們能夠在mutation中訪問傳進commit的數據。在mutations對象添加下面的函數。

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
}
不錯!如今還要作的就剩下從咱們的組件將action dispatch給實際檢索數據,而後把它渲染到咱們的應用。爲了dispatch咱們的actions,咱們要利用Vue的生命週期hooks。在咱們的例子中,咱們須要從main casino-dapp組件dispatch 咱們的action,在組件被建立以前。所以在components/casino-dapp.vue 的name屬性以後添加下面的函數:

export default {
name: 'casino-dapp', beforeCreate () {
console.log('registerWeb3 Action dispatched from casino-dapp.vue')
this.$store.dispatch('registerWeb3')
},
components: {
'hello-metamask': HelloMetamask
}
}

好了,如今咱們要從hello-metamask組件渲染這些數據,咱們全部的帳戶數據都會在這個組件中被渲染。爲了從咱們的store獲取數據,咱們須要將一個getter函數傳入computed。而後咱們能夠在咱們的模板中使用curly-braces關聯數據。


Metamask: {{ web3.isInjected }}


Network: {{ web3.networkId }}


Account: {{ web3.coinbase }}


Balance: {{ web3.balance }}






不錯,如今均可以工做了。在你的終端使用‘npm start’啓動項目,而後訪問localhost:8080。咱們如今應該能夠看到咱們的metamask數據。當咱們打開控制檯的時候,咱們應該看到在state管理模式下控制檯log輸出的信息,就像是在文章的vuex部分描述的同樣。

若是你能作到這一點,一切都很好,那麼就認真的作下去。目前這塊是這個系列最難的部分。在下一部分,咱們將學習如何輪詢Metamask的更改(如更換帳戶)和將咱們在第一部分寫的智能合約鏈接到咱們的應用。

本文地址:https://www.oschina.net/translate/create-your-first-ethereum-dapp-with-web3-and-vue-js-part

原文地址:https://itnext.io/create-your-first-ethereum-dapp-with-web3-and-vue-js-part-2-52248a74d58a

相關文章
相關標籤/搜索