使用 Web3 和 Vue.js 来创建你的第一个以太坊 dAPP(二)

(点击

上方公众号

,可快速关注)

英文:Alt Street  来源:

开源中国

mp.weixin.qq.com/s/dliCS9kgFZYXUHq0jQOwFQ

欢迎回到这个很牛的教程系列的第2部分,在教程中我们亲手构建我们的第一个分布式应用程序。 在第二部分中,我们将介绍VueJS和Vuex的核心概念,并引入web3js以与metamask进行交互。



如果你错过了第一部分,你可以在下面找到它:



  • 使用 Web3 和 Vue.js 来创建你的第一个以太坊 dAPP(一)

  • 正事: VueJS



    VueJS是一个用于构建UI的javascript框架。乍一看,它看起来与经典的moustache模板类似,但在底层为了使Vue变得响应式发生了很多事情。



    <div id=”app”>

     {{ message }}

    </div>

    var app = new Vue({

     el: "#app",

     data: {

     message: "Hello Vue!"

     }

    })

    这将是一个非常基础的Vue应用程序的结构。数据对象中的消息属性将渲染到id为"app"的元素的屏幕区域,当我们更改此消息时,它将在屏幕上更新并无需刷新。你可以在这个jsfiddle中查看它(须打开自动运行):http://jsfiddle.net/tn1mfxwr/2/ 。



    VueJS的另一个重要特性是组件。组件是小规模的、可重用的和自包含的代码片断。本质上,Web应用程序可以抽象为一颗更小的组件树。当我们开始编写我们的前端应用程序时,这将会变得更加清晰。



    使用 Web3 和 Vue.js 来创建你的第一个以太坊 dAPP(二)



    将网页抽象成组件的示例。该网页由三部分组成。其中两个组件具有子组件。



    状态的联合:Vuex



    我们将使用Vuex来管理我们的应用程序的状态。与redux类似,Vuex实现了一个仓库,作为我们app相关数据的“唯一真实数据源”。Vuex允许我们以可预测的方式操作和提供我们的应用程序所使用的数据。



    它的工作方式非常简单。组件在渲染时是需要数据的,它会派发一个动作(action)来获取它所需要的数据。获取数据的API调用发生在action的async中。 一旦数据被提取完成,action就会将这些数据提交给mutation。 之后mutation会改变我们仓库中的状态。当该组件所使用的数据在仓库中发生更改时,它将重新渲染。



    使用 Web3 和 Vue.js 来创建你的第一个以太坊 dAPP(二)



    Vuex的状态管理模式

    在继续之前...



    在第一部分中,我们使用 vue-cli 生成了 Vue 应用程序,同时还安装了需要的依赖项。 如果你还没有完成这一部分,请点击的顶部的链接。



    如果你正确地完成了一切,目录结构应该如下所示:



    使用 Web3 和 Vue.js 来创建你的第一个以太坊 dAPP(二)



    新生成的 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’。



  • <template>

     <p>Hello</p>

    </template>

    <script>

    export default {

     name: "hello-metamask"

    }

    </script>

    <style scoped>

    </style>

  • 通过引入文件,我们现在要加载hello-metamask模块到我们的主模块casino-dapp模块中,然后在我们的vue实例中关联这个模块,因此我们可以将它作为一个tag加到我们的模板中。将下面代码粘贴到casino-dapp.vue文件中:



  • <template>

     <hello-metamask/>

    </template>

    <script>

    import HelloMetamask from "@/components/hello-metamask"

    export default {

     name: "casino-dapp",

     components: {

     "hello-metamask": HelloMetamask

     }

    }

    </script>

    <style scoped>

    </style>

  • 现在如果你打开了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。

  • 使用 Web3 和 Vue.js 来创建你的第一个以太坊 dAPP(二)

  • 最后但同样重要的是(现在其实并不重要),在src中创建一个名为store的新文件夹。在下一章我们再来谈论这个。



  • 如果你在终端运行‘npm start’,然后在浏览器访问localhost:8080,你应该就能在屏幕上看到‘Hello’。如果是这样的,你就可以准备继续了。

    设置我们的Vuex store



    在这一章我们要设置我们的store。现在开始在我们的全新的store目录(上一章的最后一部分)创建两个文件:index.js和state.js;我们由state.js开始,这个文件将会作为一个新的我们检索数据的代表。



    使用 Web3 和 Vue.js 来创建你的第一个以太坊 dAPP(二)



    好的,现在我们开始在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: "<App/>"

    })



    做得不错,完成了这么多的配置,给自己一点表扬。现在我们准备好了开始通过web3 API获取我们的metamask数据,然后让他为我们的应用服务。就要实现了!



    从 Web3 和 Metamask 开始



    就像之前提到的,为了将数据获取到我们的Vue app,我们需要发送一个action来做异步API调用。我们使用promises将一些调用连接到一起,然后将其抽象成一个文件。因此在util文件夹中创建一个名为getWeb.js的新文件。将下面的代码粘贴到里面,这些代码包含了你要遵循的相当多的注解。我们在代码块下面也会提到。



    import Web3 from "web3"

    /*

    * 1. Check for injected web3 (mist/metamask)

    * 2. If metamask/mist create a new web3 instance and pass on result

    * 3. Get networkId - Now we can check the user is connected to the right network to use our dApp

    * 4. Get user account from metamask

    * 5. 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(<address>) 返回我们作为参数传过去的地址的balance。



  • 还记得我们说的在我们的Vuex store中需要在一个action产生异步API调用吗?我们现在会把它hook出来,之后从我们的组件dispatch出去。在store/index.js中我们会引入我们的getWeb3.js文件,调用它然后将它commit给一个mutation,然后在我们的store中保存。



    在你的引用语句中添加



    使用 Web3 和 Vue.js 来创建你的第一个以太坊 dAPP(二)



    然后在action对象(在你的sotre中)中我们会调用getWeb3然后commit结果。我们在逻辑中添加了大量的console.logs,因此我们可以看到进程的步骤,这会让我们对完全的dispatch-action-commit-mutation-statechange流程了解的更加透彻。

    使用 Web3 和 Vue.js 来创建你的第一个以太坊 dAPP(二)



    现在开始创建我们的mutation,它会在我们的store中将数据保存到state。通过访问第二个参数,我们可以在mutation中访问传进commit的数据。在mutations对象添加下面的函数。

    使用 Web3 和 Vue.js 来创建你的第一个以太坊 dAPP(二)



    不错!现在还要做的就剩下从我们的组件将action dispatch给实际检索数据,然后把它渲染到我们的应用。为了dispatch我们的actions,我们要利用Vue的生命周期hooks。



    在我们的例子中,我们需要从main casino-dapp组件dispatch 我们的action,在组件被创建之前。因此在components/casino-dapp.vue 的name属性之后添加下面的函数:

    使用 Web3 和 Vue.js 来创建你的第一个以太坊 dAPP(二)



    好了,现在我们要从hello-metamask组件渲染这些数据,我们所有的账户数据都会在这个组件中被渲染。为了从我们的store获取数据,我们需要将一个getter函数传入computed。然后我们可以在我们的模板中使用curly-braces关联数据。

    <template>

     <div>

       <p>Metamask: {{ web3.isInjected }}</p>

       <p>Network: {{ web3.networkId }}</p>

       <p>Account: {{ web3.coinbase }}</p>

       <p>Balance: {{ web3.balance }}</p>

     </div>

    </template>

    <script>

    export default {

     name: "hello-metamask",

     computed: {

       web3 () {

         return this.$store.state.web3

         }

       }

    }

    </script>

    <style scoped></style>



    不错,现在都可以工作了。在你的终端使用‘npm start’启动项目,然后访问localhost:8080。我们现在应该可以看到我们的metamask数据。当我们打开控制台的时候,我们应该看到在state管理模式下控制台log输出的信息,就像是在文章的vuex部分描述的一样。



    使用 Web3 和 Vue.js 来创建你的第一个以太坊 dAPP(二)

    如果你能做到这一点,一切都很好,那么就认真的做下去。目前这块是这个系列最难的部分。在下一部分,我们将学习如何轮询Metamask的更改(如更换账户)和将我们在第一部分写的智能合约连接到我们的应用。

    觉得本文对你有帮助?请分享给更多人

    关注「前端大全」,提升前端技能

    使用 Web3 和 Vue.js 来创建你的第一个以太坊 dAPP(二)

    使用 Web3 和 Vue.js 来创建你的第一个以太坊 dAPP(二)