Javascript 如何在路由中动态加载组件
我是一名Vue新手,我正在试验Vue路由器和组件的动态加载,而不使用任何附加库(因此没有网页包或类似工具) 我已经创建了一个索引页并设置了一个路由器。当我第一次加载页面时,我可以看到Javascript 如何在路由中动态加载组件,javascript,vue.js,vue-component,vue-router,Javascript,Vue.js,Vue Component,Vue Router,我是一名Vue新手,我正在试验Vue路由器和组件的动态加载,而不使用任何附加库(因此没有网页包或类似工具) 我已经创建了一个索引页并设置了一个路由器。当我第一次加载页面时,我可以看到子页面.js尚未加载,当我单击时,我可以看到子页面.js文件已加载。但是,URL不会更改,组件也不会出现 这就是我到目前为止所做的: index.html <html> <head> <script src="https://cdn.jsdelivr.net/npm/vue/di
子页面.js
尚未加载,当我单击
时,我可以看到子页面.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>
<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>
<!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>
子页面js
const router = new VueRouter({
routes: [
{ path: '/subpage', component: () => import('./subpage.js') }
]
})
const app = new Vue({
router
}).$mount('#app');
export default {
name: 'SubPage',
template: '<div>SubPage path: {{msg}}</div>'
data: function() {
return {
msg: this.$route.path
}
}
};
export default {
name: 'SubPage',
template: '<div>SubPage path: {{msg}}</div>',
data: function() {
return {
msg: this.$route.path
}
}
};
导出默认值{
名称:'子页面',
模板:'子页面路径:{{msg}}'
数据:函数(){
返回{
msg:this.$route.path
}
}
};
所以问题归结为:如何动态加载组件
如何动态加载组件
试试这个:
App.vue
Home.vue
这样,组件Home
将自动加载
这是演示:我与您分享“尽可能精简”代码库的愿望,因此在下面制作了这个简单的示例代码(也可以访问)
我也不是Vue的超级用户,但在研究时我考虑了三种可能性
- 动态
simport
jsrequire
- 老派JS生成的
包括李>
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>
<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>
<!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>
Vue懒散负荷试验
html,正文{
保证金:5px;
填充:0;
字体系列:无衬线;
}
导航a{
显示:块;
保证金:5px0;
}
主导航{
边框:1px实心;
填充:10px;
边缘顶部:5px;
}
.产出{
字体大小:粗体;
}
家
简单组件
不是那么简单的组件
函数loadComponent(组件名称、路径){
返回新承诺(功能(解决、拒绝){
var script=document.createElement('script');
script.src=路径;
script.async=true;
script.onload=函数(){
var component=Vue.component(componentName);
if(组件){
解析(组件);
}否则{
拒绝();
}
};
script.onerror=拒绝;
document.body.appendChild(脚本);
});
}
var路由器=新的VueRouter({
模式:“历史”,
路线:[
{
路径:“/”,
组成部分:{
模板:“主页”
},
},
{
路径:'/simple',,
组件:功能(解析、拒绝){
loadComponent('simple','simple.js')。然后(解析,拒绝);
}
},
{path:'/complex',component:function(resolve,reject){loadComponent('complex','complex.js')。然后(resolve,reject);}
}
]
});
var app=新的Vue({
el:“#应用程序”,
路由器:路由器,,
});
simple.js:
Vue.component("simple", {
template: "<div>Simple template page loaded from external file</div>"
});
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();
}
});
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");
})
}
}
Vue.component(“简单”{
模板:“从外部文件加载的简单模板页面”
});
complex.js:
Vue.component("simple", {
template: "<div>Simple template page loaded from external file</div>"
});
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();
}
});
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");
})
}
}
Vue.component(“复杂”{
模板:
“从外部文件加载的复杂模板页面
子页面路径:{{{path}}
外部加载的数据有一定延迟:
”,
数据:函数(){
返回{
路径:此。$route.path,
msg:“请稍候…”
};
},
方法:{
fetchData(){
var=这个;
设置超时(()=>{
/*模拟延迟的位延迟:D*/
取回(“https://jsonplaceholder.typicode.com/todos/1")
.then(response=>response.json())
。然后(json=>{
log(json);
那是=
“
”+JSON.stringify(JSON)+“
”;
})
.catch(错误=>{
console.log(错误);
那是=
获取错误:“+Error+””;
});
}, 2000);
}
},
创建(){
这是fetchData();
}
});
正如您所看到的,函数
loadComponent()
在这里执行加载组件的“神奇”操作
因此它是可行的,但它可能不是最好的解决方案,至少在以下方面:
- 使用JS插入标记可以被视为安全问题 在不久的将来
- 性能-同步加载文件会阻塞线程(这可能会 成为应用程序生命中最重要的一员)
- 我没有测试缓存等可能是生产中的一个实际问题
- 你失去了(Vue)组件的美感,比如作用域css、html和 JS可以自动绑定到网页包或其他东西
- 你松开了巴别塔的编译/播放
- 热模块更换(和状态持久性等)-我相信,已经不存在了
- 我可能忘记了其他对我来说显而易见的问题 四年级:D
希望我能帮助你:D我想看看“新的”动态导入今天有多有用(),所以我用它做了一些实验。它们确实简化了异步导入,下面是我的示例代码(没有Webpack/Babel/只有纯Chrome友好的JS) 我将保留我的旧答案()用于潜在的引用加载脚本,这种方式比动态导入()在更多的浏览器中工作 所以最后我注意到