真正的模块化
前端模块化很早就开始了,无论是 require.js,browserify 进行模块化打包, 还是 Angular 进行依赖注入,我们都可以把JS代码分成一个个小的模块并组装起来。然后我们还会通过 less 或者 sass 来把CSS文件也拆成一个个小的模块来写,甚至我们在CSS代码中感受到了 封装,继承,多态 等面向对象的特性。
然而,在 webpack 出来之前,我们所谓的模块化根本不能算作模块化。为什么这么讲,因为我们存在一个重要的问题没有解决,就是JS模块对CSS模块的依赖。
比如我们有一个JS模块 modal 那么我们直接导入并调用它就能弹出一个对话框吗?如下图所示可以吗?
理论上应该是这样的,但实际上这个 modal其实还依赖一个对应的CSS模块 modal.less ,如果不导入这个模块我们是无法弹出一个正常的对话框的,而且,导入这个CSS模块竟然不是和导入JS模块写在同一个地方,而是写在另一个CSS文件中。也就是说,其实依赖关系是这样的:
为了使用一个模块,我们需要在两个文件中分别做一次引入操作。这其实是一件非常奇怪不合理的事!我们为什么要模块化?就是为了封装一个模块,可以做到导入它就能使用,而它是如何实现的,它有什么依赖关系完全是这个模块自己处理的,也就是上图中对 modal.css 的依赖应该是 modal.js 自己处理的。
但是我们写了N年的前端却一直这样写模块,不是因为他对,而是因为我们习惯了这种错误的方式。现在用Vue我们可以完全封装一个模块的全部依赖,无论是模板、CSS还是JS,我们都不需要再去关心,只要引入这个模块就可以使用,而模块的依赖是它自己进行处理的。
那么我们的依赖关系就变成了:
其中 modal.vue 包含了全部所需要的依赖,那么我们就不在需要自己去处理对应的 CSS 甚至 模板了。这才是模块化应该达到的效果。
创建 Vue 项目
Vue 提供了一个工具 vue-cli 可以创建一个项目模板: https://github.com/vuejs/vue-cli
这里我先尝试了一下另一个模板项目:https://github.com/vuejs-templates/webpack
然后我们就可以不用 纯JS来写模块了,而是借助 webpack 来把一个模块相关的所有内容全部写到一个文件中。以之前的 todo list 为例,其实上一章讲的只是component的用法所以那样写了。我们改成一个更好的写法如下:
List.vue:
<template>
<ul>
<li v-for='todo in list'>
<label v-bind:class="{ done : todo.done }" >
<input type="checkbox" v-model="todo.done"/>
{{todo.title}}
</label>
</li>
</ul>
</template>
<script>
export default {
props: {
initList: {
type: Array
}
},
data () {
return {
list: []
}
},
events: {
add (input) {
if (!input) return false
this.list.unshift({
title: input,
done: false
})
}
}
}
</script>
<style lang="less" scoped>
ul {
margin-left: 2rem;
padding: 0;
.done {
text-decoration: line-through;
}
}
</style>
Form.vue:
<template>
<h1>{{username}}'s Todo List</h1>
<form v-on:submit="add" v-on:submit.prevent>
<input type="text" v-model="input"/>
<input type="submit" value='add' />
</form>
</template>
<script>
export default {
props: {
username: {
type: String,
default: 'Unnamed'
}
},
data () {
return {
input: ''
}
},
methods: {
add () {
this.$dispatch('add', this.input)
this.input = ''
}
}
}
</script>
Todo.vue:
<template>
<div id="todo">
<todo-form username='Lily'></todo-form>
<todo-list></todo-list>
</div>
</template>
<script>
import Form from './Form.vue'
import List from './List.vue'
export default {
components: {
'todo-form': Form,
'todo-list': List
},
events: {
add (input) {
this.$broadcast('add', input)
}
}
}
</script>
<style>
</style>
App.vue:
<template>
<todo></todo>
</template>
<script>
import Todo from './components/Todo.vue'
export default {
components: {
'todo': Todo
}
}
</script>
<style>
</style>
这样我们就把之前的 Todo List 按照 模块化 重写了一遍。模块化是构建大型应用的基础之一,但是这一点还不够,我们还需要做到:
"htmlcode">
export default {
list: [
],
add (title) {
if (!title) return
this.list.unshift({
title: title,
done: false
})
}
}
然后 我们可以把 List.vue 改成这样,这里只贴出JS部分的代码:
import Store from '../Store.js'
export default {
props: {
initList: {
type: Array
}
},
data () {
return Store
}
}
Form.vue 也不需要广播了,直接调用 Store.add 方法既可以添加:
import Store from '../Store.js'
export default {
props: {
username: {
type: String,
default: 'Unnamed'
}
},
data () {
return {
input: ''
}
},
methods: {
add () {
Store.add(this.input)
this.input = ''
}
}
}
这样一改之后,整个逻辑会清晰很多,并且应用越是复杂,越是应该抽出公有的 Store ,不然会出现广播事件满天飞的情况。
另外用这个项目模板之后,hot-reload 爽的不要不要的,刷新操作都省了。
上述的源码在这里:https://github.com/lihongxun945/vue-webpack-todo-list
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!
更新日志
- 小骆驼-《草原狼2(蓝光CD)》[原抓WAV+CUE]
- 群星《欢迎来到我身边 电影原声专辑》[320K/MP3][105.02MB]
- 群星《欢迎来到我身边 电影原声专辑》[FLAC/分轨][480.9MB]
- 雷婷《梦里蓝天HQⅡ》 2023头版限量编号低速原抓[WAV+CUE][463M]
- 群星《2024好听新歌42》AI调整音效【WAV分轨】
- 王思雨-《思念陪着鸿雁飞》WAV
- 王思雨《喜马拉雅HQ》头版限量编号[WAV+CUE]
- 李健《无时无刻》[WAV+CUE][590M]
- 陈奕迅《酝酿》[WAV分轨][502M]
- 卓依婷《化蝶》2CD[WAV+CUE][1.1G]
- 群星《吉他王(黑胶CD)》[WAV+CUE]
- 齐秦《穿乐(穿越)》[WAV+CUE]
- 发烧珍品《数位CD音响测试-动向效果(九)》【WAV+CUE】
- 邝美云《邝美云精装歌集》[DSF][1.6G]
- 吕方《爱一回伤一回》[WAV+CUE][454M]

