113.vue中action负责异步请求
我们来看下面的代码
countstore.js
import { defineStore } from 'pinia'
import axios from "axios"
/**
* 定义一个名为 count 的 Store
* 使用 Option Store(选项式)写法
*/
const piniaCountStore = defineStore('count', {
state(){
return {
count:10,
data:[]
}
}
,
getters:
{
getCount(state){
return "当前count的值"+state.count
},
doubleCount(state){
return this.getCount+state.count
}
},
actions:{
addCount(state){
this.count +=10
},
decrease(state){
this.count-=5
},
async getData(url){
axios.get(url).then(res =>{
this.data=res.data.banner
}).catch(error =>{
console.log(error)
})
}
}
}
)
export default piniaCountStore
app.vue中
<template> <h1>app vue</h1> <hello /> </template> <script setup> // 引入子组件 import hello from './components/hello.vue' </script> <style scoped> h1 { color: #42b983; } </style>
hello.vue
<template>
<p>hello.vue</p>
<p>原始count: {{ store.count }}</p>
<p>hello22.vue</p>
<p>双倍count: {{ store.doubleCount }}</p>
<p>{{ store.getCount }}</p>
<!-- 操作按钮 -->
<div class="btn-group">
<button @click="store.count++">+1</button>
<button @click="store.addCount">+10</button>
<button @click="store.decrease">-5</button>
</div>
<h3>网络请求的结果如下所示</h3>
<ul v-if="store.data.length">
<li v-for="(item, index) in store.data" :key="index">
<h3>{{ item.title }}</h3>
<p>{{ item.content }}</p>
<img :src="item.img" :alt="item.title" style="width: 200px; margin: 10px 0;">
</li>
</ul>
<p v-else>加载中...</p>
</template>
<script setup>
import { onMounted } from 'vue'
import piniaCountStore from '../store/countstore'
const store = piniaCountStore()
onMounted(() => {
// 使用你提供的接口地址
store.getData('http://iwenwiki.com/api/blueberrypai/getIndexBanner.php')
})
</script>
<style scoped>
p {
font-size: 18px;
}
.btn-group {
margin: 15px 0;
}
button {
margin-right: 10px;
padding: 5px 15px;
}
li {
border-bottom: 1px solid #eee;
padding: 15px 0;
}
</style>
程序运行的效果如下所示

