138
Learning JavaScript in Three Web Apps Dexter.Yy @

Learning JavaScript in Three Web Apps(中文)

Embed Size (px)

DESCRIPTION

iOS卡牌游戏、TodoMVC、真实的豆瓣产品,通过3个从小到大,从原始到专业的web应用项目,来学习JS语言和基于JS的前端开发

Citation preview

Page 1: Learning JavaScript in Three Web Apps(中文)

Learning JavaScript in Three Web Apps

Dexter.Yy @ ⾖豆瓣

Page 2: Learning JavaScript in Three Web Apps(中文)

Overview

• JSMatchismo

• TodoMVC

• GalEditor

Page 3: Learning JavaScript in Three Web Apps(中文)

• 斯坦福iOS应⽤用开发课程 (CS193p, Winter 2013)⾥里的卡牌游戏

• 对⽐比:Cocoa等传统客户端开发环境

• 从零搭建,不引⼊入任何依赖,不使⽤用任何库、框架、编译⼯工具

• 模块化和MVC分层

App 1 - JSMatchismo

Page 4: Learning JavaScript in Three Web Apps(中文)

把HTML看作配置⽂文件,⽽而不是数据和内容

⽤用button.card的个数来配置卡牌数量,⽤用classname和属性来配置状态

先创建⼀一个./index.html

Page 5: Learning JavaScript in Three Web Apps(中文)

创建./css/main.css

把 CSS 看作描述状态的配置⽂文件

随便找⼀一张图⽚片做卡牌背⾯面

Page 6: Learning JavaScript in Three Web Apps(中文)

DOM 是平台(浏览器)⾃自带的、

特定状态下的、彼此之间存在关系的,能被 JS 访问和调⽤用的

『UI/视图组件』实例对象

编辑 HTML 就是在编辑 runtime 中对象的状态和关系

HTML 和 CSS 是前端开发者的画板和

Interface Builder

Page 7: Learning JavaScript in Three Web Apps(中文)

创建 app.js

Page 8: Learning JavaScript in Three Web Apps(中文)

创建 app.js

ECMAScript 5 (ECMA-262-5)

Strict Mode

TC39 ECMA-262 (ECMAScript, ES, JavaScript, JS)

ECMA-357 (E4X)ECMAScript 3 (ECMA-262-3, JavaScript 1.5)

JavaScript 1.6JavaScript 1.8

ECMAScript 4 (ActionScript 3)ECMAScript 5 (ECMAScript 3.1)ECMAScript 5.1 (JavaScript 1.8.5)

ECMAScript 6 (ECMAScript Harmony, ES.next, JavaScript 2.0)

Page 9: Learning JavaScript in Three Web Apps(中文)
Page 10: Learning JavaScript in Three Web Apps(中文)

Function

Object

Function

Object -- * JS最最核⼼心的数据类型和特殊概念* A collection of named values (‘value’: any primitive datatypes, or reference to any objects)* ~= hash table* ~= dictionary* != class instance* Pass by reference (~= pointer)* 除 primitive type之外,万物皆为object* 两种创建⽅方法:Literal(字⾯面量/直接量)、‘new’操作符

Primitive datatype

Page 11: Learning JavaScript in Three Web Apps(中文)

Function

Object

Function

Function -- * 包含 executable code 的 object* Named function 或 Anonymous function* ⽤用字⾯面量创建时,有 Function Declaration 和 Function Expression 两种⽅方式* ⽤用法:structured programming (like C), late binding 的 object method、constructor、创建 lexical scope(词法作⽤用域)、Currying、传递 block (like Ruby)、元编程、……* 某些 built-in / host 对象的 executable code 是 native code

Primitive datatype

Page 12: Learning JavaScript in Three Web Apps(中文)

Function

Object

Function

Primitive datatype -- * 3 + 1:number、string、boolean + undefined* null 是 object,Infinity、NaN 等都是 number* Pass by value* 前三种有 “Wrapper Class” (like Java),但 100% 情况下都只使⽤用字⾯面量,Wrapper的价值是众多原⽣生⼯工具函数(静态⽅方法)

Primitive datatype

Page 13: Learning JavaScript in Three Web Apps(中文)

Global context

Function context

Function context

Execution context (执⾏行上下⽂文)

Stack

Page 14: Learning JavaScript in Three Web Apps(中文)

Activation object == Variable object in function context

{ app: {...}, arguments: [arguments object], this: {Global object}}

Global object == Variable object in global context

{ app: {...}, window: {Global object}, this: {Global object}, Math: {...}, Array: {...}, Object: {...}, ...}

Page 15: Learning JavaScript in Three Web Apps(中文)

export public API

data hiding、private member

(Traditional) Module Pattern

global namespace

Page 16: Learning JavaScript in Three Web Apps(中文)

相同的 Global context

Page 17: Learning JavaScript in Three Web Apps(中文)

创建 model/和

card.js

Page 18: Learning JavaScript in Three Web Apps(中文)

进⼊入 execution context

解析形式参数和所有declaration(函数声明和变量声明),填充当前上下⽂文的 Variable object

{ Card: function(){...} exports: function(){...}}

从上⾄至下执⾏行代码

退出函数上下⽂文,返回上⼀一级的上下⽂文继续执⾏行代码,刚才的 Variable object 作为 Scope 被

Card、exports 等还能继续访问的函数继续保存

Page 19: Learning JavaScript in Three Web Apps(中文)

假如代码是这样…

函数表达式和普通的变量声明

对未声明变量赋值,其实是 window.b = 10 的省略写法

函数表达式

函数声明形式参数

Page 20: Learning JavaScript in Three Web Apps(中文)

进⼊入 execution context

解析形式参数和所有declaration(函数声明和变量声明),填充当前上下⽂文的 Variable object

{ Card: function(){...} exports: undefined, a: undefined, c: undefined, d: 1}

从上⾄至下执⾏行代码

{ Card: function(){...} exports: function(){...}, a: 10, c: 30, d: 1}

Global Object:{ window: {Global}, card: function(){...}, b: 10, ...}

Page 21: Learning JavaScript in Three Web Apps(中文)

Contructor(构造函数) 是普通函数,不是Class

prototype 是普通对象

Prototype based model of OOP

new 操作符⽤用函数的 prototype 属性作为模板,复制出新的对象,Card 本⾝身的

return 只要不是对象就被忽略

以⼯工⼚厂函数 / Wrapper / 模块对象作为public API,避免紧耦合等问题

Page 22: Learning JavaScript in Three Web Apps(中文)

this 是 late binding 的

(new Card().contents)() 时, this 指向新对象,

(false || new Card().contents)() 时,this 指向 Global Object

⽤用 new 调⽤用 Card 时,在进⼊入 Card 函数上下⽂文的阶段,this 被指向复制

出来的新对象

Card 和 contents 被作为属性(property)形式的引⽤用值被调⽤用时,this 指向属性所属的对象,当作为 Identifier (⽐比如变量名)形式的引⽤用值或实际值被调⽤用时,this 被默认填充为 Global Object

Page 23: Learning JavaScript in Three Web Apps(中文)

jQuery style 的存取器(Ad-Hoc Polymorphism)

⽤用下划线前缀显式声明private member,但不存在真正的约束

this._contents 使⽤用前不需要声明,因为 JS 的 object 都是 dynamic mutable object,

不存在的属性、没有实参的形参、未赋值的变量,访问得到的都是 undefined

prototype 只应该⽤用来定义⽅方法,属性必须在构造函数内定义才能保证每个实例都持有⾃自⼰己的属性(引⽤用类型)

Page 24: Learning JavaScript in Three Web Apps(中文)

此处类似 Duck Typing(Parametric Polymorphism)因为从后⾯面的实现可以看到,函数的⾏行为总是⼀一致

⾃自省/类型判断:typeof, Array.isArray, toString,

constructor, instanceof, ...

Page 25: Learning JavaScript in Three Web Apps(中文)

block ⻛风格的 iterator(迭代器)JavaScript 1.6 array methods

⼿手动指定上下⽂文

Page 26: Learning JavaScript in Three Web Apps(中文)

compare ⾃自⼰己的上下⽂文⾥里没有声明 score 变量,会往 Scope

chain(作⽤用域链)的上层爬,找到 match 上下⽂文⾥里的 score

