七周七种前端框架四:Vue.js 构建大型应用
2016-05-04 18:09
1021 查看
真正的模块化
前端模块化很早就开始了,无论是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 按照
模块化重写了一遍。模块化是构建大型应用的基础之一,但是这一点还不够,我们还需要做到:
更好的状态管理,把不同组件共享的 State 独立出来管理
自动化测试
路由等
这里我们只做其中一个,就是把
State独立成一个单独模块。很显然,对一个 Todo List 应用来说,保存 todo list 的数据结构就是不同组件共享的
State。
之前我们为什么需要进行事件广播,就是因为不同组件之间要操作的数据就保存在
List.vue中,所以在
Form.vue中想增加一条数据的时候需要通过事件的方式去通知
List.vue来添加。
也就是其实这个数据不是
List.vue私有的,应该至少是这两个组件公有的,现在被
List.vue据为己有之后,
Form.vue没法修改它只好通过事件进行通知。
虽然事件的方式很优雅,但其实我们可以做的更好,就是把数据独立出来,这样
Form.vue和
List.vue都可以直接修改数据,而不用那么麻烦发通知。
这里我们增加一个
Store.js文件:
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
相关文章推荐
- 插件管理框架 for Delphi(一)
- 使用CSS框架布局的缺点和优点小结
- 一起动手编写Android图片加载框架
- 基于.NET平台常用的框架和开源程序整理
- 列举PHP的Yii 2框架的开发优势
- Windows窗体的.Net框架绘图技术实现方法
- 浅谈JavaScript 框架分类
- 深入探寻seajs的模块化与加载方式
- 轻量级javascript 框架Backbone使用指南
- javascript模块化简单解析
- javascript实现框架高度随内容改变的方法
- JS刷新框架外页面七种实现代码
- 超赞的动手创建JavaScript框架的详细教程
- 深入探讨前端框架react
- 在Html中使用Requirejs进行模块化开发实例详解
- 简单介绍不用库(框架)自己写ajax
- 利用ASP.NET MVC+EasyUI+SqlServer搭建企业开发框架
- asp.net4.0框架下验证机制失效的原因及处理办法
- 插件管理框架 for Delphi(二)
- 零基础学习AJAX之AJAX框架