Reputation: 1156
I'm using Laravel 5.4 and Vue.js 2. I want to load a component as async using a button. My Vue.js components are separate: example.vue and test.vue, and I load them as an HTML tag.
This is my app.js:
import './bootstrap';
import example from './components/Example.vue';
Vue.component('example', example);
const app = new Vue({
el: '#app'
});
This is the place to show components:
<How can I use Async components?div id="app">
<example2></example2>
</div>
How can I use async components?
No, I think you don't understand me. It's my component registration:
import './bootstrap';
import example from './components/Example.vue';
Vue.component('example', example);
Vue.component('example2', function (resolve) {
require(['./components/Example2.vue'],resolve)
})
const app = new Vue({
el: '#app'
});
And in require, it defaults to resolved (as showing). I don't know how I should pass the resolve and reject keys to this method in my page when I call the component.
Upvotes: 8
Views: 24525
Reputation: 11486
Async components now require the defineAsyncComponent
helper method:
// Vue.js 2.x
const asyncPage = () => import('./NextPage.vue')
// Vue.js 3.x
const asyncPage = defineAsyncComponent(() => import('./NextPage.vue'))
Another breaking change is that the component
option is renamed to loader
when defining additional options:
const asyncPageWithOptions = defineAsyncComponent({
loader: () => import('./NextPage.vue'),
delay: 200,
timeout: 3000,
error: ErrorComponent,
loading: LoadingComponent
})
Documentation: Async Components, 3.x Syntax
Upvotes: 1
Reputation: 879
You can use async components in Vue.js 2 with a styling way. Proper using async components can reduce your project loading time.
You can use an async component as like:
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
export default new Router ({
routes: [
{
path: '/',
name:'LandingPage'
component: () => import('@/containers/LandingPage.vue')
},
{
path: '/login',
name:'LoginPage'
component: () => import('@/containers/LoginPage.vue')
}
]
})
This structure looks better for component loading inside the template:
new Vue ({
el: 'app',
components: {
AsyncComponent: () => import ('./AsyncComponent.vue')
}
})
You can check out www.bdtunnel.com for more information.
Upvotes: 10
Reputation: 1413
According to the documentation on Vue.js, you have been able to define asynchronous components like this since version 2.3:
const AsyncComp = () => ({
// The component to load. Should be a Promise
component: import('./MyComp.vue'),
// A component to use while the async component is loading
loading: LoadingComp,
// A component to use if the load fails
error: ErrorComp,
// Delay before showing the loading component. Default: 200 ms.
delay: 200,
// The error component will be displayed if a timeout is
// provided and exceeded. Default: Infinity.
timeout: 3000
})
You can use this in conjunction with built-in components to load your components dynamically.
An updated link to mentioned documentation.
Upvotes: 5
Reputation: 79
One way I've done this sort of thing is to create your example2
component with the following setup:
<template>
<div>
<div v-if="inited">
<div>{{foo}}</div>
<div>{{bar}}</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
foo: '',
bar: '',
inited: false
}
},
mounted() {
var me = this
axios.get('/my/ajax/call').then(function(response) {
me.foo = response.data.foo
me.bar = response.data.bar
me.inited = true
})
}
}
</script>
Basically, anytime the component is mounted, it'll render with empty information until the AJAX call completes and then the reactive data will be updated and Vue will auto-update the reactive data elements. If you have other markup or things in the template you don't want to be visible, you can always create an inited: false
data property and set it to true
in the AJAX callback and then use either the :v-if="inited"
or :v-show="inited"
directives on a wrapper div
to hide the component's contents until the AJAX call returns.
Upvotes: 1
Reputation: 79
For async components in Vue.js, the resolve argument is the function which is called upon success of the async call, so your require() call needs to be inside the called resolve function. You just need to remove the brackets in your require() call and format that line as follows:
resolve(require('./components/Example2.vue'))
In the example below, we're using a basic setTimeout()
to emulate the async call. The resolve function will be called after 5 seconds and will load the Example2
component into the app.
In order to show/hide the Example2
component via a button click, you have to add a reactive data property in the data()
function. Then, if you take a look at App.vue's template, we're using the v-if
(https://v2.vuejs.org/v2/guide/conditional.html#v-if) directive to add/remove the Example2
component to/from the virtual DOM. You could very easily us the v-show
(https://v2.vuejs.org/v2/guide/conditional.html#v-show) directive here as well, although the component would stick around and just be hidden. You can read more about v-if
vs v-show
here: https://v2.vuejs.org/v2/guide/conditional.html#v-if-vs-v-show. This is a very common paradigm for hiding and showing modals in an app -- here's an example that shows this in action quite well: https://v2.vuejs.org/v2/examples/modal.html
import Vue from 'vue'
import App from './components/App.vue'
Vue.component('example2', function(resolve, reject) {
setTimeout(function() {
resolve(require('./components/Example2.vue'))
}, 5000)
})
const app = new Vue({
el: '#app',
render: h => h(App)
})
<template>
<div>
<div>Hello example 2!</div>
</div>
</template>
<template>
<div id="app">
<button type="button" @click="onButtonClick">Click me to add the example2 component</button>
<example2 v-if="show_example2"></example2>
</div>
</template>
<script>
export default {
name: 'app',
data() {
return {
show_example2: false
}
},
methods: {
onButtonClick() {
this.show_example2: true
}
}
}
</script>
Upvotes: 4