自学Vue开发Dapp去中心化钱包(三)

这篇具有很好参考价值的文章主要介绍了自学Vue开发Dapp去中心化钱包(三)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

本篇主要记录学习Vue并实际参与完结web3门户项目的经验和走过的弯路。拖了这么久才来还债,说项目忙那是借口,还是因为个人懒!从自学到实战Vue实际中间就1周的学习熟悉时间,学习不够深就会造成基础不稳,多次推翻重来的情况,从架子搭设到实际页面功能都存在这种情况,说来真是惭愧。最终,算是圆满完工吧。


一、项目框架

1.打包方式

vue新建项目打包方式分2种(其他的方式暂未学习):

1.使用webpack工具

学习时参照了bilibili教学老师的打包方式,也就是上篇文章(自学Vue开发Dapp去中心化钱包(二))介绍的,之后按照这个新建项目开始开发web3门户。

命令如下:

vue init webpack 项目名称

项目结构如下:

dapp 链接钱包,区块链,Vue,去中心化,区块链,vue.js,Powered by 金山文档

2.使用vue-cli工具

命令如下:

vue create 项目名称

项目结构如下:

dapp 链接钱包,区块链,Vue,去中心化,区块链,vue.js,Powered by 金山文档

总结:就学习而言,webpack打包方式新手比较适合,多数参数都能接触到,然对项目而言,再经过学习和调查后发现多数快速搭建大家用的是vue-cli工具。最终web3门户这个项目我使用了vue-cli这种打包方式的项目,结构很明朗。

2.vuex组件

store的结构上篇文章(自学Vue开发Dapp去中心化钱包(二))也介绍过,这里对文章中store的模块化重新做了优化,使其更符合“模块化”这个概念。

结构如下:

dapp 链接钱包,区块链,Vue,去中心化,区块链,vue.js,Powered by 金山文档

这里myStore,user,settings相当于3个不同的模块,存储3组不同的信息分别对应web3相关参数、用户相关参数、系统配置项相关参数。

注:Vuex持久化插件vuex-persistedstate这里主要是为了解决刷新后数据消失的问题,持久化缓存一些全局变量。使用时注意createPersistedState里面应该是模块的参数,比如myStore.account,是myStore模块下的参数account。

myStroe.js

import * as ethers from "ethers";
import {getWethAddress} from "@/config/contracts";
import {getEth_chainId} from "@/methods/common";

const state = {
    //provider对象
    provider: {},
    //合约对象
    contracts: {},
    //签名对象
    signer: {},
    //小狐狸钱包的账户address
    account: '',
    //以太坊网络ID:0x5
    net: '',
    //gas费,后续可能要用
    gasPrice: 0,
    //钱包余额
    balance: '0.0',
    //作为是否链接登录到小狐狸钱包的标志
    isConnectWallet: false,
    //绑卡列表数据,用于下拉框
    accountList: [],
    //交易计数,用于发生交易时同步刷新交易记录列表
    tradeCounter: 0,
}
const mutations = {
    saveProviderStore: (state, provider) => {
        state.provider = provider;
    },
    saveContractsStore: (state, contracts) => {
        state.contracts = contracts;
    },

    saveAccountStore: (state, account) => {
        state.account = account;
    },

    saveBalanceStore: (state, balance) => {
        state.balance = balance;
    },

    saveNetStore: (state, net) => {
        state.net = net;
    },

    saveGasPriceStore: (state, gasPrice) =>  {
        state.gasPrice = gasPrice;
    },
    saveIsConnectWallet: (state, isConnectWallet) =>  {
        state.isConnectWallet = isConnectWallet;
    },
    saveSigner: (state, signer) =>  {
        state.signer = signer;
    },
    saveAccountList: (state, accountList) =>  {
        state.accountList = accountList;
    },
    saveTradeCounter: (state, tradeCounter) =>  {
        state.tradeCounter = tradeCounter;
    },

}

const actions = {
    // 触发保存方法

    SET_PROVIDER: ({ commit }, payload) => {
        commit('saveProviderStore', payload);
    },
    SET_CONTRACTS: ({ commit }, payload) => {
        commit('saveContractsStore', payload);
    },
    SET_ACCOUNT: ({ commit }, payload) => {
        commit('saveAccountStore', payload);
    },
    SET_BALANCE: ({ commit }, payload) => {
        commit('saveBalanceStore', payload);
    },
    SET_NET: ({ commit }, payload) => {
        commit('saveNetStore', payload);
    },
    SET_GAS_PRICE: ({ commit }, payload) => {
        commit('saveGasPriceStore', payload);
    },

    SET_IS_CONNECT_WALLET: ({ commit }, payload) => {
        commit('saveIsConnectWallet', payload);
    },

    SET_SIGNER: ({ commit }, payload) => {
        commit('saveSigner', payload);
    },

    SET_ACCOUNT_LIST: ({ commit }, payload) => {
        commit('saveAccountList', payload);
    },
    SET_TRADE_COUNTER: ({ commit }, payload) => {
        commit('saveTradeCounter', payload);
    },

    async connectWallet({ dispatch }) {
        let web3Provider;
        if (window.ethereum) {
            web3Provider = window.ethereum;
            try {

                //通过
                const addressArray = await web3Provider.request({
                    method: "eth_requestAccounts",
                });

                let address = addressArray[0];
                const obj = {
                    status: "👆🏽 Write a message in the text-field above.",
                    address: address,
                };
                let chainId = await getEth_chainId();
                dispatch("setProvider",{address,chainId});
                dispatch("addWalletListener");
                return obj;
            } catch (err) {
                return {
                    address: "",
                    status: "😥 " + err.message,
                };
            }
        } else {
            return {
                address: "",
                status: (
                    <span>
          <p>
            {" "}
              🦊{" "}
              <a target="_blank" href={`https://metamask.io/download.html`}>
              You must install Metamask, a virtual Ethereum wallet, in your
              browser.
            </a>
          </p>
        </span>
                ),
            };
        }
    },

    async getCurrentWalletConnected ({ dispatch }) {
        let web3Provider;
        if (window.ethereum) {
            web3Provider = window.ethereum;
            try {
                const addressArray = await web3Provider.request({
                    method: "eth_accounts",
                });
                if (addressArray.length > 0) {
                    let address = addressArray[0];
                    //请求chain写在这里,防止beforeEach时参数还未放入store中
                    let chainId = await getEth_chainId();
                    //vuex dispatch多个参数时使用object对象传递
                    dispatch("setProvider",{address,chainId});
                    dispatch("addWalletListener");

                    return {
                        address: addressArray[0],
                        status: "👆🏽 Write a message in the text-field above.",
                    };
                } else {
                    return {
                        address: "",
                        status: "🦊 Connect to Metamask using the top right button.",
                    };
                }
            } catch (err) {
                return {
                    address: "",
                    status: "😥 " + err.message,
                };
            }
        } else {
            return {
                address: "",
                status: (
                    <span>
          <p>
            {" "}
              🦊{" "}
              <a target="_blank" href={`https://metamask.io/download.html`}>
              You must install Metamask, a virtual Ethereum wallet, in your
              browser.
            </a>
          </p>
        </span>
                ),
            };
        }
    },
    setProvider({commit},data) {
        let web3Provider;
        if (window.ethereum) {
            web3Provider = window.ethereum;
            const provider = new ethers.providers.Web3Provider(web3Provider);
            const signer = provider.getSigner();
            const contractABI = require("@/config/constants/contract-abi.json");
            const wethAddress = getWethAddress();
            const daiContract = new ethers.Contract(wethAddress, contractABI, provider);

            //先改变isConnectWallet值,后改变account值
            commit('saveNetStore', data.chainId);
            commit('saveIsConnectWallet', true);
            commit('saveAccountStore', data.address);
            commit('saveProviderStore', provider);
            commit('saveContractsStore', daiContract);
            commit('saveSigner', signer);
            //监听区块
            /*provider.on("block", (blockNumber) => {
              // Emitted on every block change
              console.log("blockNumber: " + blockNumber);
            })*/
        }
    },
    addWalletListener({commit}) {
        let web3Provider;
        if (window.ethereum) {
            web3Provider = window.ethereum;
            web3Provider.on('accountsChanged', accounts => {
                //断开链接后,初始化一些值
                if(accounts.length===0){
                    commit('saveIsConnectWallet', false);
                    commit('saveProviderStore', {});
                    commit('saveContractsStore', {});
                    commit('saveSigner', {});
                    commit('saveBalanceStore', '0.0');
                    commit('saveAccountList', []);
                }else{
                    //先改变isConnectWallet值,后改变account值
                    commit('saveIsConnectWallet', true);
                }

                commit('saveAccountStore', accounts[0]);
            });

            web3Provider.on('chainChanged', (chainId) => {
                commit('saveNetStore', chainId);
            });
        }
    },


}

