Reputation: 1334
If i'm importing component with import SearchBarPopper from './xxx'
:
import SearchBarPopper from './search-bar-popper';
export default {
components: {
SearchBarPopper,
},
};
Define ref name in template:
<search-bar-popper ref="popper" />
Then call its function when some other component triggers @click
:
methods: {
onClick(index) {
console.log(this.$refs.popper);
if (this.$refs.popper) {
this.$refs.popper.setSearchListIndex(index);
}
},
}
And it works. I got Proxy like this:
[[Target]]: Object
searchBar: Proxy {setPopperRelativeIndex: ƒ, onInputFocus: ƒ, onInputBlur: ƒ, onInputKeyUp: ƒ,
onInputKeyDown: ƒ, …}
setSearchListIndex: ƒ ()
show: (...)
$: (...)
$attrs: (...)
$data: (...)
$el: (...)
$emit: (...)
$forceUpdate: (...)
$nextTick: (...)
$options: (...)
$parent: (...)
$props: (...)
$refs: (...)
$root: (...)
$router: (...)
$slots: (...)
$store: (...)
$watch: (...)
_: (...)
It has the function I need.
Now let's retry this, let's import component with defineAsyncComponent()
:
export default {
components: {
SearchBarPopper: defineAsyncComponent(() => import('./search-bar-popper'))
},
};
Still triggred in manual event @click
, not from mounted()
or something.
This time I can't get that ref correctly:
[[Target]]: Object
$: (...)
$attrs: (...)
$data: (...)
$el: (...)
$emit: (...)
$forceUpdate: (...)
$nextTick: (...)
$options: (...)
$parent: (...)
$props: (...)
$refs: (...)
$root: (...)
$router: (...)
$slots: (...)
$store: (...)
$watch: (...)
_: (...)
Ref content still printed, but inside I can't find that funciton setSearchListIndex()
.
by the way, component SearchBarPopper
looks like this:
<template>
<div class="ls-view-home-search__popper">
<ls-collapse class="ls-view-home-search__popper__wrap" :show="show">
<search-bar-list ref="search-bar-list" />
</ls-collapse>
</div>
</template>
What is going on here?
Upvotes: 3
Views: 2315
Reputation: 31
In vue 3.0.4+
they fix that problem when you bind ref to async component (using defineAsyncComponent
).
the ref will bind to the actual component inside the <AsyncComponentWrapper>
.
btw, if you using <script setup>
in your custom component. you should use defineExpose
to expose methods or other things to be used in the parent context.
// child component
import { defineExpose } from 'vue'
// cannot be accessed from outside
function hello(){
console.log('hello')
}
// can be accessed from outside cause defineExpose
function hello2(){
console.log('hello2')
}
defineExpose({ hello2 })
Upvotes: 3
Reputation: 3543
That is because when you define a component as async (using defineAsyncComponent
), what you get is a wrapper component. The wrapper component is mounted as the direct child component of the parent, and it manages the async loading of your SeachBarPopper component.
If you look at the component tree in your vue devtools, you will see there is an extra AsyncComponentWrapper
component around your true SearchBarPopper
. Your ref
in this case is pointing to the AsyncComponentWrapper
, not the SearhBarPopper
within.
Upvotes: 3