vangleer / es-drager

A draggable, resizable, rotatable component based on vue3
https://vangleer.github.io/es-drager/
336 stars 50 forks source link

动态修改 height,无法监听到 height 变化 #57

Open luxiangqiang opened 2 months ago

luxiangqiang commented 2 months ago

描述错误

当我动态的修改 :height="height" 中的 height 时,drager 高度无变化。

重现步骤

动态的改变 height 一下。

预期行为

drager 高度会随着 height 动态的变化。

截图

image

我能确保 itemB 是响应式的,值已经确保改变了。

环境信息

其他上下文

watch( () => [props.width, props.height, props.left, props.top, props.angle], ([width, height, left, top, angle], [oldWidth, oldHeight, oldLeft, oldTop, oldAngle]) => { if (width !== oldWidth) { dragData.value.width = width } if (height !== oldHeight) { dragData.value.height = height } if (left !== oldLeft) { dragData.value.left = left } if (top !== oldTop) { dragData.value.top = top } if (angle !== oldAngle) { dragData.value.angle = angle } } )

watch( () => dragData.value, (val) => { emit('change', { ...val }) }, { deep: true } )

当我动态的改变 :height 时,在监听的 @change 中 val 返回的 height 还是初始值。

目前猜测:

1、动态改变 :height prop 时,第一个 watch 函数(监听 props)被触发。 2、这个函数更新了 dragData.value.height。 3、然后第二个 watch 函数(监听 dragData.value)被触发。 4、然而,由于 Vue 为了性能会批量更新,第二个 watch 函数中的 emit('change', { ...val }) 可能在 dragData.value 更新新的高度之前被调用。

luxiangqiang commented 2 months ago

两个 watch 可能在同一更新周期内执行,可能导致第二个 watch 在 dragData.value 实际更新之前就被调用了。

vangleer commented 2 months ago

width,height,left,top 这些属性是单向的,需要监听change事件得到最新的位置信息赋值给itemB即可

luxiangqiang commented 2 months ago

width,height,left,top 这些属性是单向的,需要监听change事件得到最新的位置信息赋值给itemB即可

我已经在 onResize (横向缩放的时候)里动态的去改变了 itemB.height 的值,我为何还要在 change 中改变 itemB.height 呢?

luxiangqiang commented 2 months ago

width,height,left,top 这些属性是单向的,需要监听change事件得到最新的位置信息赋值给itemB即可

我已经在 onResize (横向缩放的时候)里动态的去改变了 itemB.height 的值,我为何还要在 change 中改变 itemB.height 呢?

正常的操作就是我动态改变了 itemB.height 的值,你的组件高度会随着这个值的大小而改变才对,每次 change 出来的高度值,都是我更新之前的值,并不是最新的值。

luxiangqiang commented 2 months ago

width,height,left,top 这些属性是单向的,需要监听change事件得到最新的位置信息赋值给itemB即可

我已经在 onResize (横向缩放的时候)里动态的去改变了 itemB.height 的值,我为何还要在 change 中改变 itemB.height 呢?

正常的操作就是我动态改变了 itemB.height 的值,你的组件高度会随着这个值的大小而改变才对,每次 change 出来的高度值,都是我更新之前的值,并不是最新的值。

image

看我打印的 log 日志,onResize 中我动态改变 itemB.height 值,change 中打印 dragData.height 的值,其中只有两次打印的正确,其他的 change 打印的值都是我初始化的值 71.72 ,所以很奇怪,而且视图中的高度也没有更新。

luxiangqiang commented 2 months ago

width,height,left,top 这些属性是单向的,需要监听change事件得到最新的位置信息赋值给itemB即可

你直接监听 props 中的 width,height,left,top 然后更新视图中的样式不就可以了,为何还要借助 dragerData + watch 的方式间接更新呢?

vangleer commented 2 months ago

如果itemB是响应式的修改高度就没问题

<template>
  <el-button @click="handleChangeSize(list[1])">修改高度</el-button>
  <Drager
    v-for="item in list"
    v-bind="item"
    @resize="onChange(item, $event)"
  >{{ item.height }}</Drager>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import Drager from 'es-drager/index'

const list = ref([
  { left: 100, top: 100, width: 100, height: 100 },
  { left: 200, top: 200, width: 100, height: 100 },
])

function handleChangeSize(item: any) {
  item.height = 200
}

function onChange(item: any, data: any) {
  Object.keys(item).forEach(key => {
    item[key] = data[key]
  })
}
</script>

image

luxiangqiang commented 2 months ago

如果itemB是响应式的修改高度就没问题

<template>
  <el-button @click="handleChangeSize(list[1])">修改高度</el-button>
  <Drager
    v-for="item in list"
    v-bind="item"
    @resize="onChange(item, $event)"
  >{{ item.height }}</Drager>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import Drager from 'es-drager/index'

const list = ref([
  { left: 100, top: 100, width: 100, height: 100 },
  { left: 200, top: 200, width: 100, height: 100 },
])

function handleChangeSize(item: any) {
  item.height = 200
}

function onChange(item: any, data: any) {
  Object.keys(item).forEach(key => {
    item[key] = data[key]
  })
}
</script>

image

<template>
  <div class="container">
    <Drager v-for="item in list" v-bind="item" @resize="onResize(item, $event)" @change="onChange(item, $event)">{{ item.height }}</Drager>
  </div>
</template>

<script setup lang="ts">
import { nextTick, ref } from 'vue'
import 'es-drager/lib/style.css'
import Drager from 'es-drager'

const list = ref([
  { left: 100, top: 100, width: 100, height: 100 },
  { left: 200, top: 200, width: 100, height: 100 }
])

const onResize = (item: any, data: any) => {
  console.error(item.width, data.height)
  // 这里我要做动态改变高度 每次一次的值都不一样,这里暂时固定是 200 界面的元素就会闪烁
  item.height = 200
}

function onChange(item: any, data: any) {
  console.log('height', item.height)
  Object.keys(item).forEach((key) => {
    item[key] = data[key]
  })
}
</script>

<style>
.container {
  padding: 50px;
}
</style>

你试试我这个吧,横向拖拽这个地方,change出来的高度值一直是初始值,即使我已经动态调整过了。

image
vangleer commented 2 months ago

你说的这个问题确实存在,resize的时候,鼠标按下就把当前的width和height备份了,后面进行缩放的时候都是用的这个备份去计算的,所以会有闪烁的情况

luxiangqiang commented 2 months ago

你说的这个问题确实存在,resize的时候,鼠标按下就把当前的width和height备份了,后面进行缩放的时候都是用的这个备份去计算的,所以会有闪烁的情况

你那边有空方便改吗?我现在项目中好几个地方 change 出来的值都不是最新的。

vangleer commented 2 months ago

我在想什么情况下会有在移动或缩放的时候去手动修改大小的,这种需求不常见啊

luxiangqiang commented 2 months ago

我在想什么情况下会有在移动或缩放的时候去手动修改大小的,这种需求不常见啊

我现在是在搞拖拽的文本元素换行情况,拖拽的高度需要动态根据文本换行的高度变化而变化,让高度始终包含文字。

vangleer commented 2 months ago

好的,我们这边有空看一下哈