【译】解构ReactJS的Flux

用ReactJS时不要使用MVC

我将通过列出一些单向数据流的例子来将ReactJS官方实现的Flux和我写的库Reflux作比较。

Facebook的ReactJS开发小组似乎并不待见MVC框架。将MVC模式和ReactJS结合使用了一段时间后,我似乎发现了争议从何而来了。你会遇到一个问题:你应该如何处理数据?ReactJS并不在乎太多关于数据是如何传入的或者贯穿整个Web应用去处理数据。这个几乎是一个架构层面的问题,并不是ReactJS所能涵盖的。于是Facebook中的优秀开发者提出了一个函数式的方法,他们称其为:Flux

Flux的基本思想是可以在Web应用中拥有一个更加函数式的方法来处理数据。Flux介绍了Actions和Data Stores的概念来处理整个应用的事件和数据。数据流大致是这个样子的:

1
Action -> Data Store -> Component

数据的突变必须是在调用Actions时发生的,Data Stores需要监听actions并且改变store中的数据。这让数据结构保持扁平,并让数据的改变操作始终发生在Stores中,这防止了让Components自己处理数据所带来的副作用。

通过使用单向数据流,跟踪数据的改变将更加容易,因为它完全依赖于actions是如何发布的,继而影响整个应用。Components自身仅通过执行调用action来改变应用数据,这样避免了维护上的麻烦。

vertical-align属性与垂直居中

让元素居中对齐是非常常见的需求,首先是水平居中,要实现水平居中行内元素只需要在其父元素上设置text-align: center即可,对于块级元素来说让它的margin-left: automargin-right: auto即可(width不可为auto),那么垂直居中呢?找下css属性发现了vertical-align,感觉就是它了,设置个vertical-align: middle,怎么没有达到预期效果?下面来详细介绍下vertical-align这个属性以及实现垂直居中的若干方法。

vertical-align属性是干什么的

根据W3C Spec中对vertical-align属性的定义:

This property affects the vertical positioning inside a line box of the boxes generated by an inline-level element.

什么是line box?同样来自W3C Spec

The rectangular area that contains the boxes that form a line is called a line box.

这个属性仅影响了单行中行内元素的垂直位置,那么我们会涉及到的元素应该是这样的:

  • inline

  • inline-block

既然我们要垂直居中,垂直居中是相对于垂直高度而言的,然而我们知道height对inline元素无效,那么line box的高度是怎么计算的呢?(还是引用W3C Spec)

The height of a line box is determined by the rules given in the section on line height calculations.

BOM中计算元素相关尺寸或偏移量的方式汇总

元素尺寸

获取元素的尺寸(Dimension),该尺寸为该元素border-box的大小

1
2
3
var rect = element.getBoundingClientRect();  // return ClientRect object
var height = rect.bottom - rect.top;
var width = rect.right - rect.left;

属性 说明
clientHeight / clientWidth 用户可见高度 / 宽度(元素的padding-box高度 / 宽度 - 滚动条宽度)
scrollHeight / scrollWidth 元素的内容高度 / 宽度(包括元素的溢出部分)+padding
offsetHeight / offsetWidth 元素的border-box高度 / 宽度(包括元素的padding+border+滚动条+正文高度 / 宽度)

拖放文件上传功能总结

学习了下HTML5的拖放API,并做了一个拖放文件上传的Demo,server端使用了node.js,github地址

拖放API

在HTML5中,可以让DOM中的某个元素具有可拖放的属性,或者可以将浏览器外的文件拖放到浏览器中,并利用File API做一些后续的处理。先介绍下HTML5的拖放API。

要让DOM中的元素可拖放,需要设置该元素的draggable属性,并赋值为true,就像这样:

1
<div class="demo" draggable="true"></div>

然后介绍下拖放相关的事件,这是我们主要用来实现拖放逻辑的东西。

事件 产生事件的对象 描述
dragstart 被拖放的元素 开始拖放操作
drag 被拖放的元素 在拖放的过程中
dragend 被拖放的元素 拖放操作结束
dragenter 拖放过程中鼠标经过的元素 被拖放的元素进入该元素
dragover 拖放过程中鼠标经过的元素 被拖放的元素在该元素中移动
dragleave 拖放过程中鼠标经过的元素 被拖放的元素离开该元素
drop 拖放的目标元素 拖放元素被放到了该元素上

拖放操作说到底是一种数据交换的操作,即将被拖放元素上的数据传递到拖放目标上去,那么我就需要dataTransfer对象来做这个数据传递的工作。

FormData对象

兼容性:IE10+

FormData对象可以利用一些键值对来模拟表单控件的值,并在XMLHttpRequest 2.0中使用send方法来异步提交表单、上传文件。

