Vue.Draggable 拖拽方向控制完整指南:axis 一个属性锁定水平与垂直拖拽
【免费下载链接】Vue.DraggableVue drag-and-drop component based on Sortable.js项目地址: https://gitcode.com/gh_mirrors/vu/Vue.Draggable
用 Vue.Draggable 做排序,最烦的往往不是"拖不动",而是"拖歪了":任务看板上你只想上下调顺序,鼠标一抖,item 就斜着跑;图片墙想横向滑动,结果上下乱窜。其实限制拖拽方向不用自己写一行鼠标事件,底层的 SortableJS 早就留好了开关——axis。
axis 属性速览:x、y、null 各管什么
axis是 SortableJS 的原生配置项,管的是"拖拽元素跟着鼠标移动时,允许往哪个方向走":
axis="y":只允许垂直方向移动,适合任务列表、菜单排序axis="x":只允许水平方向移动,适合图片墙、标签栏- 不传(等效
null):不限制,自由拖拽
Vue.Draggable 没有把 axis 单独提成 prop,但它的做法更省事:写在标签上的非 prop 属性会被原样透传给 SortableJS。这段代码回答一个问题——你在标签上写的axis是怎么进到 Sortable 里的?关键就几行,见 src/vuedraggable.js:
// 标签上的非 prop 属性(如 axis)驼峰化后并入 Sortable 的 options const attributes = Object.keys(this.$attrs).reduce((res, key) => { res[camelize(key)] = this.$attrs[key]; return res; }, {});换句话说,<draggable :axis="...">等价于直接给 Sortable 实例传axis配置,中间没有任何封装层。
一张表看懂方向配置,一套模板跑两种方向
| 想要的效果 | axis 取值 | 容器 CSS 布局 | 典型场景 |
|---|---|---|---|
| 垂直排序 | axis="y" | 块级布局或flex-direction: column | 任务列表、看板、菜单排序 |
| 水平排序 | axis="x" | display: flex(横向一行) | 图片墙、标签页、横向列表 |
| 自由拖拽 | 不传 /null | 随意 | 宫格、自由画布 |
提醒一句:axis只约束移动方向,布局仍由 CSS 决定。方向设成y但子项排成一行,落点会非常怪——两边必须对得上。
下面这段最小模板只改axis一个值就能切换两种方向,保存后刷新即可看到纵向列表,把'y'改成'x'立刻变成可横向滚动的横条:
<template> <draggable :list="items" :axis="axis" :class="axis === 'x' ? 'row' : 'col'"> <div v-for="i in items" :key="i" class="cell">{{ i }}</div> </draggable> </template> <script> export default { data() { return { axis: 'y', // 改成 'x' 试试 items: ['A', 'B', 'C', 'D', 'E', 'F'] }; } }; </script> <style scoped> .row, .col { display: flex; gap: 8px; } .col { flex-direction: column; } .row { overflow-x: auto; } .cell { flex: 0 0 auto; /* 关键:禁止子项收缩、换行 */ width: 120px; padding: 10px; background: #f0f2f5; border: 1px solid #dcdfe6; border-radius: 4px; } </style>CSS 里有两个容易忽略的点:flex: 0 0 auto保证水平排列时子项不被挤窄、不折行;overflow-x: auto让超出的横向列表能滚动。垂直方向则不用额外处理,块级默认就往下排。
动态切换 axis 的做法:方向跟着状态走
有的页面要按状态换方向,比如窄屏走纵向、宽屏走横向。思路很直接:把 axis 绑到响应式数据上,布局类名跟它同源联动。
这里有个好消息:组件内部对$attrs有深度 watch,属性一变就会调this._sortable.option(...)同步到已存在的 Sortable 实例。所以你改:axis的值即时生效,不需要销毁重建组件。
在上一节模板外再包一层,加一排切换按钮即可,跑起来点按钮就能看到列表实时改变走向:
<template> <div> <button v-for="d in ['y', 'x', null]" :key="String(d)" @click="axis = d"> {{ d === null ? '自由' : (d === 'x' ? '水平' : '垂直') }} </button> <draggable :list="items" :axis="axis" :class="axis === 'x' ? 'row' : 'col'"> <div v-for="i in items" :key="i" class="cell">{{ i }}</div> </draggable> </div> </template>💡 要点只有一条:方向和布局类名都由同一个响应式变量驱动,别写两套判断逻辑。
常见翻车现场与修复清单
| 现象 | 大概率原因 | 修复 |
|---|---|---|
| 设了 axis 还是两个方向都能拖 | 属性名拼错(如Axis),或 CSS 布局与方向不一致 | 用:axis精确绑定;水平配 flex 横排,垂直配 column 或块级 |
| 横向列表子项被挤窄、折行 | 没禁止子项收缩 | 子项加flex: 0 0 auto+ 固定宽度,容器加overflow-x: auto |
| 长列表拖到边缘,容器不跟手自动滚动 | 没开 SortableJS 的自动滚动 | 透传:scroll="true"、:scroll-sensitivity="50"、:scroll-speed="10" |
| 动态改 axis 没反应 | 写成静态字符串axis="y",只在初始化生效一次 | 改成:axis绑定响应式数据;确认值只能是'x'/'y'或不传 |
最后一行的补充:改完值后若 DOM 上的属性纹丝不动,先看是不是少了冒号——静态属性只在初始化时生效一次,绑定属性才会随数据变化同步。
写在最后:四句话记住
- 方向限制一个
axis搞定:'y'垂直、'x'水平、不传即自由。 - axis 管方向,CSS 管布局,两者必须同向,否则落点错乱。
- 动态切换直接
:axis绑响应式数据,组件内部会自动同步,无需重建实例。 - 滚动不跟手时,补上
scroll/scroll-sensitivity/scroll-speed三件套。
想深挖细节,仓库内这几份资料足够:核心源码 src/vuedraggable.js、官方示例 example/components/、迁移指南 与 遗留选项说明,完整 API 见 README.md。
【免费下载链接】Vue.DraggableVue drag-and-drop component based on Sortable.js项目地址: https://gitcode.com/gh_mirrors/vu/Vue.Draggable
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考