Skip to content
在这一页

移动和缩放事件

效果

源码

vue
<script setup lang="ts">
import { ref, reactive, watch } from 'vue'

import type { Layout } from 'grid-layout-plus'

const layout = reactive([
  { x: 0, y: 0, w: 2, h: 2, i: '0', static: false },
  { x: 2, y: 0, w: 2, h: 4, i: '1', static: true },
  { x: 4, y: 0, w: 2, h: 5, i: '2', static: false },
  { x: 6, y: 0, w: 2, h: 3, i: '3', static: false },
  { x: 8, y: 0, w: 2, h: 3, i: '4', static: false },
  { x: 10, y: 0, w: 2, h: 3, i: '5', static: false },
  { x: 0, y: 5, w: 2, h: 5, i: '6', static: false },
  { x: 2, y: 5, w: 2, h: 5, i: '7', static: false },
  { x: 4, y: 5, w: 2, h: 5, i: '8', static: false },
  { x: 6, y: 3, w: 2, h: 4, i: '9', static: true },
  { x: 8, y: 4, w: 2, h: 4, i: '10', static: false },
  { x: 10, y: 4, w: 2, h: 4, i: '11', static: false },
  { x: 0, y: 10, w: 2, h: 5, i: '12', static: false },
  { x: 2, y: 10, w: 2, h: 5, i: '13', static: false },
  { x: 4, y: 8, w: 2, h: 4, i: '14', static: false },
  { x: 6, y: 8, w: 2, h: 4, i: '15', static: false },
  { x: 8, y: 10, w: 2, h: 5, i: '16', static: false },
  { x: 10, y: 4, w: 2, h: 2, i: '17', static: false },
  { x: 0, y: 9, w: 2, h: 3, i: '18', static: false },
  { x: 2, y: 6, w: 2, h: 2, i: '19', static: false }
])

const eventLogs = reactive<string[]>([])

const eventsDiv = ref<HTMLElement>()

watch(
  () => eventLogs.length,
  () => {
    requestAnimationFrame(() => {
      if (eventsDiv.value) {
        eventsDiv.value.scrollTop = eventsDiv.value.scrollHeight
      }
    })
  }
)

function moveEvent(i: string, newX: number, newY: number) {
  const msg = 'MOVE i=' + i + ', X=' + newX + ', Y=' + newY
  eventLogs.push(msg)
  console.info(msg)
}

function movedEvent(i: string, newX: number, newY: number) {
  const msg = 'MOVED i=' + i + ', X=' + newX + ', Y=' + newY
  eventLogs.push(msg)
  console.info(msg)
}

function resizeEvent(i: string, newH: number, newW: number, newHPx: number, newWPx: number) {
  const msg =
    'RESIZE i=' + i + ', H=' + newH + ', W=' + newW + ', H(px)=' + newHPx + ', W(px)=' + newWPx
  eventLogs.push(msg)
  console.info(msg)
}

function resizedEvent(i: string, newX: number, newY: number, newHPx: number, newWPx: number) {
  const msg =
    'RESIZED i=' + i + ', X=' + newX + ', Y=' + newY + ', H(px)=' + newHPx + ', W(px)=' + newWPx
  eventLogs.push(msg)
  console.info(msg)
}

function containerResizedEvent(
  i: string,
  newH: number,
  newW: number,
  newHPx: number,
  newWPx: number
) {
  const msg =
    'CONTAINER RESIZED i=' +
    i +
    ', H=' +
    newH +
    ', W=' +
    newW +
    ', H(px)=' +
    newHPx +
    ', W(px)=' +
    newWPx
  eventLogs.push(msg)
  console.info(msg)
}

function layoutBeforeMountEvent(newLayout: Layout) {
  eventLogs.push('beforeMount layout')
  console.info('beforeMount layout: ', newLayout)
}

function layoutMountedEvent(newLayout: Layout) {
  eventLogs.push('Mounted layout')
  console.info('Mounted layout: ', newLayout)
}

function layoutReadyEvent(newLayout: Layout) {
  eventLogs.push('Ready layout')
  console.info('Ready layout: ', newLayout)
}

function layoutUpdatedEvent(newLayout: Layout) {
  eventLogs.push('Updated layout')
  console.info('Updated layout: ', newLayout)
}
</script>

<template>
  <div ref="eventsDiv" class="event-logs">
    <div v-for="(event, index) in eventLogs" :key="index">
      {{ event }}
    </div>
  </div>
  <div style="margin-top: 10px">
    <GridLayout
      v-model:layout="layout"
      :row-height="30"
      @layout-before-mount="layoutBeforeMountEvent"
      @layout-mounted="layoutMountedEvent"
      @layout-ready="layoutReadyEvent"
      @layout-updated="layoutUpdatedEvent"
    >
      <GridItem
        v-for="item in layout"
        :key="item.i"
        :x="item.x"
        :y="item.y"
        :w="item.w"
        :h="item.h"
        :i="item.i"
        @resize="resizeEvent"
        @move="moveEvent"
        @resized="resizedEvent"
        @container-resized="containerResizedEvent"
        @moved="movedEvent"
      >
        <span class="text">{{ item.i }}</span>
      </GridItem>
    </GridLayout>
  </div>
</template>

<style scoped>
.vgl-layout {
  background-color: #eee;
}

:deep(.vgl-item:not(.vgl-item--placeholder)) {
  background-color: #ccc;
  border: 1px solid black;
}

:deep(.vgl-item--resizing) {
  opacity: 90%;
}

:deep(.vgl-item--static) {
  background-color: #cce;
}

.text {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: auto;
  font-size: 24px;
  text-align: center;
}

.event-logs {
  height: 100px;
  padding: 10px;
  margin-top: 10px;
  overflow-y: scroll;
  background-color: #ddd;
  border: 1px solid black;
}
</style>

在 MIT 协议下发布。