export default {
    state,
    mutations,
    actions
}


getter.js

// 获取最终的状态信息
const getters = {
    provider: state => state.myStore.provider,
    contracts: state => state.myStore.contracts,
    signer: state => state.myStore.signer,
    account: state => state.myStore.account,
    net: state => state.myStore.net,
    gasPrice: state => state.myStore.gasPrice,
    isConnectWallet: state => state.myStore.isConnectWallet,
    accountList: state => state.myStore.accountList,
    tradeCounter: state => state.myStore.tradeCounter,
    token: state => state.user.token,
    avatar: state => state.user.avatar,
    name: state => state.user.name,
    mrspFlag: state => state.user.mrspFlag,
    roles: state => state.user.roles,
    permissions: state => state.user.permissions,
    defaultDecimalPalces: state => state.settings.defaultDecimalPalces,
    tokenName: state => state.settings.tokenName,
    legalTender: state => state.settings.legalTender,
    legalDecimalPalces: state => state.settings.legalDecimalPalces,
}
export default getters

index.js

import Vue from 'vue';
import Vuex from 'vuex';
import myStore from '@/store/modules/myStore';
import user from "@/store/modules/user";
import settings from '@/store/modules/settings';
import getters from '@/store/getters';
import createPersistedState from 'vuex-persistedstate';

Vue.use(Vuex);

const store = new Vuex.Store({
  modules: {
    myStore,user,settings,
  },
  getters,
  plugins: [
    createPersistedState({
      paths: ['myStore.isConnectWallet', 'myStore.account', 'myStore.net']
    }),
  ],
});

export default store

二、实战经验

1.router

  1. 由于项目做了改版,存在多级子路由,这里路由路径要注意的是子路由带/和不带/是有区别的。

比如:

{
    path:'/home',
    meta: {authRequired: true},
    component: Home,
    children: [
        {path:'/', redirect: 'wallet'},
        {
            path:'wallet',
            component: Wallet,
            children: [
            {path:'/', redirect: 'balances'},
            {
                path:'balances',
                component:Balances

            },{
                path:'transfer',
                component: Transfer
            },{
                path:'swap',
                component: Swap
            },{
                path:'receive',
                component: Receive
            }]
        },
    ]
  }

如果这里的path:'balances'改为path:'/balances',子路由前面加/ ,加上/就不会拼接上父级路由的path路径,地址则为http://localhost:8080/#/balances,这样就造成点击菜单时没法联动,点击父菜单子菜单也不会切换。

完整的index.js

import Vue from 'vue'
import Router from 'vue-router'
import Login from '@/components/Login'
import Home from '@/components/Home'
import Wallet from '@/components/pages/Wallet'
import Balances from "@/views/wallet/Balances";
import Transfer from "@/views/wallet/Transfer";
import Receive from "@/views/wallet/Receive";
import Swap from "@/views/wallet/Swap";
import Bridge from '@/components/pages/Bridge'
import Deposit from "@/views/bridge/Deposit";
import Withdraw from "@/views/bridge/Withdraw";
import Card from '@/components/pages/Card'
import Bongloy from "@/views/card/Bongloy";

Vue.use(Router);


const originalPush = Router.prototype.push
Router.prototype.push = function push (location) {
  return originalPush.call(this, location).catch(err => err)
}