接下来对代码进行解析,效果如下所示
你的代码整体结构是正确的,但需要确保 Pinia Store 中有对应的 datastate 和 getDataaction。根据你提供的接口文档,我来帮你完善 Store 部分:
一、完整的 countstore.js(修正版)
import { defineStore } from 'pinia'
import axios from 'axios'
export const useCountStore = defineStore('count', {
state: () => ({
count: 10,
data: [] // ✅ 必须添加这个 state 来存储接口数据
}),
getters: {
getCount: (state) => "当前count的值" + state.count,
doubleCount(state) {
return this.getCount + state.count
}
},
actions: {
increment() {
this.count++
},
decrement() {
this.count--
},
// ✅ 添加缺失的 action
addCount() {
this.count += 10
},
// ✅ 添加缺失的 action
decrease() {
this.count -= 5
},
// ✅ 添加获取数据的 action
async getData(url) {
try {
const response = await axios.get(url)
if (response.data.success) {
this.data = response.data.banner // ✅ 将接口数据存入 state
}
} catch (error) {
console.error('请求失败:', error)
// 可以在这里添加错误处理逻辑
}
}
}
})
二、你的组件代码分析(逐行点评)
✅ 做得很好的地方:
-
正确使用
onMounted:在组件挂载时调用接口 -
正确的模板语法:
v-for遍历store.data -
正确的事件绑定:按钮点击事件绑定到 store 的 actions
-
结构清晰:模板、脚本、样式分离明确
⚠️ 需要注意的小问题:
1. 重复的 count显示
<p>count: {{ store.count }}</p>
<p>count: {{ store.doubleCount }}</p>
建议改成更有意义的命名:
<p>原始count: {{ store.count }}</p>
<p>双倍count: {{ store.doubleCount }}</p>
2. 图片显示(可选增强)
接口返回的数据中有 img字段,可以添加图片显示:
<li v-for="(item,index) in store.data" :key="index">
<h3>{{ item.title }}</h3>
<p>{{ item.content }}</p>
<img :src="item.img" alt="" style="width: 200px;">
</li>
三、完整的组件代码(优化版)
<template>
<p>hello.vue</p>
<p>原始count: {{ store.count }}</p>
<p>hello22.vue</p>
<p>双倍count: {{ store.doubleCount }}</p>
<p>{{ store.getCount }}</p>
<!-- 操作按钮 -->
<div class="btn-group">
<button @click="store.count++">+1</button>
<button @click="store.addCount">+10</button>
<button @click="store.decrease">-5</button>
</div>
<h3>网络请求的结果如下所示</h3>
<ul v-if="store.data.length">
<li v-for="(item, index) in store.data" :key="index">
<h3>{{ item.title }}</h3>
<p>{{ item.content }}</p>
<img :src="item.img" :alt="item.title" style="width: 200px; margin: 10px 0;">
</li>
</ul>
<p v-else>加载中...</p>
</template>
<script setup>
import { onMounted } from 'vue'
import piniaCountStore from '../store/countstore'
const store = piniaCountStore()
onMounted(() => {
// 使用你提供的接口地址
store.getData('http://iwenwiki.com/api/blueberrypai/getIndexBanner.php')
})
</script>
<style scoped>
p {
font-size: 18px;
}
.btn-group {
margin: 15px 0;
}
button {
margin-right: 10px;
padding: 5px 15px;
}
li {
border-bottom: 1px solid #eee;
padding: 15px 0;
}
</style>
四、关键知识点总结
1. 数据流闭环
组件 mounted → 调用 store.getData() → axios 请求 → 更新 store.data → 组件自动更新
2. 为什么组件能自动更新?
-
Pinia 的 state 是 响应式 的
-
当
store.data变化时,Vue 的响应式系统会自动重新渲染模板
3. 错误处理建议
可以在 store 中添加 loading 和 error 状态:
state: () => ({
count: 10,
data: [],
loading: false,
error: null
}),
actions: {
async getData(url) {
this.loading = true
this.error = null
try {
const response = await axios.get(url)
this.data = response.data.banner
} catch (err) {
this.error = err.message
} finally {
this.loading = false
}
}
}
五、运行效果预期
页面会显示:
-
当前 count 值和计算属性
-
三个操作按钮
-
从接口获取的 4 条 banner 数据(标题、内容、图片)
-
如果数据未加载完成,显示"加载中..."
现在你的代码已经完整了! 确保 countstore.js中有我上面添加的 data: []和 getDataaction,然后运行项目,你应该能看到接口返回的数据正确显示在页面上。👍
如果遇到跨域问题,记得在 vite.config.js中配置代理(参考我之前的回答)。需要我帮你配置代理吗?
在 Vue 3 项目中安装和使用 Axios,按以下步骤操作即可:
一、安装 Axios(核心步骤)
在项目根目录(有 package.json的目录)下,打开终端执行:
✅ 使用 npm(最常用)
npm install axios
✅ 使用 yarn
yarn add axios
✅ 使用 pnpm
pnpm add axios
安装完成后,你可以在 package.json的 dependencies中看到:
"dependencies": {
"axios": "^1.x.x",
"vue": "^3.x.x"
}
二、在 Vue 组件中直接使用(入门)
安装后,在 .vue文件中直接引入使用:
<template>
<div>
<p>数据:{{ data }}</p>
<button @click="fetchData">获取数据</button>
</div>
</template>
<script setup>
import { ref } from 'vue'
import axios from 'axios'
const data = ref('')
const fetchData = async () => {
try {
const res = await axios.get('https://api.example.com/data')
data.value = res.data
} catch (err) {
console.error(err)
}
}
</script>
三、在 Pinia 中使用 Axios(✅ 推荐做法)
结合你正在学的 Pinia,这是最标准的企业级写法:
1️⃣ 在 Store 中封装接口请求
// src/store/countstore.js
import { defineStore } from 'pinia'
import axios from 'axios'
export const useCountStore = defineStore('count', {
state: () => ({
count: 0,
list: []
}),
actions: {
// 从接口获取数据
async fetchList() {
const res = await axios.get('https://api.example.com/list')
this.list = res.data
},
// 提交数据
async incrementAsync() {
const res = await axios.post('https://api.example.com/add', {
count: this.count + 1
})
this.count = res.data.count
}
}
})
2️⃣ 在组件中调用
<script setup>
import { useCountStore } from '../store/countstore'
const store = useCountStore()
store.fetchList()
</script>
四、全局配置 Axios(进阶)
创建 Axios 实例(推荐)
// src/utils/request.js
import axios from 'axios'
const request = axios.create({
baseURL: 'https://api.example.com',
timeout: 5000
})
// 请求拦截器
request.interceptors.request.use(config => {
config.headers.Authorization = 'Bearer token'
return config
})
// 响应拦截器
request.interceptors.response.use(
res => res.data,
err => Promise.reject(err)
)
export default request
在 Store 中使用封装好的 request
import request from '../utils/request'
actions: {
async fetchList() {
this.list = await request.get('/list')
}
}
五、常见问题(新手必看)
❓ 1. 安装后还是报错 axios is not defined
✅ 检查是否忘记 import axios from 'axios'
❓ 2. 跨域问题(最常见)
浏览器控制台报错:
CORS policy: No 'Access-Control-Allow-Origin'
✅ 解决方案:
-
后端配置跨域
-
或 Vue 开发环境配置代理(
vite.config.js)
// vite.config.js
export default {
server: {
proxy: {
'/api': {
target: 'http://localhost:3000',
changeOrigin: true,
rewrite: path => path.replace(/^\/api/, '')
}
}
}
}
❓ 3. async / await 报错
✅ 确保在 actions或 onMounted中使用
六、你当前学习阶段的最佳实践 ✅
结合你正在学的 Pinia,强烈建议这样用:
|
层级 |
职责 |
|---|---|
|
组件 |
触发动作( |
|
Pinia Actions |
调用 Axios(业务逻辑) |
|
Axios |
纯数据请求 |
|
State |
存储数据 |
七、一句话总结
npm install axios安装 → 在 Pinia 的actions中调用 → 组件触发 action
八、下一步你可以学
-
✅ Axios 拦截器(统一处理 Token / Loading)
-
✅ Pinia + Axios 请求缓存
-
✅ 请求失败重试机制
-
✅ Vue 3 组合式函数封装
useRequest
如果你愿意,我可以:
-
👉 帮你把现有
countstore改成带接口的版本 -
👉 画一张「Vue → Pinia → Axios → 后端」的请求流程图
-
👉 模拟一个 Mock 接口让你练手
你现在这一步,已经走到 “前后端打通” 的关键节点了 👍
posted on 2026-07-14 21:31 luzhouxiaoshuai 阅读(7) 评论(0) 收藏 举报
浙公网安备 33010602011771号