Skip to content

v-boxresize 指令

介绍

v-boxresize 指令主要作用是监听元素的尺寸变化,并在尺寸变化时触发回调函数。

使用方法

v-boxresize 指令添加到需要支持复制功能的元素上:

vue
<template>
  <div v-boxresize="{ callback: handleResize, box: string }">Resize me!</div>
</template>

基本用法(响应式布局)

调整窗口大小试试

当前布局:大屏布局

查看代码
vue
<template>
  <div class="resize-container">
    <div v-boxresize="{ callback: onResize, box: 'content-box' }" class="resize-box">调整窗口大小试试</div>
    <p class="hint-text">当前布局:{{ layout }}</p>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import { vBoxResize } from '@cp-vuedir/core'

const layout = ref('大屏布局')

const onResize = (rect: DOMRectReadOnly, box: string) => {
  if (rect.width < 600) {
    layout.value = '小屏布局'
  } else {
    layout.value = '大屏布局'
  }
}
</script>

<style scoped>
.resize-container {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 80vh;
  background-color: var(--vp-c-bg-soft);
  font-family: 'Arial', sans-serif;
  padding: 20px;
}

.resize-box {
  width: 100%;
  height: 600px;
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: #42b983;
  color: white;
  font-size: 20px;
  font-weight: bold;
  border-radius: 10px;
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
  transition:
    background-color 0.3s ease,
    transform 0.3s ease;
}

.resize-box:hover {
  background-color: #369c6d;
  transform: scale(1.05);
}

.hint-text {
  margin-top: 20px;
  font-size: 18px;
  color: var(--vp-c-text-3);
  background-color: var(--vp-c-bg-soft);
  padding: 10px 20px;
  border-radius: 5px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
</style>

图表自适应

10
20
30
40
50

当前缩放比例: 1.00

查看代码
vue
<template>
  <div class="chart-wrapper">
    <div v-boxresize="{ callback: onResize }" class="chart-container">
      <div v-for="(value, index) in data" :key="index" class="bar" :style="{ height: value * scale + 'px' }">
        <span class="bar-label">{{ value }}</span>
      </div>
    </div>
    <p class="scale-text">当前缩放比例: {{ scale.toFixed(2) }}</p>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import { vBoxResize } from '@cp-vuedir/core'

const data = ref([10, 20, 30, 40, 50])
const scale = ref(1)

const onResize = (rect: DOMRectReadOnly) => {
  scale.value = rect.width / 500
}
</script>

<style scoped>
.chart-wrapper {
  width: 100%;
  height: 300px;
  border: 1px solid #ddd;
  border-radius: 10px;
  background-color: var(--vp-c-bg-soft);
  box-shadow: 0 4px 6px rgba(0, 0, 0, 1);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: space-between;
  padding: 20px;
}

.chart-container {
  display: flex;
  align-items: flex-end;
  justify-content: space-around;
  width: 100%;
  height: 80%;
  padding: 20px;
  background-color: var(--vp-c-bg);
  border-radius: 10px;
}

.bar {
  width: 40px;
  background-color: #42b983;
  margin: 0 5px;
  border-radius: 5px 5px 0 0;
  transition:
    height 0.3s ease,
    background-color 0.3s ease;
  position: relative;
}

.bar:hover {
  background-color: #369c6d;
}

.bar-label {
  position: absolute;
  bottom: -25px;
  left: 50%;
  transform: translateX(-50%);
  font-size: 14px;
  color: var(--vp-c-text-3);
  font-weight: bold;
}

.scale-text {
  margin-top: 10px;
  font-size: 16px;
  color: var(--vp-c-text-3);
  font-weight: bold;
  background-color: var(--vp-c-bg);
  padding: 10px 20px;
  border-radius: 5px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

@media (max-width: 600px) {
  .bar {
    width: 30px;
  }

  .bar-label {
    font-size: 12px;
  }

  .scale-text {
    font-size: 14px;
  }
}
</style>

自适应图片

自适应图片

自适应图片示例

查看代码
vue
<template>
  <div>
    <div v-boxresize="{ callback: onResize }" class="image-container">
      <img :src="imageUrl" :style="imageStyle" alt="自适应图片" class="responsive-image" />
      <div class="image-overlay">
        <p class="image-text">自适应图片示例</p>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import { vBoxResize } from '@cp-vuedir/core'

const imageUrl = 'https://picsum.photos/800/400?random=6'
const imageStyle = ref({})

const onResize = (rect: DOMRectReadOnly) => {
  if (rect.width < 400) {
    imageStyle.value = { width: '100%', height: 'auto' } // 小屏:宽度 100%,高度自适应
  } else {
    imageStyle.value = { width: 'auto', height: '100%' } // 大屏:高度 100%,宽度自适应
  }
}
</script>

<style scoped>
/* 图片容器样式 */
.image-container {
  width: 100%;
  height: 300px;
  border: 1px solid #ddd;
  border-radius: 10px;
  overflow: hidden;
  position: relative;
  background-color: var(--vp-c-bg-soft);
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}

/* 自适应图片样式 */
.responsive-image {
  display: block;
  transition:
    transform 0.3s ease,
    filter 0.3s ease;
}

/* 图片悬停效果 */
.image-container:hover .responsive-image {
  transform: scale(1.05);
  filter: brightness(0.8);
}

/* 图片遮罩样式 */
.image-overlay {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.5);
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  transition: opacity 0.3s ease;
}

/* 遮罩悬停效果 */
.image-container:hover .image-overlay {
  opacity: 1;
}

/* 图片文字样式 */
.image-text {
  color: white;
  font-size: 24px;
  font-weight: bold;
  text-align: center;
  text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5);
}

/* 响应式调整 */
@media (max-width: 400px) {
  .image-text {
    font-size: 18px;
    /* 小屏时字体减小 */
  }
}
</style>

改变页面元素尺寸,自适应字体大小

测试文本,根据容器宽度动态调整字体大小。

查看代码
vue
<template>
  <div v-boxresize="{ callback: onResize }" class="resize-container">
    <p :style="{ fontSize: fontSize + 'px' }" class="dynamic-text">测试文本,根据容器宽度动态调整字体大小。</p>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import { vBoxResize } from '@cp-vuedir/core'

const fontSize = ref(16)

const onResize = (rect: DOMRectReadOnly) => {
  fontSize.value = Math.max(12, rect.width / 20)
}
</script>

<style scoped>
.resize-container {
  width: 100%;
  height: 200px;
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: #42b983;
  border: 1px solid #369c6d;
  border-radius: 10px;
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}

.resize-container:hover {
  background-color: #369c6d;
}

.dynamic-text {
  color: white;
  font-weight: bold;
  text-align: center;
  text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
}

@media (max-width: 600px) {
  .dynamic-text {
    font-size: 18px !important;
  }
}
</style>

表单自适应

列 1列 2列 3
数据 1数据 2数据 3
数据 4数据 5数据 6
数据 7数据 8数据 9
查看代码
vue
<template>
  <div v-boxresize="{ callback: onResize }" class="table-container">
    <table class="dynamic-table">
      <thead>
        <tr>
          <th :style="{ width: columnWidths[0] + 'px' }">列 1</th>
          <th :style="{ width: columnWidths[1] + 'px' }">列 2</th>
          <th :style="{ width: columnWidths[2] + 'px' }">列 3</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>数据 1</td>
          <td>数据 2</td>
          <td>数据 3</td>
        </tr>
        <tr>
          <td>数据 4</td>
          <td>数据 5</td>
          <td>数据 6</td>
        </tr>
        <tr>
          <td>数据 7</td>
          <td>数据 8</td>
          <td>数据 9</td>
        </tr>
      </tbody>
    </table>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import { vBoxResize } from '@cp-vuedir/core'

const columnWidths = ref([100, 150, 200]) // 初始列宽

const onResize = (rect: DOMRectReadOnly) => {
  const totalWidth = rect.width
  columnWidths.value = [totalWidth * 0.3, totalWidth * 0.4, totalWidth * 0.3]
}
</script>

<style scoped>
.table-container {
  width: 100%;
  overflow-x: auto;
  border: 1px solid var(--vp-c-text-1);
  background-color: var(--vp-c-bg-soft);
  color: var(--vp-c-text-1);
}

.dynamic-table {
  width: 100%;
  border-collapse: collapse;
}

.dynamic-table th {
  background-color: var(--vp-c-bg-1);
  font-weight: bold;
  padding: 12px;
  text-align: left;
  border-bottom: 2px solid var(--vp-c-text-1);
}

.dynamic-table td {
  padding: 10px;
  border-bottom: 1px solid #ddd;
}

.dynamic-table tr:hover {
  background-color: #f5f5f5;
}

@media (max-width: 600px) {
  .dynamic-table th,
  .dynamic-table td {
    padding: 8px;
  }
}
</style>

API

属性名说明类型是否必选默认值
callback
页面尺寸变化时的回调函数
(rect: DOMRectReadOnly, box?: string) => void
null
box
盒模型类型
string
content-box

注意事项

提示

  • v-resize 指令在页面加载时不会立即触发回调函数,只有在元素尺寸发生变化时才会触发。
  • 上面示例中都需要改变浏览器窗口大小才能触发回调函数,看到具体效果。

注意浏览器兼容

  • 需要浏览器支持 ResizeObserver API
  • 对于box属性,不同浏览器对盒模型的支持可能有所不同,这里默认使用的是 content-box,如果需要使用其他盒模型,请根据实际情况添加box API
  • 可支持的盒模型类型有:border-box | content-box | device-pixel-content-box