npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@v3layout/vue3-grid-layout

v1.0.4

Published

vue3 网格拖动位置及大小布局

Readme

vue3 draggable Layout

npm install @v3layout/vue3-grid-layout

使用

key 为唯一值,自定义拖动位置修改 dragType= "customdrag"

<template>
  <VGL
    class="layout"
    v-model="state.layout"
    :cols="12"
    :rowHeight="30"
    :width="1200"
    dragType="customdrag"
  >
    <div key="a">a</div>
    <div key="b">b</div>
    <div key="c">c</div>
  </VGL>
</template>

<script>
import VGL from "@v3layout/vue3-grid-layout";
import { defineComponent, ref } from "vue";

export default defineComponent({
  components: {
    VGL,
  },
  setup() {
    const layout = [
      { i: "a", x: 0, y: 0, w: 1, h: 2, static: true },
      { i: "b", x: 1, y: 0, w: 3, h: 2, minW: 2, maxW: 4 },
      { i: "c", x: 4, y: 0, w: 1, h: 2 },
    ];
    const state = reactive({
      layout,
    });
    return {
      state,
    };
  },
});
</script>

您也可以选择直接在子对象上设置布局属性:

<template>
  <GridLayout class="layout" :cols="12" :rowHeight="30" :width="1200">
    <div key="a" :data-grid="{ x: 0, y: 0, w: 1, h: 2, static: true }">
      a
    </div>
    <div key="b" :data-grid="{ x: 1, y: 0, w: 3, h: 2, minW: 2, maxW: 4 }"">
      b
    </div>
    <div key="c" :data-grid="{ x: 4, y: 0, w: 1, h: 2 }">
      c
    </div>
  </GridLayout>
</template>

<script>
import VGL from "@v3layout/vue3-grid-layout";
import { defineComponent, ref } from 'vue';

export default defineComponent({
  components: {
    VGL
  }
});
</script>

响应使用

要使 VGL 响应,请使用“”元素:

<template>
  <ResponsiveGridLayout
    class="layout"
    :layouts="state.layouts"
    :breakpoints="{ lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0 }"
    :cols="{ lg: 12, md: 10, sm: 6, xs: 4, xxs: 2 }"
  >
    <div
      v-for="(l, i) in state.layouts.lg"
      :key="i + 1"
      :class="{ static: l.static }"
    >
      <span
        v-if="l.static"
        class="text"
        title="This item is static and cannot be removed or resized."
      >
        Static - {{ i }}
      </span>
      <span v-else class="text">{{ i }}</span>
    </div>
  </ResponsiveGridLayout>
</template>

<script>
import { Responsive as ResponsiveGridLayout } from "@v3layout/vue3-grid-layout";
import { defineComponent, ref } from "vue";

export default defineComponent({
  components: {
    VGL,
  },
  setup() {
    const generateLayout = () => {
      return Array.from({ length: 10 }, (item, i) => {
        const y = Math.ceil(Math.random() * 4) + 1;
        return {
          x: Math.round(Math.random() * 5) * 2,
          y: Math.floor(i / 6) * y,
          w: 2,
          h: y,
          i: (i + 1).toString(),
          static: Math.random() < 0.05,
        };
      });
    };
    const state = {
      layouts: { lg: generateLayout() },
    };
    return {
      state,
    };
  },
});
</script>

在响应模式下,您应该通过“layouts”属性提供至少一个断点。

使用“布局”时,最好提供尽可能多的断点,尤其是最大的断点。 如果提供了最大值,VGL 将尝试插值其余值。

您还需要提供一个“宽度”,当使用“”时,建议您使用 HOC `WidthProvider”按照以下说明。

可以通过个人的“数据网格”属性提供默认映射 项目,以便在布局插值中考虑它们。

Providing Grid Width

”和“”都使用“宽度”来计算 拖动事件上的位置。在简单情况下,HOC“宽度提供者”可用于自动确定 初始化时的宽度和窗口大小调整事件。

<template>
  <ResponsiveGridLayout
    class="layout"
    :layouts="state.layouts"
    :breakpoints="{ lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0 }"
    :cols="{ lg: 12, md: 10, sm: 6, xs: 4, xxs: 2 }"
  >
    <div
      v-for="(l, i) in state.layouts.lg"
      :key="i + 1"
      :class="{ static: l.static }"
    >
      <span
        v-if="l.static"
        class="text"
        title="This item is static and cannot be removed or resized."
      >
        Static - {{ i }}
      </span>
      <span v-else class="text">{{ i }}</span>
    </div>
  </ResponsiveGridLayout>
</template>

<script>
import { Responsive, WidthProvider } from "@v3layout/vue-grid-layout";
import { defineComponent, ref } from "vue";

const ResponsiveGridLayout = WidthProvider(Responsive);

export default defineComponent({
  components: {
    VGL,
  },
  setup() {
    const generateLayout = () => {
      return Array.from({ length: 10 }, (item, i) => {
        const y = Math.ceil(Math.random() * 4) + 1;
        return {
          x: Math.round(Math.random() * 5) * 2,
          y: Math.floor(i / 6) * y,
          w: 2,
          h: y,
          i: (i + 1).toString(),
          static: Math.random() < 0.05,
        };
      });
    };
    const state = {
      layouts: { lg: generateLayout() },
    };
    return {
      state,
    };
  },
});
</script>

如果您需要更复杂的逻辑,这允许您轻松地用自己的 Provider HOC 替换“WidthProvider”。

`WidthProvider 接受单个道具“measureBeforeMount”。如果为“true”,则“WidthProvider”将测量 安装儿童之前的集装箱宽度。如果您想完全消除任何调整大小的动画,请使用此功能 在应用程序/组件安装时。

