无法在 vue 3 composition api 中的组件上使用模板引用

新手上路,请多包涵

我想从父级获取 vue.js 组件的尺寸(我正在使用实验性 脚本设置)。

当我在组件内部使用 ref 时,它按预期工作。我得到尺寸:

 // Child.vue
<template>
  <div ref="wrapper">
   // content ...
  </div>
</template>
<script setup>
import { ref, onMounted } from 'vue'

const wrapper = ref(null)

onMounted(() => {
  const rect = wrapper.value.getBoundingClientRect()
  console.log(rect) // works fine!
})
</script>

但是我想获取父组件内部的维度。这可能吗?

我试过这个:

 // Parent.vue
<template>
  <Child ref="wrapper" />
</template>
<script setup>
import Child from './Child'
import { ref, onMounted } from 'vue'

const wrapper = ref(null)

onMounted(() => {
  const rect = wrapper.value.getBoundingClientRect()
  console.log(rect) // failed!
})
</script>

控制台记录此错误消息: Uncaught (in promise) TypeError: x.value.getBoundingClientRect is not a function


在文档中我只能找到 在子组件 中使用 template refs 的方法

这种方法是否不起作用,因为 refs 正如 rfcs 描述所说 的那样“默认关闭”?

原文由 wittgenstein 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 838
2 个回答

我今天遇到了这个问题。问题是,当使用 <script setup> 模式时,没有返回任何声明的变量。当您获得对组件的引用时,它只是一个空对象。解决这个问题的方法是在设置块中使用 defineExpose

 // Child.vue

<template>
  <div ref="wrapper">
   <!-- content ... -->
  </div>
</template>

<script setup>
import { defineExpose, ref } from 'vue'

const wrapper = ref(null)

defineExpose({ wrapper })
</script>

您在父级中设置模板引用的方式很好。您在控制台中看到 empty object { } 的事实意味着它正在运行。

就像已经说过的其他答案一样,可以像这样从父级访问子引用: wrapper.value.wrapper.getBoundingClientRect()

rfc 有一节讨论如何/为什么这样工作: https ://github.com/vuejs/rfcs/blob/master/active-rfcs/0040-script-setup.md#exposing-components-public-interface

同样重要的是要注意,使用 <script setup> 模式,父组件中的 ref 将不是 ComponentInstance。这意味着您不能像其他方式那样调用 $el 。它只会包含您在 defineExpose 中输入的值。

原文由 nVitius 发布,翻译遵循 CC BY-SA 4.0 许可协议

我不认为这必然与 <script setup> 标签相关。即使在标准脚本语法中,您的第二个示例也不会按原样运行。

问题是您将 ref 直接放在子组件上:

 <template>
  <Child ref="wrapper" />
</template>

并且对组件的引用与对该组件的 元素的引用 _不同_。它没有 getBoundingClientRect() 方法。

事实上, _Vue 3 不再要求组件具有单个根元素_。您可以将子组件定义为:

 <template>
  <div ref="wrapper1">// content ...</div>
  <div ref="wrapper2">// content ...</div>
</template>
<script >
import { ref } from "vue";

export default {
  name: "Child",

  setup() {
    const wrapper1 = ref(null);
    const wrapper2 = ref(null);

    return { wrapper1, wrapper2 };
  },
};
</script>

现在你的 Parent 组件中的 ref 应该是什么?

从您的父组件将 wrapper.value 记录到您的控制台。它实际上是您的 Child 组件中所有 refs 的对象:

 {
  wrapper1: {...}, // the 1st HTMLDivElement
  wrapper2: {...}  // the 2nd HTMLDivElement
}

你可以做 wrapper.value.wrapper1.getBoundingClientRect() ,那会很好。

原文由 Xinchao 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题