vue3 + pinia + vue-router + elementui构建web3js MetaMask钱包链接

海星吧 2022-3-17 5450

这段时间学了vue3的setup语法糖和pinia这个新的状态管理工具,并且最近都在和web3打交道,

就这样搞了个web3的封装,这比用vue2的时候只能用mixins混入来封装来的舒服多了

(用mixins很难判断自己的代码,真的很混乱)

使用之前请使用Chrome浏览器并且下载安装MetaMask钱包

创建src/utils/loadElement.js

import { ElLoading, ElMessage  } from 'element-plus'
export const lockLoadHandler = (text) => {
    return ElLoading.service({
        lock: true,
        text: text,
        // spinner: LoadSvg,
        background: 'rgba(0, 0, 0, 0.7)',
    })
}
export const PlusElMessage = (option) => {
    return ElMessage({
        duration: option.type == 'error'? 0 : 3000,
        grouping: true,
        showClose: true,
        ...option
    })
}

创建src/hooks/useWeb3.js

import Web3 from 'web3'; import { lockLoadHandler, PlusElMessage } from "@/utils/loadElement"; import { /*引入合约*/ } from '@/abis/abis.js'; function getEth() { if (typeof window.ethereum === "undefined") { const message = 'MetaMask not installed' //没安装MetaMask钱包进行弹框提示 PlusElMessage({ type: 'error', message // '请安装MetaMask' }) throw new Error('MetaMask not installed'); } else { if (process.env.NODE_ENV == 'production' && window.ethereum.chainId != '0x38') { const message = 'MetaMask currently in an informal network' PlusElMessage({ type: 'error', message // 'MetaMask 处于非正式网络中' }) throw new Error(message); } else { return window.ethereum } } } export async function useWeb3(callback) { const loadHandler = lockLoadHandler('正在获取授权...') try { const web3Provider = await getEth() const userAddress = await web3Provider.enable();//hte enable function will be removed // const userAddress = await web3Provider.request({ method: 'eth_requestAccounts' }); const web3 = new Web3(web3Provider); loadHandler.close(); callback && callback(web3, userAddress[0]) web3Provider && web3Provider.on("accountsChanged", function (accounts) { console.log('用户切换了钱包', accounts[0]);//一旦切换账号这里就会执行 callback && callback(web3, accounts[0]) }); return web3 } catch (error) { console.error(error) const message = 'User denied account access' PlusElMessage({ type: 'error', message // '请安装MetaMask' }) loadHandler.close() throw new Error(message); } } export function getContract(web3, abi, abiAddress) { return new web3.eth.Contract(abi, abiAddress) } export async function startContracts(web3) { const 合约名 = await getContract(web3, 合约json, 合约链接); return { 合约名 } } export async function getUserAddress(_web3) { let userAddress = ''; await _web3.eth.getAccounts().then(res=> userAddress = res[0]); return userAddress; }

创建src/stores/web3js.js

import { defineStore } from "pinia";
import { useWeb3, startContracts } from "@/hooks/useWeb3"
export const UseStoreWeb3js = defineStore('Web3js', {
    state: () => ({
        _web3: null,
        _address: '',
    }),
    getters: {
        web3: ({ _web3 }) => _web3,
        haveAuth: ({ _web3 }) => !!_web3,//是否被授权
        userAddress: ({ _address }) => _address,
        fromWei: ({ _web3 }) => {
            let fromWei;
            if (_web3.utils) {
                fromWei = _web3.utils.fromWei;
            }
            return fromWei;
        }
    },
    actions: {
        async startWeb3() {
            const web3InCode = await useWeb3(async (web3Eth, userAddress) => {
                // console.log('用户切换了钱包后的操作')
                this.setUserAddress(userAddress)
                this.setWeb3(web3Eth)
                const { setContracts } = UseStoreContracts();
                const contracts = await startContracts(web3Eth);
                setContracts(contracts);
            })
            return !!web3InCode
        },
        setWeb3(web3) {
            this._web3 = web3
        },
        setUserAddress(address) {
            this._address = address
        }
    }

})

export const UseStoreContracts = defineStore('contracts', {
    state: () => ({
        _Contracts: null,
    }),
    getters: {
        Contracts: ({ _Contracts }) => _Contracts,
    },
    actions: {
        setContracts(Contracts) {
            // console.log('Contracts set **---',Contracts)
            this._Contracts = Contracts
        },
    }
})

在需要用到的地方使用,最好是在app或者layout级别的组件中,这样就不必每次都去请求响应。

<script setup>
import {
    UseStoreWeb3js,
} from "@/stores/web3js"
const useStoreWeb3js = UseStoreWeb3js();
const { haveAuth, startWeb3 } = useStoreWeb3js;
if (!haveAuth) {
    console.log('获取web3')
    startWeb3();
}
</script>

如果是在vuerouter路由守卫中

import { createRouter, createWebHashHistory } from 'vue-router';
import routes from "./routes.js";
import { UseStoreWeb3js } from '@/stores/web3js.js';
const router = createRouter({
    routes,
    history: createWebHashHistory(),
});
const whitePathList = [
    '/',
    '/home',
]
router.beforeEach(async (to, from, next) => {
    const storeWeb3 = UseStoreWeb3js();
    const { startWeb3, haveAuth } = storeWeb3;
    console.log("router beforeEach", to.path)
    //验证是否被赋予权限
    if (!haveAuth && !whitePathList.includes(to.path)) {
        //没有就去请求
        try {
            console.log('try startWeb3')
            const queryWeb3 = await startWeb3();
            if (queryWeb3) {
                next(to.path)
            } else {
                next('/home');
            }
        } catch (error) {
            console.error(error)
            next('/home');
        }
    } else {
        next();
    }
})
router.afterEach((to) => {
    document.title = to.meta.title
})

export default router

好了,基本上就是这样链接上web3的钱包,至于合约的细节则自行搜索web3区块链之类的技术吧。

这里是海星吧,我们下次见。

拜拜*V*

弱鸡程序员年底还在加班
最新回复 (3)
  • 海星吧 2022-3-18
    0 2
    黑衣 看不懂,计算机专业的我表示头已经快秃了
    正常,大部分技术还是得实际遇到才会懂怎么学。
    我写这个帖子也是为了以后忘了的话可以重新记起来。
    弱鸡程序员年底还在加班
  • 海星吧 2022-3-18
    0 3
    欧派兽 奖励三级精华
    感谢感谢。
    弱鸡程序员年底还在加班
  • 海星吧 2022-3-18
    0 4
    Roogle
    弱鸡程序员年底还在加班
    • ACG里世界
      5
          
返回
发新帖