let routes =[
  {path: "*", redirect: "/"},
  {
    path:'/',
    name:"login",
    component: Login,
  },
  {
    path:'/home',
    meta: {authRequired: true},
    component: Home,
    children: [
        {path:'/', redirect: 'wallet'},
        {
            path:'wallet',
            component: Wallet,
            children: [
            {path:'/', redirect: 'balances'},
            {
                path:'balances',
                component:Balances

            },{
                path:'transfer',
                component: Transfer
            },{
                path:'swap',
                component: Swap
            },{
                path:'receive',
                component: Receive
            }]
        },{
            path:'bridge',
            component: Bridge,
            children: [
            {path:'/', redirect: 'deposit'},
            {
                path:'deposit',
                component:Deposit

            },{
                path:'withdraw',
                component: Withdraw
            }]
        },{
            path:'card',
            component: Card,
            children: [
            {path:'/', redirect: 'bongloy'},
            {
                path:'bongloy',
                component:Bongloy

            }]
        }
    ]
  },
];

export default new Router({
    mode: 'history', // 去掉url中的#
    routes:routes
})

菜单跳转时path

<router-link to="balances">{{$t(item.navname)}}</router-link>

效果:

dapp 链接钱包,区块链,Vue,去中心化,区块链,vue.js,Powered by 金山文档
  1. router里面的meta: {authRequired: true} 这个authRequired参数是做拦截路由的,当请求的路由时,验证是否需要登录认证。

需要再main.js里增加如下代码:

//拦截路由,当请求的路由时,验证是否需要登录认证,并验证当前是否已连接小狐狸且网络是0x5通道,如果不是则进入登录页面;
//authRequired是router中自定义的参数
router.beforeEach((to, from, next) => {
  if (to.matched.some(res => res.meta.authRequired)) { // 验证是否需要登陆
    if (store.getters.account&&store.getters.net===getChainId()) { // 查询本地存储信息是否已经登陆且通道正确
      next();
    } else {
      //未登录则跳转至login页面
      next({path: '/', });
    }
  } else {
    next();
  }
})

效果如下

dapp 链接钱包,区块链,Vue,去中心化,区块链,vue.js,Powered by 金山文档

2.父子方法调用

  1. 父页面调用子页面方法用this.$refs

父页面

...
<--引入的子页面-->
<my-temp-page ref="myTempPageRef" >
...

methods:{
    initEdit(row){
      this.$refs.myTempPageRef.handleUpdate(row);
    },
},

子页面

myTempPage.vue

methods:{
    handleUpdate(){
      //TODO dosomething
    },
  },
  1. 子页面调用父页面方法用this.$emit()

父页面

...
<Success  @toBack="onNotifyBack"/>
...
methods:{
    onNotifyBack(){
      //dosomething
    },
  },

子页面

success.vue

...
<button @click="toBack" class="reset-button" variant="outlined" data-testid="transaction-receipt-reset">{{ $t('lang.swap41') }}</button>
...
methods:{
    toBack(){
      this.$emit("toBack");
    },
  },

3.store的使用

  1. 页面使用语法糖获取store属性

computed: {
      ...mapState({
        balance: state => state.myStore.balance,
        address: state => state.myStore.account,
      }),
    },

...mapState是语法糖。

取值时注意不能是state.account,因为vuex结构修改成多个模块,取值时要加上定义的模块,比如state.myStore.account、state.user.email等等

  1. 页面对store属性变更

这时这里的SET_TRADE_COUNTER方法名前不加模块名

this.$store.dispatch('SET_TRADE_COUNTER', this.tradeCounter+1);
  1. 页面调用store定义的方法

同样的方法名前不加模块名

this.$store.dispatch('connectWallet').then((res) => {
  //TODO
});
  1. 在user(其他)模块中使用另外一个模块myStore里的方法

使用dispatch,参数中增加{root: true}

user.js
...
methodName({ dispatch }) {
    ...
    commit('SET_EMAIL', res.data.email)//调用自己模块更新属性方法
    dispatch('SET_ACCOUNT', 参数值,{root: true});//调用myStore里的更新account属性的方法
}

4.监听数据变化

vue监听某个值变化使用watch。

如下是监听store某个属性的变化,需是有变化时才会监听到。

