前篇确定了技术选型,门户使用Vue前端开发,此篇文章主要记录本人自学Vue以及实操搭建前端框架的过程和遇到的前端知识点和技术瓶颈难题(ps对大佬这都不是难题)。
从零学习(前提有jquery,js等开发经验)Vue,选择先通过视频学习,跟着老师实际上手操作。
所看视频来自狂神bilibili的视频:【狂神说Java】Vue最新快速上手教程通俗易懂_哔哩哔哩_bilibili
老师讲解比较风趣,到位,从零讲起,学习了Vue的框架,Vue的基础语法v-bind,v-if,v-for及事件click等使用,Vue的双向绑定,Vue组件化开发,Vue异步通信等。
下载Node.js 下载 | Node.js 中文网
下载后双击安装next到最后即可。
安装后测试是否安装成功
- cmd最好使用管理员模式
-
- //显示安装的nodejs版本
- node -v
-
- //显示安装的npm版本
- npm -v
安装国内淘宝的镜像,因为npm相关的资源国外节点可能会失败。
- cmd管理员模式
-
- npm install cnpm
- //-g代表全局使用
- npm install vue-cli -g
-
- vue list
-
- //npm未安装成功时使用
- cnpm install vue-cli -g
4.安装webpack
- npm install webpack -g
- webpack -v
- npm install webpack-cli -g
- webpack-cli -v
-
- //打包
- webpack
- //可实现监听文件发生变化自动打包
- webpack--watch
打包方式webpack
- cd d:
- vue init webpack myvue
- //确认项目名称后,后续选择否即可

这里可以直接选择安装上Vue-router路由,也可以直接N,进入项目后手动安装。

最后选择自己执行npm install即可。

目录结构应该是这样的

重要的文件有package.json,包含了所有安装的依赖及包的版本;
config里面主要是打包相关的参数,访问地址设置以及后续可能使用到的浏览器跨域问题在config/index.js文件中参数配置。
使用idea终端操作即可
- npm install
- //运行
- npm run dev

