我有 GridLayout,它有一个 GridItem(从 vue3-grid-layout 导入)。它们是可拖动且可调整大小的。当我移动项目或调整项目大小时(在完成时,而不是在更改期间),此组件(名为 Widget)会向父级(名为 Candidates 页面)发送所有项目的位置和大小的新值。父组件(候选人页面)有“保存”按钮,单击该按钮会调用保存函数,然后调用存储中的函数以将 POST 请求发送到 API 并更新位置和大小。这就是它应该如何工作的,这部分是有效的。
但是,当我第一次点击“保存”按钮,然后再次选择编辑网格时(这里不过多讨论逻辑,但是有一个名为 editMode 的变量,它决定了网格当时是否可以调整大小和可拖动) ),当我移动或调整网格项大小时,API 请求会不间断地发送。对于移动,它们都失败(可能是不正确的数据),但是对于调整大小,它们返回 200 OK。我不明白为什么要发送这些请求。
这些组件的外观如下:
小部件组件:
<grid-layout
:layout.sync="layout"
:col-num="colNum"
:row-height="30"
:is-draggable="editMode"
:is-resizable="editMode"
:vertical-compact="true"
:use-css-transforms="true"
>
<grid-item
v-for="item in layout"
:static="item.static"
:x="item.x"
:y="item.y"
:w="item.w"
:h="item.h"
:i="item.i"
:key="item.i"
@resized="resizedEvent"
@moved="movedEvent"
style="touch-action: none"
>
<WidgetsExtended
:edit-mode="editMode"
:index="item.i"
></WidgetsExtended>
</grid-item>
</grid-layout>
WidgetExtended 有一些表格,实际上显示在网格项中。对于这种情况并不重要。
<script setup>
import { ref } from "vue";
import { GridItem, GridLayout } from "vue3-grid-layout-next";
const emit = defineEmits(["updateLayout"]);
const props = defineProps({
editMode: {
type: Boolean,
required: false,
default: false,
},
});
const layout = ref([]);
const colNum = ref(12);
function movedEvent(i, newX, newY) {
emit("updateLayout", layout.value);
}
function resizedEvent(i, newH, newW, newHPx, newWPx) {
emit("updateLayout", layout.value);
}
</script>
候选人页面:
<template>
<div>
<Widgets
:edit-mode="editMode"
@updateLayout="updateLayout"
></Widgets>
<IconsEdit v-if="!editMode" @edit="editMode = true" />
<IconsSave v-if="editMode" @save="save" />
</div>
</template>
<script setup>
import { useCandidatesStore } from "~/stores/candidates";
const candidatesStore = useCandidatesStore();
const editMode = ref(false);
const newLayout = ref([]);
// function from store which sends API request
const { saveCandidatesLayout } = candidatesStore;
function save() {
editMode.value = false;
saveCandidatesLayout(newLayout.value);
}
function updateLayout(updatedLayout) {
newLayout.value = updatedLayout;
}
</script>
候选人商店:
import { defineStore } from "pinia";
import { useFetch } from "#app";
import { useAuthStore } from "./auth";
const baseUrl = import.meta.env.VITE_API_KEY + "/hr/";
export const useCandidatesStore = defineStore("candidates", () => {
const authStore = useAuthStore();
function saveCandidatesLayout(body) {
return useFetch(baseUrl + "layout/candidates", {
method: "POST",
headers: {
Accept: "application/json",
Authorization: "Bearer " + authStore.token,
},
body: body,
onResponse({ request, response, options }) {
// this part gets called non-stop, I tried to log everywhere and this is only part
return response._data;
},
onResponseError({ request, response, options }) {
throw showError({
statusCode: 401,
statusMessage: "Error: " + error,
fatal: true,
});
},
});
}
return {
saveCandidatesLayout
};
});
我什至尝试检查开发工具(网络选项卡)中请求是从哪里发送的。目前还不清楚,它看起来像是来自某个库,并且它的根源在于 pointMove -> move 函数。这些请求的发起者是 ofetch.d438bb6f.mjs:206 (fetch)。
我不明白的是,当没有与之相关的功能可以做到这一点时,移动或调整网格项大小如何直接发出API请求。
我发现问题了!感谢这篇文章https://github.com/nuxt/nuxt/issues/15741我意识到我正在向 useFetch 主体发送反应式属性,并且每次它发生变化时,都会重新发送请求。我刚刚使用 JSON.stringify(body) 并解决了问题。