dcloudio / uni-app

A cross-platform framework using Vue.js
https://uniapp.dcloud.io
Apache License 2.0
39.9k stars 3.62k forks source link

boundingClientRect当出现嵌套同一组件,获取到的尺寸信息不准确 #3385

Open chenzhili opened 2 years ago

chenzhili commented 2 years ago

问题描述 [问题描述:尽可能简洁清晰地把问题描述清楚] 当我想自实现收缩框的动画,但是对于统一个组件进行了自调的嵌套,导致获取的height 高度不准确;

复现步骤 [复现问题的步骤]

  1. 启动 '...'
  2. 点击 '....'
  3. 查看

[或者可以直接贴源代码]

// PreviewFormContainer
<template>
  <c-collapse>
    <view class="container--com">
      <grid-com
        :is="element.component"
        v-model:element="element"
        :data="data"
        :index="index"
        :models="models"
      ></grid-com>
    </view>
  </c-collapse>
</template>
<script lang="ts" setup>
import {
  Component,
  computed,
  defineComponent,
  nextTick,
  onMounted,
  Ref,
  ref,
} from 'vue'
import map2Coms from './coms/map'
import GridCom from './coms/layoutComs/GridCom.vue'

import CCollapse from './coms/externalComs/CCollapse/CCollapse.vue'
</script>
// gridCom 组件
<template>
  <view>
    <preview-form-container
          :element="col"
          :data="data"
          :models="models"
          :index="i"
        ></preview-form-container>
  </view>
</template>
<script setup lang="ts">
import PreviewFormContainer from '../../PreviewFormContainer.vue'
defineProps(['element', 'data', 'index', 'models'])
</script>

// CCollapse 组件
<template>
  <view class="c-collapse">
    <view class="c-collapse--title" @click="onClick">
      <view class="c-collapse--title__txt">
        标题
      </view>
      <uni-icons
        :class="{ 'c-collapse--icon__close': isOpen }"
        class="c-collapse--icon"
        type="top"
        size="15"
      ></uni-icons>
    </view>
    <view class="c-collapse--content" :style="style">
      <view :id="elId">
        <slot></slot>
      </view>
    </view>
  </view>
</template>

<script lang="ts">
import {
  computed,
  ref,
  getCurrentInstance,
  onMounted,
  nextTick,
  defineComponent,
} from 'vue'

export default defineComponent({
  name: 'CCollapse',
  setup() {
    const isOpen = ref(true)
    const height = ref(0)
    /* 唯一id */
    const elId = ref(`Uni_${Math.ceil(Math.random() * 10e5).toString(36)}`)

    const onClick = () => {
      isOpen.value = !isOpen.value
    }

    function getContentHeight(this: any) {
      const views = uni.createSelectorQuery().in(this)
      views
        .select(`#${elId.value}`)
        .boundingClientRect((data) => {
          console.log('========', data.height)
          height.value = data?.height as number
        })
        .exec()
    }

    const style = computed(() => {
      if (isOpen.value) {
        return {
          height: `${height.value}px`,
        }
      } else {
        return {}
      }
    })
    onMounted(() => {
      nextTick(() => {
        getContentHeight()
      })
    })

    return {
      isOpen,
      elId,
      style,

      onClick,
    }
  },
})
</script>

<style lang="scss">
.c-collapse {
  border-bottom: 1px solid #ebeef5;
  font-size: 14px;
  color: inherit;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.c-collapse--title {
  display: flex;
  align-items: center;
  justify-content: space-between;
  line-height: 48px;
}
.c-collapse--title__txt {
  color: inherit;
  font-weight: normal;
}
.c-collapse--icon {
  color: inherit;
  transform-origin: center center;
  transition: transform 0.2s ease-in-out;
  &.c-collapse--icon__close {
    transform: rotateZ(180deg);
  }
}
.c-collapse--content {
  transition: height 0.2s ease-in-out;
  overflow: hidden;
}
</style>

预期结果 [使用简洁清晰的语言描述你希望生效的预期结果] 想通过boundingClientRect 获取真实的 height 的高度做动画,当我加了style 后 就拿不真实的内部节点的高度

实际结果 [这里请贴上你的报错截图或文字] // 在未加入 style的时候拿到的高度 image

// 加了style 后 拿到的高度 image

系统信息:

补充信息 [可选] [根据你的分析,出现这个问题的原因可能在哪里?]

chenzhili commented 2 years ago

同时对应的 uni-collapse搭配uni-collapse-item时 ,对于组件 自递归也有同样的问题