computed: {
    storeTradeCounter(){
      return this.$store.getters.tradeCounter;//获取属性
    }
  },

...

watch:{
    //监听有交易发生时,刷新列表
    storeTradeCounter (newValue,oldValue) {

      //交易发送时试试修改store里的绑卡余额及钱包余额
      //dosomething
    },

  },

5.input框监听

监听输入框只能输入2位小数的数字,其他均无法输入

...
<input v-model="formData.amount" type="text" name="amount" placeholder="0.00"
                 @input="handleAmountInput(formData.amount)">
...

methods:{
    handleAmountInput(value) {
        //大于等于0,且只能输入2位小数
        let val=value.replace(/^\D*([0-9]\d*\.?\d{0,6})?.*$/,'$1');
        if(val==null||val==undefined||val==''){
          val=''
        }
        this.formData.amount = val;
      },
}

6.vue生成二维码

  1. 引入vue-qr

npm install vue-qr --save
  1. 使用

import VueQr from 'vue-qr'
...
components:{
    VueQr,
  },
...
<vue-qr
          :text="this.account"
          :size="148"
          logoSrc=""
          :logoScale="0.2">
      </vue-qr>

7.小狐狸3d logo

  1. 下载小狐狸钱包3d logo资源

本人在github上和其他网站均找了许久,最后融合到项目整了几次,总算总结出来具体哪些文件可用,并且好用的。资源如下:

Metamask小狐狸3d Logo

  1. 代码中使用

将metamask-logo放入utils下,
package.json文件中引入这2个

"gl-mat4": "1.1.4",
"gl-vec3": "1.0.3"

然后npm install

使用

...
<div id="logo-container" class="meta-mask-fox mr-2 h-10 w-auto md:h-16" ></div>
...

data(){
    return {
      viewer: null,
    }
  },

mounted () {
    //加載3D小狐狸logo
    const ModelViewer = require('@/utils/metamask-logo');
    this.viewer = ModelViewer({
      // Dictates whether width & height are px or multiplied
      pxNotRatio: true,
      width: 60,
      height: 60,
      // To make the face follow the mouse.
      followMouse: true,
      // head should slowly drift (overrides lookAt)
      slowDrift: false,
    });

    var container = document.getElementById('logo-container');
    container.appendChild(this.viewer.container);

  },
destroyed() {
    if(this.viewer!==null){
      this.viewer.setFollowMouse(true);
      this.viewer.stopAnimation();
    }
  },
  1. 效果

dapp 链接钱包,区块链,Vue,去中心化,区块链,vue.js,Powered by 金山文档

三、记录用到的方

1.金额格式化(千分位)

效果是:9775格式化为9,775.500000

/**
 * @description 格式化金额
 * @param number:要格式化的数字
 * @param decimals:保留几位小数 默认0位
 * @param decPoint:小数点符号 默认.
 * @param thousandsSep:千分位符号 默认为,
 */
export const formatMoney = (number, decimals = 0, decPoint = '.', thousandsSep = ',') => {
    number = (number + '').replace(/[^0-9+-Ee.]/g, '')
    let n = !isFinite(+number) ? 0 : +number
    let prec = !isFinite(+decimals) ? 0 : Math.abs(decimals)
    let sep = (typeof thousandsSep === 'undefined') ? ',' : thousandsSep
    let dec = (typeof decPoint === 'undefined') ? '.' : decPoint
    let s = ''
    let toFixedFix = function (n, prec) {
        let k = Math.pow(10, prec)
        return '' + Math.ceil(n * k) / k
    }
    s = (prec ? toFixedFix(n, prec) : '' + Math.round(n)).split('.')
    let re = /(-?\d+)(\d{3})/
    while (re.test(s[0])) {
        s[0] = s[0].replace(re, '$1' + sep + '$2')
    }
    if ((s[1] || '').length < prec) {
        s[1] = s[1] || ''
        s[1] += new Array(prec - s[1].length + 1).join('0')
    }
    return s.join(dec)
}

//去除千分位中的‘,'
export const delcommafy = function (num) {
    if (!num) return num;
    num = num.toString();
    num = num.replace(/,/gi, "");
    return Number(num);
};

