如何在Vue.js中实现类似Google Keep的同宽异高网格拖拽功能
在Vue.js中实现类Google Keep的拖拽布局
核心思路
Google Keep的布局本质是固定列宽、自适应高度的流式拖拽网格,关键要解决拖拽时的位置计算、高度适配和平滑过渡问题,无需盲目依赖第三方库,基于原生拖拽API或轻量封装实现反而更可控。
实现步骤
1. 基础布局搭建
用CSS Grid实现固定列宽的流式布局,天然适配高度不一致的卡片:
<template> <div class="keep-container"> <div v-for="(item, index) in notes" :key="item.id" class="note-card" draggable="true" @dragstart="handleDragStart(index, $event)" @dragover.prevent @drop="handleDrop(index)" @dragend="handleDragEnd($event)" > {{ item.content }} </div> </div> </template> <style scoped> .keep-container { display: grid; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); gap: 16px; padding: 16px; } .note-card { background: #fff; border-radius: 8px; padding: 16px; box-shadow: 0 1px 3px rgba(0,0,0,0.12); cursor: grab; min-height: 100px; word-wrap: break-word; transition: transform 0.2s ease, opacity 0.2s ease; } .note-card:active { cursor: grabbing; transform: scale(1.02); } .note-card.dragging { opacity: 0.5; } </style>
2. 拖拽逻辑实现
在Vue实例中维护笔记数组,通过拖拽事件完成元素位置交换:
<script setup> import { ref } from 'vue' const notes = ref([ { id: 1, content: '这是一条短笔记' }, { id: 2, content: '这是一条很长的笔记,内容会自动撑开高度,测试一下换行效果,看看能不能自适应高度显示完全,确保文字不会溢出卡片' }, { id: 3, content: '第三条笔记' }, { id: 4, content: '第四条,再来一段长内容:Vue.js是一个渐进式JavaScript框架,用于构建用户界面。它的核心库只关注视图层,易于与其他库或现有项目集成。' } ]) let draggedIndex = null const handleDragStart = (index, e) => { draggedIndex = index e.target.classList.add('dragging') } const handleDrop = (targetIndex) => { if (draggedIndex === null || draggedIndex === targetIndex) return // 交换数组元素完成位置更新 const draggedItem = notes.value[draggedIndex] notes.value.splice(draggedIndex, 1) notes.value.splice(targetIndex, 0, draggedItem) draggedIndex = null } const handleDragEnd = (e) => { e.target.classList.remove('dragging') } </script>
3. 体验优化细节
- 添加拖拽时的半透明效果,增强视觉反馈
- 给卡片设置最小高度,避免短内容卡片过窄
- 开启文字自动换行,确保长内容不会溢出
- 拖拽过程中禁用默认
dragover行为,保证放置事件正常触发
关于第三方库的问题
多数通用拖拽库是为等高度网格设计的,对可变高度的流式布局支持不足,要么位置计算出错,要么过渡动画生硬。自己实现可完全贴合需求,只保留必要逻辑,避免冗余代码带来的体验损耗。
内容的提问来源于stack exchange,提问作者Ben Isayev
相关产品推荐
相关产品推荐

