我是Vue的新手,我正在尝试使用vue-router和动态加载组件,而无需使用任何其他库(因此没有webpack或类似的库)。
我已经创建了索引页并设置了路由器。第一次加载页面时,我可以看到尚未加载subpage.js
,单击<router-link>
时可以看到subpage.js
文件已加载。但是,URL不会更改,组件也不会出现。
这是我到目前为止所拥有的:
index.html
<html>
<head>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
</head>
<body>
<div id="app">
<h1>Hello App!</h1>
<router-link to="/subpage">To subpage</router-link>
<router-view></router-view>
</div>
<script src="main.js"></script>
</body>
</html>
main.js
const router = new VueRouter({
routes: [
{ path: '/subpage', component: () => import('./subpage.js') }
]
})
const app = new Vue({
router
}).$mount('#app');
subpage.js
export default {
name: 'SubPage',
template: '<div>SubPage path: {{msg}}</div>'
data: function() {
return {
msg: this.$route.path
}
}
};
因此,问题归结为:如何动态加载组件?
答案 0 :(得分:0)
如何动态加载组件?
尝试一下:
App.vue
<template>
<div id="app">
<router-link to="/">Home</router-link>
<router-link to="/about">About</router-link>
<hr/>
<router-view></router-view>
</div>
</template>
<script>
export default {
name: 'app',
components: {}
};
</script>
main.js
import Vue from 'vue';
import VueRouter from 'vue-router';
import App from './App.vue';
Vue.use(VueRouter);
Vue.config.productionTip = false;
const Home = () => import('./components/Home.vue');
const About = () => import('./components/About.vue');
const router = new VueRouter({
mode: 'history',
routes:[
{path:'/', component: Home},
{path:'/about',component: About}
]
})
new Vue({
router,
render: h => h(App)
}).$mount('#app');
Home.vue
<template>
<div>
<h2>Home</h2>
</div>
</template>
<script>
export default {
name: 'Home'
};
</script>
About.vue
<template>
<div>
<h2>About</h2>
</div>
</template>
<script>
export default {
name: 'About'
};
</script>
这样,组件Home
将被自动加载。
答案 1 :(得分:0)
我与您一样希望拥有“尽可能精简”的代码库,因此在下面做了这个简单的示例代码(也可以从https://codesandbox.io/embed/64j8pypr4k访问)。
我也不是Vue超级用户,但是在研究时,我考虑了三种可能性:
import
,require
js,<script src />
个看起来最后一个方法最简单,也最省力:D可能不是最佳实践,并且可能很快就会过时(至少会提供动态导入支持)。
NB:此示例对较新的浏览器(使用本机Promises,Fetch,Arrow函数...)友好。因此,请使用最新的Chrome或Firefox进行测试:)可以通过一些polyfill和重构等方式来支持较旧的浏览器。但这将为代码库增加很多...
所以-按需动态加载组件(之前未包含):
index.html
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Vue lazyload test</title>
<style>
html,body{
margin:5px;
padding:0;
font-family: sans-serif;
}
nav a{
display:block;
margin: 5px 0;
}
nav, main{
border:1px solid;
padding: 10px;
margin-top:5px;
}
.output {
font-weight: bold;
}
</style>
</head>
<body>
<div id="app">
<nav>
<router-link to="/">Home</router-link>
<router-link to="/simple">Simple component</router-link>
<router-link to="/complex">Not sooo simple component</router-link>
</nav>
<main>
<router-view></router-view>
</main>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.0.3/vue.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue-router/2.0.1/vue-router.min.js"></script>
<script>
function loadComponent(componentName, path) {
return new Promise(function(resolve, reject) {
var script = document.createElement('script');
script.src = path;
script.async = true;
script.onload = function() {
var component = Vue.component(componentName);
if (component) {
resolve(component);
} else {
reject();
}
};
script.onerror = reject;
document.body.appendChild(script);
});
}
var router = new VueRouter({
mode: 'history',
routes: [
{
path: '/',
component: {
template: '<div>Home page</div>'
},
},
{
path: '/simple',
component: function(resolve, reject) {
loadComponent('simple', 'simple.js').then(resolve, reject);
}
},
{ path: '/complex', component: function(resolve, reject) { loadComponent('complex', 'complex.js').then(resolve, reject); }
}
]
});
var app = new Vue({
el: '#app',
router: router,
});
</script>
</body>
</html>
simple.js :
Vue.component("simple", {
template: "<div>Simple template page loaded from external file</div>"
});
complex.js :
Vue.component("complex", {
template:
"<div class='complex-content'>Complex template page loaded from external file<br /><br />SubPage path: <i>{{path}}</i><hr /><b>Externally loaded data with some delay:</b><br /> <span class='output' v-html='msg'></span></div>",
data: function() {
return {
path: this.$route.path,
msg: '<p style="color: yellow;">Please wait...</p>'
};
},
methods: {
fetchData() {
var that = this;
setTimeout(() => {
/* a bit delay to simulate latency :D */
fetch("https://jsonplaceholder.typicode.com/todos/1")
.then(response => response.json())
.then(json => {
console.log(json);
that.msg =
'<p style="color: green;">' + JSON.stringify(json) + "</p>";
})
.catch(error => {
console.log(error);
that.msg =
'<p style="color: red;">Error fetching: ' + error + "</p>";
});
}, 2000);
}
},
created() {
this.fetchData();
}
});
如您所见-函数loadComponent()
的作用是在这里加载组件。
所以它可行,但就以下(至少)方面而言,它可能不是最佳解决方案:
希望我可以帮助您:D
答案 2 :(得分:0)
我想看看今天的“新”动态导入(https://developers.google.com/web/updates/2017/11/dynamic-import)有多有用,所以我做了一些实验。它们确实使异步导入更容易,下面是我的示例代码(没有Webpack / Babel /只是纯Chrome友好的JS)。
我将保留我的旧答案(How to dynamically load components in routes)供潜在参考-加载比动态导入(https://caniuse.com/#feat=es6-module-dynamic-import)在更多浏览器中工作的脚本。
因此,最后我注意到您实际上非常非常接近您的工作-实际上,这只是导出导入的JS模块时出现语法错误(缺少逗号)。
下面的示例也对我有用(不幸的是,Codesandbox的(es)lint不允许使用该语法,但是我已经在本地对其进行了检查,并且可以使用(在Chrome浏览器中,甚至Firefox都不喜欢该语法:(SyntaxError:import关键字只能出现在模块中)));
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Page Title</title>
</head>
<body>
<div id="app">
<h1>Hello App!</h1>
<router-link to="/temp">To temp</router-link>
<router-link to="/module">To module</router-link>
<router-view></router-view>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
<script src="main.js"></script>
</body>
</html>
main.js:
'use strict';
const LazyRouteComponent = {
template: '<div>Route:{{msg}}</div>',
data: function() {
return {
msg: this.$route.path
}
}
}
const router = new VueRouter({
routes: [
{
path: '/temp',
component: {
template: '<div>Hello temp: {{msg}}</div>',
data: function() {
return {
msg: this.$route.path
}
}
}
},
{ path: '/module', name: 'module', component: () => import('./module.js')},
{ path: '*', component: LazyRouteComponent }
]
})
const app = new Vue({
router
}).$mount('#app');
和主要区别 module.js :
export default {
name: 'module',
template: '<div>Test Module loaded ASYNC this.$route.path:{{msg}}</div>',
data: function () {
return {
msg: this.$route.path
}
},
mounted: function () {
this.$nextTick(function () {
console.log("entire view has been rendered after module loaded Async");
})
}
}
所以-几乎与您的代码完全一样-但带有所有逗号;
subpage.js
export default {
name: 'SubPage',
template: '<div>SubPage path: {{msg}}</div>',
data: function() {
return {
msg: this.$route.path
}
}
};
所以-您的代码有效(我通过复制粘贴对其进行了测试)-实际上,您在template: '<div>SubPage path: {{msg}}</div>'
之后只是缺少了一个逗号。
尽管如此,这似乎仅适用于: