简体   繁体   English

使用延迟加载导入组件时,vuejs ref 未定义

[英]vuejs ref is undefined when importing component with lazy loading

I'm trying to import a component like this for lazy loading:我正在尝试导入这样的组件以进行延迟加载:

components: {SizeChartForm:() => import("@/core/components/size/SizeChartForm/SizeChartForm")},

I'm having a ref to SizeChartForm component:我有一个SizeChartForm组件的参考:

<SizeChartForm ref="sizeChart" v-model="value" />

and trying to use it in the mounted:并尝试在安装中使用它:

mounted() {
    this.$refs.sizeChart.setDisabled(false)
}

but it says sizeChart is undefined.但它说sizeChart未定义。 Even $nextTick is not working.甚至$nextTick也不起作用。

But when I use normal import it works:但是当我使用正常导入时,它可以工作:

import SizeChartForm from "@/core/components/size/SizeChartForm/SizeChartForm";
  
components: {SizeChartForm}

Vue version: 2.6.11 Vue版本:2.6.11

$nextTick is not enough - it takes much longer to load an async component. $nextTick是不够的 - 加载异步组件需要更长的时间。

Generally if you need to do some work when the child component is mounted, you should do it in child's mounted hook, not in parent's ( docs - "Note that mounted does not guarantee that all child components have also been mounted." ).一般来说,如果你需要在子组件挂载时做一些工作,你应该在子组件的挂载钩子中做,而不是在父组件中(文档- “注意, mounted不能保证所有子组件也已被挂载。” )。

Solution 1 (only for Vue 2)解决方案 1(仅适用于 Vue 2)

If moving the code to the child is not an option, you can use the (little documented) fact that Vue 2 lifecycle emits special events like hook:mounted for each lifecycle stage and those events can be listened in the parent: <child ref="child" @hook:mounted="onAsyncComponentMounted"></child>如果将代码移动到子级不是一个选项,您可以使用 Vue 2 生命周期为每个生命周期阶段发出特殊事件(如hook:mounted )的(很少记录)事实,并且可以在父级中监听这些事件: <child ref="child" @hook:mounted="onAsyncComponentMounted"></child>

Solution 2 (Vue 2 & Vue 3)解决方案 2(Vue 2 和 Vue 3)

Those events were removed in Vue 3 (I'm unable to find any documentation or anything in themigration guide but I'v tested and it doesn't work) so the best approach seems to emit some custom event from the child's mounted hook and listen for it in the parent (see second example)这些事件在 Vue 3 中被删除(我无法在迁移指南中找到任何文档或任何内容,但我已经测试过但它不起作用)所以最好的方法似乎是从孩子的mounted钩子中发出一些自定义事件和在父母那里听(见第二个例子)

Update更新

I found this tweet from the Vue core team member Damian Dulisz explaining (see the replies) that hook:xxx events are not considered public API and are not documented intentionally.我发现这条来自 Vue 核心团队成员 Damian Dulisz 的推文解释说(参见回复) hook:xxx事件不被视为公共 API,也没有刻意记录。 So from this POV and also considering it's removal in Vue 3, use the second solution...因此,从这个 POV 并考虑到它在 Vue 3 中被删除,使用第二种解决方案......

Vue 2

 // NOTE: this works only in Vue 2, not in Vue 3! const child = { template: ` <div> <input ref="input" type="text" /> </div> ` } // to simulate component async loading in browser env. const loadComponentAsync = function() { return new Promise(function(resolve, reject) { setTimeout(() => resolve(child), 2000); }) } const app = new Vue({ el: '#app', components: { 'child': () => loadComponentAsync() }, methods: { onAsyncComponentMounted() { console.log(this.$refs.child.$refs.input) } } })
 <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.14/vue.js"></script> <div id='app'> <child ref="child" @hook:mounted="onAsyncComponentMounted"></child> </div>

Vue 3

 const child = { template: ` <div> <input ref="input" type="text" /> </div> `, mounted() { this.$emit('child-mounted') } } const loadComponentAsync = function() { return new Promise(function(resolve, reject) { setTimeout(() => resolve(child), 2000); }) } const app = Vue.createApp({ components: { 'child': Vue.defineAsyncComponent(() => loadComponentAsync()) }, methods: { onAsyncComponentMounted() { console.log(this.$refs.child.$refs.input) } } }).mount('#app')
 <script src="https://unpkg.com/vue@3.1.5/dist/vue.global.js"></script> <div id='app'> <child ref="child" @child-mounted="onAsyncComponentMounted"></child> </div>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM