Vue3 | VueCli、node.js安装、nrm切换镜像源、vue项目结构解读、Router详解、VueX详解

完整原文地址见简书

更多完整Vue笔记目录敬请见《前端 Web 笔记 汇总目录(Updating)》



本文内容提要

  • VueCli部分
    • 首先需要安装nodejs
    • 安装完node会自动配套npm
    • 使用npm install nrm -g用于调整 镜像源,方便后续下载依赖
    • 这边使用淘宝镜像
    • npm uninstall vue-cli -g 检查并清除 多余的旧版本
    • 使用npm install -g @vue/cli[@版本号]安装 脚手架
    • 使用 脚手架 Vue Cli,从 创建项目 到 运行项目 的过程
    • 退出之后,把刚刚创建的项目拉进VSCode,使用VSCode启动项目
  • 初始项目结构解读
    • 源代码在src下,main.js是入口
    • App.vue文件 简读
    • 关于HelloWorld.vue文件
    • 单文件组件 的含义
  • 基于工程实现TODOList案例 --- 单组件版[App.vue]
  • 基于工程实现TODOList案例 --- 父子组件版[App.vue、ListItem.vue]
  • Vue-Router部分
    • 在代码中使用Router
    • Router的作用 及 简述
    • 首先看一下App.vue根组件怎么写
    • 解析一下这个多出来的 router/index.js 文件
    • view目录下的文件
    • 例程,拓展一个Router页面
    • 补充:Router路由懒加载语法糖 简述 与例程实战
  • VueX部分
    • 首先需要创建项目
    • --- 特性配置:
    • package.json文件
    • VueX简述
    • VueX 框架的引入、数据的定义 以及 在组件中的使用
    • 在Home.vue中 使用这个 VueX提供的 全局数据字段:
    • 如何在任一组件中 修改 VueX的 数据
    • VueX的异步操作 同步操作
    • 带参数地 修改VueX数据
    • VueX修改数据 流程设计的理解
    • 安装、使用axios发送ajax请求
    • 把上例的axios请求 封装到 actions中


VueCli部分

首先需要安装nodejs

参考博客:
--- Install Node.js
--- Node.js 安装配置


安装完node会自动配套npm


使用npm install nrm -g用于调整 镜像源,方便后续下载依赖

安装完了注意,
C:\Users\凌川江雪\AppData\Roaming\npm\nrm -> C:\Users\凌川江雪\AppData\Roaming\npm\node_modules\nrm\cli.js乃是依赖的安装代码路径;

nrm ls可以切换镜像源:

其他命令如图,安装后自然可以看到;

安装后使用时,你可能遇到这个问题:

D:\OK\nodejsOther>nrm ls
internal/validators.js:124
   throw new ERR_INVALID_ARG_TYPE(name, 'string', value);
   ^

[TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type >string. Received undefined
 at validateString (internal/validators.js:124:11)
 at Object.join (path.js:375:7)
 at Object.<anonymous> (C:\Users\凌川江雪>\AppData\Roaming\npm\node_modules\nrm\cli.js:17:20)
 at Module._compile (internal/modules/cjs/loader.js:1063:30)
 at Object.Module._extensions..js (internal/modules/cjs/loader.js:1092:10)
 at Module.load (internal/modules/cjs/loader.js:928:32)
 at Function.Module._load (internal/modules/cjs/loader.js:769:14)
 at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:72:12)
 at internal/main/run_main_module.js:17:47
] {
 code: 'ERR_INVALID_ARG_TYPE'
}

解决方案参考——nrm报错 [ERR_INVALID_ARG_TYPE] 解决方法


这边使用淘宝镜像


npm uninstall vue-cli -g 检查并清除 多余的旧版本


使用npm install -g @vue/cli[@版本号]安装 脚手架

脚手架沉淀了许多最佳实践,
可以借助它快速生成Vue工程,包括 项目目录组织、webpack打包配置等;


使用 脚手架 Vue Cli,从 创建项目 到 运行项目 的过程

命令:vue create [项目名]
vue create demo-pro
运行创建命令之后,工具会询问创建方式:

这里先选第三个,手动选择创建项目需要的特性,
接着,进入选择特性界面:
用空格进行选择,回车进行确定,
这里选择以上三个特性即可,然后回车:
选择3.x的Vue版本,回车,选择使用ESLint的方式:
这里选择第一个,出错的时候才会触发;
回车确定;