⼿手动指定上下⽂文

Page 27: Learning JavaScript in Three Web Apps(中文)

函数内的函数,都会形成 Closure (闭包),通过⾃自⼰己的 Scope 存储上层函数的

“Variable object” (因此也能访问到上层函数的 Scope 存储的更上层 “Variable object” )

假如 compare 被暴露给外部访问,则 match 的上下⽂文会⼀一直保留,不会被 GC(垃圾

回收)

Page 28: Learning JavaScript in Three Web Apps(中文)

创建deck.js

Page 29: Learning JavaScript in Three Web Apps(中文)

惰性初始化的getter

Page 30: Learning JavaScript in Three Web Apps(中文)

可选参数和默认值的实现,JS 不⽀支持 ruby/python 中的 named arguments 或 *args

Page 31: Learning JavaScript in Three Web Apps(中文)
Page 32: Learning JavaScript in Three Web Apps(中文)

缓存作⽤用域链上层的变量或函数结果,常⽤用于性能热点优化

或节省字符

从 array 中删除

Page 33: Learning JavaScript in Three Web Apps(中文)

假如有错误代码…

Page 34: Learning JavaScript in Three Web Apps(中文)

静态分析对JS开发⾮非常重要

Page 35: Learning JavaScript in Three Web Apps(中文)

JSHint

Vim ⾥里常⽤用的语法检查插件

Page 36: Learning JavaScript in Three Web Apps(中文)

每个项⺫⽬目可以有不同的 JSHint 的配置

Page 37: Learning JavaScript in Three Web Apps(中文)

测试动态环境中的debug

Page 38: Learning JavaScript in Three Web Apps(中文)

console 中的未捕获异常

Page 39: Learning JavaScript in Three Web Apps(中文)

这个按钮⾮非常重要

addCard 的 execution context

回溯跳过第三⽅方/底层代码,找到真正引发异常的逻辑

Page 40: Learning JavaScript in Three Web Apps(中文)

创建playingCard.js

(更具体的『扑克牌』)

显式声明依赖,不直接使⽤用全局变量

第⼀一次引⼊入对其他模块的依赖

Page 41: Learning JavaScript in Three Web Apps(中文)

必须⼿手动调⽤用『⽗父类』的构造函数,⼿手动绑定 this

Object.create 可以直接⽤用⼀一个对象为原型⽣生成新对象,不需要构

造函数和 new

继承的简单实现

继承的关键是原型链

Page 42: Learning JavaScript in Three Web Apps(中文)

『⼦子类』的⽅方法

在『⼦子类』原型上扩展出这些⽅方法

Page 43: Learning JavaScript in Three Web Apps(中文)

牌⾯面花⾊色的存取器

默认值

快速检索常⽤用的数据结构让API的⾏行为尽量⼀一致

Page 44: Learning JavaScript in Three Web Apps(中文)

改为静态⽅方法,频繁执⾏行的函数会⽣生成⼤大量⼀一次性的数据,影响旧浏览

器的GC性能

静态⽅方法

模块内部使⽤用的数据

Page 45: Learning JavaScript in Three Web Apps(中文)

牌⾯面⼤大⼩小的存取器

存储编号,之后查表转换

Page 46: Learning JavaScript in Three Web Apps(中文)

override『⽗父类』的 contents ⽅方法

Page 47: Learning JavaScript in Three Web Apps(中文)

创建playingCardDeck.js

(更具体的『扑克牌桌』)

Page 48: Learning JavaScript in Three Web Apps(中文)

『⼦子类』新增的初始化

Page 49: Learning JavaScript in Three Web Apps(中文)

原⽣生⽅方法得到的是 nodeList 对象,不是 Array

⽤用以上model来修改视图,测试效果

nodeList 有 length 属性、接受数字键名,所以能⽤用

Array 的迭代器(duck typing)

作为配置的HTML应该尽可能抽象和语义纯粹,⽤用于实现特定外观的

结构可由代码⽣生成

Page 50: Learning JavaScript in Three Web Apps(中文)

在⻚页⾯面⾥里使⽤用之前写的 module ⽂文件时,需要⼈人⼯工控制依赖关系(上下顺序)

导出 app 对象可以让应⽤用代码与具体⻚页⾯面解耦

Page 51: Learning JavaScript in Three Web Apps(中文)

效果是这样

Page 52: Learning JavaScript in Three Web Apps(中文)

视图相关代码常常包含 DOM 操作,与主要业务逻辑⽆无关,它们⼀一定会越来越多,越来越繁琐,喧宾夺主。

直接在视图代码中访问和依赖 model,会导致视图代码⽆无法进⼀一步抽象和通⽤用化,⽆无法与业务逻辑解耦。

在进⼀一步开发之前,先审视 app.js。

考虑以上两点,可预⻅见 app.js 会越来越⻓长,越来越像⾯面条式脚本,难以维护、扩展和抽象。

Page 53: Learning JavaScript in Three Web Apps(中文)

约定:不允许在 app.js 中直接操作 DOM

有了这个约定,就必须将视图的具体实现拆分出去,

app.js 仅⽤用于调⽤用和组合 view 和 model 模块、监听消息、公开接⼝口,也就是

controller

创建 view.js

给 view 传递纯粹的、逻辑⽆无关的数据,⽽而不是 model 本⾝身

Page 54: Learning JavaScript in Three Web Apps(中文)

Smalltalk-80

Cocoa

Ruby On Rails

ASP.NET

Model View Controller: History, theory and usage

很类似 Cocoa 的 MVC 分层

Page 55: Learning JavaScript in Three Web Apps(中文)

Cocoa 的 MVC 架构,来⾃自斯坦福CS193p

Page 56: Learning JavaScript in Three Web Apps(中文)

因为这个项⺫⽬目不复⽤用第三⽅方代码,DOM 对象本⾝身就相当于各种视图组件,view.js ⽤用来组合这些

视图组件

重构完毕,可以继续开发了,开始实现交互

Page 57: Learning JavaScript in Three Web Apps(中文)

加⼊入 view.js

Page 58: Learning JavaScript in Three Web Apps(中文)

加⼊入内部结构的样式

描述新的状态

Page 59: Learning JavaScript in Three Web Apps(中文)

快速测试不同状态,不依赖交互

Page 60: Learning JavaScript in Three Web Apps(中文)
Page 61: Learning JavaScript in Three Web Apps(中文)

先设计视图接⼝口,视图不能依赖和主动调⽤用 controller,只能⼲⼴广播消息,类似 Cocoa 的UI组件向 target

转发 action

controller 监听消息,操作数据

Page 62: Learning JavaScript in Three Web Apps(中文)

controller 操作数据之后,需要通知视图组件⽤用新的数据

更新 UI

不在初始化阶段填充卡牌内容

每次翻牌时随机填充内容

Page 63: Learning JavaScript in Three Web Apps(中文)

跳转表,将不同UI对象上的交互动作通过选择器分发给不同的handler函数

事件代理捕获整个应⽤用范围的交互事件,⽤用跳转表分发

设计视图内部的接⼝口

Page 64: Learning JavaScript in Three Web Apps(中文)

⼲⼴广播消息,传递视图⾃自⼰己加⼯工处理过的交互信息(index)

Page 65: Learning JavaScript in Three Web Apps(中文)

实现事件代理

原⽣生的 matchesSelector ⽅方法在不同浏览器⾥里名称不同,需要解决兼容性问题

Page 66: Learning JavaScript in Three Web Apps(中文)

兼容性封装,⽣生成统⼀一的常量

尽可能⽤用特性侦测,⽽而不是浏览器侦测(依靠

user agent)

动态⽣生成⽅方法名,JS 常⽤用的元编程⼿手段

Page 67: Learning JavaScript in Three Web Apps(中文)

为避免在赋值前被调⽤用, 变量声明放在顶部

函数声明可以放在任意位置,由于函数通常封装了不属于主要逻辑的具体实现,为了让代码更抽象更可读,应该拆分出去或移到不显眼的位置(底部)

Page 68: Learning JavaScript in Three Web Apps(中文)

加⼯工处理交互事件对象,⽣生成更抽象的、UI⽆无关的数据

分发给 handler 函数的事件可能来⾃自不同的UI⼦子元

素,需要统⼀一

