初探redux

初探redux

  1. 三大原则

    • 单一数据源

      整个应用的 state 被储存在一棵 object tree 中,并且这个 object tree 只存在于唯一一个 store 中。

      来自服务端的 state 可以无需编写更多代码的情况下被序列化并注入客户端中。

    • State 是只读的

      唯一改变 state 的方法就是触发 action ,action 是一个用于描述已发生事件的普通对象。

      所有的修改都被集中化处理,且按照一个接一个的顺序执行,不用担心 race condition 的出现。

      Action 就是普通对象,可以被 console 打印、序列化、储存、后期调试。

    • 使用纯函数来执行修改

    • 为了描述 action 如何改变 state tree,需要编写 reducers

    • Reducer 只是一些纯函数,它接收先前的 state 和 action,并返回新的 state。

    • 因为 reducer 只是函数,你可以控制它们被调用的顺序,传入附加数据,甚至编写可复用的 reducer 来处理一些通用任务,如分页器。

  2. 先前技术

    • Redux 的灵感来源于 Flux 的几个重要特性。和 Flux 一样,Redux 规定,将模型的更新逻辑全部集中于一个特定的层(Flux 里的 store,Redux 里的 reducer)。Flux 和 Redux 都不允许程序直接修改数据,而是用一个叫作 “action” 的普通对象来对更改进行描述。

    • Redux 并没有 dispatcher 的概念。原因是它依赖纯函数来替代事件处理器。纯函数构建简单,也不需额外的实体来管理它们。你可以将这点看作这两个框架的差异或细节实现,取决于你怎么看 Flux。Flux 常常被表述为 (state, action) => state。从这个意义上说,Redux 无疑是 Flux 架构的实现,且得益于纯函数而更为简单。

    • 应该在 reducer 中返回一个新对象来更新 state 。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      const counter = (state = 0, action) => {
      switch (action.type) {
      case 'INCREMENT':
      return state + 1;
      case 'DECREMENT':
      return state - 1;
      default:
      return state;
      }
      }
      const { createStore } = Redux;
      const store = createStore(counter);
      const render = () => {
      document.body.innerText = store.getState();
      }
      console.log(store.getState());
      // 0
      store.dispatch({ type: 'INCREMENT' });
      console.log(store.getState());
      // 1
      store.subscribe(render);
      render();
      document.addEventListener('click', ()=> {
      store.dispatch({ type: 'INCREMENT' });
      })
      expect(
      counter(0, { type: 'INCREMENT' })
      ).toEqual(1);
      expect(
      counter(1, { type: 'INCREMENT' })
      ).toEqual(2);
      expect(
      counter(2, { type: 'DECREMENT' })
      ).toEqual(1);
      expect(
      counter(1, { type: 'DECREMENT' })
      ).toEqual(0);

      subscribe , getState() , render

  3. 基础知识

    • Action

    • Action 是把数据从应用(译者注:这里之所以不叫 view 是因为这些数据有可能是服务器响应,用户输入或其它非 view 的数据 )传到 store 的有效载荷。它是 store 数据的唯一来源。一般来说你会通过store.dispatch() 将 action 传到 store。

    • 1
      2
      3
      4
      5
      6
      7
      const ADD_TODO = (text) => {
      return {
      type: 'ADD_TODO',
      id: nextTodoId++,
      text
      }
      }
    • Action 本质上是 JavaScript 普通对象。我们约定,action 内必须使用一个字符串类型的 type 字段来表示将要执行的动作。多数情况下,type 会被定义成字符串常量。当应用规模越来越大时,建议使用单独的模块或文件来存放 action。

    • 1
      import { ADD_TODO, REMOVE_TODO } from './actionType'
    • 我们应当尽量减少在 action 中传递数据。

    • Action 创建函数

    • 1
      2
      3
      4
      5
      6
      function addTodo(text) {
      return {
      type: ADD_TODO,
      text
      }
      }
    • Reducer

    • 处理 Reducer 关系时的注意事项

      开发复杂的应用时,不可避免会有一些数据相互引用。建议你尽可能地把 state 范式化,不存在嵌套。把所有数据放到一个对象里,每个数据以 ID 为主键,不同实体或列表间通过 ID 相互引用数据。把应用的 state 想像成数据库。这种方法在 normalizr 文档里有详细阐述。例如,实际开发中,在 state 里同时存放 todosById: {只要传入参数相同,返回计算得到的下一个 state 就一定相同。没有特殊情况、没有副作用,没有 API 请求、没有变量修改,单纯执行计算。 id -> todo }todos: array 是比较好的方式,本文中为了保持示例简单没有这样处理。

    • Action 处理

    • 确定 state 对象结构之后,就可以开始开发 reducer。reducer 就是一个纯函数,接收旧的 state 和 action,返回新的 state。

    • 1
      (previousState, action) => newState
    • 之所以称作 reducer 是因为它将被传递给 Array.prototype.reduce(reducer, ?initialValue) 方法。保持 reducer 纯净非常重要。永远不要在 reducer 里做这些操作:

      • 修改传入参数;
      • 执行有副作用的操作,如 API 请求和路由跳转;
      • 调用非纯函数,如 Date.now()Math.random()
    • 只要传入参数相同,返回计算得到的下一个 state 就一定相同。没有特殊情况、没有副作用,没有 API 请求、没有变量修改,单纯执行计算。

    • Redux 首次执行时,state 为 undefined ,此时可以借机设置并返回应用的初始 state。

    • 1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      import { VisibilityFilters } from './actions'
      const initialState = {
      visibilityFilter: VisibilityFilters.SHOW_ALL,
      todos: []
      };
      function todoApp(state, action) {
      if (typeof state === 'undefined') {
      return initialState
      }
      // 这里暂不处理任何 action,
      // 仅返回传入的 state。
      return state
      }

30days-React-Native

准备工作

1
2
3
4
5
1. npm install -g react-native-cli
2. react-native init YourProjectName
3. XCode 中打开刚刚创建的工程-AwesomeProject/ios/AwesomeProject.xcodeproj
4. run
5. 在index.ios.js中进行修改

flex布局

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
display: flex; //块级伸缩容器
display: inline-flex; //行内级伸缩容器
flex-direction: row; //水平方向,从左到右
flex-direction: reverse; //水平方向,从右到左
flex-direction: column; //垂直方向,从上到下
flex-direction: column-reverse; //垂直方向,从下到上
flex-wrap: nowrap; //默认值,不换行
flex-wrap: wrap; //允许换行
flex-wrap: wrap-reverse; //允许换行,若水平轴为主轴,则从下到上
flex-flow: row nowrap;
//伸缩项目在主轴上的对齐方式
justify-content: flex-start; //默认值,从主轴起始位置靠齐
justify-content: flex-end; //从主轴线结束位置靠齐
justify-content: center;
justify-content: space-between; //均匀分布在主轴,中间有空格
justify-content: space-around; //同上,但是两边各会保留一半空间
//伸缩项目在交叉轴上的对齐方式
align-items: flex-start; //交叉轴起始位置
align-items: flex-end;
align-items: center;
align-items: baseline; //根据基线对齐
align-items: stretch; //交叉轴方向拉伸至整个容器
//伸缩项目换行后在交叉轴上的对齐方式
align-content: flex-start;
align-content: flex-end;
align-content: center;
align-content: space-between; //伸缩项目在交叉轴中平均分布
align-content: space-around; //同上,但在两边各有一半空间
align-content: strectch; //在交叉轴延展以占用剩余空间
order: -1; //定义项目的排列顺序
flex-grow: 2; //定义伸缩项目的放大比例
flex-shrink: 3; //定义伸缩项目的收缩能力
flex-basis: 100px; //定义伸缩项目的基准值
flex: none | flex-grow flex-shrink flex-basis

在react-native中支持flexbox

1
2
3
4
5
6
alignItems: flex-start | flex-end | center | stretch
alignSelf: auto | flex-start | flex-end | center | strecth
flex: number;
flexDirection: row | column
flexWrap: wrap | nowrap
justifyContent: flex-start | flex-end | center | space-between | space-around

克隆项目

1
2
3
4
5
6
git clone https://github.com/fangwei716/30-days-of-react-native.git
git checkout RN@0.25
react-native-vector-icons
需要手动将字体添加到Xcode的项目中
首先将node_modules/react-native-vector-icons中的Fonts拖拽到Xocde中
编辑 Info.plist 添加你需要的字体

index.ios.js

  1. API

    • AppRegistry是 JS 运行所有 React Native 应用的入口。
      应用的根组件应当通过AppRegistry.registerComponent方法注册自己,然后原生系统才可以加载应用的代码包并且在启动完成之后通过调用AppRegistry.runApplication来真正运行应用。
    • TouchableHighlight 当按下的时候,封装的视图的不透明度会降低
      同时会有一个底层的颜色透过而被用户看到,使得视图变暗或变亮。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      renderButton: function() {
        return (
          <TouchableHighlight onPress={this._onPressButton}>
            <Image
              style={styles.button}
              source={require('./button.png')}
            />
          </TouchableHighlight>
        );
      },
      //TouchableHighlight只支持一个子节点
    • NavigatorIOS 包装了UIKit的导航功能,可以使用左划功能来返回上一界面

  • 路由

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    //一个路由是用于描述导航器中一页的对象。
    render: function() {
      return (
        < NavigatorIOS
          initialRoute={{
            component: MyView,
            title: 'My View Title',
            passProps: { myProp: 'foo' },
          }}
        />
      );
    }
    //现在 MyView 会被导航器渲染出来。它可以通过route
    属性获得对应的路由对象,导航器本身,还有所有passProps
    中传递的属性。
  • 导航器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    var MyView = React.createClass({
      _handleBackButtonPress: function() {
        this.props.navigator.pop();
      },
      _handleNextButtonPress: function() {
        this.props.navigator.push(nextRoute);
    },
      ...
    });
    //一个导航器对象包括如下函数:
    //1. push( route ) - 导航器跳转到一个新的路由
    //2. pop() - 回到上一页

day1-计时器

一个IOS系统定时APP,功能与系统定时器一致。

将页面分为时间显示部分,控制部分,显示计次共三个部分。
每个部分独立渲染组件和样式。
实现的功能有:启动定时器,计次,停止,复位。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//时间控制部分
this.setState({
currentTime: (new Date()).getTime()
})
//当前时间 = 累加时间 + 当前时间 - 开始计时时间
countingTime = this.state.timeAccumulation + this.state.currentTime - this.state.initialTime;
//换算成时,分,秒
minute = Math.floor(countingTime/(60*1000));
second = Math.floor((countingTime-60000*minute)/1000);
milSecond = Math.floor((countingTime%1000)/10);
seccountingTime = countingTime - this.state.recordTime;
secminute = Math.floor(seccountingTime/(60*1000));
//这个地方原来的作者写错了6000,在git上提了issue
secsecond = Math.floor((seccountingTime-60000*secminute)/1000);
secmilSecond = Math.floor((seccountingTime%1000)/10);
//时,分,秒小于10则补零
this.setState({
totalTime: (minute<10? "0"+minute:minute)+":"+(second<10? "0"+second:second)+"."+(milSecond<10? "0"+milSecond:milSecond),
sectionTime: (secminute<10? "0"+secminute:secminute)+":"+(secsecond<10? "0"+secsecond:secsecond)+"."+(secmilSecond<10? "0"+secmilSecond:secmilSecond),
})

day2-天气预报

一个IOS系统的天气app,数据固定

这一部分比较有难度的是对天气数据的展示处理。

以及滑动时的状态变化。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
static propTypes = {
back: React.PropTypes.func.isRequired,
};
constructor(props) {
super(props)
this.state = {
weather: weatherData,
}
}
componentDidMount() {
StatusBar.setBarStyle(1);
}
_back() {
this.props.back();
}

day3-Twitter开场动画

动画实现的思路是将中间的小图标放大,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
componentDidMount() {
Animated.timing(
this.state.transformAnim,
{toValue: 50,
duration: 1200,
delay:2000,
easing: Easing.elastic(2),
},
).start();
Animated.timing(
this.state.opacityAnim,
{toValue: 0,
duration: 800,
easing: Easing.elastic(1),
delay:2200,
},
).start();
setTimeout(() => {
this.props.hideThis();
}, 3300);
}

以及下拉刷新状态的控制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
constructor() {
super();
this.state = {
isRefreshing: false,
};
}
_onRefresh() {
this.setState({
isRefreshing: true,
});
setTimeout(() => {
this.setState({
isRefreshing: false,
});
}, 1000);
}

Javascript忍者秘籍📒

Chapter 3

函数是第一型
  1. 他们可以通过字面量进行创建
  2. 他们可以赋值给变量,数组或其他对象的属性
  3. 他们可以作为函数的返回值进行返回
  4. 他们可以拥有动态的创建并赋值的属性
  5. 此外函数还可以被调用( invoked )<一般以异步方式进行调用>
浏览器的事件轮询

类似于图形用户界面( GUI )和桌面应用程序,事件轮询大多采用下面的机制:

  1. 创建用户界面
  2. 进入轮询,等待时间触发
  3. 调用时间处理程序( addEventListener )

浏览器中,以下事件有可能穿插发生:
浏览器事件,网络事件,用户事件,计时器事件

浏览器的事件轮询是单线程的(single-threaded)。每个事件是按照队列中所放置的位置来处理的。

回调

我们定义一个函数,以便其他的一些代码在合适的地方回头再调用它。

1
2
3
4
//使用比较器进行排序
//array.sort()方法有一个重载,接受一个包含比较方法的对象
var value = [ 1,34,23,65,12,9 ];
value.sort( function ( value1,value2 ){ return value2 - value1; });

函数声明
  1. 命名一个函数时,该名称在整个函数的声明范围内是有效的。如果一个函数声明在顶层,那么window对象上的同名属性将引用到该函数。

函数会直接声明到顶层对象的同名属性

  1. 作用域
  • 变量声明的作用域开始于声明的地方,结束于所在函数的结尾,与代码嵌套无关。
  • 命名函数的作用域是指声明该函数的整个函数范围,与代码嵌套无关。

    1
    2
    3
    4
    5
    6
    function outer(){
    /* typeof inner ==='function' */
    function inner(){
    //some code here
    }
    }
  • inner( )声明在整个 outer( )中都是可用的,而数字变量只是从声明处到函数结尾处才可被调用。函数在其作用域范围内可以被提前引用。

函数调用
  • 如果实际传入的参数数量大于函数声明的形参数量时,超出的参数不会配给形参名称。
  • 当形参数量大于实际参数数量,则没有对应参数的形参会赋值为 undefined
  • 所有的函数调用都会传递两个隐式参数:arguments和this
  • arguments参数,类数组结构(可使用length,可使用下标)
  • this参数,更适合称作调用上下文
  1. 作为函数进行调用
    1
    2
    3
    4
    function hello (){};
    hello();
    var hi = function(){};
    hi();

以此种方法进行调用时,函数的上下文是全局上下文–window对象

  1. 作为方法进行调用 –其上下文对象是方法的拥有者
  2. 作为构造器进行调用 –其上下文对象是新创建的实例对象
  3. apply()和call()可以显式的指定任何一个对象作为其函数上下文。

Chapter 6 原型与面向对象

1. 实例化和原型
  • 对象实例化
    JavaScript通过构造器执行 new 操作符来初始化一个新对象。

    1
    2
    3
    4
    5
    //声明一个对象,并将对象初始化到已知状态
    var o = {};
    o.name = 'Beginning';
    o.age = 16;
    o.job = 'front-end';
  • 原型作为对象概览
    函数作为构造器进行调用时,函数的原型是新对象的概览。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
        function Ninja(){};
        Ninja.prototype.swingSword = function (){
          return true;
        }
        var ninja1 = Ninja();
        //此时对函数进行函数调用,则什么都没有发生
        // ninja1 = undefined 
        var ninja2 = new Ninja();
        //将函数作为构造器调用,不仅新对象实例被创建,而且函数原型上的方法也可以调用
      </script>
  • 实例属性
    使用 new 操作符将函数作为构造器进行调用时,其上下文被定义为新对象实例。除了通过原型给函数附加属性的形式之外,我们还可在构造器函数内通过this参数初始化值。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    function Ninja(){
    this.swung = false;
    this.swingSword = function (){
    return !this.swung;
    }
    }
    Ninja.prototype.swingSword = function (){
    return true;
    }
    var ninja2 = new Ninja();
    //在构造器内创建的实例方法会阻挡在原型上创建的同名方法。
  • 协调引用
    原型的改变会影响已经创建的对象
    查找属性时,首先查找对象自身,如果没找到,再查找构造器原型

2.通过构造器判断对象类型

我们不用知道原有的构造器函数就可以再次创建一个新实例。

1
2
3
function Ninja(){};
var ninja = new Ninja(){};
var ninja2 = new ninja.constructor();

3.继承与原型链

创建一个原型链最好的方法是,使用一个对象的实例作为另一个对象的原型。例如

1
2
//Ninja实例的原型将是Person的一个实例,该实例不仅拥有原型,还持有SuperClass的所有属性
Ninja.prototype = new Person();

1
2
3
4
5
6
7
8
9
10
11
12
function Super() {}
 
function Sub() {}
Sub.prototype = new Super();
Sub.prototype.constructor = Sub;
 
var sub = new Sub();
 
Sub.prototype.constructor === Sub; // ② true
sub.constructor === Sub; // ④ true
sub.__proto__ === Sub.prototype; // ⑤ true
Sub.prototype.__proto__ == Super.prototype; // ⑦ true

http://keenwon.com/1524.html
下面是一种可能的 forEach()实现

1
2
3
4
5
6
7
8
9
10
11
12
//先检查是否有原有方法
if(!Array.prototype.forEach){
Array.prototype.forEach = function (callback,context){
for ( var i = 0; i < this.length; i++ ){
//context||null 防止将undefined传递给call()
callback.call(context || null, this[i], i, this);
}
};
}
[a,b,c].forEach(function(value,index,array){
assert(value,"Is in position"+ index +"out of" +(array.length-1));
});

编写类风格的代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//通过Object创建一个Person类
var Person = Object.subClass({
init: function(isDancing){
this.dancing = isDancing;
},
dance: function(){
return this.dancing;
}
});
//通过Person创建一个Ninja类
var Ninja = Person.subClass({
init: function(){
this._super(false);
},
dance: function(){
return this._super();
},
swingSword: function(){
return true;
}
});
var person = new Person(true);
//person.dance() is true
var ninja = new Ninja();
//ninja.dance() is true
//ninja.swingSword() is true
//person instanceof Person is true
//Ninja is a Ninja and a Person

CSS揭秘📒

一些tips

  • 使用百分比长度来取代固定长度。
  • 需要在较大分辨率下得到固定宽度时,使用 max-width 而不是 width
    ( max-width 可以适应较小的分辨率,无须媒体查询 )
  • 不要忘记为替换元素设计一个宽度,值为100%
  • 当图片进行行列式布局时,可以使用弹性盒模型布局( flex ),或 display : inline-box 加上常规的文本折行来实现
  • 多列文本时,指定 column-width 列宽,而不是 columm-count 列数。这样就可以在较小的屏幕上自动显示为单列布局
  • 合理使用简写

预处理器( Stylus,Sass )

  • 变量,mixin,函数,规则嵌套

背景与边框

  1. 半透明边框
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    .border-container{
            width: 100%;
            height: 600px;
            background: url("http://7xspf8.com2.z0.glb.qiniucdn.com/1467012841.jpg") no-repeat;
        }
        .border-div{
            width: 200px;
            height: 200px;
            margin: auto 50px;
            border: 10px solid rgba(255,255,255,0.5);
            background: #ffffff;
            background-clip: padding-box;
        }

线上演示:http://dabblet.com/gist/012289cc14106a1bd7a5

  1. 多重边框
    1
    2
    3
    4
    5
    6
    .div {
    background: yellowgreen;
    box-shadow: 0 0 0 10px #655,
              0 0 0 15px deeppink,
                0 2px 5px 15px rgba(0,0,0,.6);
    }

线上演示:http://dabblet.com/gist/525eb8e9cdade71723c1
若只需要两重边框也可以使用 outline ,可以利用 outline-offset 来控制和元素边缘的间距。( 可为负值 )

  1. 灵活的背景定位
  • background-position
  • background-position + background-origin
  • calc( )方案
  • calc( )使用时,一定要在内部的 - 和 + 两个运算符侧各加一个空白符,否则会解析错误🙅
1
2
3
4
5
6
7
8
9
10
11
12
div {
background: url(http://csssecrets.io/images/code-pirate.svg)
            no-repeat bottom right #58a;
background-position: calc(100% - 20px) calc(100% - 10px);
/* Styling */
max-width: 10em;
min-height: 5em;
padding: 10px;
color: white;
font: 100%/1 sans-serif;
}

http://www.w3cplus.com/css3/how-to-use-css3-calc-function.html

  1. 边框内圆角
1
2
3
4
5
6
7
8
9
10
11
div {
outline: .6em solid #655;
box-shadow: 0 0 0 .4em #655; /* todo calculate max of this */
max-width: 10em;
border-radius: .8em;
padding: 1em;
margin: 1em;
background: tan;
font: 100%/1.5 sans-serif;
}

线上演示:http://dabblet.com/gist/170fe436f290083cc24c

  1. 垂直居中
    http://begin5257.github.io/2016/06/03/vertical-align-div/

如何优雅的实现垂直居中

“44年前我们就把人类送上月球了,但现在我们仍然无法再 CSS 中实现垂直居中。” –Jams Anderson

在网页设计中,每当涉及到居中时,最重要的就是将元素及其父元素居中。听起来很简单,那你有没有考虑到很多的可能性呢(⊙o⊙)?

简单的:已知宽高的元素

如果你同时知道一个元素的宽和高,并且要将元素相对其父元素垂直居中,那么使用绝对定位来实现或许是一种比较不错的办法。
已知宽高的元素

1
2
3
4
5
6
7
main{
position: absolute;
top: calc(50% - 3em); //向上移动等于父元素高度的50%及自身高度的一半
left: calc(50% - 9em); //向左移动距离等于父元素宽度的50%及自身宽度的一半
width: 18em;
height: 6em;
}

进阶: 未知宽高的元素

但页面中很多元素都是未知宽高的。
未知宽高的元素

基于绝对定位,进行扩展。

当我们在使用 translate( ) 变形函数计算百分比值时,是以这个元素自身的高度和宽度为基准来进行换算和移动的。因此,只要换用基于百分比的 CSS 变形来对元素进行偏移,就不需要在编译量中将元素的尺寸写死了。

1
2
3
4
5
6
main{
position: absolute;
top: 50%;
left: 50%;
transform: translate( -50%, 50% );
}
不适用绝对定位的情况

当我们不想使用绝对定位时,仍然可以用 translate( ) 来将这个元素以其自身宽高的一半为距离来进行移动。
可以使用 margin 来达到移动的效果。

1
2
3
4
5
6
main{
width: 18em;
padding: 13m 1.5em;
margin: 50vh auto 0; //外边距使用 vh 为单位,因为margin的百分比值是相对于其父元素的宽度作为基准解析,因此此处使用 vh
transform: translateY( -50% );
}
基于table布局

CSS table 或许是个不错的选择。
因为 table 并不像常规块级元素一样渲染。比如说当元素宽 100% 时,table 只会占据其中实际内容的宽度,而默认的块级元素则会自动的占据父级元素的100%。

1
2
3
4
5
6
7
<table style="100%">
<tr>
<td style="text-align: center; vertaical-align: center">
我是垂直居中的!
</td>
</tr>
</table>

如果考虑到页面语义化,可以这么做

1
2
3
4
5
6
7
8
9
.something-semantic {
display: table;
width: 100%;
}
.something-else-semantic {
display: table-cell;
text-align: center;
vertical-align: middle;
}
行内块法

我们甚至可以考虑使用伪元素。
如果我们将伪元素在父元素内占满 100% 的高度,然后我们将伪元素以及希望垂直居中的元素同时设置 vertrcal-align: center。

  • 然后我们就可以得到垂直居中的效果。

    这是一种比较 hack 的方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
.block {
  text-align: center;
  white-space: nowrap;
}
 
/* 将高度撑到100% */
.block:before {
  content: '';
  display: inline-block;
  height: 100%;
  vertical-align: middle;
  margin-right: -0.25em; /* Adjusts for spacing */
}
/* 要被垂直居中的元素,可以是任意宽高 */ 
.centered {
  display: inline-block;
  vertical-align: middle;
  width: 300px;
}
基于 Flexbox 的解决方案

无疑是最佳的解决方案。因为 Flexbox 就是专门针对这类需求设计的😄

1
2
3
4
5
6
7
8
body{
display: flex;
min-height: 100vh;
margin: 0;
}
main{
margin: auto;
}

当居中元素内部文本也需要居中时:

1
2
3
4
5
6
7
main{
display: flex;
align-items: center;
justify-content: center;
width:18em;
height: 10em;
}

参考:
《 CSS 揭秘》
http://css-tricks.com/centering-in-the-unknown
CSS 变形: http://w3.org/TR/css-transforms
CSS 值与单位:http://w3.org/TR/css-values
CSS 伸缩盒模型布局:http://w3.org/TR/css-flexbox

JS求和方法总结

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
//normal
var array = [1,2,3];
var sum1 = 0;
for(var i = 0 ;i < array.length ;i++) {
sum1 += array[i];
}
console.log(sum1);
// array.reduce
var sum2 = array.reduce(function (a,b) {
return a+b;
});
console.log(sum2);
// array.map
var sum3 = 0;
function getSum(item, index, array) {
sum3 += item;
}
array.map(getSum);
console.log(sum3);
// _.reduce
var sum4 = _.reduce(array, function(a, b){
return a + b;
});
console.log(sum4);
// _.reduceRight
var sum5 = _.reduceRight(array,function (a,b) {
return a+b;
});
console.log(sum5);
//邪恶的eval
var sum6 = eval(array.join("+"));
console.log(sum6);
//for in
var sum7 = 0;
for( var i in array ) {
sum7 += array[i]
}
console.log(sum7);

CSS布局(box-sizing,column,flex,inline-box布局)

  • 布局除了 position,float之外,还可以使用 inline-box
    1. vertical-align 属性会影响到 inline-block元素,你可能会把它的值设置为top。
    2. 你需要设置每一列的宽度
    3. 如果HTML源代码中元素之间有空格,那么列与列之间会产生空隙
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      nav {
      display: inline-block;
      vertical-align: top;
      width: 25%;
      border: 1px solid yellowgreen;
      }
      .column {
      display: inline-block;
      vertical-align: top;
      width: 74%;
      border: 1px solid #66BAB7;
      }

更多display

  • 清除浮动
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    .box {
    float: left;
    width: 200px;
    height: 100px;
    margin: 1em;
    border: 1px solid #66BAB7;
    }
    .after-box {
    clear: left;/*left和both都可以*/
    border: 1px solid yellowgreen;
    }


http://zh.learnlayout.com/clearfix.html
清除浮动水很深

  • column
    多列布局
    1
    2
    3
    4
    5
    6
    7
    8
    .three-column{
    border: 1px solid #66BAB7;
    padding: 1em;
    -webkit-column-count: 3;
    column-count: 3;
    -webkit-column-gap: 1em;
    column-gap: 1em;
    }

大概这么个效果

  • box-sizing
    当你设置一个元素为 box-sizing: border-box 时,此元素的内边距和边框不再会增加它的宽度。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    /*此时内边距和边框都不会增加它的宽度*/
    .simple {
    width: 500px;
    margin: 20px auto;
    border: 1px solid blue;
    -webkit-box-sizing: border-box;
    -moz-box-sizing: border-box;
    box-sizing: border-box;
    }
    .fancy {
    width: 500px;
    margin: 20px auto;
    padding: 50px;
    border: 10px solid blue;
    -webkit-box-sizing: border-box;
    -moz-box-sizing: border-box;
    box-sizing: border-box;
    }

  • flex布局

    1. 简单的 flex 布局

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      .container {
      display: -webkit-flex;
      display: flex;
      background: lightblue;
      }
      nav {
      width: 200px;
      background: #66BAB7;
      }
      .flex-column {
      flex: 1;
      -webkit-flex: 1;
      background: yellowgreen;
      }
    2. 复杂的 flex 布局

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      .container {
      display: flex;
      display: -webkit-flex;
      }
      .first {
      flex: initial;
      -webkit-flex: initial;
      width: 200px;
      min-width: 100px;
      background: red;
      }
      .none {
      flex: none;
      -webkit-flex: none;
      width: 200px;
      background: yellow;
      }
      .flex1 {
      flex: 1;
      -webkit-flex: 1;
      background: yellowgreen;
      }
      .flex2 {
      flex: 2;
      -webkit-flex: 2;
      background: #66BAB7;
      }
    3. 居中 flex 布局

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      .vertical-container {
      height: 500px;
      display: -webkit-flex;
      display: flex;
      -webkit-align-items: center;
      align-items: center;
      -webkit-justify-content: center;
      justify-content: center;
      }
      .div {
      width: 200px;
      height: 200px;
      border: 10px solid #66BAB7;
      }

安利:http://zh.learnlayout.com/toc.html

如何优雅的装系统--深度(Debian)

首先你需要一个U盘!
然后格式化它!
进入这个链接!
https://www.deepin.org/download.html
下完之后继续优雅的下载一个启动盘制作工具
之后
看官方文档
好的我们装好系统了!(注意硬盘分区)
首先换成zsh└( ̄^ ̄ )┐

接下来,第一步
你需要爬爬爬爬到墙的那边
我们选择 shadowsocks-qt5 编译源码安装
shadowsocks-qt5
看文档
但是 libqtshadowsocks-dev 找不到安装包
嗯,比较傲娇
我们这样来
libQtShadowsocks
看这个,说的很详细
好的我们装完shadowsocks了!

第二步
配置好你的shadowsocks
下载Proxy_SwitchySharp.crx
这个是我的bak配置文件
此时已能爬爬爬爬爬过墙了└( ̄^ ̄ )┐

第三步,作为我大前端,翻墙之后还有好多事情要做。
第一件,下个 Webstorm (///ω///)
//自己学怎么注册
第二件,node,npm /ω\)
//自己摸索怎么添加环境变量
//不要用apt装node
第三件,npm换淘宝源
淘宝npm
第四件,ruby,sass
如何快速装ruby
淘宝ruby
第五件,添加新的ssh-key (๑•̀ㅁ•́ฅ)
第六件⋯⋯
第七件⋯⋯

麻麻以后我不重新装系统了( •̩̩̩̩_•̩̩̩̩ )

好的好的今天的教程完 (-̇᷇̂ᴥ ̇᷇̂-)
先来张照骗

resume-maker 1.0留念

在开始校招的时候,大家都在紧张的准备简历。
Sketch,PS,AI……
我?? (⊙v⊙)那拿CSS做一个!

结果工作室蛮多小伙伴喜欢我的简历,于是就想说可不可以做一个简历生成器。
resume-maker 1.0就这样诞生啦~(≧▽≦)/~
基本的思路是:

  1. 实现登录,注册,登录保持
  2. 保证表单填入的数据刷新不丢失
  3. 主题颜色可更换
  4. 使用 express + mongodb + jade + semantic-ui + stylus 实现

广受吐槽的简洁的不能再简洁登录界面:

广受吐槽的一口气填完必须否则强迫症会死表单界面:

广受吐槽的为什么只有一个模板简历界面:

麻麻我要设计%>_<%

其实过程还是蛮头疼的。

  • 数据库的设计就是每位用户对应一份简历内容

  • 采用 mongoose 与mongo连接。
    因为简历需要的数据很多,所以每一个Schema里参数的定义就是一个大问题,我的解决方案是:给每一个参数定义一个类型( 有那么一点点心累 )

  • 还有表单界面有些模块在添加完内容之后,需要让原先增加的模块继续保持存在。
    我的解决办法是,将数据存入 localStorage,在生成页面时对 localStorage 中的数据进行判断,根据 localStorage 中的数据条数生成合适数量的表单并将 localStorage 中的数据展现在表单中。

  • 主题颜色的控制:
    目前全部采用 js 控制,but,即使原生js现在有了document.querySelectorAll这种类似作弊的 API ,还是很复杂啊(/≧-≦)/~┴┴
    后来一拍脑门想起来我用的是 Stylus ……

  • HTML语义化:
    一定要起合适且美观的id及类名,不然 heheda(ps:今天在蜻蜓FM的控制台里面看到了heheda~)
    主要是自己后期会疯:)

  • cookie的控制( js发送cookie,node处理cookie )

因为被吐槽的地方太多,包括表单填写这种非常重要的交互方式。所以,我!要!重!构!
打算开始学习使用 react 框架,后端 Python ( 感谢后端小伙伴,再次鞠躬 )

线上链接:http://resume-maker-e40c4.codingapp.com/
// 总之还是和我一起期待2.0吧 (⊙v⊙)

2016阿里前端实习生笔试

  • ~ ~!null //1
    ~:按位非操作符由一个波浪线(~)表示,执行按位非的结果就是返回数值的反码。
    1
    2
    3
    4
    ~2 === -3; //true
    ~1 === -2; //true
    ~0 === -1; //true
    ~-1 === 0; //true

~~: 类似Math.floor()的用法,某些浏览器下比 Math.floor 渲染速度快
http://rocha.la/JavaScript-bitwise-operators-in-practice

  • 选择合适的选择器选择第二个 p 标签

    1
    2
    3
    4
    5
    6
    <div>
    <p>p1</p>
    <span>span1</span>
    <p>p2</p>
    <span>span2</span>
    </div>
    1. div > :nth-last-child(2)
      //父元素倒数第二个元素
    2. p:nth-last-child(1)
      //错误
    3. p:nth-last-of-type(1)
      //仅匹配同种标签的元素,匹配到倒数第一个p
    4. p:nth-of-type(2)
      //仅匹配同种标签的元素,匹配到第二个p
    5. p:nth-child(2)
      //错误,匹配到父元素下的第二个元素
      http://www.ruanyifeng.com/blog/2009/03/css_selectors.html
  • 原生js相关基础

  • 以下属性是否与 IE9 兼容

    1
    innerHTML/innerText/children/childrennode/classname
  • 防御XSS注入攻击

  • 输入”www.taobao.com”,输出”moc.oab.www”

    1
    ("www.taobao.com").replace("tao","").split("").reverse().join("")
  • css3动画1s内实现正方形翻转

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    <style>
    #loading {
    width: 100px;
    height: 100px;
    position: absolute;
    animation: circling 1s linear 0s infinite;
    }
    @keyframes circling {
    from {
    transform: rotate(0deg);
    }
    to {
    transform: rotate(360deg);
    }
    }
    </style>
    <body>
    <div id="loading"></div>
    <body>

以前用css3写过一个摇头的(●—●)来着

http://begin5257.com/Baymax/
github地址

  • 使用css3实现一个长这样的东西

主要是星星和边框
原题 : )

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<style>
a{
border-radius: 10px;
text-shadow: 0 1px #eee;
box-shadow: 0 29px 0 rgba(222, 222, 222, 1) inset,0 0 0 6px #CACACA, 0 0 0 8px #fff, 0px 0px 0px 10px #696969, 0 2px 3px 11px #CBCBCB;
background: rgba(182, 182, 182, 0.6);
}
a:before, a:after {
font-size: 27px;
color: #888;
content: "★";
text-shadow: 0 1px #fff;
}
</style>

  • 简述一个 js弹窗组件的实现思路

    1
    触发方式,弹窗内容,消失方式
  • 设计一个可以监控全站错误并且将错误上报的 js 模块

    1
    2
    3
    使用 try-catch / window.onerror 捕获异常
    阻止常规报错
    使用 ajax 将异常发送到某个页面