这里是选择Lint的校验时机——保存时校验还是commit时校验,
这里先选择第一个,回车确定;

这里是选择要把config文件,放一个单独的文件里,还是放一个package.json里,
这里先选第一个;

最后问,刚刚这一套特性的选择需不需要保存下来方便后续使用,这里不保存;
回车后工程开始创建:

工程创建完成:
进入工程目录,
使用npm run serve启动工程:
启动中:
启动成功,开始运行:
使用浏览器访问:
cmd处ctrl + c两次可以终止运行:


退出之后,把刚刚创建的项目拉进VSCode,使用VSCode启动项目

因为我们无需每次都用cmd去启动项目;

把刚刚创建的项目拉进VSCode,准备使用VSCode启动项目:
在VS Code中,使用Terminal栏启动即可,方便快捷!
【刚拉进来可能启动不了,报9009之类的错,
这时候重启一下VSCode就是了;
如果项目中没有node_modules
则需先运行npm install安装node_modules依赖!!】
运行成功:


初始项目结构解读

注意要在VS code中安装vetur这个插件,
使得VS可以提供 语法高亮、提示 等效果:

源代码在src下,main.js是入口

--- import { createApp } from 'vue'
指明createApp的来源;
--- import App from './App.vue'
指明App实例,来自于当前文件夹下的 App.vue文件;
--- createApp(App).mount('#app')
创建实例、挂载实例:


App.vue文件 简读

--- <template>标签对的内容,
其实就等价于之前在组件实例中写的template:键模板;

--- <script>和<style>标签对自然就是js和样式的“根据地了”;

--- 其中<script>中的 name指定了根组件实例名,
component这里引入了一个子组件HelloWorld,
子组件从import HelloWorld from './components/HelloWorld.vue'
可以看出其定义的地方,即 components文件夹目录下的HelloWorld.vue

<template>
  <img alt="Vue logo" src="./assets/logo.png">
  <HelloWorld msg="Welcome to Your Vue.js App"/>
</template>

<script>
import HelloWorld from './components/HelloWorld.vue'

export default {
  name: 'App',
  components: {
    HelloWorld
  }
}
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>


关于HelloWorld.vue文件

看了一下结构,其实也没什么特殊的了,
跟上面App.vue的结构大体都是一样的:

<template>
  <div class="hello">
    <h1>{{ msg }}</h1>
    <p>
      For a guide and recipes on how to configure / customize this project,<br>
      check out the
      <a href="https://cli.vuejs.org" target="_blank" rel="noopener">vue-cli documentation</a>.
    </p>
    <h3>Installed CLI Plugins</h3>
    <ul>
      <li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-babel" target="_blank" rel="noopener">babel</a></li>
      <li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-eslint" target="_blank" rel="noopener">eslint</a></li>
    </ul>
    <h3>Essential Links</h3>
    <ul>
      <li><a href="https://vuejs.org" target="_blank" rel="noopener">Core Docs</a></li>
      <li><a href="https://forum.vuejs.org" target="_blank" rel="noopener">Forum</a></li>
      <li><a href="https://chat.vuejs.org" target="_blank" rel="noopener">Community Chat</a></li>
      <li><a href="https://twitter.com/vuejs" target="_blank" rel="noopener">Twitter</a></li>
      <li><a href="https://news.vuejs.org" target="_blank" rel="noopener">News</a></li>
    </ul>
    <h3>Ecosystem</h3>
    <ul>
      <li><a href="https://router.vuejs.org" target="_blank" rel="noopener">vue-router</a></li>
      <li><a href="https://vuex.vuejs.org" target="_blank" rel="noopener">vuex</a></li>
      <li><a href="https://github.com/vuejs/vue-devtools#vue-devtools" target="_blank" rel="noopener">vue-devtools</a></li>
      <li><a href="https://vue-loader.vuejs.org" target="_blank" rel="noopener">vue-loader</a></li>
      <li><a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">awesome-vue</a></li>
    </ul>
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  props: {
    msg: String
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h3 {
  margin: 40px 0 0;
}
ul {
  list-style-type: none;
  padding: 0;
}
li {
  display: inline-block;
  margin: 0 10px;
}
a {
  color: #42b983;
}
</style>


单文件组件 的含义

顾名思义,即一个组件就代表了一个组件,
如上的App.vueHelloWorld.vue都是单文件组件;
单独一个文件内容,就是完整的 HTML(<template>) + CSS(<style>) + JS(<script>)结构了;


基于工程实现TODOList案例 --- 单组件版[App.vue]

<template>
  <div>
    <input v-model="inputValue" />
    <button class="button" @click="handleAddItem">提交</button>
  </div>
  <ul>
    <li v-for="(item, index) in list" :key="index">
      {{ item }}
    </li>
  </ul>
</template>

<script>
import { reactive, ref
 } from "vue";

export default {
  name: "App",
  setup() {
    const inputValue = ref("");
    const list = reactive([]);

    const handleAddItem = () => {
      list.push(inputValue.value);
      inputValue.value = "";
    };
    return { list, inputValue, handleAddItem };
  },
};
</script>

<style>
  .button {
    margin-left: 20px;
  }
</style>

运行效果:


基于工程实现TODOList案例 --- 父子组件版[App.vue、ListItem.vue]

首先需要创建一个子组件单文件:


其代码:

<template>
  <div class="hello">
    <li>{{ msg }}</li>
  </div>
</template>

<script>
export default {
  name: 'ListItem',
  props: {
    msg: String
  }
}
</script>

<style>
</style>

App.vue:
与上例 主要区别就是在<script>中引入,
在<template>中修改:

<template>
  <div>
    <input v-model="inputValue" />
    <button class="button" @click="handleAddItem">提交</button>
  </div>
  <ul>
    <list-item v-for="(item, index) in list" :key="index" :msg="item" />
  </ul>
</template>

<script>
import { reactive, ref } from "vue";
import ListItem from "./components/ListItem.vue";

export default {
  name: "App",
  components: { ListItemListItem },
  setup() {
    const inputValue = ref("");
    const list = reactive([]);

    const handleAddItem = () => {
      list.push(inputValue.value);
      inputValue.value = "";
    };
    return { list, inputValue, handleAddItem };
  },
};
</script>

<style>
.button {
  margin-left: 20px;
}
</style>

运行效果同上例;


Vue-Router部分

创建带router的项目


选择特性的时候要选上Router:
这里暂时不选history mode,会使用 hash Router,
适配会简单些:
其他配置:


在代码中使用Router

创建好工程项目后,同样把它拉到VScode里面,
可以看到这里的目录,
可以看到main.js中,多了一个.use(router)


Router的作用 及 简述

作用:根据url的不同,展示不同的内容;

如下,运行项目,默认urlhttp://localhost:8080/#/,展示主页(Home页):

编写url——http://localhost:8080/#/about访问,则展示about页:


首先看一下App.vue根组件怎么写

<template>
  <div id="nav">
    <router-link to="/">Home</router-link> |
    <router-link to="/about">About</router-link>
  </div>
  <router-view/>
</template>

<style>
</style>

--- router-link是定义 跳转路由的标签,
to属性可以配置url尾部参数【前部 自动补上 网站根地址】,
标签内容配置显示的内容;
点击标签内容,即跳转到,to补全url 指向的页面!!
如果有写<router-view/>,则不跳转,乃显示在<router-view/>中;

--- <router-view/>则是
根据router-link以及网页url组成的url路由
router/index.js 文件中的 路由对象(如下一节的routes)里,
找到对应的组件路由属性,拿到对应的组件文件路径
view目录中找到 对应的组件 去显示!


解析一下这个多出来的 router/index.js 文件

import { createRouter, createWebHashHistory } from 'vue-router'
import Home from '../views/Home.vue'

const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home
  },
  {
    path: '/about',
    name: 'About',
    // route level code-splitting
    // this generates a separate chunk (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
  }
]

const router = createRouter({
  history: createWebHashHistory(),
  routes
})

export default router

--- createRouter是vue-router的一个函数,用于创建和初始化Router;
同时这里第二个参数 使用了路由参数routes

--- 注意 定义routes参数这里,
path定义 路径、name定义 名称、component进行 组件的引入;
routers里的组件既称之为component
也称之为view,子组件的单文件都放在view文件夹下;


view目录下的文件

-- 可以看到Home.vue这里其实引用一个HelloWorld子组件:


例程,拓展一个Router页面

  • 首先App.vue添加 router-link:
  • views目录下创建 单文件组件:
  • router/index.js 的Object Array中,定义一个对应的路由元素:

完事,运行,点击Heheda,效果:


补充:Router路由懒加载语法糖 简述 与例程实战

如上例程中,router/index.js 中的这个写法,
component 这里使用了 import的方式 引入了组件,
这是一种懒加载、异步加载(如模板注释:lazy-loaded)的方式,
即当网页跳到这一页的时候,才会加载对应的资源文件,否则不加载;

而如 Home页的加载方式,
则是普通的常规加载:

所以,
--- 异步加载的方式:
首页打开会快点,节省不必要的资源占用,
但是在切换到懒加载页面时,则需要花费一定的额外加载时间;

--- 同步加载的默认方式:
则可能 一开始打开首页等页面 会慢一些,
但是会把其他页面一开始就加载好,切换的时候会快一点;

--- 具体选择哪种方式,就根据业务需要进行选择;

...
const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home
  },
  {
    path: '/heheda',
    name: 'Heheda',
    component:  () => import(/* webpackChunkName: "about" */ '../views/Heheda.vue')
  },
  {
    path: '/about',
    name: 'About',
    // route level code-splitting
    // this generates a separate chunk (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
  }
]
...

试验,运行上个例程,之后打开浏览器测试工具:

跳到Home页,刷新页面,然后清理记录,再点击about页,
可以看到这个时候页面才加载about的资源:


VueX部分

首先需要创建项目


--- 特性配置:
老规矩,创建项目之后把项目拉进VScode启动与开发;

package.json文件


VueX简述

VueX 其实就是一个数据管理框架
它创建了一个全局的、唯一的数据仓库

当一个前端项目特别大的时候,
或者类似 几十个页面 同步共享 某部分数据 的场景,
我们不可能还是用props、provide、inject等语法去传递数据,
这个时候我们需要一个更加完善的数据管理方案;


VueX 框架的引入、数据的定义 以及 在组件中的使用

main.js中use它:

store /index.js创建仓库,
这里在state中准备了一个测试数据:

在Home.vue中 使用这个 VueX提供的 全局数据字段:

这里借助computed属性,
通过this.$store.state.myTestString获取到 数据字段:

<template>
  <div class="home">
    <img alt="Vue logo" src="../assets/logo.png">
    <h1>{{myTestString}}</h1>
  </div>
</template>

<script>
// @ is an alias to /src

export default {
  name: 'Home',
  computed: {
    myTestString() {
      return this.$store.state.myTestString;
    }
  }
}
</script>

运行效果:

在About.vue中也试一下:

<template>
  <div class="about">
    <h1>This is an about page</h1>
    <h1>{{myTestString}}</h1>
  </div>
</template>


<script>
export default {
  name: 'About',
  computed: {
    myTestString() {
      return this.$store.state.myTestString;
    }
  }
}
</script>

运行效果:


如何在任一组件中 修改 VueX的 数据

流程总结:
要修改数据的组件,
发起dispatch(事件) --->

store/index.jsactions
dispatch的事件 进行 监听 和回调处理,
然后发起一个commit(事件) --->

store/index.jsmutations
commit的事件 进行 监听 和回调处理,
处理逻辑中,完成对数据的修改;

--- 首先,需要在事件触发的函数里,
派发一个action,
改变数据 这里在About.vue中,
我们派testChange【这玩意是可以自定义的】的action,
this.$store.dispatch("testChange");

<template>
  <div class="about">
    <h1 @click="handleClick">This is an about page</h1>
    <h1>{{ myTestString }}</h1>
  </div>
</template>


<script>
export default {
  name: "About",
  computed: {
    myTestString() {
      return this.$store.state.myTestString;
    },
  },
  methods: {
    handleClick() {
      this.$store.dispatch("testChange");
    },
  },
};
</script>

--- 接着在store/index.jsactions里,即这个VueX全局数据仓库中,
dispatch的 监听回调处理,
store/index.js中的actions会响应任意组件的dispatch

--- 再接着,
actions里 对应的回调方法中,使用commit('自定义事件名')
触发一个mutations
store/index.js中的mutations
会响应actionscommit

--- 最后,
store/index.js中的mutations里,
actionscommit的监听回调,
在对应commit的 事件回调函数中(如testChange()),
修改数据(如this.state.myTestString = "lueluelue";)即可;

import { createStore } from 'vuex'

export default createStore({
  state: {
    myTestString: "heheda",
  },
  mutations: {
    testChange() {
      console.log("mutations --- testChange");
      this.state.myTestString = "lueluelue";
    }
  },
  actions: {
    testChange() {
      console.log("actions --- testChange");
      this.commit('testChange');
    }
  },
  modules: {
  }
})

运行:

点击文本,
可见完成了数据的修改,效果:
点击到Home页,
可见这边的数据也跟着改变了,
体现了VueX的全局特性


以上是比较完整的步骤,而如果修改数据的时候不涉及异步操作,则可以简化上述流程

即省略组件的dispatchstore的actions的步骤,
组件直接就commit,
然后回调到store的mutations,
直接修改数据:

运行效果基本同上例;


VueX的异步操作 同步操作

VueX建议在mutations中只进行立即执行的同步操作
如果要进行异步操作,必须要在actions中进行,
也就是要采用上上节的步骤 进行VueX数据的修改;

例程,首先需要组件发起dispatch:


接着在actions中进行异步操作:

import { createStore } from 'vuex'

export default createStore({
  state: {
    myTestString: "heheda",
  },
  mutations: {
    testChange() {
      console.log("mutations --- testChange");
      this.state.myTestString = "lueluelue";
    }
  },
  actions: {
    testChange() {
      setTimeout(() => {
        console.log("actions --- testChange");
        this.commit('testChange');
      }, 2000);
    }
  },
  modules: {
  }
})

运行,点击文本,两秒后文本(即背后的数据)自动改变:


带参数地 修改VueX数据

--- About.vue
dispatch时,
传递的 第一个参数为action
第二个参数为意图改动的目标数据参数

<template>
  <div class="about">
    <h1 @click="handleClick">This is an about page</h1>
    <h1>{{ myTestString }}</h1>
  </div>
</template>


<script>
export default {
  name: "About",
  computed: {
    myTestString() {
      return this.$store.state.myTestString;
    },
  },
  methods: {
    handleClick() {
      this.$store.dispatch("testChange", "xixixihehehe");
    },
  },
};
</script>

--- store/index.js:

--- actions中的 事件回调函数,自动生成两个形参,
第一个为store实例,
第二个为 组件中dispatch 传递过来的 数据参数;

--- mutations的 事件回调函数,也自动生成两个形参,
第一个为 state实例,
它的值是 以Proxy的结构存储着
回调当前事件处理函数的时刻 store 数据仓库的 状态【即 state属性】,
第二个为 actions中commit 【同步操作时,也可以是组件中的commit】
传递过来的 数据参数;

import { createStore } from 'vuex'

export default createStore({
  state: {
    myTestString: "heheda",
  },
  mutations: {
    testChange(state, str) {
      console.log("mutations --- testChange");
      console.log("mutations --- testChange --- state", state);
      state.myTestString = str;
    }
  },
  actions: {
    testChange(store, str) {
      setTimeout(() => {
        console.log("actions --- testChange");
        console.log("actions --- testChange --- store", store);
        // this.commit('testChange');
        store.commit('testChange', str);
      }, 2000);
    }
  },
  modules: {
  }
})

运行,点击文本,
两秒后字体改变,效果:


VueX修改数据 流程设计的理解

这样设计,
--- 可以把同步操作的逻辑封装在mutations中处理,
把异步操作的逻辑封装在actions中处理;

--- 又可以通过对触发事件名自定义
对特定的业务处理逻辑、修改数据代码块 做标记;

--- 如此使得项目可维护性高、可拓展性高、可读性高,
出问题时容易排查,拓展代码时也比较方便;


在setup【compositionAPI】中使用VueX

--- Home.vue:

<template>
  <div class="home">
    <img alt="Vue logo" src="../assets/logo.png" />
    <h1>{{ myTestString }}</h1>
  </div>
</template>

<script>
import { useStore } from "vuex";
export default {
  name: "Home",
  setup() {
    const store = useStore();
    const myTestString = store.state.myTestString;
    return { myTestString };
  },
};
</script>

运行效果:


使用toRefs整理上述代码
<template>
  <div class="home">
    <img alt="Vue logo" src="../assets/logo.png" />
    <h1>{{ myTestString }}</h1>
  </div>
</template>

<script>
import { toRefs } from "vue";
import { useStore } from "vuex";
export default {
  name: "Home",
  setup() {
    const store = useStore();
    const { myTestString } = toRefs(store.state);
    return { myTestString };
  },
};
</script>

运行效果同上例;


在About页中 试试 setup中修改数据

--- About.vue

