You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel 9+Vue 3中如何实现事件触发即时生效?

问题描述

我使用Laravel 9、Vue.js 3和Vite开发一个简单电商网站,点击「加入购物车」按钮后功能正常,但购物车图标上的数量必须刷新页面才会更新。以下是相关代码:

加入购物车组件

<template>
      <div class="flex items-center justify-between py-4">
        <button
            class=" bg-orange-700 text-black rounded-md cursor-pointer text-xs font-semibold px-3 py-2 m-4 "
            v-on:click.prevent="addToCart"
        >
            Ajouter au panier
        </button>
    </div>
</template>

<script setup >
import useProduct from '../composables/products'
import axios from 'axios';
import Emitter from 'pico-emitter';

const {add} = useProduct()
const productId = defineProps(['productId'])

const emitter = new Emitter();

const addToCart= async()=>{
    await axios.get('/sanctum/csrf-cookie');
    await axios.get('/api/user')
        .then(async(res)=>{
            let cartCount= await add(productId);
            emitter.emit('refreshCartCount',cartCount);
            console.log(cartCount)
        })
        .catch(err=>console.log(err));
}
</script>

导航栏购物车组件

<template>
        <div class="hidden space-x-8 sm:-my-px sm:ml-10 sm:flex mr-10">
        <a href="/shoppingCart" class="relative">
            <span class="absolute -top-1 left-4 rounded-full bg-indigo-700 w-5 h-5 text-xs text-white flex items-center justify-center">{{ cartCount }}</span>
            <svg xmlns="http://www.w3.org/2000/svg" class="h-7 w-7 text-sm font-medium leading-5 text-gray-600 " fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
            <path stroke-linecap="round" stroke-linejoin="round" d="M16 11V7a4 4 0 00-8 0v4M5 9h14l1 12H4L5 9z" />
            </svg>
        </a>
    </div>
</template>

<script setup>
import Emitter from 'pico-emitter';
import {onMounted,ref} from 'vue';
import useProduct from '../composables/products'; 

const {getCount}= useProduct();
const cartCount=ref(0)

const emitter = new Emitter();

emitter.on('refreshCartCount',function(count){
    cartCount.value = count
});

onMounted(async()=>{
    cartCount.value = await getCount();
    console.log(cartCount.value)
});
</script>

逻辑处理文件(composables/products.js)

import axios from "axios";

export default function useProduct(){
    const add = async(productId)=>{
        let response = await axios.post('/api/products',{  
            productId: productId
        });
        return response.data.count;
    }

    const getCount = async() =>{
        let response = await axios.get('/api/products/count');
        return response.data.count;
    }

    return {
        add,
        getCount
    }
}

问题根源与修复方案

问题核心

你代码中的两个组件各自创建了独立的Emitter实例,二者完全没有关联。加入购物车组件触发的refreshCartCount事件,导航栏组件的监听器根本接收不到,所以数量不会实时更新。

修复方法

方法1:使用全局共享的Emitter实例

创建一个全局Emitter实例,让两个组件共用:

  1. 新建emitter.js文件:
import Emitter from 'pico-emitter';
export default new Emitter();
  1. 修改加入购物车组件的script部分:
// 替换原有Emitter导入和实例化代码
import emitter from '../emitter';

const addToCart= async()=>{
    await axios.get('/sanctum/csrf-cookie');
    await axios.get('/api/user')
        .then(async(res)=>{
            let cartCount= await add(productId);
            emitter.emit('refreshCartCount',cartCount);
            console.log(cartCount)
        })
        .catch(err=>console.log(err));
}
  1. 修改导航栏组件的script部分:
// 替换原有Emitter导入和实例化代码
import emitter from '../emitter';

emitter.on('refreshCartCount',function(count){
    cartCount.value = count
});

方法2:使用Vue内置的Provide/Inject(更贴合Vue生态)

利用Vue的依赖注入传递更新逻辑:

  1. 在根组件(如App.vue)中提供全局状态和更新方法:
<script setup>
import { ref, provide, onMounted } from 'vue';
import useProduct from './composables/products';

const { getCount } = useProduct();
const cartCount = ref(0);

provide('cartCount', cartCount);
provide('updateCartCount', (newCount) => {
    cartCount.value = newCount;
});

onMounted(async () => {
    cartCount.value = await getCount();
});
</script>
  1. 修改加入购物车组件:
import { inject } from 'vue';

const updateCartCount = inject('updateCartCount');

const addToCart= async()=>{
    await axios.get('/sanctum/csrf-cookie');
    await axios.get('/api/user')
        .then(async(res)=>{
            let cartCount= await add(productId);
            updateCartCount(cartCount);
            console.log(cartCount)
        })
        .catch(err=>console.log(err));
}
  1. 修改导航栏组件:
import { inject } from 'vue';

const cartCount = inject('cartCount');

方法3:使用Pinia状态管理(推荐用于中大型项目)

购物车属于全局状态,用Pinia管理更规范:

  1. 安装Pinia:
npm install pinia
  1. 创建stores/cart.js:
import { defineStore } from 'pinia';
import axios from 'axios';

export const useCartStore = defineStore('cart', {
    state: () => ({
        count: 0
    }),
    actions: {
        async addProduct(productId) {
            const response = await axios.post('/api/products', { productId });
            this.count = response.data.count;
        },
        async fetchCount() {
            const response = await axios.get('/api/products/count');
            this.count = response.data.count;
        }
    }
});
  1. 在main.js注册Pinia:
import { createPinia } from 'pinia';
app.use(createPinia());
  1. 修改加入购物车组件:
import { useCartStore } from '../stores/cart';

const cartStore = useCartStore();

const addToCart= async()=>{
    await axios.get('/sanctum/csrf-cookie');
    await axios.get('/api/user')
        .then(async()=>{
            await cartStore.addProduct(productId);
        })
        .catch(err=>console.log(err));
}
  1. 修改导航栏组件:
import { useCartStore } from '../stores/cart';
import { onMounted } from 'vue';

const cartStore = useCartStore();

onMounted(async()=>{
    await cartStore.fetchCount();
});

模板中直接使用{{ cartStore.count }}即可。


内容的提问来源于stack exchange,提问作者Arthur

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 21:48:30