使用方法文章来源地址https://www.toymoban.com/news/detail-673545.html

import {formatMoney} from "@/utils/fixednumber";
...
formatMoney(‘9775’, 6);//格式化成小数点6位带千分位的货币金额9,775.500000
...

2.校验

// utils.js

// 全局函数
export function validateMobile(str) {
    // 检查手机号码格式
    return /^((13[0-9])|(14[5-9])|(15([0-3]|[5-9]))|(16[6-7])|(17[1-8])|(18[0-9])|(19[1|3])|(19[5|6])|(19[8|9]))\d{8}$/.test(
        str,
    );
}

export function validateEmail(str) {
    // 检查邮箱格式
    return /^([A-Za-z0-9_\-.])+@([A-Za-z0-9_\-.])+\.([A-Za-z]{2,4})$/.test(str);
}

export function validateMoney(str) {
    // 检查金额格式
    return /^([1-9]\d*(\.\d{1,2})?|([0](\.([0][1-9]|[1-9]\d{0,1}))))$/.test(str);
}

export function validateBonMoney(str) {
    // 检查金额格式
    return /^([1-9]\d*(\.\d{1,6})?|([0](\.([0][1-9]|[1-9]\d{0,1}))))$/.test(str);
}

export function validatePhone(str) {
    // 检查电话格式
    return /^(0\d{2,4}-)?\d{8}$/.test(str);
}

export function validateQQ(str) {
    // 检查QQ格式
    return /^[1-9][0-9]{4,}$/.test(str);
}