创建FormData

通过new关键字调用构造器,构造器接受一个可选参数(HTMLFormElement),根据现有表单得到FormData:

1
2
3
4
var fData = new FormData();

var form = document.getElementById('my-form');
var oData = new FormData(form);

为FormData添加数据

FormData数据仅暴露出一个方法append,用于往FormData中追加数据,第一个参数为字符串,代表key,第二个参数为字符串、File对象或Blob对象,其他类型都会被转换为字符串。

1
2
3
fData.append('key1', 'value1');
fData.append('key2', 'value2');
xhr.send(fData);

当FormData中有File时,XMLHttpRequest的请求头中的Content-Type被自动设置为multipart/form-data

创建并触发自定义事件、模拟事件

本文介绍了创建了使用原生JavaScript API创建事件对象并模拟触发事件的方法。


创建自定义事件对象

可以通过Event构造器来创建一个事件对象:

1
var event = new Event('build');

在IE中,虽然有Event这个构造器,但是直接用new来构造会抛出异常,可以使用一个更老的方法,调用document.createEvent来创建一个事件对象并使用e.initEvent来初始化这个事件对象:

1
2
var event = document.createEvent('Event');
event.initEvent('build', true, true);

第二个参数代表bubbles,表示事件是否可冒泡。第三个参数代表cancelable,表示事件是否可被取消(preventDefault)。

触发事件

在事件目标对象(通常是一个HTMLElement)上调用dispatchEvent来触发某个事件,触发的事件由传递的事件对象决定, 比如触发上面自定义好的build事件:

1
2
3
4
var event = document.createEvent('Event');
event.initEvent('build', true, true);
var box = document.getElementById('box');
box.dispatchEvent(event);

也可以通过这个办法来模拟事件的触发,比如模拟mouseenter事件:

1
2
3
4
var event = document.createEvent('MouseEvent');
e.initEvent('mouseenter', true, true);
var box = document.getElementById('box');
box.dispatchEvent(event);

Javascript语言精粹笔记整理

这两天读了一下《Javascript语言精粹》一书,没有想象中的惊艳,不过在薄薄的100多页中浓缩了许多Javascript的编程技巧,值得细细品味。于是做了该笔记,算是对Javascript知识体系的一个回顾和整理,但并没有把书中的代码直接copy&paste,而是对技巧的罗列,其中对继承那部分,有一些自己的理解。

CSS Reset及相关思考

有一个专门讲CSS Reset的站点。 site

由于各大浏览器的user agent样式(即默认样式)不同,为了尽可能避免浏览器之间样式的差异,重置了css样式,让浏览器之间可以由一个基本相同的样式基准,并在该基准的基础上进行开发。

引入CSS Reset样式

引入CSS Reset,意味着告诉浏览器将所有元素应用上reset的样式,再使用针对页面或业务的特定样式。对于页面加载而言,这不算一个最优的方式,但对于组织css代码而言是一个好方法,因为页面针对不同浏览器都在一个统一的基准上开发。

而通常来说CSS Reset网上有许多现成的(可以去上面的链接里找),但直接引入或者直接复制黏贴不是推荐的做法,这里我直接引用:

The reset styles given here are intentionally very generic. I don’t particularly recommend that you just use this in its unaltered state in your own projects. It should be tweaked, edited, extended, and otherwise tuned to match your specific reset baseline. Fill in your preferred colors for the page, links, and so on. In other words, this is a starting point, not a self-contained black box of no-touchiness.

简单地说,引入bootstrap后,即使html中没有定义任何class或者inline style,依然可以呈现出优雅的页面,即推荐大家根据自己的需求定制自己的CSS Reset,而不是直接拷贝(虽然确实省事)。

Shebang

wiki链接

在计算机科学中,Shebang(也称为Hashbang)是一个由井号和叹号构成的字符序列(#!),其出现在文本文件的第一行的前两个字符。 在文件中存在Shebang的情况下,类Unix操作系统的程序载入器会分析Shebang后的内容,将这些内容作为解释器指令,并调用该指令,并将载有Shebang的文件路径作为该解释器的参数。

1
#!/bin/sh

开头的文件在执行时会实际调用/bin/sh程序(通常是Bourne shell或兼容的shell,例如bash、dash等)来执行。

语法

Shebang这一语法特性由#!开头,即井号和叹号。 在开头字符之后,可以有一个或数个空白字符,后接解释器的绝对路径,用于调用解释器。Shebang行也可以包含需要传递到解释器的特定选项。然而,选项传递的方式随实现的不同而不同。

使用#!/usr/bin/env脚本解释器名称是一种常见的在不同平台上都能正确找到解释器的办法。

Node global bin#!/usr/bin/env node