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

基于Laravel API实现Vue拖拽卡片位置持久化方案咨询

Laravel + Vue 拖拽卡片位置持久化实现方案

1. 数据库字段补充

首先确保卡片表包含所属看板ID和排序位置字段,若已有迁移文件,可新增迁移添加字段:

// 执行命令创建迁移:php artisan make:migration add_board_and_position_to_cards_table
public function up()
{
    Schema::table('cards', function (Blueprint $table) {
        $table->unsignedBigInteger('board_id');
        $table->integer('position')->default(0);
        
        // 关联看板表外键
        $table->foreign('board_id')->references('id')->on('boards')->onDelete('cascade');
    });
}

public function down()
{
    Schema::table('cards', function (Blueprint $table) {
        $table->dropForeign(['board_id']);
        $table->dropColumn(['board_id', 'position']);
    });
}

执行迁移生效:php artisan migrate

2. Laravel API 实现

路由定义

在routes/api.php中添加更新卡片位置的路由:

use App\Http\Controllers\CardController;

Route::put('/cards/{card}/position', [CardController::class, 'updatePosition']);

控制器方法

在CardController中实现位置更新逻辑:

public function updatePosition(Request $request, Card $card)
{
    // 参数验证
    $request->validate([
        'board_id' => 'required|exists:boards,id',
        'position' => 'required|integer|min:0'
    ]);

    // 更新卡片所属看板与位置
    $card->update([
        'board_id' => $request->board_id,
        'position' => $request->position
    ]);

    return response()->json($card, 200);
}

模型配置

在Card模型中设置可填充字段:

protected $fillable = ['title', 'content', 'board_id', 'position']; // 其他业务字段按需添加

3. Vue 组件中调用API保存位置

假设使用vue.draggable实现拖拽,在拖拽结束回调中发起API请求:

<template>
  <div class="boards-container">
    <div v-for="board in boards" :key="board.id" class="board">
      <h3>{{ board.name }}</h3>
      <draggable 
        v-model="board.cards" 
        @end="handleDragEnd($event, board.id)"
        group="kanban"
      >
        <div v-for="card in board.cards" :key="card.id" class="card">
          {{ card.title }}
        </div>
      </draggable>
    </div>
  </div>
</template>

<script>
import draggable from 'vuedraggable'
import axios from 'axios'

export default {
  components: { draggable },
  data() {
    return {
      boards: []
    }
  },
  mounted() {
    // 页面加载时拉取已排序的看板与卡片数据
    this.fetchBoardsWithCards()
  },
  methods: {
    async fetchBoardsWithCards() {
      const response = await axios.get('/api/boards')
      this.boards = response.data
    },
    async handleDragEnd(event, targetBoardId) {
      const draggedCard = event.item.__vue__.$data.card // 按组件实际结构获取卡片数据
      const newPosition = event.newIndex

      try {
        await axios.put(`/api/cards/${draggedCard.id}/position`, {
          board_id: targetBoardId,
          position: newPosition
        })
        // 同步本地数据
        draggedCard.board_id = targetBoardId
        draggedCard.position = newPosition
      } catch (error) {
        console.error('位置保存失败:', error)
        // 失败时回滚拖拽状态
        event.cancel()
      }
    }
  }
}
</script>

4. 确保加载时数据正确排序

在Laravel看板数据接口中,强制卡片按position升序返回:

// BoardController中获取看板及关联卡片
public function index()
{
    $boards = Board::with(['cards' => function ($query) {
        $query->orderBy('position', 'asc');
    }])->get();

    return response()->json($boards);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 04:26:18