Grid Layout Props

VGL 支持以下属性(详见源代码):

//
// 基础属性
//

// 宽度
width: number,

// 是否自定大小
autoSize?: boolean = true,

// 列数
cols?: number = 12,

// 取消文字
draggableCancel?: string = '',

// A CSS selector for tags that will act as the draggable handle.
// For example: draggableHandle:'.MyDragHandleClassName'
// If you forget the leading . it will not work.
draggableHandle?: string = '',

// Compaction type.
compactType?: ('vertical' | 'horizontal' | null) = 'vertical';

// 布局属性
layout?: Array<{i?: string, x: number, y: number, w: number, h: number}> = null, // If not provided, use data-grid props on children

// 间距属性
margin?: [number, number] = [10, 10],

// 内间距属性
containerPadding?: [number, number] = margin,

// 高度
rowHeight?: number = 150,

// Configuration of a dropping element. Dropping element is a "virtual" element
// which appears when you drag over some element from outside.
// It can be changed by passing specific parameters:
//  i - id of an element
//  w - width of an element
//  h - height of an element
droppingItem?: { i: string, w: number, h: number }

//
// Flags
//
isDraggable?: boolean = true,
isResizable?: boolean = true,
isBounded?: boolean = false,
// Uses CSS3 translate() instead of position top/left.
// This makes about 6x faster paint performance
useCSSTransforms?: boolean = true,
// If parent DOM node of ResponsiveVueGridLayout or VueGridLayout has "transform: scale(n)" css property,
// we should set scale coefficient to avoid render artefacts while dragging.
transformScale?: number = 1,

// If true, grid can be placed one over the other.
// If set, implies `preventCollision`.
allowOverlap?: boolean = false,

// If true, grid items won't change position when being
// dragged over. If `allowOverlap` is still false,
// this simply won't allow one to drop on an existing object.
preventCollision?: boolean = false,

// If true, droppable elements (with `draggable={true}` attribute)
// can be dropped on the grid. It triggers "onDrop" callback
// with position and event object as parameters.
// It can be useful for dropping an element in a specific position

isDroppable?: boolean = false,
// Defines which resize handles should be rendered.
// Allows for any combination of:
// 's' - South handle (bottom-center)
// 'w' - West handle (left-center)
// 'e' - East handle (right-center)
// 'n' - North handle (top-center)
// 'sw' - Southwest handle (bottom-left)
// 'nw' - Northwest handle (top-left)
// 'se' - Southeast handle (bottom-right)
// 'ne' - Northeast handle (top-right)
//
resizeHandles?: Array<'s' | 'w' | 'e' | 'n' | 'sw' | 'nw' | 'se' | 'ne'> = ['se'],

// class to the `draggableCancel` prop.
resizeHandle?: VNode
  | ((
      resizeHandleAxis: ResizeHandleAxis,
      ref: VueRef<HTMLElement>
    ) => VNode)

//
// Callbacks
//

// Callback so you can save the layout.
// Calls back with (currentLayout) after every drag or resize stop.
onLayoutChange: (layout: Layout) => void,

//
// All callbacks below have signature (layout, oldItem, newItem, placeholder, e, element).
// 'start' and 'stop' callbacks pass `undefined` for 'placeholder'.
//
type ItemCallback = (layout: Layout, oldItem: LayoutItem, newItem: LayoutItem,
                     placeholder: LayoutItem, e: MouseEvent, element: HTMLElement) => void,

// Calls when drag starts.
onDragStart: ItemCallback,
// Calls on each drag movement.
onDrag: ItemCallback,
// Calls when drag is complete.
onDragStop: ItemCallback,
// Calls when resize starts.
onResizeStart: ItemCallback,
// Calls when resize movement happens.
onResize: ItemCallback,
// Calls when resize is complete.
onResizeStop: ItemCallback,