<template>
  <div class="about">
    <h1 @click="handleClick">This is an about page</h1>
    <h1>{{ myTestString }}</h1>
  </div>
</template>


<script>
import { toRefs } from "vue";
import { useStore } from "vuex";
export default {
  name: "About",
  setup() {
    const store = useStore();
    const { myTestString } = toRefs(store.state);
    const handleClick = () => {
      store.commit("testChange", "xixixihehehe");
    };
    return { myTestString, handleClick };
  }
};
</script>

--- store/index.js:

import { createStore } from 'vuex'

export default createStore({
  state: {
    myTestString: "heheda",
  },
  mutations: {
    testChange(state, str) {
      console.log("mutations --- testChange");
      console.log("mutations --- testChange --- state", state);
      state.myTestString = str;
    }
  },
  modules: {
  }
})

运行,到About页,


点击文本:
Home页数据同步:


试一下 setup异步处理

--- About.vue

<template>
  <div class="about">
    <h1 @click="handleClick">This is an about page</h1>
    <h1>{{ myTestString }}</h1>
  </div>
</template>


<script>
import { toRefs } from "vue";
import { useStore } from "vuex";
export default {
  name: "About",
  setup() {
    const store = useStore();
    const { myTestString } = toRefs(store.state);
    const handleClick = () => {
      store.dispatch("testChange", "xixixihehehe");
    };
    return { myTestString, handleClick };
  }
};
</script>

--- store/index.js

import { createStore } from 'vuex'

export default createStore({
  state: {
    myTestString: "heheda",
  },
  mutations: {
    testChange(state, str) {
      console.log("mutations --- testChange");
      console.log("mutations --- testChange --- state", state);
      state.myTestString = str;
    }
  },
  actions: {
    testChange(store, str) {
      setTimeout(() => {
        console.log("actions --- testChange");
        console.log("actions --- testChange --- store", store);
        // this.commit('testChange');
        store.commit('testChange', str);
      }, 2000);
    }
  },
  modules: {
  }
})


使用axios发送ajax请求

  • 首先需要安装axios:

找到一个fastmock接口,
https://www.fastmock.site/mock/ae8e9031947a302fed5f92425995aa19/jd/api/user/register
其内容:


在About.vue中请求数据并显示:
--- 主要注意要import
--- get方法的参数为url,访问数据接口;
--- then接收 接口回复;

<template>
  <div class="about">
    <h1 @click="handleClick">This is an about page</h1>
    <h1>{{ myTestString }}</h1>
  </div>
</template>


<script>
import { toRefs } from "vue";
import { useStore } from "vuex";
import axios from "axios";
export default {
  name: "About",
  setup() {
    axios
        .get(
          "https://www.fastmock.site/mock/ae8e9031947a302fed5f92425995aa19/jd/api/user/register"
        )
        .then((response) => {
          console.log("response", response);
          const msg = response.data.desc;
          console.log("response.data.desc", msg);
        });

    const store = useStore();
    const { myTestString } = toRefs(store.state);
    const handleClick = () => {
      store.dispatch("testChange", "xixixihehehe");
    };
    return { myTestString, handleClick };
  },
};
</script>

运行效果:


把上例的axios请求 封装到 actions中

--- About.vue

<template>
  <div class="about">
    <h1 @click="handleClick">This is an about page</h1>
    <h1>{{ myTestString }}</h1>
  </div>
</template>


<script>
import { toRefs } from "vue";
import { useStore } from "vuex";
export default {
  name: "About",
  setup() {
    const store = useStore();
    const { myTestString } = toRefs(store.state);
    const handleClick = () => {
      store.dispatch("testChange", "xixixihehehe");
    };
    return { myTestString, handleClick };
  },
};
</script>

--- store/index.js

import { createStore } from 'vuex'
import axios from "axios";

export default createStore({
  state: {
    myTestString: "heheda",
  },
  mutations: {
    testChange(state, str) {
      console.log("mutations --- testChange");
      console.log("mutations --- testChange --- state", state);
      state.myTestString = str;
    }
  },
  actions: {
    testChange(store) {
      axios
        .get(
          "https://www.fastmock.site/mock/ae8e9031947a302fed5f92425995aa19/jd/api/user/register"
        )
        .then((response) => {
          console.log("response", response);
          const msg = response.data.desc;
          console.log("response.data.desc", msg);
          store.commit('testChange', msg);
        });
    }
  },
  modules: {
  }
})

运行:

点击文本,两秒后: