前端框架Vue.js构建大型应用浅析


Posted in Javascript onSeptember 12, 2016

真正的模块化

前端模块化很早就开始了,无论是 require.js,browserify 进行模块化打包, 还是 Angular 进行依赖注入,我们都可以把JS代码分成一个个小的模块并组装起来。然后我们还会通过 less 或者 sass 来把CSS文件也拆成一个个小的模块来写,甚至我们在CSS代码中感受到了 封装,继承,多态 等面向对象的特性。

然而,在 webpack 出来之前,我们所谓的模块化根本不能算作模块化。为什么这么讲,因为我们存在一个重要的问题没有解决,就是JS模块对CSS模块的依赖。

比如我们有一个JS模块 modal 那么我们直接导入并调用它就能弹出一个对话框吗?如下图所示可以吗?

理论上应该是这样的,但实际上这个 modal其实还依赖一个对应的CSS模块 modal.less ,如果不导入这个模块我们是无法弹出一个正常的对话框的,而且,导入这个CSS模块竟然不是和导入JS模块写在同一个地方,而是写在另一个CSS文件中。也就是说,其实依赖关系是这样的:

前端框架Vue.js构建大型应用浅析

为了使用一个模块,我们需要在两个文件中分别做一次引入操作。这其实是一件非常奇怪不合理的事!我们为什么要模块化?就是为了封装一个模块,可以做到导入它就能使用,而它是如何实现的,它有什么依赖关系完全是这个模块自己处理的,也就是上图中对 modal.css 的依赖应该是 modal.js 自己处理的。
但是我们写了N年的前端却一直这样写模块,不是因为他对,而是因为我们习惯了这种错误的方式。现在用Vue我们可以完全封装一个模块的全部依赖,无论是模板、CSS还是JS,我们都不需要再去关心,只要引入这个模块就可以使用,而模块的依赖是它自己进行处理的。

那么我们的依赖关系就变成了:

前端框架Vue.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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
键盘 keycode的值 javascript时触发事件时很有用的要素
Nov 02 Javascript
jquery中获得元素尺寸和坐标的方法整理
May 18 Javascript
js在数组中删除重复的元素自保留一个(两种实现思路)
Aug 22 Javascript
JavaScript字符串对象toLowerCase方法入门实例(用于把字母转换为小写)
Oct 17 Javascript
jQuery实现在新增加的元素上添加事件方法案例分析
Feb 09 Javascript
深入理解react-router@4.0 使用和源码解析
May 23 Javascript
angularjs路由传值$routeParams详解
Sep 05 Javascript
VUE简单的定时器实时刷新的实现方法
Jan 20 Javascript
微信小程序的tab选项卡的实现效果
May 15 Javascript
javascript实现的图片预览和上传功能示例【兼容IE 9】
May 01 Javascript
JS实现电脑虚拟键盘打字测试
Jun 24 Javascript
如何利用JavaScript实现二叉搜索树
Apr 02 Javascript
jQuery过滤选择器用法示例
Sep 12 #Javascript
强大Vue.js组件浅析
Sep 12 #Javascript
超详细的JS弹出窗口代码大全
Apr 18 #Javascript
使用JS实现图片展示瀑布流效果的实例代码
Sep 12 #Javascript
关于javascript的一些知识以及循环详解
Sep 12 #Javascript
基于AngularJS实现iOS8自带的计算器
Sep 12 #Javascript
Javascript6中字符串的四个新用法分享
Sep 11 #Javascript
You might like
Body是什么,该怎么喝出咖啡里的口感
2021/03/03 咖啡文化
thinkphp 多表 事务详解
2013/06/17 PHP
php实现简单的语法高亮函数实例分析
2015/04/27 PHP
javascript实现删除前弹出确认框
2015/06/04 Javascript
Bootstrap每天必学之按钮(一)
2015/11/24 Javascript
jQuery点击按钮弹出遮罩层且内容居中特效
2015/12/14 Javascript
url传递的参数值中包含&amp;时,url自动截断问题的解决方法
2016/08/02 Javascript
单击按钮发送验证码,出现倒计时的简单实例
2017/03/17 Javascript
jQuery遍历节点方法汇总(推荐)
2017/05/13 jQuery
vue实现文章内容过长点击阅读全文功能的实例
2017/12/28 Javascript
解析Angular 2+ 样式绑定方式
2018/01/15 Javascript
从零开始封装自己的自定义Vue组件
2018/10/09 Javascript
解决IOS端微信H5页面软键盘弹起后页面下方留白的问题
2019/06/05 Javascript
jQuery表单选择器用法详解
2019/08/22 jQuery
python list语法学习(带例子)
2013/11/01 Python
10款最好的Web开发的 Python 框架
2015/03/18 Python
Python遍历目录中的所有文件的方法
2016/07/08 Python
Python爬虫:通过关键字爬取百度图片
2017/02/17 Python
利用python对Excel中的特定数据提取并写入新表的方法
2018/06/14 Python
关于Python 常用获取元素 Driver 总结
2019/11/24 Python
在flask中使用python-dotenv+flask-cli自定义命令(推荐)
2020/01/05 Python
Django Model中字段(field)的各种选项说明
2020/05/19 Python
解决Python安装cryptography报错问题
2020/09/03 Python
教你如何用python操作摄像头以及对视频流的处理
2020/10/12 Python
Python机器学习工具scikit-learn的使用笔记
2021/01/28 Python
HTML5跳转小程序wx-open-launch-weapp的示例代码
2020/07/16 HTML / CSS
Camper鞋西班牙官方网上商店:西班牙马略卡岛的鞋类品牌
2019/03/14 全球购物
C语言面试题
2015/10/30 面试题
remote接口和home接口主要作用
2013/05/15 面试题
电气自动化自荐信
2013/10/10 职场文书
护士试用期自我鉴定
2014/02/08 职场文书
党员岗位承诺口号大全
2014/03/28 职场文书
公务员诚信承诺书
2014/05/26 职场文书
土木工程专业本科生求职信
2014/10/01 职场文书
2016自主招生校长推荐信范文
2015/03/23 职场文书
实现GO语言对数组切片去重
2022/04/20 Golang