// 检查验证码格式
export function validateSmsCode(str) {
    return /^\d4$/.test(str);
}
// 校验 URL
export function validURL(url) {
    const reg =
        /^(https?|ftp):\/\/([a-zA-Z0-9.-]+(:[a-zA-Z0-9.&%$-]+)*@)*((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(:[0-9]+)*(\/($|[a-zA-Z0-9.,?'\\+&%$#=~_-]+))*$/
    return reg.test(url)
}

// 校验特殊字符
export function specialCharacter(str) {
    const reg = new RegExp(
        // eslint-disable-next-line quotes
        "[`~!@#$^&*()=|{}':;',\\[\\]<>《》/?~!@#¥……&*()——|{}【】‘;:”“'。,、? ]"
    )
    return reg.test(str)
}

/**
 * @param value
 * 测试密码是否满足条件,包括四种类型
 * 密码6-20位,必须包含大写字母,小写字母,数字及特殊字符
 */
export function validPassword(value) {
    const num = /^.*[0-9]+.*/
    const low = /^.*[a-z]+.*/
    const up = /^.*[A-Z]+.*/
    const spe = /^.*[^a-zA-Z0-9]+.*/
    const passLength = value.length > 5 && value.length < 21
    return num.test(value) && low.test(value) && up.test(value) && spe.test(value) && passLength
}

3.复制到粘贴板

export function copyToClipboard(content) {
    if (window.clipboardData) {
        window.clipboardData.setData('text', content);
    } else {
        (function (content) {
            document.oncopy = function (e) {
                e.clipboardData.setData('text', content);
                e.preventDefault();
                document.oncopy = null;
            }
        })(content);
        document.execCommand('Copy');
    }
};

四、待继续整理

到了这里,关于自学Vue开发Dapp去中心化钱包(三)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【区块链技术开发】OpenZeppelin智能合约库:提高智能合约的安全性和可靠性,加速去中心化应用DApp的开发与部署。

    专栏:【区块链技术开发】 前期文章: 【区块链技术开发】使用Infura连接以太坊节点和OpenZeppelin库来构建安全、可靠的智能合约 【区块链技术开发】 Solidity使用Truffle Box工具实现预构建模板、自动化部署、创建智能合约示例代码 【区块链技术开发】 Solidity使用truffle工具创建

    2023年04月24日
    浏览(38)
  • Web3.0 DApp(去中心化应用程序)设计架构

    先来回顾下 Web2.0 应用程序架构,一图胜千言:   图示是对大多数 Web 2.0 应用程序如何工作的一个很好的抽象总结。以一个博客平台为例: 首先 ,必须有一个地方来存储基本数据,也就是数据库; 其次 ,要有后端代码(用 Node.js、Java 或 Python 等语言编写),用于定义业务逻

    2024年02月02日
    浏览(41)
  • 前端和Java验签以太坊钱包签名实现中心化登录

    相信做过一些dapp项目的小伙伴都知道,当dapp需要和中心化的业务系统交互时,怎么验证登录成了一个问题。要dapp输入登录账户密码就很奇怪,违背了设计初衷,不登录吧,中心化系统又没有安全可言。 故此需要一个特定的动作。只有当钱包持有人授权登录(连接钱包),前

    2024年04月23日
    浏览(20)
  • Web3钱包和身份验证:安全和去中心化的新标准

    在数字化的今天,我们正处于一个互联网技术迅速发展的时代。Web3作为一个革命性的概念,正在逐渐改变我们对互联网的看法和使用习惯。在这一变革中,Web3钱包和身份验证成为了核心组成部分,它们不仅为我们提供了安全和去中心化的解决方案,还重新定义了在线身份、

    2024年04月28日
    浏览(30)
  • 使用Web3.js与OKX Web3钱包进行交互:实现去中心化应用的无缝连接

    随着Web3.0技术的不断发展,越来越多的开发者开始探索如何利用去中心化钱包与区块链网络进行交互。在这篇文章中,我们将深入探讨如何通过Web3.js库来连接和操作OKX Web3钱包,以实现对加密货币、NFT以及链上智能合约的管理和交易。 Web3.js 是一个由以太坊社区开发的核心

    2024年02月19日
    浏览(38)
  • Moralis去中心化Web3应用开发教程

    Moralis去中心化Web3应用开发教程 课程英文名:Moralis Web3 dApp Programming 此视频教程共5.5小时,中英双语字幕,画质清晰无水印,源码附件全 下载地址 百度网盘地址:https://pan.baidu.com/s/1ZzB2fNGRraKYNo-ArnRLOg?pwd=n999 课程介绍:https://www.aihorizon.cn/189 课程内容 你想只用JavaScript来开发

    2024年02月16日
    浏览(42)
  • Solidity中的去中心化金融(DeFi)应用开发

    去中心化金融(Decentralized Finance,DeFi)是基于区块链技术的一种新型金融模式,它通过智能合约和去中心化应用程序(DApps)实现了传统金融中的各种功能,如借贷、交易、存款和投资,而无需依赖传统金融机构。Solidity是一种专为以太坊平台设计的智能合约编程语言,它成

    2024年02月09日
    浏览(38)
  • 探索数字未来:DApp钱包Defi引领新纪元

    ​小编介绍:10年专注商业模式设计及软件开发,擅长企业生态商业模式,商业零售会员增长裂变模式策划、商业闭环模式设计及方案落地;扶持10余个电商平台做到营收过千万,数百个平台达到百万会员,欢迎咨询。 随着区块链技术的飞速发展和普及,加密货币已经成为全

    2024年03月22日
    浏览(41)
  • DApp创建本地钱包并实现签名转账(BSC,Polygon,ETH)

    安装ether.js 引入ether.js:的三种方法 es3: es5/es6 javascript/typescript es6 这里默认为你已经了解 地址、密码、私钥、助记词、Keystore 之间的关系,所以不再过多介绍,只列出他们之间的关联: 使用到的ethers的Wallet类: createRandom 返回一个带有随机私钥的新钱包,由加密安全的熵源生成。如

    2024年02月09日
    浏览(29)
  • 开发者-ChatGPT meets Web3.0 用AI赋能去中心化应用

    ChatGPT meets Web3.0: 用AI赋能去中心化应用 随着Web3.0的到来,去中心化应用(dApps)正在成为新的热点。与传统的Web2.0应用相比,Web3.0应用具有更高的安全性、更好的隐私保护、更好的用户掌控和更广阔的应用场景等优势。作为一种强大的人工智能技术,ChatGPT在这个领域的应用也

    2023年04月26日
    浏览(35)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包