利⽤用 button 元素原⽣生的状态

Page 69: Learning JavaScript in Three Web Apps(中文)

设计消息接⼝口

实现消息接⼝口

Page 70: Learning JavaScript in Three Web Apps(中文)

⽐比构造函数更简单的对象⼯工⼚厂

缺点是每次⽣生成新对象都需要重复⽣生成这些函数,

且不能继承。但是在有必要的时候,这个函数的内部可以很⽅方便的重构为⽤用构造函数实现

Page 71: Learning JavaScript in Three Web Apps(中文)

⼲⼴广播瞬时消息

监听/订阅/观察消息

取消订阅

Page 72: Learning JavaScript in Three Web Apps(中文)

实现UI更新接⼝口

Page 73: Learning JavaScript in Three Web Apps(中文)

加⼊入状态栏和次数统计

Page 74: Learning JavaScript in Three Web Apps(中文)

把 UI组件 / DOM 对象组合到⾃自⼰己⾝身上,类似

Cocoa ⾥里的 outlet

更新状态栏⾥里的次数统计

Page 75: Learning JavaScript in Three Web Apps(中文)

实现类似其他语⾔言的字符串格式化

Page 76: Learning JavaScript in Three Web Apps(中文)

⽤用相同的更新⽅方法来初始化视图

实现更新卡牌接⼝口

Page 77: Learning JavaScript in Three Web Apps(中文)

初始化时没有传⼊入数据,所以字符串拼接时会把不存在属性的值 undefined 转

成字符串

Page 78: Learning JavaScript in Three Web Apps(中文)

format 也能充当最简单的JS模板转换

基于字符串的JS模板

Page 79: Learning JavaScript in Three Web Apps(中文)

模板转换⽅方法都会⾃自动将 undefined 处理为空字符串

Page 80: Learning JavaScript in Three Web Apps(中文)

除了UI的内容,也更新UI的状态

尽可能只在 JS 或主要代码逻辑⾥里处理状态的迁移转换,不要实现状态细节,将具体实现和描述交给 css 之类的配置

⽂文件和 DSL (领域语⾔言)

Page 81: Learning JavaScript in Three Web Apps(中文)

更新数据的状态,从⽽而更新视图的状态

Page 82: Learning JavaScript in Three Web Apps(中文)

交互(点击)后的效果

Page 83: Learning JavaScript in Three Web Apps(中文)

在 css ⾥里描述状态的细节(过渡效果动画)

css3 的 transition ⾃自动为状态的切换⽣生成过渡动画

Page 84: Learning JavaScript in Three Web Apps(中文)

测试交互效果

Page 85: Learning JavaScript in Three Web Apps(中文)

另⼀一种动画实现,引⼊入 animate.css 中的⼀一个关键帧动画

Page 86: Learning JavaScript in Three Web Apps(中文)

css 同样要⼿手动管理依赖和先后顺序

Page 87: Learning JavaScript in Three Web Apps(中文)

初始化动画配置

切换状态触发关键帧动画

Page 88: Learning JavaScript in Three Web Apps(中文)

测试交互效果

Page 89: Learning JavaScript in Three Web Apps(中文)

解决交互之后,开始实现真正的游戏逻辑

创建 cardMatchingGame.js

Page 90: Learning JavaScript in Three Web Apps(中文)

通过参数传递把 Deck 或其『⼦子类』的实例『组合』进来,避免当前模块依赖具体的

Deck 模块

Page 91: Learning JavaScript in Three Web Apps(中文)

翻牌时的游戏规则

改变 model 的状态

Page 92: Learning JavaScript in Three Web Apps(中文)

游戏规则需要调⽤用 playingCard 的 match ⽅方法

Page 93: Learning JavaScript in Three Web Apps(中文)

重载 Card 的 match ⽅方法,实现不同的积分奖励

Page 94: Learning JavaScript in Three Web Apps(中文)

奖励、惩罚和成本

Page 95: Learning JavaScript in Three Web Apps(中文)

⽤用 HTML 配置来初始化游戏把扑克牌桌的实例组合到游戏规则⾥里

Page 96: Learning JavaScript in Three Web Apps(中文)

⽣生成数据、更新视图的代码不属于主要业务逻辑,应该单独组织到⼀一起

牌桌被组合到游戏规则⾥里之后,controller不需要维护⾃自⼰己的牌桌

Page 97: Learning JavaScript in Three Web Apps(中文)

数据中的状态尽可能交给 model ⾃自⼰己来维护,在 controller ⾥里尽量只调⽤用 model 的抽象接⼝口,⽽而不是直接修改 model 中的

数据状态

Page 98: Learning JavaScript in Three Web Apps(中文)

增加状态栏⾥里积分的更新接⼝口

Page 99: Learning JavaScript in Three Web Apps(中文)

实现积分的更新接⼝口

Page 100: Learning JavaScript in Three Web Apps(中文)

积分的UI

Page 102: Learning JavaScript in Three Web Apps(中文)

Source code: https://github.com/dexteryy/JSMatchismo

Page 103: Learning JavaScript in Three Web Apps(中文)

• 著名开源项⺫⽬目• 对⽐比:其他JS应⽤用开发框架

• oz.js⽀支持的模块化

• 复⽤用第三⽅方模块/组件(OzJS微框架)

• ⽤用包管理⼯工具管理依赖• 项⺫⽬目中的源代码⽂文件都必须是能直接在浏览器⾥里使⽤用的静态⽂文件

App II - TodoMVC

Page 105: Learning JavaScript in Three Web Apps(中文)

第三⽅方组件都会下载安装到专⻔门的⺫⽬目录

包管理⼯工具(bower)⾃自动读取的项⺫⽬目配置,

包含对第三⽅方组件的依赖

TodoMVC 项⺫⽬目提供的外观实现

Page 106: Learning JavaScript in Three Web Apps(中文)

⽤用包管理⼯工具初始化项⺫⽬目,⾃自动下载安装依赖的第三⽅方项⺫⽬目

Page 107: Learning JavaScript in Three Web Apps(中文)
Page 108: Learning JavaScript in Three Web Apps(中文)

⾼高级浏览器⾥里不需要 ES5 shim

新增 main.js,相当于上个项⺫⽬目中⻚页⾯面内的inline script,增加了模块相关的配置

把模块名关联到包管理⼯工具的安装路径

oz.js实现的模块化机制的配置

禁⽌止使⽤用全局变量

Page 109: Learning JavaScript in Three Web Apps(中文)

在动态环境⾥里⾃自动处理模块的依赖和加载,不需要⼿手动维护⽂文件的使⽤用和先后顺序

Page 110: Learning JavaScript in Three Web Apps(中文)

有了第三⽅方model库(NervJS),model 模块不但书写更简洁了,也更强⼤大了

扩展出条⺫⽬目model⾃自⼰己的⽅方法

model 中的数据模式(schema)和默认值

Page 111: Learning JavaScript in Three Web Apps(中文)

列表model的成员是条⺫⽬目model

Page 112: Learning JavaScript in Three Web Apps(中文)

view.js 仍然像上个项⺫⽬目⼀一样⽤用事件代理(SovietJS)维护交互逻辑

Page 113: Learning JavaScript in Three Web Apps(中文)

双击和键盘事件

事件代理的初始化

Page 114: Learning JavaScript in Three Web Apps(中文)

因为可以复⽤用第三⽅方的 UI 组件了,view.js 现在主要承担组合这些组件、提供更抽象 API 的⼯工作,避免 UI组件之间的耦合

Page 115: Learning JavaScript in Three Web Apps(中文)

view/actionview 是 UI库⾥里 moui/actionview 的进⼀一步封装,满⾜足项⺫⽬目的业务需求

view.js ⾥里使⽤用 view组件的接⼝口,⽽而不是直接⽤用 DOM 的接⼝口

Page 116: Learning JavaScript in Three Web Apps(中文)

⽤用 view/actionview 封装出更具体的警告框和确认框组件

Page 117: Learning JavaScript in Three Web Apps(中文)
Page 118: Learning JavaScript in Three Web Apps(中文)

model 组件的初始化和操作

不再需要像上个项⺫⽬目⼀一样每次修改 model 都需要⼿手动调⽤用

updateUI

Page 119: Learning JavaScript in Three Web Apps(中文)

