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

wit*_*ein 5 ref vue.js vue-component vuejs3 vue-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>
Run Code Online (Sandbox Code Playgroud)

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

我试过这个:

// 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>
Run Code Online (Sandbox Code Playgroud)

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


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

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

nVi*_*ius 55

我今天遇到了这个问题。问题是,使用该<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>
Run Code Online (Sandbox Code Playgroud)

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

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

rfc 有一节讨论了它的工作原理:https://github.com/vuejs/rfcs/blob/master/active-rfcs/0040-script-setup.md#exusing-components-public-interface

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


Xin*_*hao 11

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

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

<template>
  <Child ref="wrapper" />
</template>
Run Code Online (Sandbox Code Playgroud)

并且对组件的引用与对该组件的元素的引用不同它没有方法。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>
Run Code Online (Sandbox Code Playgroud)

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

wrapper.value从您的父组件登录到您的控制台。它实际上是子组件中所有引用的对象:

{
  wrapper1: {...}, // the 1st HTMLDivElement
  wrapper2: {...}  // the 2nd HTMLDivElement
}
Run Code Online (Sandbox Code Playgroud)

你可以wrapper.value.wrapper1.getBoundingClientRect()这样做,效果很好。


Bou*_*him 6

您可以使用如下所示的字段来访问根元素$el

<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.$el.getBoundingClientRect()
  console.log(rect) 
})
</script
Run Code Online (Sandbox Code Playgroud)