// Calls when an element has been dropped into the grid from outside.
onDrop: (layout: Layout, e: Event, item?: LayoutItem) => void,
// Calls when an element is being dragged over the grid from outside as above.
// This callback should return an object to dynamically change the droppingItem size
// Return false to short-circuit the dragover
onDropDragOver: (e: DragEvent) => { w?: number; h?: number } | false;

// Ref for getting a reference for the grid's wrapping div.
innerRef?: Ref<"div">

Responsive Grid Layout Props

可以改用响应式网格布局。它支持上述所有道具,除了“布局”。 新属性和更改如下:

// {name: pxVal}, e.g. {lg: 1200, md: 996, sm: 768, xs: 480}
// Breakpoint names are arbitrary but must match in the cols and layouts objects.
breakpoints?: Object = {lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0},

// # cols -> 设置
cols?: Object = {lg: 12, md: 10, sm: 6, xs: 4, xxs: 2},


// margin (in pixels). Can be specified either as horizontal and vertical margin, e.g. `[10, 10]` or as a breakpoint -> margin map, e.g. `{lg: [10, 10], md: [10, 10], ...}.
margin: [number, number],


// containerPadding (in pixels). Can be specified either as horizontal and vertical padding, e.g. `[10, 10]` or as a breakpoint -> containerPadding map, e.g. `{lg: [10, 10], md: [10, 10], ...}.
containerPadding: [number, number],


// layouts is an object mapping breakpoints to layouts.
// e.g. {lg: Layout, md: Layout, ...}
layouts,

//
// Emit
//

// 使用断点和新#cols进行回调
onBreakpointChange: (newBreakpoint: string, newCols: number) => void,

// 回调,以便保存布局。
// 所有布局都由断点设置关键帧。
onLayoutChange: (currentLayout: Layout, allLayouts) => void,

// 宽度更改时回调,以便您可以根据需要修改布局。
onWidthChange: (containerWidth: number, margin: [number, number], cols: number, containerPadding: [number, number]) => void;

Grid Item Props

VGL 支持网格项或布局项上的以下属性。当初始化网格时, 构建布局数组(如上面的第一个示例),或将此对象附加为“数据网格”属性 每个子元素(如第二个示例)。

如果在项目上提供了“数据网格”,则它将优先于“布局”中具有相同键(“i”)的项目。

请注意,如果提供了一个网格项但不完整(缺少“x、y、w 或 h”中的一个),则会出现错误 将被抛出,以便您更正布局。

如果没有为网格项提供属性,则将生成一个宽度和高度为“1”的属性。

您可以为每个维度设置最小值和最大值。这是为了调整大小;如果调整大小,当然没有效果 已禁用。如果你的分钟和最大值重叠不正确,或者你的初始尺寸不正确,就会抛出错误 超出范围。

直接定义的任何“”属性都将优先于全局设置的选项。For 例如,如果布局具有属性“isDraggable:false”,但网格项具有道具“isDraggable:true”,则该项 将是可拖动的,即使该项标记为“static:true”。

{

  // 唯一key值
  i: string,

  // 这些都是网格单位,而不是像素
  x: number,
  y: number,
  w: number,
  h: number,
  minW?: number = 0,
  maxW?: number = Infinity,
  minH?: number = 0,
  maxH?: number = Infinity,

  // 拖动位置和拖动尺寸都需要
  static?: boolean = false,
  // 是否是要拖动位置
  isDraggable?: boolean = true,
  // 是否需要拖动尺寸
  isResizable?: boolean = true,
  // 默认情况下,控制柄仅显示在右下角(东南角).
  resizeHandles?: Array<'s' | 'w' | 'e' | 'n' | 'sw' | 'nw' | 'se' | 'ne'> = ['se']
  // 若为true且可拖动,则项目将仅在网格内移动。
  isBounded?: boolean = false
}

Grid Item Heights 和 Widths

网格项宽度基于容器和列数。网格单元高度的大小基于“rowHeight”。

请注意,具有“h=2”的项的高度n 不是具有“h=1”的项高度的两倍,除非您没有“margin”

为了使网格不参差不齐,当一个项目跨越网格单位时,它也必须跨越边距。因此,您必须为每个单位添加高度、宽度或边距。因此,实际像素高度为“(行高度h)+(边距 h(h-1)”。

例如,当“rowHeight=30”、“margin=[10,10]”和高度为 4 的单位时,计算结果为“(304)+(103)”`

如果这对您来说是个问题,请设置margin=[0,0],并在元素内容内处理元素之间的视觉间距。

License

MIT