vue3+ts 动态获取组件高度, 动态获取DOM结构高度

项目场景:

计算需要获取某个组件的高度, 但是组件有展开和收起两种状态, 高度不一样, 需要监视组件状态变化, 在变化高度后重新调取计算方法


解决方案:

  • 使用ResizeObserver API,帮助我们监听DOM节点的变化,这种变化包括但不仅限于:某个节点的出现和隐藏、某个节点的大小变化

1、observer =new ResizeObserver()实例, 然后绑定变化后调用的方法
2、调用ResizeObserver的方法observe(), 绑定监听的DOM结构
3、页面销毁时, 调用ResizeObserver的方法disconnect(),取消监听,防止内存泄漏

<script setup>
  import {ref,onMounted,onUnmounted} from  "vue"
   let observer: ResizeObserver | null = null;
  const searchBoxRef = ref(null)
  const handleResize = ()=>{console.log("被调用")}
  onMounted(() => {
    observer = new ResizeObserver(handleResize); //handleResize 节点变化后调用的方法
    observer.observe(searchBoxRef.value); //searchBoxRef.value 为DOM结构
  });
  onUnmounted(() => {
    // 取消监听
    observer&&observer.disconnect()
  });
</script>

 
<think>我们正在解决的是:在Vue 3和TypeScript环境下,如何获取组件实例并调用子组件中的方法。 根据引用[1]、[3]、[5]的内容,我们可以总结出两种主要方法: 1. 使用模板引用(ref)直接获取组件实例,然后调用其暴露的方法。 2. 通过自定义事件(emit)由子组件向父组件传递信息,但这种方法不直接获取实例,而是通过事件触发。 然而,用户的问题明确要求获取组件实例并使用子组件中的方法,因此我们重点介绍第一种方法(模板引用)。 步骤: 1. 在父组件中,使用`ref`函数创建一个引用变量,并通过泛型或`InstanceType`指定子组件的类型,以确保类型安全。 2. 在子组件中,使用`defineExpose`暴露需要被父组件调用的方法或属性。 3. 在父组件的模板中,将子组件的`ref`属性绑定到之前创建的引用变量。 4. 在父组件中,通过引用变量的`value`属性访问子组件实例,并调用其方法。 注意:在Composition API和`<script setup>`语法中,引用变量在模板中绑定后,其值会在子组件挂载后自动更新。 引用[3]和[5]提供了示例代码,但引用[3]中使用了`ref<any>()`,这会导致失去类型检查。我们应该使用`InstanceType<typeof ChildComponent>`来获得更好的类型安全。 下面我们提供一个完整的示例,包括类型安全的处理。 示例代码: 子组件(ChildComponent.vue): 使用`defineExpose`暴露方法。 ```vue <script setup lang="ts"> import { ref } from &#39;vue&#39;; // 子组件的数据 const message = ref<string>(&#39;Hello from child!&#39;); // 子组件的方法 const doSomething = (param: string) => { console.log(param); message.value = param; }; // 暴露方法给父组件 defineExpose({ doSomething, message }); </script> <template> <div>{{ message }}</div> </template> ``` 父组件(ParentComponent.vue): 使用模板引用并指定类型。 ```vue <template> <button @click="callChildMethod">调用子组件方法</button> <ChildComponent ref="childRef" /> </template> <script setup lang="ts"> import { ref } from &#39;vue&#39;; import ChildComponent from &#39;./ChildComponent.vue&#39;; // 创建引用变量,并指定类型为子组件的实例类型 const childRef = ref<InstanceType<typeof ChildComponent> | null>(null); const callChildMethod = () => { if (childRef.value) { // 调用子组件暴露的方法 childRef.value.doSomething(&#39;父组件传递的参数&#39;); // 也可以访问子组件暴露的数据 console.log(childRef.value.message); } }; </script> ``` 关键点: - 在父组件中,我们使用`InstanceType<typeof ChildComponent>`来获取组件的实例类型,这样在调用方法或访问属性时,TypeScript会进行类型检查。 - 初始值设为`null`,因为组件在挂载之前引用为`null`,所以我们在调用之前需要检查`childRef.value`是否存在。 - 子组件通过`defineExpose`明确暴露哪些方法或属性,未暴露的将无法访问。 引用[1]也提到了这种方法,并指出这是推荐的方式。 注意事项: - 避免在子组件未挂载时访问引用(例如在`onMounted`之前),所以通常在事件处理函数或生命周期钩子中访问。 - 如果使用选项式API,可以通过`this.$refs`访问,但同样需要类型断言(如引用[5]所示),但Composition API是更现代的方式。 因此,在Vue 3 + TypeScript中获取组件实例并调用子组件方法,推荐使用模板引用配合`defineExpose`和`InstanceType`。 相关问题: 1. 如何在Vue 3中通过自定义事件实现父子组件通信? 2.Vue 3组合式API中,如何正确使用`defineExpose`? 3. 在TypeScript中,如何为Vue组件的模板引用定义复杂类型? 4. Vue 3中,使用模板引用获取DOM元素和获取组件实例有什么区别?</think>在 Vue 3 + TypeScript 环境中获取组件实例并调用子组件方法,主要有以下两种推荐方式,结合引用内容说明如下: ### 方法 1:使用模板引用(Ref)直接调用(推荐) 这是最直接的方式,通过 `ref` 获取组件实例并调用其暴露的方法: ```vue <!-- 父组件 Parent.vue --> <template> <button @click="callChildMethod">调用子组件方法</button> <!-- 绑定 ref 到子组件 --> <ChildComponent ref="childRef" /> </template> <script setup lang="ts"> import { ref } from &#39;vue&#39; import ChildComponent from &#39;./ChildComponent.vue&#39; // 1. 声明 ref 变量并指定类型(使用 InstanceType 确保类型安全) const childRef = ref<InstanceType<typeof ChildComponent> | null>(null) // 2. 调用子组件方法 const callChildMethod = () => { if (childRef.value) { // 调用子组件暴露的方法 childRef.value.doSomething(&#39;父组件传递的参数&#39;) // 访问子组件暴露的数据 console.log(childRef.value.childData) } } </script> ``` ```vue <!-- 子组件 ChildComponent.vue --> <script setup lang="ts"> import { ref } from &#39;vue&#39; // 子组件数据 const childData = ref<string>(&#39;子组件初始数据&#39;) // 子组件方法 const doSomething = (param: string) => { console.log(&#39;收到父组件参数:&#39;, param) childData.value = &#39;数据已更新&#39; } // 3. 关键:暴露需要被父组件访问的属性和方法 defineExpose({ doSomething, childData }) </script> ``` **关键点说明**: 1. **类型安全**:使用 `InstanceType<typeof ChildComponent>` 确保父组件能正确识别子组件暴露的属性和方法[^3] 2. **引用初始化**:初始值设为 `null`,组件挂载后自动更新引用 3. **方法暴露**:子组件必须使用 `defineExpose` 显式暴露方法[^1] 4. **空值检查**:调用前需检查 `childRef.value` 是否存在 ### 方法 2:通过自定义事件(Emit)间接调用 当不需要直接操作子组件实例时,可通过事件通信: ```vue <!-- 父组件 Parent.vue --> <template> <ChildComponent @child-event="handleChildEvent" /> </template> <script setup lang="ts"> const handleChildEvent = (data: string) => { console.log(&#39;收到子组件数据:&#39;, data) } </script> ``` ```vue <!-- 子组件 ChildComponent.vue --> <script setup lang="ts"> const emit = defineEmits<{ (e: &#39;child-event&#39;, data: string): void }>() const triggerEvent = () => { emit(&#39;child-event&#39;, &#39;子组件传递的数据&#39;) } </script> ``` ### 两种方法对比 | **特性** | **模板引用** | **自定义事件** | |------------------|----------------------------------|------------------------------| | 直接访问实例 | ✅ 是 | ❌ 否 | | 类型安全 | ✅ 强(InstanceType) | ✅ 强(defineEmits) | | 组件耦合度 | ⚠️ 较高(需知道子组件结构) | ✅ 低(通过接口通信) | | 适用场景 | 需要直接操作子组件状态/方法 | 单纯的数据传递 | | 代码侵入性 | ⚠️ 需修改子组件(defineExpose)| ✅ 无 | ### 最佳实践建议 1. **优先使用模板引用** 当需要直接操作子组件方法或访问其内部状态时[^5] 2. **严格类型定义** 始终使用 `InstanceType<typeof Component>` 避免类型错误[^3] 3. **生命周期注意** 在 `onMounted` 后访问 ref,确保组件已挂载 4. **最小暴露原则** 子组件只暴露必要的方法和属性,保持封装性[^1] 5. **组合使用** 复杂场景可同时使用 ref + emit 满足不同需求[^4] > 根据引用[3]和[5]的示例,模板引用是Vue 3+TS环境下最常用的直接操作子组件的方式,但需配合`defineExpose`和类型定义才能保证类型安全[^1][^3][^5]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值