可能遇到的问题:
1.npm不是内部或外部命令。
解决File-> Settings -> Tools -> Terminal -> Shell path中内容由cmd.exe修改为C:\Windows\System32\cmd.exe全路径。
再不行时,桌面idea工具图标右键->属性->兼容性->以管理员身份运行此程序,重新idea。
2.npm install失败,检查是否提示了package.json中组件版本过高或者过低问题;试试cnpm install
- //安装vue-router,--save也可以写--S,指在本项目中安装
- npm install vue-router --save
-
- //安装axios
- npm install axios
-
- //安装element-ui
- npm i element-ui -S
-
- //安装vuex,vuex-persistedstate,后续会介绍使用此组件
- cnpm install vuex@3.6.2 vuex-persistedstate --save
-
- //安装vue-i18n国际化
- npm install vue-i18n@8.26.5
9.安装后启动
npm run dev
main.js中全局加载组件
- //main.js中全局加载
-
- import Vue from 'vue'
- import App from '@/App'
- import router from '@/router'
- import store from '@/store/index';
- import ElementUI from 'element-ui';
- import 'element-ui/lib/theme-chalk/index.css';
- import VueI18n from 'vue-i18n';
- import { getMonthFirstDay,getFormatDate,getMonthLastDay,addNotBlankRule,parseTime, resetForm, addDateRange, selectDictLabel, selectDictLabels, handleTree } from "@/utils/yufu/commonUtils";
-
- // 全局方法挂载
- Vue.prototype.parseTime = parseTime
- Vue.prototype.resetForm = resetForm
- Vue.prototype.addDateRange = addDateRange
- Vue.prototype.selectDictLabel = selectDictLabel
- Vue.prototype.selectDictLabels = selectDictLabels
- Vue.prototype.handleTree = handleTree
- Vue.prototype.addNotBlankRule = addNotBlankRule
- Vue.prototype.getMonthLastDay = getMonthLastDay
- Vue.prototype.getFormatDate = getFormatDate
- Vue.prototype.getMonthFirstDay = getMonthFirstDay
-
- Vue.prototype.msgSuccess = function (msg) {
- this.$message({ showClose: true, message: msg, type: "success" });
- }
-
- Vue.prototype.msgError = function (msg) {
- this.$message({ showClose: true, message: msg, type: "error" });
- }
-
- Vue.prototype.msgInfo = function (msg) {
- this.$message.info(msg);
- }
- Vue.prototype.myConfirm = function(msg,f1,f2){
- this.$confirm(msg,"Warning", {
- confirmButtonText: "Yes",
- cancelButtonText: "No",
- type: "warning"
- }).then(f1).then(f2).catch(()=>{
- //this.msgInfo("已取消");
- });
- }
- Vue.prototype.myConfirm2 = function(msg,title){
- return this.$confirm(msg,title||"操作信息", {
- confirmButtonText: "确定",
- cancelButtonText: "取消",
- type: "warning"
- }).catch(()=>{
- this.msgInfo("已取消");
- });
- }
- //设置全局缓存常量
- window.cacheData = {}
-
- /*---------挂载全局使用-----------*/
- Vue.use(ElementUI);
- Vue.use(VueI18n);
-
- const i18n = new VueI18n({
- locale: 'en', //切换语言
- messages: {
- zh: require('@/language/zh.js'),
- en: require('@/language/en.js'),
- },
- });
-
- new Vue({
- el: '#app',
- router,
- store,
- i18n,
- render: h => h(App),
- components: { App },
- template: '
' - })
创建index.js:vue的路由组件,router目录下创建index.js
- //项目目录下创建router目录,router目录下创建index.js
-
- //index.js
- //导入依赖
- import Vue from 'vue'
- import Router from 'vue-router'
- //页面组件
- import TransferAccounts from '@/views/TransferAccounts'
-
- //Vue加载使用
- Vue.use(Router);
-
-
- //解决因版本问题多次点击后前端console报错问题
- const originalPush = Router.prototype.push
- Router.prototype.push = function push (location) {
- return originalPush.call(this, location).catch(err => err)
- }
-
-
- export default new Router({
- mode: 'history', // 去掉url中的#
- routes: [
- {
- path:'/transferAccounts',//指定路由路径
- name:"transferAccounts",//起个别名,可忽略
- component: TransferAccounts//这个是路由的组件,就是需要跳转到的组件页面
- }
- ]
- })
其他地方使用,使用前需要main.js全局挂载,见3.1Vue全局加载
- //js代码调用时
- this.$router.push('/login')
-
- //template中使用
- //import先引入组件,然后template中使用router-link to路由路径。
- //必须加上
-
- id="app">
-
Hello App!
-
-
-
-
-
"/">Go to Home -
"/about">Go to About -
-
-
-
文档路径:Element - The world's most popular Vue UI framework
- import Vue from 'vue';
- import ElementUI from 'element-ui';
- import 'element-ui/lib/theme-chalk/index.css';
- import App from './App.vue';
-
- Vue.use(ElementUI);
-
- new Vue({
- el: '#app',
- render: h => h(App)
- });
- import Vue from 'vue'
- import VueI18n from 'vue-i18n'
-
- Vue.use(VueI18n)
-
- const i18n = new VueI18n({
- locale: 'en', //切换语言
- messages: {
- zh: require('@/language/zh.js'),
- en: require('@/language/en.js'),
- },
- });
-
- new Vue({
- el: '#app',
- router,
- store,
- i18n,
- render: h => h(App),
- components: { App },
- template: '
' - })
zh.js
- //zh.js
-
- export const lang = {
- swap1: '转账',
- swap2: '充值',
-
- };
en.js
- //en.js
-
- export const lang = {
- swap1: 'Transfer',
- swap2: 'Recharge',
-
- };
- 1.标签中
{{ $t('lang.swap1') }}
-
- 2.script中
- this.$message.error(this.$t('lang.swap5')+'');
-
- 3.标签上,使用`:`绑定使用
"$t('lang.swap58')" show-word-limit v-model="ruleForm.to"> -
- <el-dialog :title="$t('lang.swap74')" :visible.sync="dialogVisible" width="30%">
- <AddBindAcctDialog :visible.sync="dialogVisible" @getList="getList"/>
- el-dialog>
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式 + 库,采用集中式存储管理应用的所有组件的状态,解决多组件数据通信。Vuex 是什么? | Vuex
为什么我要使用,我做的这个钱包门户设计小狐狸钱包多个账户地址的切换,实时监听切换并刷新展示页面数据。因为store可以存储数据状态,发生改变时只需管理数据的实际状态就可以达到所有组件中数据的唯一性,实时性。

官方提供的最简单的store
- import { createApp } from 'vue'
- import { createStore } from 'vuex'
-
- // 创建一个新的 store 实例
- const store = createStore({
- state () {
- return {
- count: 0
- }
- },
- mutations: {
- increment (state) {
- state.count++
- }
- }
- })
-
- const app = createApp({ /* 根组件 */ })
-
- // 将 store 实例作为插件安装
- app.use(store)
- ├── index.html
- ├── main.js
- ├── api
- │ └── ... # 抽取出API请求
- ├── components
- │ ├── App.vue
- │ └── ...
- └── store
- ├── index.js # 我们组装模块并导出 store 的地方
- ├── actions.js # 根级别的 action
- ├── mutations.js # 根级别的 mutation
- └── modules
- ├── cart.js # 购物车模块
- └── products.js # 产品模块
本人项目中的模块化结构

实际代码
- //index.js
-
- import Vue from 'vue';
- import Vuex from 'vuex';
- import state from '@/store/state';
- import * as actions from '@/store/actions';
- import * as mutations from '@/store/mutations';
- import * as getters from '@/store/getters';
- import createPersistedState from 'vuex-persistedstate';
-
- Vue.use(Vuex);
-
- const store = new Vuex.Store({
- state,
- actions,
- mutations,
- getters,
- plugins: [
- createPersistedState({
- paths: ['isConnectWallet', 'account'],
- }),
- ],
- });
-
- export default store
- export default {
- //provider对象
- provider: {},
- //合约对象
- contracts: {},
- //签名对象
- signer: {},
- //小狐狸钱包的账户address
- account: '',
- net: 0,
- //gas费,后续可能要用
- gasPrice: 0,
- //钱包余额
- balance: '0.0',
- //作为是否链接登录到小狐狸钱包的标志
- isConnectWallet: false,
- //绑卡列表数据,用于下拉框
- accountList: [],
- //交易计数,用于发生交易时同步刷新交易记录列表
- tradeCounter: 0,
- };
-
- export const saveProviderStore = (state, provider) => {
- state.provider = provider;
- };
-
- export const saveContractsStore = (state, contracts) => {
- state.contracts = contracts;
- };
-
- export const saveAccountStore = (state, account) => {
- state.account = account;
- };
-
- export const saveBalanceStore = (state, balance) => {
- state.balance = balance;
- };
-
- export const saveNetStore = (state, net) => {
- state.net = net;
- };
-
- export const saveGasPriceStore = (state, gasPrice) => {
- state.gasPrice = gasPrice;
- };
- export const saveIsConnectWallet = (state, isConnectWallet) => {
- state.isConnectWallet = isConnectWallet;
- };
- export const saveSigner = (state, signer) => {
- state.signer = signer;
- };
- export const saveAccountList = (state, accountList) => {
- state.accountList = accountList;
- };
- export const saveTradeCounter = (state, tradeCounter) => {
- state.tradeCounter = tradeCounter;
- };
- // 获取最终的状态信息
- export const provider = state => state.provider;
- export const contracts = state => state.contracts;
- export const signer = state => state.signer;
- export const account = state => state.account;
- export const net = state => state.net;
- export const gasPrice = state => state.gasPrice;
- export const balance = state => state.balance;
- export const isConnectWallet = state => state.isConnectWallet;
- export const accountList = state => state.accountList;
- export const tradeCounter = state => state.tradeCounter;
-
- // 触发保存方法
- export const SET_PROVIDER = ({ commit }, payload) => {
- commit('saveProviderStore', payload);
- };
- export const SET_CONTRACTS = ({ commit }, payload) => {
- commit('saveContractsStore', payload);
- };
- export const SET_ACCOUNT = ({ commit }, payload) => {
- commit('saveAccountStore', payload);
- };
- export const SET_BALANCE = ({ commit }, payload) => {
- commit('saveBalanceStore', payload);
- };
- export const SET_NET = ({ commit }, payload) => {
- commit('saveNetStore', payload);
- };
- export const SET_GAS_PRICE = ({ commit }, payload) => {
- commit('saveGasPriceStore', payload);
- };
-
- export const SET_IS_CONNECT_WALLET = ({ commit }, payload) => {
- commit('saveIsConnectWallet', payload);
- };
-
- export const SET_SIGNER = ({ commit }, payload) => {
- commit('saveSigner', payload);
- };
-
- export const SET_ACCOUNT_LIST = ({ commit }, payload) => {
- commit('saveAccountList', payload);
- };
- export const SET_TRADE_COUNTER = ({ commit }, payload) => {
- commit('saveTradeCounter', payload);
- };
-
-
- .........其他代码
-
- export const setProvider = ({commit},address) => {
- let web3Provider;
- if (window.ethereum) {
- web3Provider = window.ethereum;
-
- .....获取web3钱包中的一些熟悉,地址,provider,合约对象等
-
- //commit('saveAccountStore', address);//另外一种方式
- SET_ACCOUNT({commit},address);
- SET_PROVIDER({commit},provider);
- SET_CONTRACTS({commit},daiContract);
- SET_IS_CONNECT_WALLET({commit},true);
- SET_SIGNER({commit},signer);
-
- }
- };
-
-
- 1.action.js中要改变数据状态时
-
- //commit('saveAccountStore', address);//另外一种方式
- SET_ACCOUNT({commit},address);
-
- 2.组件中,使用语法糖获取值
-
- import {mapState} from "vuex";
-
- export default {
- computed: {
- ...mapState(['account']),
- getAccount() {
- if (this.account) {
- return '0x...' + this.account.substring(this.account.length - 4, this.account.length);
- } else {
- return '';
- }
- },
- },
- }
-
- 3.组件中,不使用语法糖获取值
-
- this.$store.getter.account;
-
- 4.组件中使用语法糖调用方法
- methods: {
- handleLogin() {
- this.$store.dispatch('connectWallet');
- },
- }
-
- 5.组件中改变store数据状态
- let balanceStr = '0.0';
- this.$store.dispatch('SET_BALANCE', balanceStr);
-

- 1.install安装
- 2.js文件中引入即可使用
-
- import * as ethers from 'ethers';
-
- 获取钱包余额
-
- const balance = await daiContract.balanceOf(address);
- let balanceStr = ethers.utils.formatUnits(balance, 18);
-
主要学习使用Vue的基础语法,然后跟随老师实际操作,最后自己搭建Vue前端的整体框架。安装依赖组件,并学习各个组件的用法。接下来文章介绍Vue框架使用中遇到的问题及解决方法。打脸待续