我同意您对“尽可能精简”代码库的愿望,因此在下面制作了这个简单的示例代码(也可通过 https://codesandbox.io/embed/64j8pypr4k 访问)。
我也不是 Vue 高级用户,但在研究时我想到了三种可能性;
- 动态
imports,
-
requirejs,
- old school JS 生成
<script src /> 包括。
看起来最后一个最简单,也最省力:D 可能不是最佳实践,可能很快就会过时(至少在动态导入支持之后)。
注意:这个例子对更新的浏览器很友好(带有原生 Promises、Fetch、Arrow 函数...)。所以 - 使用最新的 Chrome 或 Firefox 进行测试 :) 支持旧版浏览器可以通过一些 polyfills 和重构等来完成。但这会给代码库增加很多...
所以 - 按需动态加载组件(之前不包括在内):
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() 在此处执行加载组件的“神奇”事情。
所以它有效,但就(至少)以下方面而言,它可能不是最好的解决方案:
- 用JS插入标签可被视为安全问题
在不久的将来,
- 性能 - 同步加载文件阻塞线程(这可以
成为应用生命后期的主要禁忌),
- 我没有测试缓存等。在生产中可能是一个真正的问题,
- 您失去了 (Vue) 组件的美感 - 例如作用域 css、html 和
可以自动捆绑Webpack之类的JS,
- 你失去了 Babel 编译/转译,
- 热模块更换(和状态持久性等) - 我相信已经消失了,
- 我可能忘记了其他明显的问题
高级高级:D
希望我对你有所帮助:D