可以监听 model 的改变,⾃自动更新 UI

(View Model Binder)

⽤用 model ⾃自⼰己的⽅方法⽣生成纯数据传给视图

Page 120: Learning JavaScript in Three Web Apps(中文)

这个项⺫⽬目是包含多个 URL 的单⻚页应⽤用,app.js 像服务器端web框架的 controllter ⼀一样管理路由

Page 121: Learning JavaScript in Three Web Apps(中文)
Page 123: Learning JavaScript in Three Web Apps(中文)

• 真实的⾖豆瓣产品• 对⽐比:服务器端web框架中的静态⽂文件

• 项⺫⽬目中的⽂文件都是源代码,不再兼任『静态⽂文件』

• 静态环境中的预处理/编译/构建

• ⽤用任务管理⼯工具整合⼤大量⼯工具和⼯工作流• 应⽤用本⾝身的组件化,业务逻辑的分层,与服务器端视图解耦

App III - GalEdtitor

Page 124: Learning JavaScript in Three Web Apps(中文)
Page 125: Learning JavaScript in Three Web Apps(中文)

增加了任务管理⼯工具(Grunt)的配置

从包管理安装的⽂文件中⾃自动提取项⺫⽬目需要的部分,按项⺫⽬目⾃自⼰己的组织结构来放置(grunt-dispatch)

Page 126: Learning JavaScript in Three Web Apps(中文)

因为第三⽅方组件的进⼀一步组织,模块配置简单了很多

main.js 不再像上个项⺫⽬目那样初始化应⽤用,⽽而是变成了单纯的配置,相当于JS的构建脚本

Page 127: Learning JavaScript in Three Web Apps(中文)

JS模板也被拆分为独⽴立的源代码⽂文件

模板⽂文件被编译成JS模块

Page 128: Learning JavaScript in Three Web Apps(中文)

css 也可以模块化和复⽤用第三⽅方库( scss/

compass )

Page 129: Learning JavaScript in Three Web Apps(中文)

项⺫⽬目构建过程中会将 js、css、html、图⽚片、JS模板分别从源⽂文件编译为⺫⽬目标⽂文件,再构建出发布⽂文件,再⽤用这些⽣生成的静态⽂文件填充 public ⺫⽬目录

Page 130: Learning JavaScript in Three Web Apps(中文)

静态环境中的构建

⽤用 grunt-furnace 构建模板模块

⽤用 Ozma 构建 JS 的静态⽂文件

Page 131: Learning JavaScript in Three Web Apps(中文)

上个项⺫⽬目中在动态环境中处理的模块加载改为在静态环境⾥里完成,Ozma 会将项⺫⽬目⾥里的JS源⽂文件按需要打包到静态⽂文

件中(⼀一个或多个)

Page 132: Learning JavaScript in Three Web Apps(中文)

浏览器⾥里只需要加载最少量的⽂文件

Page 133: Learning JavaScript in Three Web Apps(中文)

在⻚页⾯面⾃自⾝身的代码中配置、修改、扩展、初始化和组织

调⽤用 app 的 API

docs/index.html ⽤用于应⽤用本⾝身(离线客户端)的演⽰示和调试,没有特定的后端,所以保存图⽚片是纯前端

模拟

Page 134: Learning JavaScript in Three Web Apps(中文)

⽤用本地存储

Page 135: Learning JavaScript in Three Web Apps(中文)

在真实产品中的⻚页⾯面模板(后端视图)⾥里使⽤用时,实现真正的保存图⽚片

功能

Page 136: Learning JavaScript in Three Web Apps(中文)

⽤用后端视图中输出的数据(相当于预加载)初始化应⽤用,如果没有数据,则另外请求后端API

业务逻辑可抽象出组件、应⽤用、⻚页⾯面三个层次,前两个都可以是通过包管理⼯工具引⼊入的⼦子项⺫⽬目

(独⽴立代码仓库)

Page 137: Learning JavaScript in Three Web Apps(中文)

课后思考

• 将第⼀一个项⺫⽬目跟⾮非web的GUI开发⽅方式做对⽐比

• 三个项⺫⽬目中代码的相似之处• 前两个项⺫⽬目的约束被解除之后带来的改变