Coder Social home page Coder Social logo

f2e-journey / xueqianban Goto Github PK

View Code? Open in Web Editor NEW

This project forked from zhaoda/spring

321.0 321.0 56.0 464 KB

学前班 - 学前端

Home Page: http://f2e-journey.github.io/xueqianban/

License: MIT License

JavaScript 95.12% CSS 3.91% HTML 0.97%
f2e weekly

xueqianban's Introduction

f2e-journey

《我的前端之旅》(2012-01-10创建)最初这只是一个简单的豆列, 当时就是想记录下自己学习前端时看过哪些书, 精选出自己最喜欢/最合适, 对自己来说收益最大的书. 这样如果别人也想学前端的时候, 我就可以推荐这些书给他们.

后来随着自己的阅读量增加, 又陆续加了些网络资源(例如博客文章等)进来, 使用豆列的形式来编辑感觉越来越不方便了, 最终我决定让它"发展壮大", 前端之旅从这里开始.

我的前端之旅

前端在计算机领域其实算是一个新新职业, 也就是最近几年飞速发展起来的, 很多人都是"转前端", 我也是.

所以我本身也不是一开始就立志做前端的, 但由于自己非常喜欢前端, 也一直没有离开过这个领域. 凭借着自己的兴趣, 每天积累一点, 一步一步地走到今天. 其实身边也没有什么高手大神, 只是看过文章"千千万"(略带夸张成份), 其中不乏有大神的"教导", 让我受益匪浅, 因此我很想推荐出来, 绝对都是我认为最好的, 因为这就是我自己正在经历的一场精彩的旅程啊.

就目前来说, 想成为一名"专业"的前端, 缺乏专门/专业的地方来学习(学校基本上都还没有专门开设前端课程). 而前端的知识领域又涉及非常之广, 各方面的书籍倒是不缺, 各种入门文章也比比皆是. 但想从中找到优秀的进阶之路, 确实需要耐心.

那么我们做为过来人, 有责任让后来者少走弯路, 整理出前端最佳(就个人经历而言)的入门指南.

最后

祝: 旅途愉快!

推荐书籍

那么前端我们需要学些什么呢?

就前端而言, 所有要学的东西都是围绕着 HTTP/HTML/CSS/JS(JavaScript) 这4项 Web 基础技术来走的.

推荐教程

  • A Practical Guide to HTML & CSS

    认为是最好的入门系列, 分初级和高级

  • w3school 在线教程中所有的HTML/CSS/JS教程

    虽然有很多人不再推荐了, 但我就是从这里起步的, 可以多结合MDN来看看

  • CSS 101: interactive tutorial

    让你重新认识CSS

  • 前端工程开发实践

    宝岛友人分享的前端实践

  • JavaScript 标准参考教程

    全面介绍了 JavaScript 核心语法(ECMAScript 5.1版本), 从最简单的开始讲起, 循序渐进、由浅入深, 力求清晰易懂。所有章节都带有大量的代码实例, 便于理解和模仿, 可以用到实际项目中, 即学即用

  • JavaScript 核心

    「深入ECMA-262-3」系列, 以便你对 JavaScript 核心部分(对象/原型链/构造函数/执行上下文/作用域链/闭包/This)有更深的理解

  • JavaScript The Right Way

    让你对 JavaScript 有更全面的了解

  • 前端开发笔记本

    涵盖了 Web 前端开发所需的全部基本知识以及所对应的学习路径 - 前端开发工程师(网易云课堂微专业)

    • 最基础的页面制作(PS 切图)
    • HTML/CSS/JS/DOM
    • 页面架构(常用的布局解决方案)
    • 产品前端架构
    • 前端工程师职责有哪些? 如何与别人分工协作?
    • 如何设计接口, 技术选型
  • 全栈工程师培训材料

    阮一峰老师整理的一份技术清单, 涵盖前端开发的历史和趋势, React 技术栈, Node 应用开发, 前端工程简介. 特别推荐《前端开发的历史和趋势》

    • 什么是前端(前端:针对浏览器的开发,代码在浏览器运行/后端:针对服务器的开发,代码在服务器运行)
    • 前端开发的历史演变(前后端不分 -> 前后端分离 -> 全栈工程师)
    • 前端MVC框架的兴起(Backbone -> Angular -> React)
    • 全栈工程师和全栈技能(单个程序员的生产力要求越来越高)
    • 前端开发的未来(现在基于 Web 的前端技术,将演变为未来所有软件的通用的 GUI 解决方案)
  • Bootstrap

    可以说是一个里程碑似的前端框架, 从此我们的页面不再简陋而风格混乱. 从中可以"偷学"的东西实在是太多了(栅格/响应式/组件等等等等). 如果你每天都在使用它, 那么请更深入地去了解它, 学习下它是如何规划 CSS(命名), 又是如何写出一个 jQuery 插件. 它会告诉你, 在现实项目中应该怎样写 HTML/CSS/JS, 这些都是你值得借鉴的, 更何况它经历了那么多版本的更新, 那么多项目的考验. 当你真正去研究一个框架时, 你的收获肯定比你仅仅是使用要来的多得多.

编码规范

无规矩不成方圆, 我们如何才能写出高端大气上档次的代码呢? 要知道代码主要是给人阅读的, 只是偶尔让计算机执行一下.

HTML

CSS

  • 编写如一、符合习惯的CSS的原则

  • NEC : 更好的CSS样式解决方案

  • CSS Guidelines

  • RSCSS

    • Components, named with 2 words (.blog-post)
    • Elements, named with 1 word (.blog-post > .title)
    • Variants, named with a dash prefix (.blog-post.-with-icon)
    • Helpers, named with an underscore prefix (_pull-left)
    <!-- BEM -->
    <form class="site-search site-search--full">
        <input  class="site-search__field" type="text">
        <button class="site-search__button"></button>
    </form>
    <!-- rscss -->
    <form class="site-search -full">
        <input  class="field" type="text">
        <button class="button"></button>
    </form>

JavaScript

Versioning

如果你编写了某个软件或者某个组件, 你知道如何制定版本号吗?

  • 语义化版本

    Consider a version format of X.Y.Z (Major.Minor.Patch).

    版本格式:主版本号.次版本号.修订号,版本号递增规则如下:

    • 主版本号:当你做了不兼容的 API 修改, 当主版本号递增时, 次版本号和修订号必须归零
    • 次版本号:当你做了向下兼容的功能性新增, 当次版本号递增时, 修订号必须归零
    •     修订号:当你做了向下兼容的问题修正

    注意事项

    • 进行新的项目开发时, 版本号从 0.1.0 开始
    • 主版本号为 0(0.y.z) 的软件处于开发初始阶段, 一切都可能随时被改变. 这样的公共 API 不应该被视为稳定版
    • 1.0.0 的版本号用于界定公共 API 的形成. 这一版本之后所有的版本号更新都基于公共 API 及其修改内容

    先行版本号(pre-release)及版本编译信息(build metadata)可以加到"主版本号.次版本号.修订号"的后面作为延伸

    • pre-release: 表示当前版本是一个不稳定的版本, 使用它时需要注意风险
    • 建议使用这种 <major>.<minor>.<patch>-<stage>.<num> 的形式, 其中 <stage> 一般选用: alpha、beta、rc, 对于标记部分的比较, 是根据 ASCII 字母表中的顺序来进行的

    一个典型的版本号发展示例

    • 0.1.0
    • 0.1.1
    • 0.1.2
    • ......
    • 0.16.0
    • 1.0.0-alpha.1
    • 1.0.0-alpha.2
    • 1.0.0-beta.1
    • 1.0.0-rc.1
    • 1.0.0
    • 1.0.1
    • ......
    • 1.1.0-alpha.1
    • ......
    • 1.1.0
    • ......

    版本号范围标记, 建议在写法上采用"通配符的写法"跟进每个小版本更新, 即书写为 1.x 表达的版本号范围 2.0.0 > 1.x >= 1.0.0

提交代码时, 也应该遵循一定的规范来编写提交说明, 这样就能够提供更多的历史信息, 方便快速浏览

  • Commit message 和 Change log 编写指南

    <type>(<scope>): <subject>
    <BLANK LINE>
    <body>
    <BLANK LINE>
    <footer>
    

    Type

    • feat: A new feature
    • fix: A bug fix
    • docs: Documentation only changes
    • style: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)
    • refactor: A code change that neither fixes a bug nor adds a feature
    • perf: A code change that improves performance
    • test: Adding missing or correcting existing tests
    • chore: Changes to the build process or auxiliary tools and libraries such as documentation generation

    Git Commit Guidelines | Developing AngularJS | Keep a Changelog

文案风格

统一的文案、排版, 能有效降低团队成员之间的沟通成本, 增强网站的气质

一入前端深似海

恭喜你, 在前端的道路上终于迈出了坚实的一步. 我想说的是入门以后, 前端的路才刚刚开始.

路漫漫其修远兮, 吾将上下而求索.

xueqianban's People

Contributors

bitdeli-chef avatar ufologist avatar zhaoda avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

xueqianban's Issues

我的 React 之旅

最近上手了 create-react-app 工具, 大大降低了 React 的使用门槛, 扫清了 N 多搭建环境的障碍. 再也不必折腾 N 多工具就可以开启你的 React 之旅了(从此你再也不好意思说 React 好麻烦了)

以前你可能需要准备的环境有:

  • es2015环境(2016年已过大半, 是时候开始使用新的标准了)
  • JSX 环境(写 React, JSX 你势必要用起来的)
  • webpack 环境(打包在所难免)

现在有了 create-react-app, 你只需下面几个命令就够了

npm install -g create-react-app

create-react-app my-app
cd my-app/

npm start
npm run build
  • One Dependency
  • Zero Configuration

Your environment will have everything you need to build a modern React app:

  • React, JSX, and ES6 support.
  • A dev server that lints for common errors.
  • Import CSS and image files directly from JavaScript.
  • Autoprefixed CSS, so you don’t need -webkit or other prefixes.
  • A build script to bundle JS, CSS, and images for production, with sourcemaps.

下面正式开启我的 React 之旅

React Tutorial 学习笔记

React is all about modular, composable components.

For our comment box example, we'll have the following component structure:

- CommentBox
  - CommentList
    - Comment
  - CommentForm

Note that native HTML element names start with a lowercase letter, while custom React class names begin with an uppercase letter.

We pass some methods in a JavaScript object to React.createClass() to create a new React component.

The most important of these methods is called render which returns a tree of React components that will eventually render to HTML.

The <div> tags are not actual DOM nodes; they are instantiations of React div components.

React is safe. We are not generating HTML strings so XSS protection is the default.

You can return a tree of components that you (or someone else) built.

This is what makes React composable: a key tenet of maintainable frontends.

ReactDOM.render() instantiates the root component, starts the framework, and injects the markup into a raw DOM element, provided as the second argument.

The ReactDOM module exposes DOM-specific methods, while React has the core tools shared by React on different platforms (e.g., React Native).

It is important that ReactDOM.render remain at the bottom of the script for this tutorial. ReactDOM.render should only be called after the composite components have been defined.

var CommentBox = React.createClass({
  render: function() {
    return (
      <div className="commentBox">
        Hello, world! I am a CommentBox.
      </div>
    );
  }
});
ReactDOM.render(
  <CommentBox />,
  document.getElementById('content')
);

Data passed in from a parent component is available as a 'property' on the child component.
These 'properties' are accessed through this.props.

We access named attributes passed to the component as keys on this.props and any nested elements as this.props.children.

<Comment author="Pete Hunt" num={1}>This is one comment</Comment>

this.props.author   => Pete Hunt           // string
this.props.num      => 1                   // number
this.props.children => This is one comment // any nested elements

That's React protecting you from an XSS attack. There's a way to get around it but the framework warns you not to use it:

<span dangerouslySetInnerHTML={ {__html: '<input type="text"/>'} } />

props are immutable: they are passed from the parent and are "owned" by the parent.

To implement interactions, we introduce mutable state to the component.

this.state is private to the component and can be changed by calling this.setState().
When the state updates, the component re-renders itself.

render() methods are written declaratively as functions of this.props and this.state.
The framework guarantees the UI is always consistent with the inputs.

getInitialState() executes exactly once during the lifecycle of the component and sets up the initial state of the component.

componentDidMount() is a method called automatically by React after a component is rendered for the first time.

Controlled components

A Controlled component does not maintain its own internal state; the component renders purely based on props.

// User input will have no effect on the rendered element because React has declared the value to be Hello!.
render: function() {
    return <input type="text" value="Hello!" />;
}

// To update the value in response to user input, you could use the onChange event:
render: function() {
    return <input type="text" value={this.state.value} onChange={this.handleChange} />;
}

React attaches event handlers to components using a camelCase naming convention.

React.createClass() automatically binds each method to its component instance, obviating the need for explicit binding.

Autobinding and Event Delegation

  • every method is automatically bound to its component instance (except when using ES6 class syntax)
  • React doesn't actually attach event handlers to the nodes themselves. When React starts up, it starts listening for all events at the top level using a single event listener.

最后奉上代码大家可以尝尝鲜

// es2015
import React, {
    Component
} from 'react';

class CommentBox extends Component {
    constructor(props) {
        super(props);

        this.state = {
            comments: props.comments,
            text: 'init'
        };
    }
    componentDidMount() {
        console.log('a component is rendered for the first time');
    }
    render() {
        return (
            <div>
                <ul>{this.state.comments.map(function(comment) {
                    return <li key={comment.id}>{comment.text}</li>
                })}</ul>
                <input ref="commentInput" onChange={this.handleChange.bind(this)} type="text" value={this.state.text} />
                <br/>
                <span dangerouslySetInnerHTML={ {__html: this.state.text} }></span>
            </div>
        );
    }

    handleChange(event) {
        // 设置组件状态, 会自动刷新 UI, 即自动调用 render 方法
        this.setState({
            comments: this.state.comments.concat({
                id: Date.now(),
                text: event.target.value       // 可以通过 event 来获取元素
            }),
            text: this.refs.commentInput.value // 也可以通过 refs 来获取元素
        });
    }
}
CommentBox.propTypes = {
    comments: React.PropTypes.array.isRequired
};

export default CommentBox;


// use component
<CommentBox comments={ [{id: 1, text: 'comment1'}] } />

班会第 10 期

  • 技术
    • 如何写出一个好的 Web 页面

    • dropload 移动端下拉刷新、上拉加载更多插件

    • 前端的变革

      发布

      前端工程师开始有真正意义上的“发布”,我之前跟团队同学开玩笑说,在这之前,前端连搞出线上故障的能力都没有——不要以为这是好事,没风险意味着没价值。

      分离与同构

      手机淘宝目前的一个核心能力有关——API网关,通俗点说,就是所有的服务端提供API,而且通过统一的出口提供出来。这个便利条件,促成了一个前所未有的前端开发模式:前端开发纯静态页面,跟客户端调用同一套服务端API。

      性能

      一切没有线上监控的性能优化都是耍流氓。

    • 移动端适配专题

      • 移动端页面适配方案

      • 移动前端开发之viewport的深入理解

        在移动设备上进行网页的重构或开发,首先得搞明白的就是移动设备上的viewport了,只有明白了viewport的概念以及弄清楚了跟viewport有关的meta标签的使用,才能更好地让我们的网页适配或响应各种不同分辨率的移动设备。

        ppk把移动设备上的viewport分为layout viewport 、 visual viewport 和 ideal viewport 三类,其中的ideal viewport是最适合移动设备的viewport,ideal viewport的宽度等于移动设备的屏幕宽度,只要在css中把某一元素的宽度设为ideal viewport的宽度(单位用px),那么这个元素的宽度就是设备屏幕的宽度了,也就是宽度为100%的效果。ideal viewport 的意义在于,无论在何种分辨率的屏幕下,那些针对ideal viewport 而设计的网站,不需要用户手动缩放,也不需要出现横向滚动条,都可以完美的呈现给用户

        • layout viewport
        • visual viewport
        • ideal viewport(理想的 viewport)

        利用meta标签对viewport进行控制, 把当前的viewport宽度设置为 ideal viewport 的宽度

        <meta name="viewport" content="width=device-width, initial-scale=1">

        关于 initial-scale 缩放

        visual viewport宽度 = ideal viewport宽度  / 当前缩放值
                 当前缩放值 = ideal viewport宽度  / visual viewport宽度
        
      • 移动端适配问题

        Android & iOS设计尺寸规范

        淘宝网触屏版为什么rem跟px混用?有什么好处?为什么不都用rem?

        rem用于随屏幕伸缩的尺寸。px用于正文文字大小、细边框等不宜随屏幕伸缩的尺寸。

        考虑到字体的点阵信息,一般文字尺寸多会采用 16px 20px 24px等值,若以rem指定文字尺寸,会产生诸如21px,19px这样的值,会导致字形难看,毛刺,甚至黑块,故大部分文字应该以px设置。

        一般标题类文字,可能也有要求随屏幕缩放,且考虑到这类文字一般都比较大,超过30px的话,也可以用rem设置字体。

        移动端适配等式: 设备宽度/设计稿宽度 = 某个元素某一距离实际值/该元素在设计稿的值

        例子:
        一个5s宽度320/设计稿宽度640 = 一个元素的高度未知/设计稿上它的高度为20
        可以推出它的实际高度为10,通常我们使用rem作为等式前的值,但是因为太小无法作为html根字体大小使用,所以适当放大,通常为了方便计算,放大100倍,即为:

        document.documentElement.fontSize = document.documentElement.clientWidth / 640 (或实际设计稿宽度) * 100
        

        那么此时在设计稿上量的的某一距离,比如43px,就等于0.43rem。

        至于文字,我们通常不用rem,因为由于不同的rem计算方式会产生很多奇怪的大小,使得文字出现糊掉或者模糊的情况,通常我们使用媒体查询事先设置好body的字体大小,这样来确保文字的正常显示。即为:rem处理适配距离的问题,em处理文字大小问题。

    • css动画的steps

      steps是设置的每一步动画的跳跃步数,而不是整个动画的跳跃步数。举个例子:

      @-webkit-keyframes ani{
         0%{...}
         50%{...}
         100%{...}
      }
      .xxx:hover{
         -webkit-animation:ani 2s steps(10);
      }

      上面的代码指的是0%~50%之间有10个跳跃,50%~100%之间有10个跳跃。而不是0%~100%之间有10个跳跃。

    • Zepto事件委托的小坑

    • Chrome 监听 console 打开

      var re = /x/;
      var i = 0;
      console.log(re);
      re.toString = function () {
        return '第 ' + (++i) + ' 次打开控制台';
      };
    • transform下的fixed布局失效问题

      <div style="transform:translateZ(0);">
          <img src="/img/fixed/1.png" style="position:fixed;top: 0;">
      </div>

      CSS3 transform对普通元素的N多渲染影响

    • G2

      一个由纯 javascript 编写、强大的语义化图表生成工具,它提供了一整套图形语法,可以让用户通过简单的语法搭建出无数种图表,并且集成了大量的统计工具,支持多种坐标系绘制,可以让用户自由得定制图表,是为大数据时代而准备的强大的可视化工具。

    • 如何解决使用了 Framework7 后图片无法长按保存的问题

    • 听《七周七并发模型》作者Paul 讲:编程语言演变对开发者的意义

      我们当今所使用的很多语言,都是在90年代中期的时候所发明出来。所以在90年代中期的时候发生了什么大事件呢?它是如何进一步改变了整个编程界,答案就是网络。

      语言的流行度和三点有关:第一个是客户端网页编程,第二个是函数式编程,第三个是并发和并行的编程。

      我认为首先,最好的应对方式就是去学习新的编程语言!

      第二个建议是再去学习另外一个新的编程语言。

      第三,我们要学习函数式编程。

      最后,去学习并发并行的编程。

    • LeanCloud 与阿里云到底有什么区别?

      个人感觉几乎开发中需要使用的服务器产品,阿里云应该都提供了。这些产品更偏向于较底层的服务,用户要想使用起来需要具备一定的能力。

      为什么我们每次做一个产品都要反反复复地开发这些差不多一样的逻辑呢?比如账号系统、数据存储、短信验证、邮件验证、推送服务甚至是即时聊天,有没有办法让这些东西拿来就用,让自己能够最快速地投入开发呢?当然有办法,这就是 LeanCloud 所做的事情。

    • 程序员进阶宝典

      • 初级软件开发工程师,他们考虑的是“怎么做”
      • 中级软件开发工程师,他们考虑的是“为什么”
      • 高级软件开发工程师,他们考虑的是“是什么”
  • 产品
    • 什么是好的互联网产品

      产品好不好,其实没有一个统一的标准,因为产品类型不同,评价产品好坏的标准就不同。目前的互联网产品,大概可以分成运营驱动型、体验驱动型、技术驱动型和资源驱动型这四类

    • 「拒绝传统」看Facebook以三大法宝化茧成蝶:人才吸引,工程师文化和项目开发流程

      Facebook项目开发流程和工程师的绩效管理机制

      • Facebook的工程师文化是怎样的

        如果你有什么想法,有创新的、古灵精怪的各种想法都可以,马上去做!

      • Facebook团队组成:设计师、产品经理和工程师

        自己没有分清优先级,去做一些比较简单或者自己喜欢,或者是觉得自己能做的事情,而不是做最有影响力的事情

        特别你是在一个上升期的互联网公司的话,给你任务的速度很多时候是超过你的处理速度的。所以这个时候,你在接到一个被分配的任务或者一个email要求你干什么的时候,你不是要马上可以做,而是要强迫自己停顿下,分清现在这个任务的优先级,然后分配好开始时间,之后再开始做。

        那些垃圾任务有着一种诱惑;诱惑着没有定力的人一直去做,一直去做,感觉自己特别有成就感,特别“忙碌和充实”。所以要小心!

      • Facebook是怎样利用OKR进行人才管理的?

      • 师夷长技以制夷:对**互联网公司有什么启示?

    • AntV

      • 数据图表

        图表的作用,是帮助我们更好地看懂数据。选择什么图表,需要回答的首要问题是 「我有什么数据,需要用图表做什么」 , 而不是 「图表长成什么样」

        数据图表

      • 设计规范

        基于大量可视化案例,沉淀了一套优雅的设计规范

班会第 39 期

  • 技术
    • 我的 ThinkJS 之旅 - 从前端向后端迈进

      ThinkJS 这么玩了一圈下来, 我们发现其实对于前端来说, 后端也没有想象中的那么难, 还能将 ES6/7 这样的新技术运用到项目中, 而不像在浏览器上随便用个什么新特性都畏畏缩缩, 担心兼容性问题, 何乐而不为呢?

      如果你以前感觉前后端跨界似鸿沟般难以逾越, 现在借助 ThinkJS 这么智能的框架, 前端也可以很块上手做后端的开发, 什么接口, 什么访问数据库都是小 case. 况且基于 Node.js 平台从开发到上线到运维都已经很成熟了, 工具和生态圈都很完善而且很活跃, 大型互联网公司早就用于生产环境了, 这方面没有什么后顾之忧.

      前端向后端迈进地主要的难点还是在于模型这一块, 对数据库比较陌生的前端多补补课, 把各种关联模型搞清楚, 不出几日已然就是全栈工程师了.

      俗话说万事开头难, 最后我只想告诉大家: Node.js 已经彻底改变了前端, 扩大了前端的圈子, 每一个前端工程师都应该拿起这个有力的武器, 在这个前端最好的时代, 实现自己的理想.

    • css3 animation 属性众妙

      • animation-delay
        • 轮播

        • 序列动画: 京东2017海外招聘

          京东2017海外招聘

        • 无限循环的序列动画

          负值会让动画从它的动画序列中某位置立即开始

        • 调试动画

          animation-play-state 设置为 pausedanimation-delay 设置成不同的负值,可以查看动画在不同帧时的状态,便于进行动画调试

      • animation-fill-mode
        • 保持结束状态: forwards

        • 开始前状态

          换句话说,backwards 作用的是 animation-delay 的时间段,应用第一个关键帧的样式。

      • animation-direction
        • 进/退场动画复用
      • animation-play-state
        • 翻页动画控制
        • 轮播的交互
      • animation-timing-function
        • 作用于 @keyframes 中设置的两个关键帧之间的,这一点在该属性值为 steps() 时可明显感知

        • 逐帧动画: 从而告别不可控的 gif 时代

          我们知道,rem 的计算会存在误差,因此使用雪碧图时我们并不推荐用 rem。如果是逐帧动画的话,由于计算的误差,会出现抖动的情况。

    • CSS新特性

      对于前端而言,最深的体会就是“贵圈真乱”。不停的在变,而且变得很快。其实对于技术而言,他将一直是会向前发展的,所以做为前端的我们需要保持一颗热爱学习的心态

      当有新东西出来之时,你没有一定的预知感,没有一定的好奇感,没有一定的尝试心,那么注定你将跟着人家的屁股后面追赶,而且追的好累,还不一定能追上

      我们要聊的CSS新特性主要有

      • CSS Box Alignment: 用来控制元素在容器中对齐方式
      • CSS Grid Layout: 双维布局
      • CSS Shapes: 原来你在 Web 中的任何一个元素都是矩形盒子, shape-outside: circle(50%); 让文本绕着一个圆形的图片进行排列
      • Conditional CSS: @supports
      • CSS自定义属性(CSS变量)
      • CSS混合模式
      • CSS滤镜
      • element() 函数
      • CSS制作路径动画
    • 2016年前端开发者深度调研,看看别人使用什么技术体系

      • CSS
        • BEM
        • Autoprefixer
      • JavaScript
        • Gulp/Webpack
        • jQuery/Loadash
        • React/Vue/Angular
        • Jasmine/Mocha
        • Babel
    • 如何打造公司级公共前端团队 - 滴滴公共 FE 团队的实践和产出

      滴滴公共FE团队现在有十多个小伙伴,男女比例为 1: 1

      主要包含以下几大职能方向:

      • H5运营富交互动画案例方向
      • WebApp和端交互方向
      • 统一支付方向
      • 公司通用类 MIS 业务前端研发和服务配置化方向
      • 数据可视化和地图方向
      • 公司级组件库建设方向
      • 统一Nodejs服务(API、微服务、MIS等)
      • 跨端体验方向
      • 新技术孵化方向

      团队的实践和产出

      • 公司级组件库:魔方

        与公司设计团队和交互团队沟通,至上而下,统一 UI 视觉规范、交互规范
        PC/H5/可视化/前端规范/品牌规范/动画案例库

        技术:

        • PC 端
          • Angular + sass + webpack
        • H5 端:
          • 第一版:zepto + dmu(优化版的 gmu) + styl + handlebars + webpack
          • 第二版:vue + webpack
        • 前端规范:
          • jsbridge: ES6 + (webpack || rollup) + babel
          • 唤起app: 统一的中间页服务 + iframe 请求 schema
        • 数据可视化:canvas 类库封装 + 统一 theme + 上层配置化
        • 地图可视化:底层适配高德和腾讯,采用动态打包(webpack + require.ensure)
      • 公司级统一运营服务:TMS

        前端修改上线尤为频繁、如何解决资源推送 CDN、达到快速、高效、智能的上线流程

        技术:

        • 采用更定制化的Nodejs服务框架(从 Sailsjs 参考了很多) + mongo + pm2
        • 结合公司发布系统、定制日志监控和脚本化运维规范
      • MIS 服务化、配置化、GUI 化以及前后端分类

        随着业务发展,随之配套的各种 MIS 运营、管控、数据可视化系统,业务需求紧急、前端同学人力投入大、联调效率低

        前端同学依赖的构建工具和编辑器各异,有时候初始化开发环境都需要1-2天

        • 与后端同学沟通数据接口规范、推行 RESTFul API、沉淀业务组件库
        • 联调方式以 wiki 为准、统一出处
        • 前后端独立分开部署、后端 API 通过跨域或者反向代理等方式通信
        • 成熟的Nodejs服务化:脚手架、配置化、生产测试环境隔离命令脚本化
        • 微服务化:权限、登录、邮件等微服务化或者 SDK 化
      • 公司级组件库以及MIS系统的技术实践

      • WebApp首页公共化: 滴滴WebApp实践经验分享

        技术:

        • scrat完成打包+构建。
        • gmu实现组件化。
        • 前端模板handlebar。
        • combo服务。
      • H5 统一登录 SDK

        • 采用Facebook的统一登录方案,登录状态ticket缓存在passport域名下,打通滴滴各个域名的登录态
        • 业务线和运营活动页面接入只需引入一个JS,登录SDK提供login、logout、isLogin等接口,使用简单方便
      • Npm Private

        前端项目越来越多,内部产出的工具包也比较多,如何自建一个私有库

      如何打造公司级公共前端团队

      • 技术氛围和培养机制
        • 除了利用合理、稳定、高效的技术解决方案来服务日常的业务支撑外,考虑到前端技术的日新月异,我们也沉淀和创造一个统一的技术氛围
        • 敢于超越,专业性要求高
        • 能够沉浸在技术里面,去思考问题,最终产出
        • 敢于挑战自己惧怕的东西,克服困难,战胜自己
        • 写作&分享: 沟通和沉淀才能让知识更记忆深刻
        • 组内定期沟通:保持每周部分同学的沟通、每周全组周会
        • 公司比较早创办的 DDFE 的前端技术群
        • DDFE 前端技术微信公众号
        • DDFE Weekly
        • DDFE Github blog
      • 鼓励和提倡技术革新
        • 在技术上鼓励创新和不断打磨沉淀优化,鼓励团队的小伙伴通过一些工具和技术手段来解决一些重复性的事情
        • 让团队的很多同学熟悉前端独立部署、如何和不同的端交互以及他们内部相关的技术组成
      • 沉淀和解决业务痛点
      • 有规划、有目标、有理想
        • 除了满足业务需求外,还需要告诉团队方向在哪里、我们的计划是否是可以落地的
      • 客服意识要强

      技术上:一般我自己会保持比较高的阅读范围和一些国内外优秀的技术群

      • 每月一本的技术书籍
      • 定期也会和一些比较资深的前辈取取经
      • 参加一些业内比较知名的大会,比如最近的Qcon
      • 长期保持技术文章沉淀总结分享的习惯
    • 基于 gulp 的前端静态资源版本管理

      浏览器缓存基本认识

      • 强缓存: 200 from cache, 不发请求到服务器

        通过服务器返回response header中的Expires或者Cache-Control的时间来决定是否从本地读取缓存资源

      • 协商缓存: 304 Not Modified, 需要发送一个请求到服务器

        当浏览器对某个资源的请求没有命中强缓存,就会发一个请求到服务器,验证协商缓存是否命中,如果协商缓存命中,请求响应返回的http状态为304。当浏览器收到304响应时,就会直接从本地缓存读取资源

        协商缓存是利用的是【Last-Modified,If-Modified-Since】和【ETag、If-None-Match】这两对Header来管理的

      前端刷新缓存的方式

      • 资源重新命名,如: index.js 更新为 index_a083082f.js
      • 资源链接添加变化的参数,如:index.js 更新为 index.js?hash=a083082f, 一般添加资源更新日期或文件内容的hash值

      从可用性角度说,大型web应用中,资源重新命名是最优的选择,因为新的资源文件不会覆盖正在运行的资源文件. HTML文件强制不缓存,就能很好的达到WEB应用版本更新的目的

      手动修改文件版本号,只适用于非常小型的应用。我们需要的是一个自动化的前端工具来做这件事。

      • gulp-hash-list 读取资源,计算hash值,按指定的格式生成一个清单文件
      • gulp-asset-revision 读取资源列表的清单文件,替换HTML中的js,css等资源引用地址

      其实Gulp生态已经有gulp-rev + gulp-rev-collector这种优秀的方案,但是它只支持生成新的文件名,不支持添加参数的形式。

      gulp-hash-listgulp-asset-revision不仅可以支持生成新文件,同时支持添加参数的形式刷新资源版本号,以更新缓存。

    • 滴滴出行·DDFE 技术周刊(第六期) @liangmiao930617

      割裂的前端工程师--- 2017年的预测

      随着业务的不同,每个团队在前端技术点开始有所分化:

      • 重型SPA页面
      • Hybrid方式的Web页面
      • 活动页面
      • 游戏等其他
      • 第一,这表现出前端整个领域发展比较迅速,各方面都有参与到,没有和时代脱节。第二,有各种细分的领域,大家可以做到一专多精,不用害怕失业的烦恼。因为每一个方向都可以做的很深,动力很足。第三,利于交流,各种不同分支的人,可以拿出自己特长的技术来相互交流,取长补短,构建更加系统的知识网络。

      HTML5 元素选择流程图

      HTML5 元素选择流程图

      iSource Browser——在你的 iPhone/iPad 上调试移动端网页

      与君同行的前端周刊(第十一期)

      HTML5游戏引擎深度测评 / 2016年 最火的 15 款 HTML5 游戏引擎

      • Phaser:文档教程,和案例方面都很不错,功能也算的上丰富。非常适合独立游戏开发和小团队使用。
      • Egret:性能不错,在工作流方面支持非常优秀,适应中度和重度HTML5游戏开发,有较多商业项目验证,非常适合商业团队使用。
      • cocos2d-js:老牌引擎,其性能在排名中居中,工作流支持相对完整,推荐。
      • Hilo:阿里前端团队作品,偏向于前端开发工程师,与游戏专业开发距离较大,推荐做HTML5营销小交互的使用。
    • 如何增强单页应用的体验

      所谓单页应用,指的是在一个页面上集成多种功能,甚至整个系统就只有一个页面,所有的业务功能都是它的子模块,通过特定的方式挂接到主界面上。

      单页应用的弱点

      • 对搜索引擎不友好
      • 开发难度相对较高

      如何尽可能增强单页应用的操作体验?

      • 路由的规划: 路由可以理解为 URL 与界面状态的对应关系
      • 服务端推送: 即使页面开着不动, 服务端也主动发送消息过来, 通常使用 WebSocket 之类的技术来实现
      • 断线重连机制: 良好的内存管理, 版本的自动升级
      • 操作补偿机制: 连续进行了几步操作之后, 发现之前的操作失败了, 后续处理会非常复杂
      • 本地缓存: 甚至可以让用户脱机使用我们的应用, 把所有产生的这些变更都缓存, 等到联网的时候再批量同步合并回去
      • 热更新: 每次更新的代码模块也推送过来, 并且作为补丁应用到当前系统上
      • 良好的内存管理: 要想让用户能够长期开着应用, 还需要管理好内存
      • 服务端预渲染: 虽然单页应用跟服务端渲染是存在矛盾的

      我们提到了这些能够提升单页应用体验的方式,如果实现出来,肯定是可以让使用者非常愉悦的,但需要冷静权衡理想与现实之间的差距

      • 我要做的是一个怎样的东西?
      • 我的开发团队是怎样的实力?
      • 我们有怎样的历史负担?
      • 值不值得这么做?
      • 能不能做得了?
    • 前端开发应该怎么学

      作为一个后端程序员,如果不了解前端,属于技能上的缺失,不仅无法独立完成一个完整的产品,而且在思维上不会站在前端程序员的位置上思考,即将来如果成为一个系统设计师,设计出来的软件也很有可能存在缺陷,反之亦然。这也是为什么整个行业越来越鼓吹全栈工程师,这个概念并不是虚幻不实际的,而是企业对人才的一种实实在在的需求,即人们常说的复合人才的一种,全栈工程师对于一个企业来说价值巨大。

      发现以前失败主要是因为自己的重视程度不高,加上前端技术栈确实庞大,如果随随便便就可以学到的技能,那其实本身它的含金量就不高;学习任何一个新技能都应该注重它的学习过程,首先要分析这个技能的主要框架,然后针对框架的每一个知识点,做大量的实践及练习,这样你才能够’快速’学会一门新技能。

    • Window 命令行下快速复制文件夹

      # 复制文件和目录树
      xcopy ccc ddd /i/f/s/e/y
      xcopy f:\ccc f:\ddd /i/f/s/e/y
      
      执行的结果如下
      ---------------------------
      F:\ccc\a.png -> D:\ddd\a.png
      F:\ccc\b.jpg -> D:\ddd\b.jpg
      F:\ccc\test\c.gif -> D:\ddd\test\c.gif
      复制了 8 个文件
      ---------------------------
      
      # 添加 /d 参数表示下次只复制更新过的文件
      xcopy ccc ddd /i/f/s/e/y/d
      
  • 产品
    • 推荐!设计师与程序员不能错过的 10 个酷站

      • UpLabs 汇集了网站前端作品设计、 Android / iOS UI 设计等大量的资源
      • Collect UI 你可以快速找到登录与付费界面、404 界面、搜索界面等素材
      • SiteInspire 可以说是网页设计师必备灵感来源网站
      • One Page Love 汇集了优秀的单页网站、模版等资源的分享站点
      • Resource Cards 专为设计师、开发者提供各种优秀、丰富的资源网站, 包含了 12 大类,涉及图片、字体、图标、设计工具等设计师常用的免费资源,以及 HTML/CSS/JS、Bootstrap 等开发者需要的免费资源

班会第 40 期

  • 技术

    • Sails.js 起航 - 后端框架选秀

      对比下 ThinkJS, 可以看到 Sails 的功能更为强大, 当然也就会更加地复杂...

    • text-spinners

      Pure text, CSS only, font independent, inline loading indicators

      Every Spinner is a fixed sized element with a pseudo element whose content is set to the parts of the spinner divided by \A to create line breaks.

      Then a stepped keyframe animation shifts the pseudo element up one line-height per step.

      text-spinners

    • Refills

      Patterns/Components/Type Systems: 常用的 UI 模式/组件/排版

      • centered navigation
      • footers
      • accordion / tabs / vertical tabs
      • cards
      • badges
      • breadcrumbs
      • icon bullet points
      • scroll on page
      • side image
      • tables
      • button group
      • hover tile animation
      • modal
      • pagination
      • dropdown
      • progress bars
      • search bar
      • switch
      • tooltip
      • comments
      • device
      • flex boxes
      • grid items
      • hero unit
      • search tools
      • expander
      • flashes
      • image with gradient overlays
      • parallax
      • ribbon
      • responsive video embed
      • sliding panel
      • stats
      • textures
    • 构建稳固的、可升缩的CSS框架的八大原则

      我们追求的是一个稳固的、可升缩的CSS框架

      • 面向组件

      • 沙盒

        将组建进行拆分并不一定能能使得其按照我们的期望进行加载,如:一个组件的样式可能会对其他组件的样式产生不可预计的影响。诸如CSS基础特性和具有唯一全局性性质的命名空间的标识符就能造成这种影响。

      • 善用类来定义CSS

      • 将组件的相关代码放在一起

        会对组件的组件化起到很大的作用

      • 使用一致的类命名空间

        CSS只具有一个单一的、无区分性的命名空间, BEM 来完成对于命名空间的命名, 我们将选用一种命名标准并贯彻执行

      • 让命名空间和文件名间具有映射关系

        quick-open-file

      • 防止在组件外定义样式

        如果所有的组件都只使用了附有独特命名空间前缀的类名, 我们敢说这些样式绝对不会和它人的重合

      • 防止泄漏组件内的样式

        • 决不在样式文件中使用元素名称
        • 在命名空间中将元素名与选择器 > 配合使用
      • 考虑元素的边界问题

      • 松散的聚合外来样式

        定义好了一堆mixin指令供你在需要的地方使用,而不会随意暴露出风格样式

      知道这些规则后,才能知道在什么时候可以去打破它

    • sanitize HTML with jQuery prevent Application from XSS attacks

      // 小心 XSS 漏洞
      $('<img src=1 onerror=alert(1)>');
      $.parseHTML('<img src=1 onerror=alert(1)>'); // jQuery 3.0+
    • 你所不知道的跨域资源共享(CORS)

      • 简单请求 (Simple Request)
      • 预检测请求 (Preflight Request)
      • force preflight flag
    • JBox

      极光宝盒: 纯粹的通知解决方案

      • 简单配置
      • 消息聚合
      • App订阅: 无需注册,扫码即可接收通知
      • 使用场景
        • 用于服务器监控
        • 用于作业通知

      API 文档

      • 发送消息

        向 webhook url 发送 JSON payloads

        POST https://jbox.jiguang.cn/v1/message/{integration_id}/{token}
        
        {
            "title": "消息的标题,可以为空",
            "message": "消息内容,不能为空",
            "url": "跳转 url ,手机端点击消息跳转的链接,为空不跳转(注意这个地方要加 http 前缀)"
        }
        
    • iOS应用支持IPV6,就那点事儿

      自从5月初Apple明文规定所有开发者在6月1号以后提交新版本需要支持IPV6-Only的网络

      Starting June 1, 2016 all apps submitted to the App Store must support IPv6-only networking. Most apps will not require any changes because IPv6 is already supported by NSURLSession and CFNetwork APIs.

      If your app uses IPv4-specific APIs or hard-coded IP addresses, you will need to make some changes. Learn how to ensure compatibility by reading Supporting IPv6 DNS64/NAT64 Networks

      • IPV6-Only支持是啥?

        首先IPV6,是对IPV4地址空间的扩充。

        目前当我们用iOS设备连接上Wifi、4G、3G等网络时,设备被分配的地址均是IPV4地址

        但是随着运营商和企业逐渐部署IPV6 DNS64/NAT64网络之后,设备被分配的地址会变成IPV6的地址,而这些网络就是所谓的IPV6-Only网络,并且仍然可以通过此网络去获取IPV4地址提供的内容。

        客户端向服务器端请求域名解析,首先通过DNS64 Server查询IPv6的地址,如果查询不到,再向DNS Server查询IPv4地址,通过DNS64 Server合成一个IPV6的地址,最终将一个IPV6的地址返回给客户端。

        NAT64-DNS64-ResolutionOfIPv4_2x.png

      • Apple如何审核支持IPV6-Only?

        这里说的支持IPV6-Only网络,其实就是说让应用在 IPv6 DNS64/NAT64 网络环境下仍然能够正常运行。但是考虑到我们目前的实际网络环境仍然是IPV4网络,所以应用需要能够同时保证IPV4和IPV6环境下的可用性

      • 应用如何支持IPV6-Only?

        • Use High-Level Networking Frameworks;
        • Don’t Use IP Address Literals;
        • Check Source Code for IPv6 DNS64/NAT64 Incompatibilities;
        • Use System APIs to Synthesize IPv6 Addresses;

      针对苹果最新审核要求为应用兼容IPv6

      • 不建议使用底层的网络API
      • 不要用IP地址
      • 检查不兼容IPv6的代码
      • 本地搭建IPv6测试环境

      关于阿里云 ECS 服务器是否支持 IPV6 的回复

      阿里云ECS的操作系统对于IPV6的支持并未做特别的限制,如果您需要系统能支持ipv6协议,您按照对应的系统的配置方法来配置即可, 但目前ECS主机的网络尚不支持IPV6

      如果您指的是苹果官方如下的通知: https://developer.apple.com/news/?id=05042016a, 这个通知主要是要求2016年6月1日后提交到AppStore的应用必须支持IPV6协议,而不是说APP应用的服务端必须要有IPV6网络

  • 产品

    • HiPPTER

      • PPT资源导航
        • PPT模板
        • 素材包
        • PPT达人微博
        • 设计灵感补给站
        • 配色工具
        • 高清图库/图标/音乐/视频资源
      • 大数据速查
        • 网络趋势分析
        • 新媒体数据分析
        • 网站排名 & 分析/APP数据查询 & 工具/游戏榜单 & 分析
        • 金融投资 & 企业背调
        • 社会调查 & 生活数据
        • 数据分析报告

班会第 8 期

  • 技术
    • BFC标准入门

      BFC并不神秘,它只是一个描述块级盒该怎么排布的布局规则

    • 12个JavaScript技巧

      • 使用!!操作符转换布尔值
      • 使用+将字符串转换成数字
      • 并条件符(&&)
      • 使用||运算符实现默认值
      • 在循环中缓存array.length
      • 检测对象中属性
      • 获取数组中最后一个元素
      • 数组截断
      • 替换所有
      • 合并数组
      • 将NodeList转换成数组
      • 数组元素的洗牌
    • 小王的架构师之路

      小王同学和大家不一样, 不但填了空, 工作之余还经常琢磨着这个框架为什么这么设计, 有什么问题, 用起来有什么不爽

      小王经常会给维护框架的核心组提一些建议, 刚开始的时候这些建议看起来还没什么价值,小王不管, 还是努力的学习,积极思考

      小王还非常热心助人,别人的工作遇到难题,他都会尽力相助, 即便是占用自己的时间小王也觉得很值得: 解决一个问题自己的能力就会提升

      从一个被别人领导的一个普通程序员, 变成了领导别人的一个技术组长,以前是别人设计,自己开发, 现在是自己设计,指导别人开发

      小王知道, 要想自己变得优秀, 一定要多和更优秀的人在一起交流,要想成长, 一定要站在比自己更高的职位上进行思考, 学习那些人的思考方式

      小王还特别注意业界有什么最新,最热的技术, 然后想办法把这些技术运用公司的项目中, 或者提升代码质量,或者提升工作效率

      做新项目的时候 ,小王甚至在脑海里想如果是自己来做设计, 应该会怎么做, 等到架构师把架构设计出来, 小王会做个比较, 看看自己那些地方考虑不周。自己觉得有争议的地方还会找架构师讨论

    • 支付宝架构师:从工程师到架构师的成长之路

      • 架构师的定义
      • 架构的职责
      • 架构师的成长
    • 架构漫谈

      • 什么是架构?
      • 认识概念是理解架构的基础
      • 如何做好架构之识别问题
      • 如何做好架构之架构切分
      • 什么是软件
      • 软件架构到底是要解决什么问题?
      • 架构师没有话语权,还架什么构!
      • 从架构的角度看如何写好代码
      • 理清技术、业务和架构的关系
    • 将 Web 应用性能提高十倍的10条建议

      • 反向代理服务器和负载均衡
      • 缓存动态和静态数据
      • 压缩数据
      • 系统性能调优
      • 服务器性能调优
      • 监视系统活动来解决问题和瓶颈
    • 如何面试程序员

      • 当前技能是不是满足团队要求
      • 是不是有较强的学习能力,在未来可以继续成长
      • 是不是有很好的自我驱动力,不需要跟在屁股后面催着干活
      • 团队协作,是不是能融入团队
    • Let's Encrypt,免费好用的 HTTPS 证书

  • 产品
    • Make it run, make it right, make it fast

      • Make it work: 这个阶段的重点在于需求的响应,以最快的速度实现需求
      • Make it right: 这个阶段的重点在于保障系统的稳定,同时优化设计和重构。
      • Make it fast: 这个阶段的重点在于系统的性能优化,包括项目流程效率的优化。

      这三个阶段不是孤立的,而是一个整体,同时又是有先后次序的。

      总结一下

      • Make it work: 首先最低限度满足项目需求,将初步结果拿出来演示,根据反馈快速调整
      • Make it right: 需求稳定后,对代码进行重构,良好的设计,易于维护和扩展
      • Make it fast: 设计稳定后,对实际运行情况中出现的性能问题进行优化
    • 《构建之法》读后感之项目计划

      在定项目计划的时候,我一般会分成以下几步:

      • 第一步,在目标(项目需求)明确后,开始预估项目计划,这时候精确度不需要太高,精确到周为单位即可。
      • 第二步,对项目需求和团队成员进行同步,确保项目成员充分理解项目需求,将任务分配下去后,让项目成员自行评估各自项目计划
      • 第三步,对项目成员的计划进行一一核查,参照第一步预估的时间,对过于乐观的和过于宽松的,都要一起把计划细化,细节仔细推敲探讨,确保计划科学合理
      • 第四步,完成最终计划,并确定几个关键里程碑,确保在里程碑的时候能交付一定的内容
    • 您的项目现在处于哪个阶段

      devstore-productHome

班会第 20 期

  • 技术
    • Load Awesome

      An awesome collection of — Pure CSS — Loaders and Spinners

    • HTML5 跨域通信 API - window.postMessage()

    • 跨域页面消息通信的坑与填

    • 逐渐去掌握 React(作为一名 Angular 开发者)

      directive -> component

      propTypes是一个验证组件所需参数的方法。你可以把个别参数标记为“必需的”或“可选的”(默认它们都是可选的),把它想象成类型检测吧。

      如果你指定了propTypes并说明一个参数是必需的,然后你忘记把它传进来,你就会在控制台得到一个提示信息。

      比起 Angular 这真的太棒了!当你忘记给指令传参时你就再也不怕莫名其妙地报错了。

      你可以把 props 看作是传给组件的属性。就像在指令里,你会在 HTML 元素里传递属性一样 - props 会在 JSX 元素里被当作属性传递。

      JSX

      • 那并不是字符串
      • 那并不是HTML
      • 它是给我们提供了一种用函数调用去创建 DOM 元素的语法糖

      一个指令的控制器和模板通常会紧紧关联在一起,所以很自然地,它们就像是硬币的两面。把代码分离到不同的文件里并不会自动导致关注点分离。

      有很多很好的理由去说明为什么需要把逻辑和视图层给分离开,但当你回头再看会发现同样也有很多很好的理由去合并它们。

    • 用 React 做出好用的 Switch 组件

      React-Switch

      做出一个支持手指滑动操作的 Switch 组件,提升用户体验

      无论多么复杂的手势系统,他们都会基于四个最基础的触摸事件:touchstart/touchmove/touchend/touchcancel

      在固定不动的元素上检测手势事件,这会为你减少很多bug

    • 使用 Three.js 的 3D 制作动画场景:飞行者

      The Aviator: The Game | Codrops

      创建一个 Three.js 的项目,我们至少需要以下这些:

      • 场景: 把这看作一个舞台,将需要呈现的对象都添加进去;
      • 相机: 在这情况下,我们将使用透视相机,但它也可能是正投影相机;
      • 渲染器: 使用 WebGL 渲染器显示所有的场景;
      • 渲染一个或多个对象: 在我们的例子中,我们会创建飞机,大海,天空(一些云);
      • 光源: 有不同类型可用的光源。在我们的项目中,我们主要用到营造氛围的半球光和制造阴影的方向光。
      function init() {
         // 创建场景,相机和渲染器
         createScene();
         // 添加光源
         createLights();
         // 添加对象
         createPlane();
         createSea();
         createSky();
         // 调用循环函数,在每帧更新对象的位置和渲染场景
         loop();
      }
    • 聊一聊移动调试那些事儿

      • chrome 模拟手机调试
      • 真机调试之android手机+Chrome
      • 真机调试之iphone + safari
      • UC浏览器
      • 微信内置浏览器调试(微信 Web 开发者工具)
      • 万能大法之weinre
      • 抓包

      总结

      • 调试不要浪费时间,能用chrome调试,非得用weinre就不值当了。上面的方法中,越在上面的方法,越简单易用。建议优先采用,以省时为主。
      • 针对实在没办法的情况(少数情况),使用各种针对性的调试方法,可以帮我们调试碎片化的环境。
      • DEBUG也是一门艺术,难度并不一定低于写代码,所以调试的时候,要多动脑筋,比如fiddler可以和weinre组合使用,调试线上问题,又或者可以通过fiddler把页面中的信息发送给服务器,进行观察。
      • 调试的时候,要勇于先猜想,再论证猜想。比如,一个BUG,感觉是出在某块儿代码处。那就要集中调试这块儿代码。如果猜想错了,再进行猜想,如果对了,就是一大收获。
      • 复现不出来BUG怎么办?-----猜!看现象,听描述,猜着复现,有时候真的就能碰上。
    • 聊一聊前端存储那些事儿

      • cookie

        • cookie在每次请求的时候都会被带上。你总不想每次访问自己网站接口或者文件的时候都带上一堆可能用不到的信息把?这样会增大请求包的大小。
        • cookie可以设置访问域, 建议给重要信息cookie字段加上HttpOnly标识。加上了这个标识的话,我们的客户端js是无法读到
        • 如果设定了cookie的超时时间的话,那么cookie将在到期的时候失效。如果没有设定,那么cookie就是session级别的啦(在浏览器退出时才结束)
        • 建议存储一些同步访问页面的时候必须要被带到服务端的信息
      • sessionStorage

        存储于客户端。服务端是无法直接拿到的, 只有当前设定sessionStorage的页面才能访问,而且不同的两个tab之间不能互通, 以tab为级别的session(关闭后再打开同一个页面也没有了, 必须是刷新当前tab的页面), 即只有页面刷新才不会清除掉sessionStorage, 剩下的均会清理掉sessionStorage

      • localStorage

        如果用户不清理的话,localStorage是可以永久存储的, 大小一般限定为4M左右. 只有当前设定localStorage的域可以取到数据,其他域名不可以取

      • websql与indexeddb

        websql的标准,官方已经不打算维护了,转而维护了新的indexeddb,读者可能会问了,那直接说indexeddb就好了,为啥还要说websql,因为websql虽然过时了,但是其兼容性却出奇的好,几乎是移动端均可用呀

        websql更像是关系型数据库, 并且使用sql语句进行操作, indexeddb更像是nosql, 直接使用js的方法操作数据即可

    • 聊一聊网页的分段传输与渲染那些事儿

      http1.1中引入了一个http首部,Transfer-Encoding:chunked。这个首部标识了实体采用chunked编码传输,chunked编码可以将实体分块儿进行传输,并且chunked编码的每一块内容都会自标识长度。这给了web开发者一个启示,如果需要多个数据,而多个数据均返回较慢的话。可以处理完一块就返回一块,让浏览器尽早的接收到html,可以先行渲染。

      虽然最后总的处理时长不变,但是采用了分段输出的网页,可以尽早的将一段HTML渲染到客户端,这样用户可以使用先到达的部分。另一方面,尽早的页面反馈,也可以减少用户等待的焦躁情绪。综上,使用此种优化方法,可以提速网页的渲染速度。

      基于这个原理实现: bigpipe

    • 我脑海中的优秀技术团队

      • 好奇心

        当一个开发纠结于自己做的一些初级实现的事情的价值的时候, 不如多思考你对于团队的价值, 对于与业务的价值. 例如推动团队技术规范标准化, 业务性能的优化, 引入新工具新技术解决现有技术问题, 开发工具或者脚手架提高团队开发效率, 了解客户端和后端的知识做跨团队的融合合作放大开发价值. 什么是架构师, 不就是解决这些问题. 当然, 前提是扎实的基础.

      • 持之以恒的学习

        你是如何“持续学习”的,你看过一篇文章之后,对于其中涉及的一些知识点,你如何去强化?如何去实践?甚至如何引入到工作中来?你的工作或者是项目都做得平平无奇,那你看书看论坛都是在看什么呢?看了之后又解决了什么问题?

      • 分析解决问题的方式

        你在遇到技术难题的时候,如何解决?google?这些是最基本的,你如何判别一个解决方案的正确性?你如何一步一步分析问题?如何debug你的代码?然后,解决问题之后,你做了什么思考?是否是你的知识面有问题,需要系统补充下某个方面的技术点?你是否研究了它周边的知识?写一篇博客,备忘顺便分享给网友?这里又涉及到知识管理的方面。总之每次遇到问题其实都是一次对你的知识面的扩充时机,最终这些都会变成你的经验。在工作多年之后,这些潜移默化的知识会让你能够快速对一个问题作出判断,会在你脑海中形成一套体系,帮助你快速分析和解决问题

      通过这些细节发现一个人的潜力:好奇心决定了你能在技术这条道路上走多久;学习方式决定了你能够在这条道路上越走越高;而解决问题的方式则决定了你能否形成方法论,成为一位真正的资深工程师

      • 团队是否在朝着一个更好的方向成长?

        你这个团队是否有“目标”“规划”“预期”

      • 团队做事方式是否规范?

        代码规范/方法规范/流程规范

        规范化的最终目的,一个是提高开发效率,另一个是确保团队开发的可持续性,减少“坑”出现的几率

      • 共同成长和价值定位

        • 有足够的挑战,有机会接触各种问题并解决以此获得经验积累
        • 团队认可我的价值
        • 团队有足够的成长空间
    • 浅谈web架构之演化过程

      大型网站特点

      • 高并发,大流量
      • 高可用
      • 海量数据
      • 用户分布广泛,网络情况复杂
      • 安全环境恶劣
      • 需求快速变更,发布频繁,产品发布频率是极高的
      • 渐进式发展。好的互联网产品都是慢慢运营出来的,不是一开始就开发好的。

      演化过程

      • 一台服务器(服务器操作系统用Linux,应用程序使用PHP开发,部署在apache上,数据库使用Mysql)
      • 应用服务和数据服务分离
        • 应用服务器需要处理大量的逻辑,所以需要强大的CPU
        • 数据库服务器需要快速磁盘检索和数据缓存,所以需要更大的内存和更快的硬盘
        • 文件服务器需要存储大量用户上传的文件,所以需要更大的硬盘
      • 使用缓存改善网站性能(二八定律:80%的业务访问集中在20%的数据上)
      • 应用服务器集群改善并发能力
        • 对于网站架构而言,只要能通过增加一台服务器的方式改善负载压力,就可以以同样的方式持续增加服务器不断改善系统性能,从而实现系统的可伸缩性。
        • 通过负载均衡调度服务器,进行负载均衡。如果很更多的用户,就在集群中加入更多的应用服务器,使应用服务器的负载压力不再成为整个网站的瓶颈。
      • 数据库读写分离(主从热备功能)
      • 使用反向代理和CDN加速网站响应
        • CDN和反向代理的基本原理都是缓存
        • CDN部署在网络提供商的机房,使用户在请求网站服务时,可以从距离自己最近的网络提供商机房获取数据
        • 反向代理则部署在网站的中心机房,当用户请求到达中心机房后,首先访问的服务器是反向代理服务器,而如果,就将其直接返回给用户。
      • 使用分布式文件系统和分布式数据库系统
        • 业务分库,将不同业务的数据库部署在不同的物理服务器上。
      • 使用NoSQL和搜索引擎
      • 业务拆分
        • 通过使用分而治之的手段将整个网站业务分为不同的产品线,分归不同的业务团队负责。
        • 各应用之间可以通过一个超链接建立关系,也可以通过消息队列进行数据分发,当然最多的还是通过访问同一数据存储系统来构成一个关联的完整系统。
      • 分布式服务
        • 将这些共用的业务提取出来,独立部署, 通过分布式服务调用共用业务服务完成具体业务操作。
    • 浅谈web架构之架构设计

      架构模式

      基本的网站架构

      • 分层

        将系统在横向维度上切分成几个部分,每个部分负责一部分相对比较单一的职责,然后通过上层对下层的依赖和调用组成一个完整的系统。

        • 应用层(负责具体业务和视图展示,如网站首页以及搜索输入和结果展示)
        • 服务层(为应用层提供服务支持,如用户管理服务,购物车服务)
        • 数据层(提供数据存储访问服务,如数据库、缓存、文件、搜索引擎等)
      • 分割

        纵向方面对软件进行切分。将不同的功能和服务分割开来,包装成高内聚低耦合的模块单元。

      • 分布式

        分层和分割的主要目的是为了切分后的模块便于分布式部署

        • 分布式应用和服务
        • 分布式静态资源
        • 分布式数据和存储
        • 分布式计算
      • 集群

      • 缓存(CDN/反向代理/本地缓存/分布式缓存)

      • 异步

      • 冗余

      • 自动化

      网站的伸缩性是指不需要改变网站的软硬件设计,仅仅通过改变部署的服务器数量就可以扩大或者缩小网站的服务处理能力。

      扩展性和伸缩性

      • 扩展性:指对现有系统影响最小的情况下,系统功能可持续扩展或提升的能力。表现在系统基础设施稳定不需要经常变更,应用之间较少依赖和耦合,对需求变更可以敏捷响应。也就是说当系统增加新功能时,不需要对现有系统的结构和代码进行修改。核心**是模块化,并在此基础上,降低模块间的耦合性,提高模块的复用性。
      • 伸缩性:指系统能够通过增加(减少)自身资源规模的方式增强(减少)自己计算处理事务的能力。也就是说利用集群的方式增加服务器数量,提高系统的整体事务吞吐呢能力。
    • 淘宝前端国际化方案探索

      • 国际化的流程和步骤
        • 针对来源判断用户所属区域
        • 通过 IP 地址进行判断
        • 淘宝IP地址库
        • 记录 Cookie 并提供用户切换地区、语言、货币的功能
      • 针对特定区域进行国际化处理
        • 页面内容改变(固定文字/动态数据/图片)
        • 页面交互样式改变
      • 国际化的部署服务器

      国际化方案探索脑图

    • 客服平台总结

      • Vue
      • NodeJs/Npm
      • ES6/7
      • Webpack/Gulp
      • Sass/Jade
      • Webscoket
      • 目录结构
      • 发布流程
      • 本地调试
    • 微信Android热补丁实践演进之路

      热补丁:让应用能够在无需重新安装的情况实现更新,帮助应用快速建立动态修复能力。

      有淘宝的Dexposed、支付宝的AndFix以及Qzone的超级热补丁方案

      了解各项热补丁技术的优缺点,同时也能对它的应用场景有着更加全面的认识

      微信热补丁方案: 全量替换新的Dex: Tinker, 简单来说,在编译时通过新旧两个Dex生成差异patch.dex。在运行时,将差异patch.dex重新跟原始安装包的旧Dex还原为新的Dex。

      一个完善的热补丁系统

      • 网络通道: 这里要解决的问题是决定补丁以何种方式推送给哪部分的用户
      • 上线与后台管理平台: 这里主要包括热补丁的上线管理,历史管理以及上报分析,报警监控等
  • 产品
    • 100个弹框设计小结

      由于屏幕的尺寸愈来愈大,有时候为了在大屏幕下有更好的视觉表现,对于一些较复杂的弹框,可以选择做2种尺寸适配

      背景锁定与滚动条引起的抖动问题, 由于页面滚动条从有到无,页面会晃动,这样糟糕的体验显然是不能容忍了,于是,对元素进行处理,右侧增加一个滚动条宽度(假设宽度是widthScrollbar)的透明边框。

      要尽量避免在弹框上再弹一层弹框,2层蒙版会让用户觉得负担很重。可以改用轻量弹框或重新把交互梳理。

      蒙版增强品牌感, 过去我们对蒙版颜色可能没有仔细关注过,也许颜色不是纯黑#000,就是纯白#fff。其实蒙版的颜色及透明度可以再深入搭配的,例如产品是蓝色调性的可以在黑色中混入一点蓝色,产品是轻盈的可以用白色或淡灰色,或者尝试用没那么深的颜色搭配高一点透明度等等,根据产品的调性设计出一个适合产品气质的蒙版。

      网页设计也日趋移动化。可以想像将会有一大波移动上的体验会搬到网页设计上

      随著产品愈来愈追求简洁,UI也变得愈来愈轻盈

    • 各种「弹窗」有学名,从此不再分不清

      各种「弹窗」有学名,alert, dialog, popup, notification, lightbox, popover 傻傻分不清楚

班会第 22 期

  • 技术
    • puer-mock

      一个简单易用 mock server, 为你提供可配置的接口和随机数据.

      为什么你需要一个 mock server

    • 聊一聊移动web分辨率的那些事儿

      苹果发布ios的时候,肯定会想到成千上万的PC网页,没法在自己的IOS系统上运行起来时间多么蛋疼的事情啊。但是呢,这些网页都是按照PC屏幕的大小写的呀。

      动不动就出现两个500多px的宽的div并列。这在当时640*960屏幕大小的iphone4上显示的话,简直是毁灭性的。(会各种折行,样式错乱),那么细致如苹果肯定不允许这种事情发生。

      于是苹果公司的攻城狮们想出了一个歪招,那就是告诉浏览器,“你在一个980宽的大屏幕下在渲染呢”,浏览器就按照了980宽的方式,渲染出来页面图像。可是到了浏览器这边,其实是拿到了一张渲染好的、比屏幕大的网页图像。此时,苹果再把这张图像,缩放一下,缩为屏幕大小。(我们平时也经常这样干,把一张大图片用双指放大缩小)

      可以更改的布局宽度: viewport

      几次变迁: iphone6的普通扩大, iphone6 plus的扩大高清度

      几代iphone手机的分辨率

    • 移动端样式小技巧

      • line-height

        line-height的兼容问题不太好解决,容器高度越小,显示效果的差距越明显。稍微大一点的高度,最好把line-height设置为高度+1px,两个平台显示都还不错。

      • 多行省略

        .multiple-line-ellipsis {
            display: -webkit-box;    /* 1. -webkit-box 布局 */
            overflow: hidden;        /* 2. 设置元素超出隐藏 */
            text-overflow: ellipsis; /* 3. 设置超出样式为省略号 */
            -webkit-line-clamp: 2;   /* 4. 设置2行应用省略 */
            -webkit-box-orient: vertical;
            /* 酌情控制行高和字体大小 */
            /* line-height: 18px; */
            /* font-size: 14px; */
        }
      • 梯形角标的实现

      • 图文标题

        如果有图文对齐的需求的话,个人建议才用before伪元素来布局,before可以相对文案来定位

      • 左右宽度自适应

        我的方案是用box布局,左侧的容器设置box-flex:1,右侧不管它

      • display:inline-block

        行内元素在水平和垂直排列的时候会有间距

      • 模拟滚动

        模拟滚动也是在项目中遇到的常见布局。布局要求弹层出来后,弹层中的内容可以滚动,弹层背后的列表不能随弹层滚动而滚动。并且在弹层上滑动的时候,整个页面也不能随之滚动。

        页面内容、蒙层、蒙层中的内容互为兄弟节点,防止点击时页面穿透

    • gulp plugins 插件介绍

      gulp API 和一些常用的 gulp 插件

    • Stream手册

      src.pipe(dst)

      a.pipe(b).pipe(c).pipe(d)

      a.pipe(b);
      b.pipe(c);
      c.pipe(d);

      这和你通常在命令行或者终端中使用pipe一样:
      a | b | c | d

    • 移动前端—图片压缩上传实践

      在做移动端图片上传的时候,用户传的都是手机本地图片,而本地图片一般都相对比较大,拿iphone6来说,平时拍很多图片都是一两M的,如果直接这样上传,那图片就太大了,如果用户用的是移动流量,完全把图片上传显然不是一个好办法。

      直接在前端压缩图片,已经成了很多移动端图片上传的必备功能了

      在移动端压缩图片并且上传主要用到filereader、canvas 以及 formdata 这三个h5的api。逻辑并不难。整个过程就是:

      (1)用户使用input file上传图片的时候,用filereader读取用户上传的图片数据(base64格式)

      (2)把图片数据传入img对象,然后将img绘制到canvas上,再调用canvas.toDataURL对图片进行压缩

      (3)获取到压缩后的base64格式图片数据,转成二进制(Blob)塞入FormData,再通过XmlHttpRequest提交FormData。

      说起来好像挺简单,其实还是有些坑的。

    • 用中文编写javascript代码

      // 将下面的代码复制到 Chrome Console 中执行
      var  = {数量: 5, : 2},
          大猫 = {数量: 5, : 4},
          小猫 = {数量: 5, : 4},
           = {数量: 5, : 4};
      
      var 算腿 = function (, 带的那谁) {
          var  = 0,
              谁的数量 = .数量;
      
          while (谁的数量 >= 1) {
               += .;
      
              // 如果有[带的那谁],就递归
              if (带的那谁) {
                   += 算腿(带的那谁);
              }
      
              谁的数量 -= 1;
          }
      
          return ;
      };
      
      var 到底TM有多少条腿 = function (所有的东西) {
          var  = 0;
      
           += 算腿(所有的东西[0], 所有的东西[1]);
      
          // [谁]和[带的那谁]的计算完了,下一个
          所有的东西.shift();
      
          // 如果还有东西,就递归
          if (所有的东西.length >= 2) {
               += 到底TM有多少条腿(所有的东西);
          }
      
          return ;
      };
      
      到底TM有多少条腿([, 大猫, 小猫, ]);
    • WEB前端 -“懒人”养成计划

      人类历史上曾诞生了琳琅满目的懒人科技,不断迁就着人性的弱点,有汽车、火车、飞机这种大型地、颠覆式发明,也有一些非常酷炫的小型创意,甚至还诞生了不错的服务,事实上,整个第三产业的市场就是来源于“懒人不想做的事情”。这些创意在改变人类生活的同时,也改变了懒汉的定义,在拥有了大量的新鲜玩意之后,他们的境界正大有提高,事实上,懒已经不是完全意义上的贬义词,在一定程度上,代表着高逼格。

      由于近几年前端的野蛮生长以及前端应用的多元化和复杂化,整个技术形态已经跟几年前纯做页面的时代完全迥异了。主要观念的变化总结来看在于一点,现在的前端开发面向的是web app而不是web page。前端如今已经脱离了茹毛饮血、刀耕火种的原始社会,开始步入了工业时代。 感谢这个快速发展的环境,给了页面狗,一个偷懒的机会:依靠新工具,新技术,极大的提高生产力。

      • 工欲善其事,必先利其器: EMMET:前端神器,页面仔必备啊!
      • 让CSS可编程,带你装逼带你飞
      • 快速创建前端静态网站 – http-server
      • 自动化构建工具GULP – 串起你的整个项目
      • 珍惜键盘,远离F5 – Browsersync
    • Api manage platform

      根据项目管理接口,开发人员新建项目后再新建接口,书写接口文档,统一进行管理

  • 产品
    • 功能性动画UX设计——打造优秀的过渡转场效果

      功能性动画(functional animation)是有明确、合理目标的微动画。它能减少认知负荷,防止变化盲视,营造更好的空间关系。另外,动画让用户界面更贴近生活。
      成功的动画设计具有以下六个特征:响应性, 关联性, 自然, 目的性, 清晰

      • 保持过渡动画简短,因为用户会频繁看到它们。控制动画持续时间在300ms或更短。
      • 过渡效果应当明确、简洁、连贯、清晰。记住,在动画方面,少即是多。我们应该只专注于动画能为用户带来的实际价值。
      • 动画不是随意为之。每个操作背后都有其目的。动画对用户起引导作用,突出重要内容。无论你的应用是欢乐幽默型还是严肃直接型,动画的运用原则都有助于你提供清晰、快速、连贯的用户体验。
    • 所谓的“微信OS”会掀起HTML5的二次革命吗?

      呼之欲出的应用号将会把微信变成一个“操作系统”,让一个个web应用在“微信OS”上运行,从而迈出微信商业化的最重要一步

班会第 12 期

  • 技术
    • 关于烂代码的那些事 - 为什么每个团队存在大量烂代码

      • 如果只是一个人维护的代码,满足功能和性能要求倒也足够了。
      • 如果在一个团队里工作,那就必须易于理解和测试,让其它人员有能力修改各自的代码。
      • 越是处于系统底层的代码,扩展性也越重要。
    • 代码重构之道

      重构之道与重构之术

    • 你要避免的软件开发模式

      • IDD(IDE-Driven Development)
      • DDD(Debugger-Driven Development)
      • PDD(Print-Driven Development)
      • BDD(Bug-Driven Development)
      • RDD(Rat-race-game-Driven Development)
    • 谈谈面向对象编程

      • 你觉得在面向对象编程中,最重要的**是什么?
      • 如果有人提及「继承」,我会让她写个她在工作中使用继承的例子
      • 如果有人提及「多态」,我会让她解释一下多态,并让她写个她在工作中使用多态的例子
      • 如果有人提及「代码重用」,我会让她谈谈她对代码重用的理解,并附上一个工作中重用的例子

      Scott Wlaschin 在他那著名的 Funtional programming patterns 中提到,types are not classes。
      在函数式编程里面,类型实际上是一种接口,它是数据和数据可以产生的行为间的一座桥梁:

      而「类」是「类型」的一种实现方式。从这个意义上讲,「会飞」(flyable) 是一个类型,「鸟」实现了 flyable,而「鸭子」无法实现 flyable,所以「鸭子」并不是「鸟」的子类型。弄明白了这一点,我们就不会傻乎乎地去根据生活经验,把「鸭子」继承在「鸟」的名下。

    • 我是一个线程

      以故事的形式讲述了线程的一生, 何为资源加锁, 为什么要资源加锁

    • 关于小米在开源上的五大原则,一位20年开源老兵的思辩

      在小米我一直推行这几个原则

      • 快。快速选型,快速定位,快速掌握,快速推出产品
      • 绝不重造轮子。宁愿学习掌握,化为己有而不要自己重写,这个投入远远大与前者
      • 不用则已,要用则精
      • 永远抱着开放与共享的态度
  • 产品

班会第 4 期

班会第 14 期

  • 技术
    • JavaScript 被忽视的细节

      1234567890..toLocaleString(); // 1,234,567,890
      1234567890..toLocaleString('zh-Hans-CN-u-nu-hanidec', {useGrouping: false}); // 一二三四五六七八九〇
      new Date().toLocaleString(); // 2016/6/20 下午1:30:53

      JSON.stringify 接受三个参数,很多人都知道第三个参数可以设置空白字符来美化输出,但是你可能不知道第二个参数的作用,它为 {Array|Function} 类型,如果为 Array 则用于过滤 key,如果为 Function 则可以对 value 做处理

    • 用 CSS 隐藏页面元素的 5 种方法

      • opacity: 从视觉上隐藏元素。而元素本身依然占据它自己的位置并对网页的布局起作用。内容会被读屏软件阅读, 它也将响应用户交互
      • visibility: 被隐藏的元素依然会对我们的网页布局起作用。与 opacity 唯一不同的是它不会响应任何用户交互。此外,元素在读屏软件中也会被隐藏。也能够实现动画效果, 事实上可以用这一点来实现元素的延迟显示和隐藏。举个例子,我们要实现淡入淡出效果,显然是需要改变透明度的,但是,元素即使透明度变成0,虽然肉眼看不见,但是,在页面上,元素还是可以点击,还是可以覆盖其他元素的,这显然是有问题的,我们最最希望的是在元素淡出动画结束后,元素可以自动隐藏!visibility的响应就是为这个需求而生的!
      • display: 真正隐藏元素。确保元素不可见并且连盒模型也不生成。使用这个属性,被隐藏的元素不占据任何空间。不仅如此,一旦 display 设为 none 任何对该元素直接打用户交互操作都不可能生效。此外,读屏软件也不会读到元素的内容。这种方式产生的效果就像元素完全不存在。任何这个元素的子孙元素也会被同时隐藏。为这个属性添加过渡动画是无效的,它的任何不同状态值之间的切换总是会立即生效。
      • position: 将元素移出可视区域
      • clip-path: 元素自身不再显示,它也依然占据本该占据的矩形大小,它周围的元素的行为就如同它可见时一样。用户交互例如鼠标悬停或者点击在剪裁区域之外也不可能生效。在我们的例子里,剪裁区大小为零,这意味着用户将不能与隐藏的元素直接交互。这个属性能够使用各种过渡动画来实现不同的效果。
    • 这些地方你不需要使用 JavaScript

      • Tooltips :hover
      • 下拉菜单 :hover
      • 可见性切换 :checked
    • Pure CSS Tabs

    • Flexbox adventures

    • 聊一聊淘宝首页和它背后的一套

      • 淘宝首页的整理变迁
        • PHP 下的淘宝首页
        • PHP 到 Node 的变迁
        • Node,不一样的模式
      • 淘宝首页的性能优化
        • 页面渲染逻辑
        • 一起来看看淘宝首页的个性化
        • 淘宝首页性能优化实践
      • 淘宝首页的稳定性保障
        • 兜底容灾机制
        • 监控预警机制
        • 上线前的自动化检测
      • 淘宝首页的敏捷措施
        • 健康检查
        • 接口 Hub
        • 快捷通道

      PC与无线齐飞,Web共Native一色——天猫首页全解密

      天猫前端基础技术体系MAP简介

    • 前端代码异常日志收集与监控

      收集日志的方法

      • 主动判断
      • try..catch 捕获
      • window.onerror 捕获全局错误
        收集日志存在的问题
      • 跨域情况下,返回的结果是 Script error. 使用 crossOrigin 参数跳过跨域限制. 服务器也要设置 Access-Control-Allow-Origin 的响应头
      • 压缩代码无法定位到错误的具体位置. 有什么办法,可以定位错误的具体位置,或者说有什么办法可以缩小我们定位问题的难度呢?可以这样考虑:打包的时候,在每两个合并的文件之间加上 1000 个空行
      • error 事件的注册. 多次注册 error 事件,不会重复执行多个回调
      • 收集日志的量. 没有必要将所有的错误信息全部送到 Log 中,这个量太大了, 可以添加一个采样率.
      • window.onerror 这个错误监听一定要放到最前头
    • 大话 程序猿 眼里的 接口

    • 大话 程序猿 眼里的 WEB安全

    • 大话 程序猿 眼里的 高并发

    • H5 Crash 研究

      H5 Crash 的原因不太明显,但是从经验上判断和摸索,大致归类为以下三种:内存问题, Layers 数问题, 并发过多问题

      • 通过 opacity、animation、positon 等方式创建层,即便是 1w 个,页面也没有明显变化;但是使用 transform 创建 2k~5k 个层,页面会卡顿几秒后立即闪退;
      • 内存是条红线,测试发现,一次性消耗 20M 的内存,会导致客户端立即闪退;
      • 并发请求也是存在响应问题的,Fetch API 和 CSS Resource 并发 1k 请求没有出现问题,但是 XHR 和 Script Resource 请求,问题特别明显,虽然没有导致页面闪退,但是页面已经进入了假死状态。
    • H5浏览器和webview后退刷新方案

      在移动端HTML5浏览器和webview中,“后退到前一个页面”意味着:前一个页面的html/js/css等静态资源的请求(甚至是ajax动态接口请求)根本不会重新发送,直接使用缓存的响应,而不管这些静态资源响应的缓存策略是否被设置了禁用状态。除非请求是JS发送的,且每次发送时,都在url中加入了随机数。

      后退返回到上一个页面的表现,一句话总结就是:html/js/css/接口等资源直接使用前一次请求过的,而JS中的代码从头开始重新执行了一遍。这在一些场景下会导致严重的bug,所以才会提出“后退刷新”的需求。

      “后退刷新”的目标是浏览器在后退返回到前一个页面时,能从server端请求到一个全新的的页面内容(即status code 200 ok或status code 304 not modified的页面响应,而不是status 200 from cache根本不向server端请求)进行加载展示并重新执行JS代码。

      The browser does not respect HTTP caching rules when you click the back button.

      绕过这个问题比较便捷的方法是页面中使用 JS 来请求后端的接口以展现数据, 每次展示都通过接口来获取数据(添加时间戳强制无使用缓存)

    • 一篇文章读懂React

      以简单直观、符合习惯的(idiomatic)方式去编程,让代码更容易被理解,从而易于维护和不断演进。这正是React的设计哲学。

      React最有价值的是声明式的,直观的编程方式。

      使用JSX直观地定义用户界面。在这里你可以利用熟悉的JavaScript语法去定义界面,在你的思维过程中其实已经不需要存在模板的概念,需要考虑的仅仅是如何用代码构建整个界面

      所谓组件,就是状态机器。React将用户界面看做简单的状态机器。当组件处于某个状态时,那么就输出这个状态对应的界面。通过这种方式,就很容易去保证界面的一致性。在React中,你简单的去更新某个组件的状态,然后输出基于新状态的整个界面。React负责以最高效的方式去比较两个界面并更新DOM树。这种组件模型简化了我们思考的方式:对组件的管理就是对状态的管理。组件是React中构建用户界面的基本单位。它们和外界的交互除了状态(state)之外,还有就是属性(props)。事实上,状态更多的是一个组件内部去自己维护,而属性则由外部在初始化这个组件时传递进来(一般是组件需要管理的数据)。React认为属性应该是只读的,一旦赋值过去后就不应该变化。

      每一次界面变化都是整体刷新

      一个数据模型的变化可能导致分散在界面多个角落的UI同时发生变化。界面越复杂,这种数据和界面的一致性越难维护。在Facebook内部他们称之为“Cascading Updates”,即层叠式更新,意味着UI界面之间会有一种互相依赖的关系。开发者为了维护这种依赖更新,有时不得不触发大范围的界面刷新,而其中很多并不真的需要。React的初衷之一就是,既然整体刷新一定能解决层叠更新的问题,那我们为什么不索性就每次都这么做呢。简而言之就是,UI界面是一棵DOM树,对应的我们创建一个全局唯一的数据模型,每次数据模型有任何变化,都将整个数据模型应用到UI DOM树上,由React来负责去更新需要更新的界面部分。事实证明,这种方式不但简化了开发逻辑并且极大的提高了性能。

      单项数据流动/使用只读数据来建立数据模型

      React对UI层进行了完美的抽象,写Web界面时甚至能够做到完全的去DOM化:开发者可以无需进行任何DOM操作。因此,这也让对UI层进行整体替换成为了可能。React Native正是将浏览器基于DOM的UI层换成了iOS或者Android的原生控件。而Flipboard则将UI层换成了Canvas。

    • 一文看透丑陋而又神奇的JSX

      JSX这种混合使用JavaScript和XML的语言第一眼看上去很“丑陋”,也很神奇,但是其语法和背后的逻辑却极其简单。JSX本身并不是什么高深的技术,可以说只是一个比较高级但很直观的语法糖

      为什么使用JSX

      前端界面的最基本功能在于展现数据,为此大多数框架都使用了模板引擎

      几乎每种框架都有自己的模板引擎。传统MVC框架强调界面展示逻辑和业务逻辑的分离,因此为了应对复杂的展示逻辑需求,这些模板引擎几乎都不可避免的需要发展成一门独立的语言,每个框架都有自己的模板语言语法。而这无疑增加了框架的门槛和复杂度。

      如果说掌握一种模板语言并不是很大的问题,那么其实由模板带来的架构复杂性则是让框架也变得复杂的重要原因之一

      为了解决这些复杂度,框架本身需要精心的设计,以及创造新的概念(例如Angular的Directive)。这些都会让框架变得复杂和难以掌握,不仅增加了开发成本,各种难以调试的Bug还会降低开发质量。

      React直接放弃了模板而发明了JSX。看上去很像模板语言,但其本质是通过代码来构建界面,这使得我们不再需要掌握一门新的语言就可以直观的去定义用户界面:掌握了JavaScript就已经掌握了JSX。这里不妨再引用之前文章举过的例子,在展示一个列表时,模板语言通常提供名为Repeat的语法,例如在Angular中:

      React组件通过唯一的props接口避免了逻辑复杂性,让开发测试都更加容易。这种特性完全得益于虚拟DOM机制,让你可以每次props改变都能以整体刷新页面的思路去考虑界面展现逻辑。

    • Interactive Resume

    • 如何重构一个大型历史项目——百度经验改版总结

      这次遇到可能影响进度的风险点主要都是来自经验的老代码,历史数据结构,各种边界case。有些东西,你不看老模块的代码是不可能知道的,所以还是要把老代码全部看懂才行。

    • 京东618:三大系统防作弊,挑战直面用户的困难

      所有的网站前台系统在设计上都会遵循数据闭环、动静分离、异步化、无状态、水平扩展几个原则进行设计保证系统的稳定性、扩展性以及对于业务瞬息万变的响应。

      我们将从用户可以直接感知的前端业务风控系统进行剖析:

      • 交易订单风控系统
      • 爆品抢购风控系统
      • 商家反刷单系统

      我们开发了前端使用的“三峡系统”来为前端系统提供接口的监控、降级、切换一站式服务。“三峡”,顾名思义就是作为一个总闸来控制所有前端系统对接口的调用和内容展示。从接口的性能、可用性、数据正确性几个方面进行监控,并提供便捷的降级和切换功能。这样可以保证一旦监控发现依赖的接口服务性能或可用性下降,我们就可以一键式从后台对接口服务进行降级、切换处理保证前台页面展示。

      对于外部,由于我们是处在系统链的最前端,所以我们会建立主动沟通机制,和各个团队进行随时随地的沟通,来预防和解决任何可能出现影响用户体验的问题。同时,由于我们部门所负责的各个系统全部面向客户,有任何的小问题都会严重影响到客户体验。因此,我们也建立了问题快速响应的专职团队,负责及时解决客户反馈的任何问题。将用户体验的损失降低到最低。

    • 阿里资深前端工程师桐木:站在10年研发路上,眺望前端未来

      近几年我们不同团队也尝试了 ng、avalon、react、vue 这些 mv*的框架,这个方向最终被我们收拢到 PC React、无线 vue & react 的路线上来。

      WebView有哪些历史负担呢?

      • 标准兼容上的包袱
      • 浏览器的内部机制以及js语言在设计上,其实也有一些历史包袱
      • WebView本身确实也在越变越快,但有些OS的限制或者一些设备老旧WebView的存在,会导致碎片问题,这也在拖慢我们的脚步

      老郭的BeeFramework/Samurai、阿里的birdnest,是在甩前两项包袱,一方面取Web标准的子集,一方面把所有东西都拉到Native的runtime里执行;FB的React Native和阿里的Weex,主要在甩第一项包袱(部分优化了第二项);Mozilla的Servo致力于并行化和GC,主要是在甩第二项包袱;Intel的crosswalk、微信的X5、阿里的UCWebView等,是在一定范围内甩第三项包袱……大家为了甩掉这些包袱,都提出了不同的解决方案。

      不论大家走哪条路,有一个共识还是大家都找到了的,那就是看齐Web的几个标准。因为Web的技术体系在UI的描述能力以及灵活度上确实设计得很优秀的,而且相关的开发人员也好招。所以,如果说混合开发指的是Native里运行一个Web标准,来看齐Runtime来写GUI,并桥接一部分Native能力给这个Runtime来调用的话,那么它应该是一个永恒的潮流。

      其实前端的发展在这两年已经有了不小的突破了,之前是一些边界上的扩张(服务端、移动端),然后是工程化及生态的完善(模块化、包管理),近期是语言、标准本身的一些进化。

    • Commit message 和 Change log 编写指南

    • 提问须知

      问编程问题,最重要的是能让别人能轻松复现你说的现象,最好的办法是提供 SSCCE(Short, Self Contained, Compilable, Example), 就是能复现你描述的现象的完整能编译运行的(短)代码

  • 产品
    • BAT解密(一):聊聊技术发展的驱动力

      是什么推动了一个互联网企业的技术发展?

      几个典型的派别:潮流派, 保守派, 跟风派

      互联网企业的业务基本上可以大概分为两类:一类是提供“产品”,一类是提供“服务”。

      一个互联网企业的发展,归根结底就是业务的发展,而影响一个互联网企业的业务发展的主要有3个因素:市场、技术、管理。我称之为业务发展铁三角,任何一个因素的不足都将导致企业业务的发展停滞不前。

      对于“产品”类的业务,答案其实很明显:技术创新不断推动业务的发展。

      这个道理和传统的制造行业的产品创新是一样的:产品上的技术创新 -> 带来更强大的功能 -> 推动产品的市场不断扩大 -> 市场扩大竞争更加激烈 -> 反过来又对技术创新提出了更高的要求,如此循环往复,技术创新不断的推动产品的提升、业务的扩展。

      而对于“服务”类的业务,答案和产品类业务正好相反:业务发展推动技术的发展。

      用户选择一个产品的根本驱动力是其“功能”,例如功能是否强大,外观是否漂亮,用户体验是否良好;而用户选择一个服务的根本驱动力不是功能,而是“规模”。

      当“规模”成为业务的决定因素后,服务模式的创新成为了业务发展的核心驱动力,而产品只是为了完成服务而提供给用户。以淘宝为例:淘宝提供的“网络购物”是一种新的服务,这种业务与传统的到实体店购物是完全不同的,而为了完成这种业务,需要“淘宝网”、“支付宝”、“一淘”、“菜鸟物流”等多个产品。

      服务类的业务发展路径是这样的:提出一种创新的服务模式 -> 吸引了一批用户 -> 业务开始发展 -> 吸引了更多用户 -> 服务模式不断完善和创新 -> 吸引越来越多的用户,如此循环往复。

    • BAT解密(二):聊聊业务如何驱动技术发展

      互联网业务千差万别,但由于他们具有“规模决定一切”的相同点,其发展路径也基本上是一致的。互联网业务发展一般分为几个时期:初创期、快速发展期、竞争期、成熟期。

      不同时期的差别主要体现在两个方面:复杂性、用户规模。

      发展期

      时期 优点 缺点
      堆功能期 方便快捷,系统改动很小 开始较快,但越来越慢
      优化期 方便快捷,系统改动很小 开始较快,但越来越慢
      架构期 长效作用明显,做一次可以顶几年 改动大,实施的过程较长,短则半年,长则1 ~ 2年

      竞争期

      • 系统数量的量变带来了技术工作的质变
      • 重复造轮子
      • 系统交互一团乱麻

      成熟期

      • 用户量增大对技术带来的第一个挑战就是性能要求越来越高
      • 用户量增大对技术带来的第二个挑战就是可靠性要求越来越高
        应对这些挑战的方式却可以概括为1个字“拆”,简单来说就是“一台不够拆为两台,两台不够拆为4台。以此类推”
      • 拆硬件:数据库分库分表、业务处理分开到多个机器
      • 拆地点:双机房部署、多机房部署、数据中心
      • 拆功能:例如将购物系统拆分为登录认证子系统、订单系统、查询系统、分析系统等
        当然,“拆”只是手段,“合”起来才是关键
      阶段 用户规模 业务阶段 技术影响
      婴儿期 0 ~ 1万 初创期 用户规模对性能和可靠性都没有什么压力,技术人员可以安心睡好觉。
      幼儿期 1万 ~ 10万 初创期 用户规模对性能和可靠性已经有一点压力了,主要体现为单台机器(服务器、数据库)可能已经撑不住了,需要开始考虑拆分机器,但这个时候拆分还比较简单,因为机器数量不会太多。
      少年期 10万 ~ 100万 发展期 用户规模对性能和可靠性已经有较大压力了,除了拆分机器,已经开始需要将原来大一统的业务拆分为更多子业务了。
      青年期 100万 ~ 1000万 竞争期 用户规模对性能和可靠性已经有很大压力了,集群、多机房等手段需要开始用上了。虽然如此,技术人员还是很Happy的,毕竟到了此时公司已经发展得非常不错了。
      壮年期 1000万 ~ 1亿 竞争期 &成熟期 用户规模对性能和可靠性已经有非常大压力了,可能原有的架构和方案已经难以继续扩展下去,需要推倒重来。不过如果你真的身处这样一个公司,虽然可能有点辛苦,但肯定会充满干劲,因为这样的机会非常难得也非常锻炼人!
      巨人期 1亿 + 成熟期 和壮年期类似,不过如果你真的身处这样一个公司,虽然可能有点辛苦,但估计做梦都要笑醒了!因为还没有哪个互联网行业能够同时容纳两家1亿+用户的公司。

      通过前面的分析,我们可以看到业务驱动技术发展的两大主要因素是复杂性和用户规模,而这两个因素的本质原因其实都是“量变带来质变”。
      应对业务质变带来的技术压力,不同时期有不同的处理方式,但不管什么样的方式,其核心目标都是为了满足业务的“快”的要求,当你发现你的业务快不起来的时候,其实就是技术的水平已经跟不上业务发展的需要了,技术变革和发展的时候就到了。更牛逼的做法是在问题还没有真正暴露出来就能够根据趋势预测下一个转折点,提前做好技术上的准备,这对技术人员的要求是非常高的。
      在应对复杂性和用户规模带来的技术压力时,“拆”是一种常见的的手段,可以拆系统、拆业务、拆机器、拆地点。等等,总之一句话:哪里不满足就拆哪里!但拆容易,如何将拆完后的东西“合”起来才是关键。

    • 产品之器 Sketch

班会第 38 期

  • 技术

    • 十年 杭研技术秀 | 网易蜂巢的工业化前端架构

      • 模块化: 分工产生效能

        将一个大文件拆分成相互依赖的小文件,再进行统一的拼装和加载,这为多人协作提供了可能

        • JS的模块化

          在ES6之前,JavaScript一直没有模块系统,这对开发大型复杂的前端工程造成了巨大的障碍

          技术选型:Webpack + Babel + ES6

        • CSS的模块化

          虽然SASS、LESS、Stylus等预处理器实现了CSS的文件拆分,但没有解决CSS模块化的核心问题:选择器的私有化问题(全局污染问题)

          技术选型:PostCSS + CSS Modules

      • 组件化: 现代化生产的分工协作要求工业部件遵循互换性原则

        模块化只是在语言层面上,对代码的拆分;而组件化是基于模块化,在设计层面上,对UI(用户界面)的拆分

        从UI拆分下来的每个包含模板(HTML)+样式(CSS)+逻辑(JS)功能完备的结构单元,我们称之为组件。

        组件化除了要处理组件这种本身的封装,还要处理组件之间的逻辑(JS)继承,样式(CSS)扩展和模板(HTML)嵌套等关系。

        组件化实际上是一种按照模板(HTML)+样式(CSS)+逻辑(JS)三位一体的形式对面向对象的进一步抽象。

        页面上所有的东西都是组件。页面是个大型组件,可以拆成若干个中型组件,然后中型组件还可以再拆,拆成若干个小型组件,小型组件也可以再拆,直到拆成DOM元素为止。DOM元素可以看成是浏览器自身的组件,作为组件的基本单元。

        传统前端框架/类库的**是先组织DOM,然后把某些可复用的逻辑封装成组件来操作DOM,是DOM优先;而组件化框架/类库的**是先按顶层设计来构思组件,然后用DOM这种基本单元结合相应逻辑来实现组件,是组件优先。

        • 组件的分类

          按照组件的代码组成,组件可以分为:HTML、HTML+CSS、JS、HTML+JS、HTML+CSS+JS。

          按照组件的通用性(复用性),组件可以分为以下三类

          • 通用组件:不同产品间可以复用的组件
          • 通用业务组件:仅在同一产品中可以复用的组件
          • 业务组件:不可以复用的组件
        • 组件库

          技术选型:RegularJS + Regular UI + Cloud UI

      • 规范化: 现代工厂制度是工业革命发展的必然产物

        • 目录结构

        • 编码规范

          技术选型:ESLint

      • 自动化: 现代工业其所以区别于工场手工业,是由于机器起了主要的作用

        • 图标合并

          技术选型:SpriteSmith + FontCustom

        • 可视化组件文档

          前端开发和后端开发不同的是,前端开发是可视化的

          后端文档只要写个markdown文件,放在git仓库就能阅读;而在前端文档中,你写个m-modal-lg,别的开发者根本不知道你这个模态框多大,是个什么样子,去翻源码也无法感知组件的具体使用场景。

          技术选型:PostMark + JSDoc

        • 前端自动化测试

          技术选型:Karma + Mocha + Expect.js

        • 构建工具

          技术选型:Gulp

    • 爬虫工具箱

      用途

      • 作为 HttpToolbox 的 Node.js 版
      • 列举了爬虫抓取网站的一般场景
      • 作为开发爬虫项目的模版
    • 白话网站架构演进

      网站架构的演进不外乎两个原因:

      • 用户越来越多,意味着并发要求越来越高
      • 数据越来越多,意味着存储挑战越来越大

      演进历程

      • 上古时代: 一个数据库加一个应用服务器,应用服务器直接开门迎客
      • 读写分离: 一个 Master 数据库负责数据写入,另外有一到多个 Slave 数据库负责数据读取。Master 和 Slave 之间的数据会自动同步
      • 负载均衡: 负责接收用户发过来的请求,然后看哪个应用服务器比较有空闲,就把请求发送给相应的应用服务器执行
      • 动静分离: 把静态的内容和动态的内容分离,分别放在不同的服务器上,减少中间交互环节,从而提高效率
      • 内容分发网络: CDN(Content Delivery Network)让一个区域的用户访问那个区域的服务器,涉及到动态 DNS 解析的技术
      • 数据库集群: 大容量的分布式数据库
      • 缓存: 把经常读的数据放在缓存里来提高效率

      最终的架构图

    • 五种通用WEB应用服务架构

      • 所有东西都放在一个服务器上
        典型的Web应用程序将包括Web服务器,应用程序服务器和数据库服务器

      • 数据服务器分离

      • 负载均衡

        负载平衡器可以添加到服务器环境中,以通过在多个服务器之间分配工作负载来提高性能和可靠性

      • 主备互用,读写分离

    • Nock

      Nock is an HTTP mocking and expectations library for Node.js

      Nock can be used to test modules that perform HTTP requests in isolation.

      For instance, if a module performs HTTP requests to a CouchDB server or makes HTTP requests to the Amazon API, you can test that module in isolation.

      Nock works by overriding Node's http.request function. Also, it overrides http.ClientRequest too to cover for modules that use it directly.

      var http = require('http');
      // HTTP mocking and expectations library
      var nock = require('nock');
      
      // intercept every HTTP call to http://myapp.iriscouch.com
      nock('http://myapp.iriscouch.com').get('/users/1')
                                        .reply(200, {
                                            _id: '123ABC',
                                            _rev: '946B7D1C',
                                            username: 'pgte',
                                            email: '[email protected]'
                                        });
      
      var opt = {
          method: 'GET',
          host: 'myapp.iriscouch.com',
          port: 80,
          path: '/users/1'
      };
      var req = http.request(opt, function(res) {
          console.log(res.statusCode);
          var body = '';
          res.on('data', function(data) {
              body += data;
          }).on('end', function() {
              console.log(body);
          });
      });
      req.end();
    • iOS 升级HTTPS通过ATS你所要知道的 @Monine

      苹果规定2017年1月1日以后,所有APP都要使用HTTPS进行网络请求,否则无法上架

      苹果强制升级的HTTPS不仅仅是在接口HTTP上加个S那么简单: 需要满足的是iOS9中新增App Transport Security(简称ATS)特性:

      • 必须是苹果信任的CA证书机构颁发的证书
      • 后台传输协议必须满足: TLS1.2 (这很重要, 后面的自制证书满足这个条件是前提)
      • 签字算法
      • 证书必须使用SHA256或者更好的哈希算法进行签名,要么是2048位或者更长的RSA密钥,要么就是256位或更长的ECC密钥。

      目前有两种升级到HTTPS得方法:

      • 第三方认证的颁发CA证书(推荐)
      • 自己制作证书(这种不知道能不能满足苹果的审核)

      iOS 10 适配 ATS(app支持https通过App Store审核)

      需要解决的问题(iOS 9、iOS10及以上)

      • app内服务器网络请求访问支持https(即一般的请求)
      • webview内支持任意http访问
      • 第三方sdk接入与支持http访问
  • 产品

    • 互联网盈利模式研习笔记2:佣金与分成

      互联网的常见盈利模式,是帮助客户达到某种目的,然后收取佣金或者按照一定的比例从客户的收入中分成

      佣金和分成都不是互联网发明的名词,而是在整个商业社会中由来已久的概念,是已经形成的商业秩序,而这些商业秩序在互联网行业被沿用

      • 电商平台(一般是B2C会采用这类模式)

        每一件商品成交后,天猫都会从成交额中收取一定比率的“服务费”

      • 团购与优惠券

        真正能让利润最大化的方法是,将同一件商品以较高价格卖给那些不太在乎钱的人,同时以较低价格卖给那些在乎钱的人。这种策略在营销学中有一个专门的名词来描述,叫做“价格歧视”。

      • 开放平台

        开放平台的主要盈利模式,就是从在它之上运行的app的收入中提成

      • 互联网金融

        因为支付宝的原理是,将货款先付给阿里巴巴,等收到货,满意后再通知阿里,这时钱才真正到达卖家的账户中。而阿里是家正规的大公司,信用还是信得过的。所以我认为,支付宝与淘宝当年面对卖家的免费政策一起,成就了淘宝的今天

        支付宝的盈利模式之一,是针对商家的“担保交易收款”

      总结:佣金与分成模式的典型闭环

    • 更接近于现实的社交产品设计2——社会化广告

      • 想请人吃饭,有两家餐馆可以选择,看起来档次差不多,但是其中一家门庭若市,甚至会有排队的现象;另一家偌大的大厅几十桌位置只有2桌有人吃饭。于是你选择了前者——即便需要排队。
      • 想买一台电脑,但是自己不懂技术,看不懂配置单,也不知道什么牌子好。正摸不着头脑的时候,想起有个朋友是腾讯的工程师,技术很牛,上次见他,好像是用… 哎?什么牌子来着?哦,Thinkpad!于是自己也买了台Thinkpad。
      • 想去淘宝买水货iPhone,又怕被骗;翻卖家的信用记录?那玩意儿很多都是刷出来的!这时候想起有个朋友好像上个月在淘宝上买了一部,看他用的还不错,应该挺靠谱。于是去问他:“兄弟,把你上次买iPhone的淘宝店铺发我一下~”

      我们每一个人都是“社会人”,我们每一天都要与他人接触和交流,我们的行为总是会受到社会上其他个体的一些影响。

      “社会化广告”就是其中比较有代表性的例子

      • 从广告形式上看,它是:带有社会化元素的广告
      • 从投放渠道上看,它是:能够利用产品的社交特性来提升推广效果的广告

      加上了“赞”按钮, 这跟请人吃饭找人多的餐馆道理一样

      好友赞

      这个看起来更像是文章开始的场景中提到的直接向好友索要店铺地址的情况。对于一个广告来说,它拥有你信任的朋友的消费经验,可信度显然更高一些,同时无形中也拉进了用户跟广告的距离。

      被好友赞过的广告

      加上互动性和社会化元素后,广告的形式可以千变万化,甚至可以让用户不觉得这是广告,而心甘情愿的去点击,去帮助传播。但是从广告系统和投放的角度来看,这里最大的难题并不是形式的创新,而是将有趣的形式标准化,投票、优惠券等形式都是可以很容易标准化的。

      对于广告主来说,社会化媒体上的广告有很多优势,例如:精确定向、操作容易、低门槛

      广点通可以针对用户的地域、年龄、性别等维度进行精准广告投放

      总结

      • 在日常生活中,我们的决策经常会受他人的影响,在互联网上也是一样
      • 有趣的形式和有用的内容不但能提高交易成功的概率,还有利于传播
      • 社交网站得天独厚的用户信息蕴含着巨大的商业价值

班会第 13 期

  • 技术
    • 微信广告入门学习

      太多干货了... 强烈推荐

      WxMoment 是由微信朋友圈广告团队面向广告详情页开发者提供的一个 JavaScript 库。
      通过使用 WxMoment,开发者可以简单的实现详情页中的常见功能,例如:微信分享、横屏提示、网页统计等。

    • Weex by Alibaba

      A framework for building Mobile cross-platform UI

      借鉴 Web 开发的优势, 使用精简后的 Web 技术, 重构移动端前端 App 开发

      精简 HTML, 精简 CSS, 增强 JS

      这种思路也可以瞄一瞄 NativeScript by Telerik

      NativeScript is a cross-platform framework for building native apps using JavaScript, CSS and XML.

    • 标签流or脚本流:前端开发中的两个极端

      零散的标签和JS -> 全部封装在JS里面 -> 全部搞成标签, 少写JS

    • 使用 ES6 写更好的 JavaScript

      • let 和 const 带来的块级作用域
      • 箭头函数带来的 this 的词法作用域
      • 简写属性和方法,以及 getter 和 setter 函数
    • javascript中自定义事件和声明调用函数有什么区别?

      实际上事件机制就是从回调函数转化而来的。事件模式算是订阅/发布模式的一种,它的好处在于绑定事件和触发事件是互相隔离的,并且可以动态的添加和删除

    • JavaScript Puzzlers!

      or: do you really know JavaScript?
      (or: how insane do you think JavaScript actually is?)

    • 使用 BEM 来模块化你的 CSS 代码

      .block {}
      .block__element {}
      .block--modifier {}
      .block__element--modifier {}
    • Using Flexbox: Mixing Old and New for the Best Browser Support

      flex 布局虽好, 但一定要注意添加支持flexbox的老语法版本

      .page-wrap {
          display: -webkit-box;      /* OLD - iOS 6-, Safari 3.1-6 */
          display: -moz-box;         /* OLD - Firefox 19- (buggy but mostly works) */
          display: -ms-flexbox;      /* TWEENER - IE 10 */
          display: -webkit-flex;     /* NEW - Chrome */
          display: flex;             /* NEW, Spec - Opera 12.1, Firefox 20+ */
      }
    • 减少 JPG 文件大小

      你永远都不应该把 JPG 文件的质量值设置为 100

      JPEG 文件的质量值在 100 到 75 之间变化通常只会对图片质量造成非常微小的、很不明显的改变,但是却能显著减小文件的尺寸。
      也就是说许多图片在 75 的质量值时看起来依然很好,但却只有 95 质量值时一半的文件大小。
      当质量值减小到 75 以下时,造成的视觉上的差异会扩大,而文件尺寸的节约会减少。

      imgmin 项目进一步地显示了大多数的大型网站都倾向于将他们 JPG 图片的质量值设置在 75 上下波动

    • 平行空间大事记暨官网上线历程

      全平台兼容的 @font-family 能兼容目前所有平台的网页字体是如何设置的呢?

      html, body {  
          font-family: "San Francisco", "Helvetica Neue", "Lucida Grande", "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Heiti SC", "WenQuanYi Microhei", "Microsoft Yahei", Arial, sans-serif;
      }

      San Francisco 放首位,用于检测操作系统是否为最新的 El Capitan,否则退而求其次,使用Helvetica Neue(苹果设备目前就这两种默认西文字体)。Lucida Grande 主要用于适配 Ubuntu 系统的西文字体,Windows 系统并不自带此字体,所以并不会 fallback 到 Windows 上来。Segoe UI 是自 Windows Vista 操作系统以来的默认 Windows 西文字体。

      接着到中文字体部分:PingFang SC 放首位,依然为了适配苹果设备,否则退而求其次,使用Hiragino Sans GB(冬青黑体。之前 OS X 默认中文字体);Heiti SC 主要是为了适配 iOS9 之前版本的 iOS 系统机型。WenQuanYi Microhei(文泉驿微黑) 是某些 Linux 系列操作系统的默认中文字体。Microsoft Yahei 是自 Windows Vista 以来 Windows 默认中文字体。最后的 Arial 和 sans-serif 是最后一道 fallback,用于 Windows XP 以及完全没有以上中文字体的操作系统使用。

      如果在项目中使用了字体子集化方案,可以在微软雅黑之前放入自定义字体。对于苹果系统,建议保持其系统默认字体设置,不强制使用自定义字体;对于 Windows、android,建议能使用自定义字体即使用。

    • 您不能错过的 Safari 10.0 新特性

      • Shadow DOM
      • 在OS X以及iOS系统上的Safari已经对被誉为Javascript语言重大变革的——ECMAScript 2015 标准(亦称为ES 6)实现完整支持。
      • 在iOS上内嵌自动播放视频
      • CSS3的object-position属性支持
      • 支持SVG的路径裁切
      • 支持 #RBGA 以及 #RRGGBBAA的颜色值写法
    • FreeCodeCamp中文社区

      编程学习指南

      • 计算机博大精深,初学者很容易迷失其中。选定一个方向并坚持下去很重要,Web开发毋庸置疑是首选。
      • 编程语言众多,选择一门最容易入门的语言即可,JavaScript就很适合。
      • 学编程有三点非常重要:英语、逻辑、细心:
      • 英语好的同学看英文书籍、文档,写代码非常流畅,所以印度人比**人在这块更有优势;
      • 编程最重要的就是培养你的逻辑思维,永远记住:思维是人脑最核心的东西;
      • 在编程中经常被一个符号、一个字母的拼写失误而卡住半天,所以优秀的程序员永远都是粗中带细。
      • 编程是互联网时代的通行技能,它既没有那么高深莫测、也没有那么简简单单。
      • 看书学编程、犹如在岸学游泳;
      • 很多人都有这种错觉:看书、看视频、听老师讲课发现看懂了、听懂了就以为学会编程了,一到实际操作发现问题重重。
      • 任何你能看到、听到的东西都是他人总结的知识点,如果你不实践、不消化、不转化成自己的东西,那这些知识永远是他人的,不是你自己的。
      • learning by doing 实践是学习编程的重中之重;
      • 在掌握最小知识点后,就应该立刻开始实践,在实践中发现更多知识点;
      • 遇到困难先看错误提示、然后搜索,最后通过聊天室求助,兴许遇见志同道合的好基友;
      • 英文是学习编程的最大障碍,所以一款好用的中英文词典是你的好帮手。
    • 前端工具

    • 我们的精神角落

    • 不一样的前端手指操

      前端手指操

    • 全民K歌增量升级方案

      • 编译打包APK(未写入渠道号)
      • 服务器用新旧APK(未写入渠道号)生成差异包
      • APK写入渠道号,供用户下载使用
      • 用户本地APK删除渠道号
      • 根据用户使用版本下载差异包
      • 用本地删除渠道号的APK+下载的差异包生成最新版本APK
  • 产品
    • 产品经理要懂多少技术

      『核心提示』 产品经理不需要在技术上登峰造极,但必须要赢得程序猿的尊敬

      • 对技术的理解
      • 美学的修养
      • 强大的学习能力
      • 无限热情
    • 黑客对 Uber 使出「水土不服」技能,用户钱包受到10000点伤害

      乌云白帽子提交多个 Uber 的安全报告,比如 Uber优步客户端接口设计不当可导致撞库攻击、我是如何尝试登陆别人的uber的,发现 Uber 缺乏对**本土的撞库风气进行考虑,这也是很多洋企的通病 Twitter推特登陆接口可撞库 ,导致的后果就如小扎一样被黑客花样虐待!因为 Uber 的账号是手机号码,所以 Uber 的撞库以及爆破搞起来简直如鱼得水。

      当然,你会说这又能有啥?不知道一些 Uber 用户是不是有经历过自己账号被莫名消费的情况,实际上黑产早已经摸索出这种体验非常好的洗钱方式—— Uber 代叫 。他的模式是通过微信或者 QQ 进行线上沟通,你只需支付很低的价格(一般是20~30,随便坐车),告诉他你在哪,要去哪,和联系手机号,不一会车就到位,下车啥都不用管拍拍屁股走人。

      你应该明白了,其实这个代叫方就是控制了大量 Uber 账号,通过代叫的方式给 Uber 内的钱洗出来,但不是等价的,正因为乘客能捞这么大便宜,所以代叫服务非常火爆。各种成熟的网店、QQ 群甚至公众号早已铺天盖地。成都商报的记者也曾就 Uber 用户绑定的支付被盗刷通过自己的方式做过一些多方位的调查 解密“Uber 代叫”黑色产业链

      对于企业,应该在自己的账户机制上做些主动的防范考虑,比如:

      • 客户端多次登录错误弹出验证码,防止机器登录尝试;
      • 对超出登录异常阈值的 IP 进行封锁;
      • 收紧并尽量统一话碎片登录入口;
      • 给出现异常登录的账号足够的安全提示;

      还可以看看微软在用户安全上做出硬气的态度与手段: 微软禁止用户使用泄漏密码库中的常用密码

    • 8年创业反思:技术人应该如何选择创业项目?

      技术人应该如何选择创业项目

    • 写给程序员的管理入门课程 -《格鲁夫给经理人的第一课》

      「任务导向组织」和「功能导向组织」

      任务导向组织是以具体的完成某件事情为目标而形成的组织。功能导向组织是以完成某个细分功能而形成的组织。这两种组织各有优缺点,很多时候需要以混合的形式存在于一家公司,而具体如何混合,在不同的公司差异相当大。拿互联网公司来举例,我所在的猿题库是更偏向「任务导向组织」的公司,我们公司旗下有三款产品:猿辅导、猿题库、小猿搜题。这三个产品下面,各种有着完整并且独立的运营、产品、开发、测试、UI 团队。而我之前工作的网易有道,就是一家更偏向「功能导向组织」的互联网公司,因为在网易有道,有着全公司统一的测试团队、UI 团队。还有一些公司,他们甚至将全公司的移动端开发都集中成一个移动开发团队。

    • 我的博客历程(99 篇/2012年)

班会第 18 期

班会第 18 期

  • 技术
    • 解读ThoughtWorks技术雷达

      ThoughtWorks在每年都会出品两期技术雷达,这是一份关于技术趋势的报告,它比起一些我们能在市面上见到的其他各种技术行情和预测报告,更加具体,更具可操作性,因为它不仅涉及到新技术大趋势,比如云平台和大数据,更有细致到类库和工具的推介和评论,从而更容易落地。

      技术雷达在四个象限(技术,工具,平台,语言和框架)中, 不管你是个人开发者,对于新工具和技术有执着的追求,寄希望于从新工具和技术那里获取改进每日工作的灵感,或者你是技术领导者需要针对自己的系统做技术选型,以及对未来技术趋势的把握,技术雷达都会是一份很好的参考。

      • 手持一份技术雷达,更新技能和工具
      • 停止对不推荐技术的过度投资
      • 看技术演进动态
    • 两端对齐

      别想多了,只不过是两端对齐而已

      对齐效果

      .justify {
          text-align: justify;
      }
      .justify__item {
          display: inline-block;
      }
      .justify::after {
          content: "";
          display: inline-block;
          width: 100%;
      }

      虽然 text-align:justify 属性是全兼容的,但是要使用它实现两端对齐,需要注意在模块之间添加[空格/换行符/制表符]才能起作用

    • magicCss

      大量使用了 before 、after 伪元素,transparent border ,多重线性与径向渐变,多重内外阴影,实现了许多奇妙的图形

      • 气泡三角形
      • 切角/弧形切角
      • 单个颜色实现 hover 和 active 时的明暗变化效果
      • 梯形/饼图/平行四边形/菱形
      • 折角
      • 下划线
      • spectiveBlur
      • 条纹背景图/混合模式背景图/随机背景图
      • 晴天(sun)/多云(cloudy)/雨(rainy)/微风(breeze)/彩虹(rainbow)/夜空璀璨(starry)/雷电(thunder)/雪(snowy)
      • 五角星
      • 太极图
      • 美队盾牌/纽扣/电池电量显示
      • Chrome/Opera/IE/safari/sogou/firefox
      • 波浪水纹效果
      • 利用滤镜实现混合效果
      • 纯CSS实现title属性hover效果
      • 文字故障效果
    • 基于用户行为的图片等资源预加载

      • 图片的懒加载和预加载
      • 基于用户行为的资源预加载
      • prefetch/prerender
    • 推荐10 个短小却超实用的 JavaScript 代码段

      • 判断日期是否有效
      • 获取一组元素的最大宽度或高度
      • 高亮文本
      • 文字动效
      • 逐个隐藏元素
      • 限制文本字数
      • 判断相应式布局中当前适配度
      • 全局计数
      • 嵌入优酷视频
      • 创建动态菜单或下拉列表
    • 自文档化的JavaScript代码的开发方法

      我们经常容易犯一个错误:我们修改了一段代码,但是忘记修改更新注释。混乱的注释并不会打断你代码的执行,但是想象一下debug的时候会发生什么事情。你认真地阅读了注释,它说的是一件事,但是代码干的是另一件事。结果是,你浪费了很多时间发现注释是错误的,甚至最糟糕的是,你可能完全被误导了。

      有一些办法可以来帮助减少代码注释的必要性。我们可以利用某些编码技巧来让我们的代码变得更清晰,例如就是利用编程语言的特点。这样不仅能帮我们的代码变得更加清晰易理解,而且还能能帮助我们改善程序的设计。

      • 结构类自文档化: 使用代码的结构和目录来让代码变得清晰
        • 将代码移动到函数里面
        • 使用变量代替表达式
        • 代码分块
        • 使用纯函数
        • 目录和文件结构
      • 命名自文档化: 例如函数或变量命名让代码更易理解
        • 在计算机领域有量大难题:缓存失效和命名。–Phil Karlton
      • 语句相关自文档化: 我们利用语言的特性来让代码变得清晰
    • 工具武装的前端开发工程师

      • 各种编辑器 SublimeText/Atom/Vim/HBuilder/Brackets/Visual Studio Code
      • 命令行工具
      • 版本控制Git/SVN
      • 数据库
      • 设计/产品, 推荐使用Mockplus
    • photoshop使用实践

      • 基本配置, 保存工作区
      • 切图
      • 删除背景
      • 改变图层颜色
      • 去掉文字或修改
      • 抠图
    • 前端数据之美 -- 基础篇

      前端的数据其实有很多,从大众普遍关注的 PV、UV、广告点击量,到客户端的网络环境、登陆状态,再到浏览器、操作系统信息,最后到页面性能、JS 异常,这些数据都可以在前端收集到。数据很多、很杂,不进行很好的分类肯定会导致统计混乱,也不利于统计代码的组织,下面就对几种普遍的数据需求进行了分类:

      • 访问
        • PV/UV:最基础的 PV(页面访问数量)、UV(独立访问用户数量)
        • 页面来源:页面的 refer,可以定位页面的入口
        • 操作系统:了解用户的 OS 状况,帮助分析用户群体的特征,特别是移动端,iOS 和 Android 的分布就更有意义了
        • 浏览器:可以统计到各种浏览器的占比,对于是否继续兼容 IE6、新技术(HTML5、CSS3 等)的运用等调研提供参考价值
        • 分辨率:对页面设计提供参考,特别是响应式设计
        • 登录率:百度也开始看重登陆,登陆用户具有更高的分析价值,引导用户登陆是非常重要的
        • 地域分布:访问用户在地理位置上的分布,可以针对不同地域做运营、活动等
        • 网络类型:wifi/3G/2G,为产品是否需要适配不同网络环境做决策
        • 访问时段:掌握用户访问时间的分布,引导消峰填谷、节省带宽
        • 停留时长:判断页面内容是否具有吸引力,对于需要长时间阅读的页面比较有意义
        • 到达深度:和停留时长类似,例如百度百科,用户浏览时的页面到达深度直接反映词条的质量
      • 性能
        • 白屏时间:用户从打开页面开始到页面开始有东西呈现为止,这过程中占用的时间就是白屏时间
        • 首屏时间:用户浏览器首屏内所有内容都呈现出来所花费的时间
        • 用户可操作时间:用户可以进行正常的点击、输入等操作
        • 页面总下载时间:页面所有资源都加载完成并呈现出来所花的时间,即页面 onload 的时间
        • 自定义的时间点:对于开发人员来说,完全可以自定义一些时间点,例如:某个组件 init 完成的时间、某个重要模块加载的时间等等
      • 点击
        • 页面总点击量
        • 人均点击量:对于导航类的网页,这项指标是非常重要的
        • 流出 url:同样,导航类的网页,直接了解网页导流的去向
        • 点击时间:用户的所有点击行为,在时间上的分布,反映了用户点击操作的习惯
        • 首次点击时间:同上,但是只统计用户的第一次点击,如果该时间偏大,是否就表明页面很卡导致用户长时间不能点击呢?
        • 点击热力图:根据用户点击的位置,我们可以画出整个页面的点击热力图,可以很直观的了解到页面的热点区域
      • 异常
        • 异常的提示信息:这是识别一个异常的最重要依据,如:’e.src’ 为空或不是对象
        • JS 文件名
        • 异常所在行
        • 发生异常的浏览器
        • 堆栈信息:必要的时候需要函数调用的堆栈信息,但是注意堆栈信息可能会比较大,需要截取
    • 美团性能分析框架和性能监控平台

      快糙猛的方式注定不是可持续的,很快,我们遇到了瓶颈,具体是什么瓶颈呢?

      • 如果把业界最佳实践当成燃料,而性能优化当成驾车远行的话,我们的燃料很快就烧完了,因为大家总结出来的通用的优化手段总是有限的,而我们的目标还没有达到;
      • 因为我们只采集了结果指标,只知道整体表现如何,面对异常波动我们显得特别无力,因为显示世界影响性能的因素太多了,对于到底发生什么事情了,我们无从得知;
      • 由于对性能缺少内窥,我们无法找到更多的优化点,实际上,我们需要一个类似于显微镜的东西,来看看应用内部还有哪些可优化的地方;

      面对这些瓶颈,我们需要想办法去突破它。在坐下来想办法之前,我们往后退一步,仔细考虑这样一个问题:我们到底在优化什么东西?是文档的生成速度?页面资源的加载速度?页面的渲染速度?或者说更高大上的用户体验?这些问题想清楚了,才能分析的更彻底。其实,大多数的性能优化工作都开始于瀑布流图的分析

      我们把项目详情页的资源分为以下几部分:

      • 主文档,即页面的内容,在拿到主文档之前,浏览器啥都干不了
      • 核心 CSS,和首屏图片,在拿到这些之后,浏览器可以开始渲染了
      • 核心 JS,拿到这些内容之后,页面的交互被丰富,但是也会阻塞
      • 其他内容,比如雪碧图,统计脚本等

      根据《高性能网站建设指南》上的数据以及我们的观察,整个页面的加载可以划分为 3 大块:网络时间、后端时间、前端时间,发生在网络和后端的时间占到整体加载时间的 10% 和 20%,而前端资源加载时间占到整体加载时间的 70% ~ 80%。

    • 7 天打造前端性能监控系统

      • Day 1 为什么要监控性能?

        “If you cannot measure it, you cannot improve it” ———— William Thomson

      • Day 2 有什么可用的工具?

        Page Speed/WebPagetest/PhantomJS

      • Day 3 开始线上真实用户性能监控

        为了持续监控不同网络环境下用户访问情况与页面各功能可用状况,我们选择在页面中植入 JS 来监控线上真实用户访问性能,同时利用已有的分析工具作为辅助,形成一套完整多元的数据监控体系,为产品线的评估与优化提供可靠的数据。

      • Day 4 如何采集性能数据?

        Navigation Timing接口

        白屏时间出现在头部外链资源加载完附近,因为浏览器只有加载并解析完头部资源才会真正渲染页面

        可以在浏览器 head 内底部加一句 JS 统计头部资源加载结束点

        统计首屏时间, 首屏位置调用 API 开始统计 -> 绑定首屏内所有图片的 load 事件 -> 页面加载完后判断图片是否在首屏内,找出加载最慢的一张 -> 首屏时间

        用户可操作默认可以统计domready时间

        总下载时间默认可以统计onload时间

        为了获取用户网络类型,可以通过测速的方式来判断不同 IP 段对应的网络

        网络耗时统计

        数据采集完之后我们可以在页面加载完之后统一上报

      • Day 5 如何分析性能数据?

      • Day 6 如何利用监控数据解决问题?

      • Day 7 总结

      • 福利——前端性能学习资料整理

    • 聊一聊百度移动端首页前端速度那些事儿

      我们的业务就是 https://m.baidu.com 别以为只有一个搜索框,我们还有下面丰富的卡片内容,可以提供各式各样的服务

      “百度首页要秒开”却是一个共识,在利用上了缓存的情况下,我们的首页包大小gzip后只有11.1k左右。耗时也就是500多毫秒。大部分用户“秒开”不是事儿。

      • 静态文件在哪里: 为了求快,首页是没有js和css外链的,这样会再发起多次请求。所以,整个首页渲染出来,只需要一次请求(除了iconfont)。其他的首屏所需要的js与css,全部在上线前,编译时,编译内联至HTML中
      • 缓存: 把不变的js/css/html全部存储到localstorage中去,下次加载首页的时候。在特定的位置,不必再从服务端把特定位置的js/css/html传过来。只需要传一句话----"<script>readlocalstorage();</script>"就行
      • 外链: 我们将所有的js/css等静态文件,通过一个接口全部返回
      • DOM也缓存: 我们的模板和数据,也会被缓存至localstorage中, 不变的数据,缓存下来是可以带来信息量的不重复传输的
      • 使用iconfont
      • 卡片的异步加载与缓存
      • 不在首屏的就要异步化
      • 少量静态文件的域名: 我们的logo与iconfont均是放在m.baidu.com域下的,这样节省了DNS的解析。虽然可能带来的问题是,发送图片请求的时候,会携带cookie。但是我们的cookie也是极少的。这点上性能还是有所提升的。
      • 极小的图片base64化: 对于小于1k的图片,我们将其变为base64编码,并融入到css中,一起换存到localstorage中去,这样即节省了网络请求,同时使图片也可以缓存到local中去了。
    • 性能测试应该怎么做

      为什么平均值不靠谱

      我们知道,性能测试时,测试得到的结果数据不总是一样的,而是有高有低的,如果算平均值就会出现这样的情况,假如,测试了10次,有9次是1ms,而有1次是1s,那么平均数据就是100ms,很明显,这完全不能反应性能测试的情况,也许那1s的请求就是一个不正常的值,是个噪点,应该去掉。所以,我们会在一些评委打分中看到要去掉一个最高分一个最低分,然后再算平均值。

      最为正确的统计做法是用百分比分布统计。也就是英文中的TP – Top Percentile ,TP50的意思在,50%的请求都小于某个值,TP90表示90%的请求小于某个时间。

      比如:我们有一组数据:[ 10ms, 1s, 200ms, 100ms],我们把其从小到大排个序:[10ms, 100ms, 200ms, 1s],于是我们知道,TP50,就是50%的请求ceil(4_0.5)=2时间是小于100ms的,TP90就是90%的请求ceil(4_0.9)=4时间小于1s。于是:TP50就是100ms,TP90就是1s。

      为什么响应时间(latency)要和吞吐量(Thoughput)挂钩

      系统的性能如果只看吞吐量,不看响应时间是没有意义的。我的系统可以顶10万请求,但是响应时间已经到了5秒钟,这样的系统已经不可用了,这样的吞吐量也是没有意义的。所以,吞吐量的值必需有响应时间来卡。比如:TP99小于100ms的时候,系统可以承载的最大并发数是1000qps。这意味着,我们要不断的在不同的并发数上测试,以找到软件的最稳定时的最大吞吐量。

      为什么响应时间吞吐量和成功率要挂钩

      这应该不难理解了,如果请求不成功的话,都还做毛的性能测试

      如何严谨地做性能测试

      • 定义一个系统的响应时间latency,建议是TP99,以及成功率
      • 在这个响应时间的限制下,找到最高的吞吐量
      • 在这个吞吐量做Soak Test,比如:使用第二步测试得到的吞吐量连续7天的不间断的压测系统
      • 找到系统的极限值。比如:在成功率100%的情况下(不考虑响应时间的长短),系统能坚持10分钟的吞吐量
      • 做Burst Test。用第二步得到的吞吐量执行5分钟,然后在第四步得到的极限值执行1分钟,再回到第二步的吞吐量执行5钟,再到第四步的权限值执行1分钟,如此往复个一段时间,比如2天
      • 低吞吐量和网络小包的测试
    • 谷歌的代码管理

      为什么 Google 要把几十亿行代码放在一个库?

      这个代码仓库包含10亿个文件、3500万次提交记录,大小为86TB,用户达到几万人。工作日每秒有50万次请求,高峰时80万次,大部分来自自动构建和测试系统。

      Git 的特点是,所有历史记录都会复制到用户的本地机器,所以不适合大型项目,必须拆分成更小的库。以 Android 为例,该项目一共包含800多个独立的仓库。

      Google 采用"主干开发"(trunk-based development)。代码一般提交到主干的头部。这样保证了所有用户看到的都是同一份代码的最新版本。

      "主干开发"避免了合并分支时的麻烦。谷歌一般不采用分支开发,分支只用来发布。大多数时候,发布分支是主干某个时点的快照。以后的除错和功能增强,都是提交到主干,必要时 cherry-pick 到发布分支。与主干长期并行的开发分支,在谷歌极少见。

      由于不采用"分支开发",谷歌引入新功能,一般在代码中使用开关控制。这避免了另起一个分支,也使得通过配置切换功能变得容易,一旦新功能发生故障,很容易切换回旧功能。等到新功能稳定,再彻底删除旧代码。谷歌有类似A/B测试的路由算法,评估代码的表现,由于存在配置开关,这种测试很容易实现。

      单一代码仓库主要有以下优点。

      • 统一的版本
      • 广泛的代码共享和复用
      • 简化的依赖管理
      • 原子性变动
      • 大规模代码析构
    • 我的编程之路

      今天多学一点知识, 明天就少写一行代码

      作者在编程之路上的经历, 去过哪些公司, 遇到哪些人, 做过哪些事, 读过哪些书

      • div+css布局 | 基础的语义化 | JavaScript基础 | jQuery | 兼容性问题
      • 单页应用(SAP) | MVC | Ajax | HTTP | 模块化 | 构建工具 | Node.js
      • Objective-C | w3cplus
      • 混合应用(Hybrid App) | 对Native(iOS端)的熟悉程度不亚于前端(HTML,CSS,JavaScript)
      • 携程的App和手机网站全部使用Hybrid技术来构建,一套代码运行在三端(iOS,Android,Mobile). 在无线事业部感觉每一天都过的很新鲜,因为我能做很多事情,一是验证自己的想法,二是积累了大量的实践经验,三是我可以做更多混合编程的东西. 携程的技术栈(当时使用的是requirejs,zepto,backbone,underscore搭建起来的技术栈)
      • 通过bridge(自定义协议)与Native进行交互
      • 研究了phoneGap的技术,比如在“后台”相对于前端Native就是后台,进行网络,线程的优化
      • 研究了辅助前端调试的工具,比如远程代理,客户端App代理
      • 使用Node.js跑SEO页面,对Node.js掌握的比较全面了,采用新的技术解决回调过深的问题
      • 用ionic快速搭建了跑在三端(iOS,Android,微信端)的每日优鲜App
      • 学习了react,es2015,webpack
      • 开始去了解和掌握react native的知识
      • 更深入的学习了iOS,包括有新推出的Swift语言
      • 关注的点更多的是在于编程**方面,比如最佳的实践,如何采用合适的技术栈搭建产品,编程的规范,自动化CI方面等基础设施的研究
      • 对于开源社区的依赖程度更高了,比如现今成了Github的重度用户
      • 保持对新技术的敏感/遇到问题该怎么办/组织自己的开发环境/老生常谈的如何学习/弄个云服务器
    • 微信App支付全解析

      微信移动支付的申请、接入、使用、确认支付结果等相关流程

    • GraphQL and Relay 浅析

      GraphQL 与 REST

      GET /users/1
      

      现在,我想获取id为1的用户的名字,年龄和他所有朋友的名字

      GraphQL 实现的方案:

      {
        user(id: 1) {
          name
          age
          friends {
            name
          }
        }
      }
      

      REST 实现的方案:

      GET /users/1 and GET /users/1/friends
      或
      GET /users/1?include=friends.name
      

      发现区别了吗?用 REST 要不就发多次请求,要不就得用一个不方便扩展的语法。
      日后扩充资源也没有冗余,你只会获得你想要的资源。还是用上面的例子,如果 user 多了个属性 gender 会怎么样?在 REST 的方案中,如果客户端不变,取到的结果是会多了 gender 属性,而在 GraphQL 方案中,客户端是不会获取到 gender 属性的。

    • BAT及各大互联网公司2014前端笔试面试题

      JavaScript篇,Html,Css篇

    • 一套框架,多种平台 - Angular 2

      由官方正式发布的中文版开发文档

    • React Native 高质量学习资料汇总

      不管你想不想学 React(Native), 他就是那么任性的流行

  • 产品
    • 电商类型产品的数据分析

      针对电商类型的产品,Sensors Analytics设计了一系列的预置事件

      • 访问首页
      • 搜索商品/浏览商品
      • 用户注册
      • 提交订单/支付订单/取消订单
      • 接收商品/售后服务
    • 深度解剖:为什么淘宝造物节的 H5 能炸了我的朋友圈?

      从原理上来说,开发者实际只是用了一个非常常规的展示技术,就是CSS3的空间变换命令,而这个所谓的3D场景是一个不折不扣的伪3D。实际用户们早就见过这种玩法了,只不过以前都是用在真实场景图片上,而这次是首次用在插画上,所以会给人完全不同的新鲜感。

      其实这就是CSS位置变换命令的一个巧妙用法,开发者将所有的图等距离大小切割成了一条条,并把它们围成一个圆形,这样在体验上就创造了一个空间。利用一些算法和简单技术就创造了比较丰富的视觉表现,这真是非常聪明的用法!

      H5空间原理的示意图

      如果你把这支H5丢给创意人,说它创意非常赞!他大概会非常不屑的告诉你,这只不过是一个小聪明,谈何创意?如果你把这支H5拿给程序员,说这个H5技术有多好,他则会很不理解的反问你,这么简单的东西,好在哪里?最后你又拿它给设计师看,说H5设计做的好,他更会郁闷到,这哪里有设计,不就是一组很炫酷的插画么?

      当我们抛开这些所谓专业人士的所谓专业观点之后,你会惊奇的发现,绝大多数用户会认为这是一支创意、技术、设计都很赞的作品!

Sails.js 起航 - 后端框架选秀

Sails.js 请先做个自我介绍吧

Sails is a lightweight framework that sits on top of Express.

  • Sails.js

    The web framework of your dreams

  • ThinkJS

    The Web framework beyond your dreams

对比下 ThinkJS, 可以看到 Sails 的功能更为强大, 当然也就会更加地复杂...

新建一个项目跑起来

具体文档请参考官方的 Getting Started, 新建项目成功后访问 http://localhost:1337/ 来查看效果, 以下示例基于 [email protected] 版本

npm install sails -g

sails new test-sails
cd test-sails
sails lift

由于 Sails 没有自带 autorealod 功能, 开发阶段你修改代码后必须每次重启 sails lift, 这样实在是太麻烦了, 因此推荐开发阶段推荐使用 nodemon 执行 nodemon app.js 来自动重启, 另外 sails console 是一个非常实用的命令行工具.

官方提供的文档只是做了分类, 没有向导似的文档, 让你可以一步接一步从入门到进阶, 因此文档看起来会让人觉得混乱费劲, 建议先从 Controllers 看起.

Controllers

Controllers (the C in MVC) are the principal objects in your Sails application that are responsible for responding to requests from a web browser, mobile application or any other system capable of communicating with a server. They often act as a middleman between your models and views. For many applications, the controllers will contain the bulk of your project’s business logic.

Controllers are comprised of a set of methods called actions. Actions are bound to routes in your application, so that when a client requests the route, the action is executed to perform some business logic and send a response.

完整的 controller 示例

列举了一般开发中所需要的功能

// api/controllers/HelloController.js
// sails generate controller hello index foo bar
//
// blueprint action route 机制会自动创建路由来连接 controller 的方法
// http://sailsjs.com/documentation/concepts/controllers/routing-to-controllers
// http://sailsjs.org/documentation/reference/blueprint-api
//
// 因此对应的路由规则为 /:controllerIdentity/:nameOfAction
// 这里 hello 即为 controller 的 Identity, nameOfAction 即各个方法名
module.exports = {
    // 默认的 action
    // http://sailsjs.com/documentation/reference/configuration/sails-config-blueprints
    // actions: true
    // Whether routes are automatically generated for every action
    // in your controllers (also maps index to /:controller) '/:controller',
    // '/:controller/index', and '/:controller/:action'
    //
    // http://localhost:1337/hello
    index: function(req, res) {
        // 获取 URL
        console.log('url', req.method, req.host, req.url, sails.getBaseUrl());

        // 获取请求参数
        // pathparam 必须在 config/routes.js 中配置 URL Slugs 路由
        // http://sailsjs.com/documentation/concepts/routes/url-slugs
        console.log('pathparam-a', req.params['a']);
        console.log('pathparam-b', req.params['b']);
        console.log('urlparam-c', req.query['c']);
        console.log('GET param', req.query);
        console.log('POST param', req.body);
        console.log('param', req.allParams());

        // 更多的 req res 方法
        // http://sailsjs.com/documentation/reference/request-req
        // http://sailsjs.com/documentation/reference/response-res
        return res.send('index');
    },
    // http://localhost:1337/hello/file
    file: function(req, res) {
        console.log('POST param', req.body);
        // http://sailsjs.com/documentation/concepts/file-uploads
        req.file('fileField').upload(function(err, uploadedFiles) {
            return res.send({
                body: req.body, // 包含 form 表单中除开 file 类型的其他字段的值
                files: uploadedFiles
            });
        });
    },
    // http://localhost:1337/hello/foo
    foo: function(req, res) {
        // 对应 api/responses 中的文件名
        return res.ok({foo: 'bar'});
        // 返回 JSON/JSONP
        // return res.json({a: 1});
        // return res.jsonp({a: 1}); // http://localhost:1337/hello/foo?callback=abc
        // 跳转页面
        // return res.redirect('http://sailsjs.com');
    },
    // http://localhost:1337/hello/global
    global: function(req, res) {
        // [Globals](http://sailsjs.com/documentation/concepts/globals)
        console.log('Globals: The App Object (sails)', sails.config.environment);
        sails.log.info('Globals: Models', Hello.find);
        sails.log.info('Globals: Services', Baz.find);
        return res.send(sails.config.environment);
    },
    // http://localhost:1337/hello/model
    model: function(req, res) {
        // 首先需要配置 api/models/Hello.js 的 attributes 属性来映射数据库字段
        // 否则只会查询出一个 id 字段(必须数据库表也有这个字段)
        // module.exports = {
        //     tableName: 'hello1', // 自定义表名
        //     attributes: {
        //         name: {},
        //         abc: {
        //             columnName: 'name1'
        //         },
        //         name2: {}
        //     }
        // };
        // 通过 Globals 方式来使用 Model
        Hello.find({
            // id: 1
        }).then(function(data) {
            res.ok(data);
        });

        // 指定 SQL 语句执行查询
        Hello.query('select * from hello where id = ?', [2], function(err, rawResult) {
            console.log('sql', rawResult);
        });
    },
    // http://localhost:1337/hello/view
    view: function(req, res) {
        // 变量赋值和模版渲染
        // 默认渲染 views/hello/view.ejs
        return res.view({
            title: '我们一起来学习 Sails',
            author: 'Sun'
        });
    }
};

重点内容

听听吐槽

其他选择

  • Express
    • Express application generator

      提供了很好的路由模块化组织方式, 具体代码可以参考 expressjs/generator

      // routes/index.js
      var express = require('express');
      var router = express.Router();
      router.get('/', function(req, res, next) {
          res.send('index');
      });
      module.exports = router;
      -----------------------
      // routes/users.js
      var express = require('express');
      var router = express.Router();
      router.get('/', function(req, res, next) {
          res.send('user index');
      });
      module.exports = router;
      -----------------------
      // app.js
      app.use('/', require('./routes/index'));
      app.use('/users', require('./routes/users'));
    • Express Middleware

  • Koa
    • 路由中间件

      Koa 没有自带路由中间件, 可以使用 koajs/route 这个简单的实现, 不过一般推荐使用 koa-router 功能更全.

      // routes/index.js
      var Router = require('koa-router');
      var router = new Router();
      router.get('/', function *() {
          this.body = 'index';
      });
      module.exports = router;
      -----------------------
      // routes/users.js
      var Router = require('koa-router');
      var router = new Router();
      router.get('/', function *() {
          this.body = 'user index';
      });
      module.exports = router;
      -----------------------
      // app.js
      app.use(require('./routes/index.js').prefix('/').routes());
      app.use(require('./routes/users.js').prefix('/users').routes());
    • Joi Object schema description language and validator for JavaScript objects.

    • Boom HTTP-friendly error objects

  • Node.js Frameworks
    • MVC
      • Sinatra-like
      • Rails-like
    • Full-stack
    • REST API

班会第 19 期

  • 技术
    • 22个必备的CSS小技巧

      • 类似Photoshop的混合模式 mix-blend-mode
      • 渐变边框
      • z-index 的过渡
      • currentColor 当前的颜色
      • object-fit 类似 background-size
      • 单选框和复选框的样式
      // Unicode编码在CSS和HTML中的写法是不一样的
      // 在CSS中它是一个以反斜杠为开始的十六进制数, 例如: \2713
      // 在HTML中它可以是十进制的,例如: &#10003; 也可以用十六进制: &#x2713;
      HTML -> &#10003;
      HTML -> &#x2713;
      CSS  -> content: "\2713";
      JS   -> console.log(0x002713);
      JS   -> '✓'.charCodeAt(0).toString(16);
      JS   -> console.log('\u2713');
      
      • CSS中的计数器
      counter-reset: counterName;
      counter-increment: counterName ±num;
      content: counter(counterName, list-style-type);
      • 不使用图片的“汉堡”图标 box-shadow/background gradient/UTF-8(直接使用标准符号:Unicode: U+2630, HTML: &#9776)
      • @supports
      /*You can check prefixes*/
      @supports (display: -webkit-flex) or (display: -moz-flex) or (display: flex) {
          section {
              display: -webkit-flex;
              display: -moz-flex;
              display: flex;
              float: none;
          }
      }
      • 父子元素的 visibility
      • position: sticky
      • 新的尺寸单位(vw, vh)
      width: 1vw; /* 浏览器窗口宽度的1% */
      • 文字被选中时的效果 ::selection {}
      • 元素内滚动 -webkit-overflow-scrolling: touch
      • unicode classes
      /* 但这其实是用来搞笑的,千万不要在大型项目中使用,因为不是所有的电脑都支持Unicode符号 */
      .★ {
          /**/
      }
      • 子元素(padding/margin)的百分比是相对于父元素的宽度
      .parent {
          height: 400px;
          width: 200px;
      }
      .child {
          width: 80%;          /* parentWidth  * 90% */
          height: 50%;         /* parentHeight * 50% */
          padding-top: 10%;    /* parentWidth  * 25% */
          padding-left: 20%;   /* parentWidth  * 25% */
          margin-top: 10%;     /* parentWidth  * 25% */
          margin-left: 20%;    /* parentWidth  * 25% */
      }
      • 火狐浏览器的按钮边距
      button::-moz-focus-inner,  
      input[type="reset"]::-moz-focus-inner,  
      input[type="button"]::-moz-focus-inner,  
      input[type="submit"]::-moz-focus-inner {  
          border: none;
          padding:0;
      }
      • color + border = border-color 定义了一个元素的文字颜色,意味着这个元素的边框颜色也被定义了
      input[type="text"] {  
          color: red;
          border: 1px solid;
      }
    • Create React apps with no build configuration

      npm install -g create-react-app
      create-react-app hello-world
      npm start
      npm run build
      
    • 微信开发--iframe中使用微信api

      微信 JSSDK API 是不能在iframe中进行签名认证的

      微信限制了api的调用,不能在iframe中进行api的签名认证,只能在主页面中使用. 所以解决方法就是在父页面实现微信api的签名认证,然后iframe里利用

      window.parent.wx.xxx;
      window.top.wx.xxx;
    • 微信中的阿里(淘宝天猫支付宝)

      关键至于通过iframe避开屏蔽

      <iframe src="https://item.taobao.com/item.htm?id=534848052763" width="100%" height="100%" style="position: absolute;left: 0;top: 0;z-index: 1;width: 100%;height: 100%;border: none;"></iframe>

      BUT~~
      亲测微信 6.2 还可以使用这个黑魔法, 最新版的微信上这个魔法已经失效了!!!, 所以还是放弃吧少年~

    • URL详解与URL编码

      scheme://host[:port#]/path/.../[;url-params][?query-string][#anchor]

      function parseURL(url) {
          var a =  document.createElement('a');
          a.href = url;
          return {
              source: url,
              protocol: a.protocol.replace(':',''),
              host: a.hostname,
              port: a.port,
              path: a.pathname.replace(/^([^/])/,'/$1'),
              query: a.search,
              params: (function(){
                  var ret = {},
                      seg = a.search.replace(/^\?/,'').split('&'),
                      len = seg.length, i = 0, s;
                  for (;i<len;i++) {
                      if (!seg[i]) { continue; }
                      s = seg[i].split('=');
                      ret[s[0]] = s[1];
                  }
                  return ret;
              })(),
              hash: a.hash.replace('#',''),
              relative: (a.href.match(/tps?:\/[^/]+(.+)/) || [,''])[1],
              file: (a.pathname.match(/([^/?#]+)$/i) || [,''])[1],
              segments: a.pathname.replace(/^\//,'').split('/')
          };
      }
      
      var myURL = parseURL('http://a.com:8080/dir/index.html?id=2&m=h#top');
      
      myURL.source;   // = 'http://a.com:8080/dir/index.html?id=2&m=h#top'
      myURL.protocol; // = 'http'
      myURL.host;     // = 'a.com'
      myURL.port;     // = '8080'
      myURL.path;     // = '/dir/index.html'
      myURL.query;    // = '?id=2&m=h'
      myURL.params;   // = { id: 2, m: h }
      myURL.hash;     // = 'top'
      myURL.file;     // = 'index.html'
      myURL.segments; // = ['dir', 'index.html']

      用 encodeURIComponent() 的作用是对 URL 中的参数进行编码

      var param = "http://www.b.com?t=123&s=456"; // 要被编码的参数
      URL = "http://www.a.com?foo=" + encodeURIComponent(param);
    • jQuery 3.0 的新特性

      • 使用 requestAnimationFrame 处理动画
      • escapeSelector 转义包含特殊意义的字符串
      $('.abc\\.def')
      • 支持SVG的类操作方法
      • 简易的 show/hide/toggle 逻辑, 将只为inline styles服务,不再为computed styles效力了
      // in 3.0 we have -
      /*case #1*/ $("<div/>").show().appendTo("body")[0].style.display; // ""
      /*case #2*/ $("<div/>").hide().appendTo("body")[0].style.display; // "none"
      
      // Whereas before, in 2.x, we had -
      /*case #2*/ $("<div/>").show().appendTo("body")[0].style.display; // "block"
      /*case #2*/ $("<div/>").hide().appendTo("body")[0].style.display; // "none"
      • .width() 和 .height() 支持小数
    • CodePush

      CodePush is a cloud service that enables Cordova and React Native developers to deploy mobile app updates directly to their users’ devices. It works by acting as a central repository that developers can publish certain updates to (e.g. JS, HTML, CSS and image changes), and that apps can query for updates from (using our provided client SDKs).

    • 微服务选型之Modern Node.js

      1. 被误解的Node.js:除了性能,都是病?
      • 单线程,会死?
        • Everything runs in parallel except your code
        • 小集群:单台服务器上多个实例, pm2模块,绝大部分的产品环境部署都使用pm2的
      • 异步(callbackhell)太恶心?
        • 同步代码
        • callback hell
        • Promise/A+
        • generators/yield
        • async/await
      • 接入层?
        • 很多公司用Node.js做接入层,比如阿里系的天猫和淘宝,后端大量的C/C++和Java,前端用Node.js一点点替换PHP,据说如果都替换完成,可以每年服务器上节省电费700百万(不知真假)
        • 所谓的接入层就API层以前的(前端 + httpserver-by-node),然后Node去调用API服务,返回给前端。Node的作用就是控制器,从API取数据,然后返回给渲染层。
      1. 现代的Node.js:构建微服务利器
      • 小而美: 保持模块足够小(内聚),模块应该只做一件事!
      • 同步的Node.js
      • 善用npm,实现3化(模块化、最小化、服务化)
      • 微服务选型
    • 大搜车NodeJS日志规范化与分析监控

      ELK + Souche-Alert 日志预警运维系统

      • ELK 日志分析3剑客,是 Elasticsearch + logstash + kibana 的简称
      • filebeta 日志收割机
      • logstash 日志中转站
      • Kibana 强大的日志可视化面板

      ELKstack 中文指南 在实时数据检索和分析场合,三者通常是配合共用

    • 给你的Node.js项目部署HTTPS

      SSL For Free 申请免费的SSL证书(三个月免费,在到期之前sslforfree会发邮件通知你来更换证书)

    • 课多周刊

    • 前端开发面试题

      • 如何在页面上实现一个圆形的可点击区域?
      • Amazon主页的左上角有一个商品分类浏览的下拉菜单 没有延迟,而且子菜单也不会在不应该的时候消失。它是怎样做到这一点的呢?
  • 产品
    • 动效实战派|做交互动效你一定要知道“这三点”

      好的动效应能聚焦用户的注意,能展示界面中各元素是如何组织连接呈现,也能暗示或直接体现出各元素的功能性。动效设计的先行者谷歌为我们定义了好的动效设计的目的:

      • 引导用户在视图间有效聚焦
      • 暗示户完成一个手势操作后,将要触发的效果
      • 展现不同元素之间的层级和空间关系
      • 缓解用户的等待,让应用处理数据(如抓取内容或读取新视图)
      • 突出个性化,新鲜感,愉悦感
    • 设计师如何制作舒适动感的MG动画

      MG全称是Motion Graphic运动图形

      更贴近现实生活的运动

      加速度 | 弹性 | 延迟(惯性)| 随机 层次感(细节)| 运动修饰 | 具有特色的转场

    • 企业经营离不开这三个概念

      做企业有三个教科书一样的概念,就是产品领先,客户贴近和运营卓越。一般的企业守住一个优势,然后其他两个做到60分以上,这个企业就已经相当优秀了。

      比如,餐饮业,米其林餐厅是行业领先;海底捞是客户贴近;麦当劳是运营卓越。

NodeJS 写的 csv 文件 Excel 打开是乱码

在使用 Node.js 写一个包含中文内容的 csv 文件时, 用 UltraEdit 打开是正常的, 没有乱码.
但使用 Microsoft Excel 打开时, 就是一坨乱码.

nodejs-csv-ms-excel-messy.png

真是郁闷, 肯定是掉坑里面了, 让我们查查资料看看, 想必碰到这个问题的人不止我一个.

  • NodeJS CSV导出文件名和内容乱码解决

    // 解决excel打开内容乱码
    var dataBuffer = Buffer.concat([new Buffer('\xEF\xBB\xBF', 'binary'), new Buffer(data)]);
  • 怎么解决数据保存到csv文件乱码问题

    由于 node.js 只支持 ascii、utf8、base64、binary 编码方式, 不支持 MS 的 utf-8 + BOM 格式, 所以 excel 打开中文乱码

    解决方法已经很明显了,既然excel需要BOM,每次写入数据前先加入一个BOM就可以了嘛。utf-8对应的BOM是EF BB BF

用上面提到代码果然就解决了乱码问题.

var fs = require('fs');

var content = '中文1,a1,b1,123\n中文2,a2,b2,456';

var msExcelBuffer = Buffer.concat([
    new Buffer('\xEF\xBB\xBF', 'binary'),
    new Buffer(content)
]);
fs.writeFileSync('test.csv', msExcelBuffer);
// 直接写入 csv, 使用 excel 打开会是乱码
// fs.writeFileSync('test.csv', content);

nodejs-csv-ms-excel-messy-result.png

班会第 31 期

从这一期开始由于新学了一门很费精力的技能, 叫做奶爸攻略, 以后班会的内容还希望大家一起努力, 遵循学前班的宗旨, 将班会办得更好

鼓励每个人都参与进来, 分享自己前端的所见所闻

在分享的过程中, 将知识和快乐传递给大家, 更是锻炼了自己总结和沟通的能力.


  • 技术
    • 更轻更快的Vue.js 2.0与其他框架对比

      Vue.js 2.0 版本已经发布了

      渲染层基于一个轻量级的Virtual DOM实现进行了重写,该Virtual DOM实现fork自snabbdom。新的渲染层相比v1带来了巨大的性能提升,也让Vue 2.0成为了最快速的框架之一。

      Vue 2.0介于Angular 1和React之间。它是现代化的并且很容易学习和使用

      vue 与 react, Angluar1, Angular 2 的各种对比

      在 Vue 中指令和组件分得更清晰。指令只封装 DOM 操作,而组件代表一个自给自足的独立单元 —— 有自己的视图和数据逻辑。在 Angular1 中两者有不少相混的地方。

    • Vue 2.0 的建议学习顺序 by 尤雨溪(Vue 的作者) @px0078

      • 起步
      • 前端生态/工程化
      • Vue 进阶
    • 前端工程之模块化

      模块化是一种处理复杂系统分解成为更好的可管理模块的方式,它可以把系统代码划分为一系列职责单一,高度解耦且可替换的模块,系统中某一部分的变化将如何影响其它部分就会变得显而易见,系统的可维护性更加简单易得。

      • 前端模块化并不等于 JavaScript 模块化
      • JavaScript 模块化并不等于异步模块化
      • 前端模块化带来的性能问题
      • 模块化为打包部署带来的极大不便
      • 模块化基础架构
        • 模块静态资源管理
        • 模块依赖关系处理
        • 模块加载
        • 模块沙箱

      如何解决模块加载问题,我们可以通过静态资源加载框架来解决,主要包含前端模块加载框架,用于 JavaScript 模块化支持,控制资源的异步加载。后端模块化框架,用于解决 JavaScript 同步加载、CSS 和模板等模块资源的加载,静态资源加载框架可以用于对页面进行持续的自适应的前端性能优化,自动对页面的不同情况投递不同的资源加载方案,帮助开发者管理静态资源,抹平本地开发到部署上线的性能沟壑

  • 产品
    • 你还在用轮播图吗 @Monine

      事实上,“万能和事佬”轮播图的点击率通常都很低,转化效果也并不好,却往往占用了页面最抢眼的大面积位置。想象这么一个场景:当你走进图书馆想找一本特定的书阅读时,一个销售员挡在你面前让你先看一个大广告图,然后等你还没读完具体讲了什么内容时,他又突然换了一张,是不是很惹人厌呢?大部分轮播图的设计也是如此。

      设计不当的轮播图容易被用户当成与他想浏览的内容不相关的广告图片而直接无视

      体验好的轮播图应该如何设计

      • 让轮播图看起来像是站点的一部分
      • 慎用自动切换
      • 给予清晰的操作反馈和内容预期
    • 疑似facebook内部高效工作指南

班会第 15 期

  • 技术
    • weex 正式开源了

      将所有 demo 跑了一遍, 觉得 HTML5 渲染引擎下比较卡(特别是 list-demo.we), 感觉好像施加了太多魔法有点罩不住...

    • 使用Flexible实现手淘H5页面的终端适配

      简述基于 Flexible 的适配方案

      • 在页面中使用 flexible.js
      • 不要设置 <meta name="viewport">
      • 设计稿的宽度(px 单位), 例如: 750px(iPhone6)
      • 测量元素在设计稿中的尺寸(px 单位), 例如: 120px * 150px
      • 页面中的元素使用 rem 单位
      • 单位计算公式: 元素尺寸rem = 元素设计稿尺寸px / (设计稿宽度px / 10)
      • 例如:
        // 页面中的元素使用 rem 单位
        120px / (750px / 10) = 1.6rem
        
        // 适配的 rem 基准值
        html font-size = deviceWidth / 10
        // flexible.js 会先设置 meta viewport scale, 再设置 html font-size
        // 注意这里取 getBoundingClientRect 是在 width=device-width 没有 scale 的情况下
        html font-size = (docEl.getBoundingClientRect().width * dpr) / 10
        // flexible.js 设置了 meta viewport scale 后, 不需要乘以 dpr, 即为 deviceWidth
        // 例如 iPhone6 的 dpr 为 2, 即 scale = 1 / 2 = 0.5
        // 主要是通过整体缩放来做出 0.5px 边框的效果, 否则出来的 1px 边框像是 2px
        // 在 scale 为 0.5 的情况下, docEl.getBoundingClientRect().width 得到的是 750px
        html font-size = docEl.getBoundingClientRect().width / 10
        
        // 所以页面中的元素最终才能转回到正确的 px 单位
        120px = 1.6rem * (375px * 2 / 10)
        120px = 1.6rem * (750px / 10)
        120px = 1.6rem * (设计稿的宽度 / 10)
        

      日常工作当中,视觉设计师给到前端开发人员手中的视觉稿尺寸一般是基于 640px(iPhone5)、750px(iPhone6)以及 1125px(iPhone6 Plus) 宽度为准。至于为什么?大家应该懂的(考虑Retina屏)。

      iPhone6的设备宽度和高度为 375pt * 667pt,可以理解为设备的独立像素;而其dpr为2,根据上面公式,我们可以很轻松得知其物理像素为 750pt * 1334pt。

      在不同的屏幕上,CSS像素所呈现的物理尺寸是一致的,而不同的是CSS像素所对应的物理像素具数是不一致的。在普通屏幕下1个CSS像素对应1个物理像素,而在Retina屏幕下,1个CSS像素对应的却是4个物理像素。

      为了应对这多么的终端设备,设计师和前端开发之间又应该采用什么协作模式?

      手机淘宝团队适配协作模式

      手淘设计师和前端开发的适配协作基本思路是:

      • 选择一种尺寸作为设计和开发基准
      • 定义一套适配规则,自动适配剩下的两种尺寸(其实不仅这两种,你懂的)
      • 特殊适配效果给出设计效果

      大致流程:

      • 手淘设计师常选择 iPhone6 作为基准设计尺寸
      • 交付给前端的设计尺寸是按 750px * 1334px 为准(高度会随着内容多少而改变)
      • 前端开发人员通过一套适配规则自动适配到其他的尺寸
      • 移动端适配的方案——flexible方案
        • 动态改写 <meta> 标签(不需要在代码中写 viewport)
        • <html> 元素添加 data-dpr 属性,并且动态改写 data-dpr 的值
          • 只对 iOS 设备进行 dpr 的判断,对于 Android 系列,始终认为其 dpr 为 1
          • 主要是因为安卓的 dpr 分类太多了(不只是有1,2,3还有1.5之类的)
        • <html> 元素添加 font-size 属性,并且动态改写 font-size 的值
        • 页面中的元素通过 rem 单位来设置尺寸
        • 将视觉稿分成100份(主要为了以后能更好的兼容vh和vw),而每一份被称为一个单位a。同时1rem单位被认定为10a
        • 如无特殊情况,width/height/padding/margin 都使用 rem,border-width 和 font-size 使用 px
        • 文本字号不建议使用rem, 而是使用 px 作为单位。只不过使用[data-dpr]属性来区分不同dpr下的文本字号大小
          • 我们在iPhone3G和iPhone4的Retina屏下面,希望看到的文本字号是相同的
          • 我们不希望文本在Retina屏幕下变小
          • 我们希望在大屏手机上看到更多文本
          • 绝大多数的字体文件都自带一些点阵尺寸,通常是16px和24px,我们不希望出现13px和15px这样的奇葩尺寸
          • 并不是绝对, 还是需要分场景的来决定是使用 px 还是 rem
        • 请不要再使用 CSS Sprites, 移动互联网时代需要合理利用 Sprite 不然反对性能造成影响(解码内存消耗)

      示例:

      • 750px 的设计稿: 1rem = (750 / 100) * 10 = 750 / 10 = 75, <html> 对应的 font-size 即 75px
      • 对于视觉稿上的元素尺寸换算,只需要原始的 px 值除以 rem 基准值即可
      • 例如视觉稿中的图片尺寸是 120px * 120px, 120(原始px) / 75(rem基准值), 即 1.6rem * 1.6rem

      移动端高清、多屏适配方案

      没有布局适配(上图)和用rem布局适配(下图)的对比图:

      很明显可以看出,rem适配的各个区块的宽高都会随着手机屏宽而改变,最最明显的可以看一下图片列表那部分,最后一张图视觉稿要求只出现一点点,rem布局在任何屏幕下都显示的很好。

    • 提升你的CSS姿势

      CSS的学习是一个典型的低门槛,高瓶颈的过程,第一次接触CSS的时候觉得一切是如此简单,直到后面越学越发现自己一无所知。本文则是从四个方面来讨论如何编写可扩展、可维护的CSS代码:

      • 使用合理的语义化命名
      • 模块化
      • 遵循命名规范
      • 遵循单一职责原则
        所以说理解 BEM, 用好 BEM, 你就是高手了
    • css3d动画学习心得:一个小游戏实践

      游戏的demo

    • JavaScript 节流函数 Throttle 详解

      给相应事件添加延迟执行的逻辑

    • 从被误解到最流行:聊聊 JavaScript 的那些闪光点

      JavaScript 曾经是一门兼容性最糟糕、升级最困难的语言。然而在最近几年,随着 Babel 等编译器的兴起,越来越多的 JavaScript 开发者们都放开了手,开始在生产环境中使用那些尚未被纳入标准的语言特征了。使用了 Babel 的项目需要在发布之前引入一个「构建」的步骤,将使用了较新的语言特征的源代码转译为兼容性更好、被所有浏览器所支持的早期版本的 JavaScript,所以开发者就不必再去关心用户的浏览器是否支持这项新特征了。

      除了对 JavaScript 本身的增强,社区中还有着上百种编译成 JavaScript 的「方言」: CoffeeScript, TypeScript...

      JavaScript 的标准库仅包含了非常有限的功能,某种程度上来说这也是件好事 —— 精简的标准库给第三方库留出了充分的竞争空间,真正得到大家认可的库才会被广泛使用,而不仅仅因为它被包含在了标准库中。

      JavaScript 语言本身并没有定义得非常好的「范式」,你可以使用函数式的风格,还可以使用面向对象的风格

      JavaScript 不仅可以在浏览器中运行,因为它精简的语言核心(甚至不包括任何 IO 相关的功能),现在已经被移植到了其他很多平台:

      • Node.js:提供了访问文件系统、进行网络操作的 API,用于构建 Web 后端等服务器程序。
      • Ionic / Cordova:提供访问移动设备的 API,使用 Web 技术来构建移动应用。
      • Electron:让 JavaScript 可以同时访问 Web 和 Node.js 的 API,以便用 Web 技术来构建桌面应用。
      • React Native:用 JavaScript 去操作原生 UI 组件来构建移动应用。
    • 去哪儿网司徒正美:avalon及通用MVVM的设计原理分析

      • MVVM出现的必然性: MVVM带来了维护性大大提高
      • MVVM与backbone等库的比较: MVVM的代表大概是angular, 而MVC则是backbone
      • MVVM的实现: 解决重点是如何实现最小化刷新, 核心是绑定系统
        • 定时器
        • 函数包裹
        • 属性劫持
        • 上帝setter,getter
        • 编译系统
        • 组件系统
    • 链家网前端总架构师杨永林:我的8年架构师成长之路

      前端架构师就是那种在前端领域提出开发的指导原则,在原则下设计开发框架和开发工具,让更多的开发者可以协同工作的人。

      前端构建工具哪个更好?你能掌握哪个,哪个就是最好的。因为说到底,工具是为你的业务服务的,你可能需要对它做些改造或者是写一些扩展,在这个时候你发现你对他的熟悉变的很重要。构建工具的迁移成本还是挺高的,我不太推荐频繁地变更它,所以最好不要追着流行走,还是要根据自己团队的特点,因地制宜地选择一款合适的。如果不是超大型的应用,其实build的结果的影响并没有太大的差异,与其想着哪个更好哪个更牛逼,不如将其中一个玩熟玩透。

      您认为对Web访问性能的优化需要关注哪些方面?一是你所服务产品的形态,用户关心什么。二是评测标准,用什么来测量性能的好坏。

      度量前端性能的指标有哪些?我们一般用首屏时间来评估,一般的性能检测服务商都能提供这个指标。在监控的过程中,一是要关注长期趋势的变化,如果不是突发状况,单点的数据的绝对值是没有意义的,要收集长期的数据,分析其中的变化,当有变更的时候尤其要关注数据的变化。二是关注最差25%的状况

      我们知道,解决一个问题的手段有很多,在这个过程中取舍就很重要了,我们也知道,没有银弹,很少能遇见那种全面优势的解决方案,大部分方案都是牺牲掉一部分东西来换取一部分东西。因此,作为架构师,不仅要对各个技术方案的特点、成本要熟知(也就是编程能力和架构知识),还要学会如何选择。显然,架构师需要根据产品的特点和发展方向做出决定,在前端领域的架构要能让配合的团队对接的顺畅。那么在这个过程中,良好的沟通能力、同理心、利他的思维方式,就显得很重要了。因为我们不仅要完成开发任务,也要思考在自己的领域内如何帮助项目解决问题。

    • 15年双11手淘前端技术巡演 - H5性能最佳实践

      • 68.67%无线交易

      • 系统&网络环境统计数据(手淘2015)

      • 传统优化(PC时代YAHOO 23条web性能优化军规)

      • 请求数优化

      • 合理使用 iconfont

      • 首屏多个动态接口合并请求

        日常的业务中,一个页面往往拆分出多个异步数据接口(后端开发说:解耦),甚至首屏也需要3-5个接口(如动态banner区块,推荐内容,商品列表等),有些还有嵌套关系。但是这些对页面性能造成不小的影响

      • 禁止重定向

        页面&静态资源的重定向会造成巨大的性能损耗。特别使用前端JS脚本来实现页面跳转的。

      • 图片优化

        • 使用WebP格式, 为公司省 70% 的流量费用

          Banner部分 WebP 对比

        • CDN服务上生成各个尺寸和质量的图片(近100个规格)

          合理的使用CDN图片尺寸可以带来下载图片的性能提升,还可以减少不必要的内存消耗。 我们日常中会用到的尺寸,每浪费10像素的宽高都可以造成很大的内存资源浪费。

          计算方式

        • 合理的生成紧凑的Sprite图片,即可以带来更少的请求数,又高性能低消耗

          解码内存消耗: w * h * 4(宽 * 高 * 每个像素4个字节)

      • 域名最终形态(建议)

        • 页面请求域名一个(html)
        • 静态资源(css, js)一个
        • 图片资源一个(img)
        • 动态数据一个(api)
        • 数据统计一个(stat)
      • 预加载和离线化方案

      2015 双11 战绩

      2015双11 H5页面性能汇总

    • 好RESTful API的设计原则

      你所能做的最重要一件事来提高服务的价值就是创建一个API。因为随着其他服务的成长,有这样一个API会使你的服务或者核心应用将有机会变成一个平台。

      • 版本化
      • 过滤器
      • 预期的返回文档
      • 认证
      • 认识原始的HTTP封包
    • Node.js

      Node.js is a JavaScript runtime built on Chrome's V8 JavaScript engine.

  • 产品
    • 微信用户属性

      • 总体设备比例
      • iOS版本比例
      • iOS设备比例
      • Android设备前5
      • Android版本比例

班会第 30 期

  • 技术
    • backend-api 发布 1.1.0 版本

      • [feat] 新增设置统一的前置处理方法
      • [feat] 新增设置统一的成功处理方法
      • [feat] 新增业务错误
      • [feat] 新增设置处理异步操作的方式(callback or promise), 只允许使用某一种方式
      • [feat] 完善代码的注释并增加测试用例来确保代码的质量
    • 防止 iframe 页面中的链接重定向父级页面

      iframe 页面中的链接是可以让父级页面重定向的, 要防止这种情况, 可以通过 iframe 的 sandbox 属性来控制.

    • ConEmu

      Customizable Windows terminal with tabs, splits, quake-style

      ConEmu-Maximus5

      需要经常用到命令行的 Windows 用户, ConEmu 是个不错的选择

    • 听“JavaScript 疲乏”听疲乏了

      极限编程方法论创造者在 1983 年所说的:

      “让它工作,用正确的方法做,还要快,”——肯特·贝克(Kent Beck)

      如果你正在地狱中穿行,请继续保持前行。——丘吉尔

    • 在 2016 年学 JavaScript 是一种什么样的体验?

      前端技术名词快速科普帖, 标题可以改为,《前端开发从入门到放弃》

      我竟然知道所有的这些名词...

      react大方向没错,模块化,es6这些等等都是未来的必然趋势。而且前端一直以来就是需要不断有活力注入,至于要学到什么程度,我觉得基本的东西掌握了,再多的新库也是建立在之前的基础上,也不可能掌握所有的新技术。

      重要的应该是要做的东西是不是需要用到这些新的东西,更好更高效能解决问题的技术才是着眼点吧。

      有更好的工具,我为什么不用呢?当然兼容性,跨平台这些一直都是要考虑的,这取决于要做的东西的需求,面向群体等。


      我要开发一个网页,用来展示用户的最新动态。我想我应该通过后端接口获取数据,然后用一个 table 来展示数据,用户可以对数据进行排序。
      如果服务器上的数据变化了,我还需要更新这个 table。我的思路是用 jQuery 来做。

      可别用 jQuery!现在哪还有人用 jQuery。现在是 2016 年了,你绝对应该用 React。

      • jQuery
      • React
      • JSX
      • Babel
      • ES2016
      • 模块管理器(AMD 或者 CommonJS )
      • 打包(Browserify)
      • npm 仓库安装依赖
      • 用 npm 安装 React 然后用 Browerify 来打包就好了?
      • 任务管理工具(Grunt/Gulp/Broccoli/Makefiles/Webpack)
      • 是的,不过显然我们做 Web 开发的,喜欢先把事情搞复杂,然后回归到最朴素的状态。每年我们都是这么搞的。你就看着吧,过不了两年,我们就可以在网页上写汇编了。
      • 刚才不是说应该把所有依赖打包成一个文件吗?
      • 但是等 HTTP/2 普及之后,不打包反而更好
      • 强类型语言(Typescript)
      • Flow
      • 函数式编程很叼的
      • Ramnda
      • Fetch API
      • 回调地狱
      • Promise
      • 天呐我到底需要多少个库?
      • 这是 JS,同一件事情有上千个库在做。我们了解库,而且我们有最好的库,我们有海量的库,要什么有什么。
      • await
      • 用 Typescript 写代码,用 Fetch 发起异步请求,所有代码编译成 ES6,然后用上 Babel 的 stage–3 配置项,把 ES6 转译成 ES5。所有代码用 SystemJS 加载。如果你用不了 Fetch,就加个 polyfill,或者用 Bluebird、Request 或者 Axios,这样你就可以用 await 来处理 Promise 了
      • 状态变更(Flux/Redux)
      • 如果你只是想展示数据,其实你不需要 React。你只需要一个模板引擎
      • 我不做了,我不做 Web 了,我也不想再碰 JS 了
      • 没事,过不了几年,我们都会用 Elm 或者 WebAssembly 了
      • 我要回后端去了,我受不这些变动、版本更新、编译和转译了,JS 社区如果觉得有人能跟上它的脚步,那这个社区就是疯了
      • 我理解你。我建议你去 Python 社区
      • 听说过 Python 3 吗?

      译者注:最后一句「听说过 Python 3 吗?」是讽刺 Python 3 发布已经 8 年了,Python 社区却依然在使用 Python 2.7。而 JS 社区正好相反,把还没有实现的语言特性都用到生成环境中了!

    • JavaScript fatigue fatigue

      • Don’t try to know everything
      • Go for depth in areas you love
      • When in doubt about what to learn next, you can always go back to fundamentals:
      • HTML/CSS/JavaScript/HTTP (which technologies are fundamental depends on your work)
      • Non-technological skills: time management, social skills (communication, team building, …), health, management processes and so on.
    • 技术的执念

      过载的信息

      身处这样的信息过载环境,我们很难不为自己对信息的缺乏而感到不安,担心自己错过了什么重要的信息,这种担心和焦虑会促使我们进一步将时间消耗在对信息的获取上,从而更无暇思考什么是真正重要的。

      《如何阅读一本书》将书分为两类:一种是提供资讯/信息(known)的,一种是帮助你理解(understand)信息的。相对于理解来讲,资讯本身其实并不那么重要。
      我们大部分人目前采用的碎片化的阅读方式无法提供给我们足够的“理解力”。我们都有这样的体验,有些书特别耗费脑力,读起来很累,而另一些书则非常轻松,易于消费。
      碎片话的阅读方式易于消费,只需要很少的思考就可以读懂,但是危害严重,它们并不会让帮助你提升理解力。

      但是直觉上我们会选择容易的事情来做,虽然这种浅层次的阅读只对扩展信息/资讯有帮助,对提升理解力则几乎无用。
      而我们在处理日常工作中的问题时,能真正帮助的,只有理解了的那部分知识。

      在成为一个专家之前,你需要先对要学习的领域有一个全面的认识

      对于过载的信息

      你无法掌握所有的知识,你只需要采取先建立广度,再建立深度的原则即可:

      • 做减法(在建立了知识框架之后,有针对性的学习)
      • 主动,深度阅读经典
      • 为那些有趣但非自己关注方向的知识赋予较低的优先级
    • 运营活动规范

      由于运营活动的零散性,导致了团队不同人员所开发的页面在维护层面上很难形成统一,也增加了相互协助的难度,从而造成不同人员之间修改代码存在安全隐患的风险。为此,制定统一开发规范,方便团队后期协作、提高开发效率。

      活动目录命名规范: promote/201606/xxxx(活动英文名)

      REM标准

      • 页面的尺寸适配统一使用 REM 与 px 结合来完成,定高不定宽(通常布局使用rem,模块大小采用px),示例Demo;可以辅助地使用 zoom/scale
      • 375px 宽度下,<html>节点的 font-size20px

      z-index 标准

      • z-index 最大值不得超过 700
      • z-index 取值范围
        • 普通元素: 0~100
        • floating/吸顶/吸底: 101~200
        • 弹窗: 201~300
        • loading/分享蒙层: 301~400
    • 从域名到网站,只需四步,轻松访问

      • 注册域名

      • 准备服务器和网站

      • 服务器备案

        根据规定,只要是用于网站服务的服务器,都需要进行备案(约 20 个工作日),只有备案成功网站才可以使用

      • 绑定域名,并设置域名解析

      • 服务器上绑定您的域名

      • 通过域名解析将域名与服务器 IP 地址绑定

      • 网站可访问

    • 前后端分离了,然后呢?

      即使通过API来解耦前端和后端开发过程,前后端通过RESTFul的接口来通信,前端的静态内容和后端的动态计算分别开发,分别部署,集成仍然是一个绕不开的问题 — 前端/后端的应用都可以独立的运行,但是集成起来却不工作。我们需要花费大量的精力来调试,直到上线前仍然没有人有信心所有的接口都是工作的。

      前后端仅仅通过接口来编程,这个接口可能是JSON格式的RESTFul的接口,也可能是XML的,重点是后台只负责数据的提供和计算,而完全不处理展现。而前端则负责拿到数据,组织数据并展现的工作。这样结构清晰,关注点分离,前后端会变得相对独立并松耦合。

      在这样一个复杂的系统中,后台任意端点的失败都可能阻塞前端的开发流程,因此我们会采用mock的方式来解决这个问题

      这个mock服务器可以启动一个简单的HTTP服务器,然后将一些静态的内容serve出来,以供前端代码使用。这样的好处很多:

      • 前后端开发相对独立
      • 后端的进度不会影响前端开发
      • 启动速度更快
      • 前后端都可以使用自己熟悉的技术栈(让前端的学maven,让后端的用gulp都会很不顺手)

      提供mock数据是远远不够的。我们需要的mock应该还能做到:

      • 前端依赖指定格式的mock数据来进行UI开发
      • 前端的开发和测试都基于这些mock数据
      • 后端产生指定格式的mock数据
      • 后端需要测试来确保生成的mock数据正是前端需要的

      简而言之,我们需要商定一些契约,并将这些契约作为可以被测试的中间格式。然后前后端都需要有测试来使用这些契约。一旦契约发生变化,则另一方的测试会失败,这样就会驱动双方协商,并降低集成时的浪费。

      前后端分离是一件容易的事情,而且团队可能在短期可以看到很多好处,但是如果不认真处理集成的问题,分离反而可能会带来更长的集成时间。通过面向契约的方式来组织各自的测试,可以带来很多的好处:更快速的End2End测试,更平滑的集成,更安全的分离开发等等。

    • 我们真的缺前端工程师吗?

      其实我们并不缺前端工程师,我们缺的是优秀的前端工程师

      不从系统的角度来思考,不真正做一些后端开发/配置,并不能算是前端工程师,或者可以被称为偏前端工程师(partial frontend developer)

      开发工作不应该仅仅局限在编码上,作为开发者/工程师,应该尽可能的多了解一些上下文:比如我们的项目最终是给谁用的,需求从何而来,项目是如何部署在线上的等等。

      项目是如何部署在线上的

      简而言之,开发者视野应该放开开阔一些。不要将自己局限在某种角色上,不但不要局限在前端/后端开发上,压根就不要局限在开发这种角色本身上,你在系统中,可以是设计师,还可以是业务分析师。虽然不一定最终要你去转行做BA,或者UX,但是更广阔的视野可以使你更加高效的发挥自己的作用,也可以在和别的角色互动式,快速的了解上下文。

      我所理解的,前端不一定要熟知所有这些知识和技能,但是一定不要认为自己做好了前端的一亩三分地就足够了,不要给自己设限。跨界会给你带来难以估量的好处,一个角色做久了,难免会产生一些盲点。这时候,换个视角,从其他角色的角度来看待你的工作,又会有很多新的发现。而且不仅如此,很可能你会发现之前很麻烦,很难搞定的事情,在新的方法/视角下变得很容易。

      尝试从系统级别去解决一个问题,而不是将问题抛给另外一个角色(后端工程师,UX或者QA)

      我们缺的从来都不是前端/后端工程师,而是工程师(或者那些会系统思考,并总是想着解决问题的人)

    • 互联网项目架构经验分享

      项目的质量指标:功能,性能和扩展性

      架构设计的主要过程

      • 确定问题域

        以我的的经验来看,扩展把我关键问题,优先满足关键问题的性能,确定最小功能集。确定最小功能集的优势可以快速实现,快速验证需求的准确性,每次需求开发都完成最小和最关键的需求

      • 数据建模

        数据建模时的几个心得:

        • 数据表包含自增id,创建时间createTime,更新时间updateTime和版本号version
        • 不使用外键
        • 不使用id作为表关联,虽然我们不创建外键约束,但是不代表表之间没有关联关系, 表间的关联使用全局的唯一id的方式一个更好的选择
        • 应用最初的设计最符合设计原则和设计**的, 我们应该尽量的坚持最初的设计,克服其他因素的影响
        • 最初设计系统时尽量少的使用冗余字段去提供查询的方便性和性能. 如果系统真的流量比较大,查询性能太低,可以通过把读服务从业务系统中分离

        以下是电商应用部分表(商品和订单业务相关)设计,仅供参考:

        电商应用部分表

      • 模块划分

        如果数据模型主要为满足功能目标的话,模块划分会比较多的兼顾性能和扩展性

        • 单实例结构
        • 集群结构
        • 分布式结构
        • 混合结构

        如何选择系统结构,可以从如下几方面考虑:

        • 系统是否能满足未来2-3年的增长
        • 人力因素, 量力而行
        • 时间因素,很多互联网公司的工期不是技术评估的,是由”市场”确定的,所以火烧眉毛的时候就别讲究性能和扩展了,上线再说。
        • 架构不是一成不变的,不断增加的访问和不断变化的需求改变着系统的架构。快速响应,不断迭代才是互联网应用的方式。所以最初的架构,尽量的做到高内聚低耦合,这样不断的提高系统的短板,逐渐完善系统结构
      • 关键流程描述

        关键流程描述是检查系统架构是否满足需求和指导开发的必要条件。关键流程描述是使用流程图解决关键问题的过程,它的使用者是团队其他成员和自己,所以格式不重要,其他人能明白就好。

      • 技术选型

        • 如果非必要请使用常用的技术,框架等
        • 熟悉的优于强大的,尽量采取团队比较熟悉的技术或者使用团队中有人可以指导的技术
      • 代码实现

        代码首先是给人读的,其次才是给机器读,所以良好的代码结构是项目存活更长时间的良药

        • 代码分层:功能单一原则
        • 命名规范
        • 注释风格
      • 验收测试

        积极配合测试团队对项目的测试,他们是为项目健康上线保驾护航的人,不是挑刺的人

      • 总结

        • 同样的题目有多种解法,我们做的只是其中的一种,所以要接受别人的质疑和建议,这样才能使系统完善。
        • 没有银弹,没有解决一切问题的方法,那么也不可能使用一种方法解决所有问题,所以要根据需求,团队,时间等选择合适的方式方法。
    • 如何从菜鸟成长为(伪)架构师

      如何更高效的学习?

      大多数人每天能留给自己学习的时间有限,这个阶段如何提升学习效率就成了要解决的重点

      体系化的学习

      更有效率的学习方法: 带着问题学习

      沟通的核心不是你说了什么,而是你想要让对方了解什么、让他做什么

      想要恰到好处的进行沟通简单来说有几条原则:

      • 确保各方对背景的理解一致
      • 去掉对方不能/不需要理解的内容
      • 确保在对方失去注意力前尽快说出重点
      • 不要说没有意义的内容浪费其他人的时间

      程序的生命力

      大部分程序都能实现功能,但是如果把“时间”这个也作为一个考虑的维度的话,就会意识到一个合格的项目需要考虑更多的东西:更通用的使用方式、易于理解的文档、简单而易于扩展的设计,等等。而想要毁掉程序的生命力也很简单:做的更复杂,更定制化,让更少的人参与。

    • 如何持久化你的项目经历

      对上一个项目的总结,真正会为帮助我们在将来的项目中做决策,甚至会影响我们学习效率,解决问题能力的是:深度回顾

      深度回顾可以帮助我们梳理知识,将实际的案例归纳总结为实际可用的知识

      • 我在项目里学到了什么?
      • 项目的背景介绍
      • 该项目以何种方式,为那些用户,带来了什么样的价值?(business model是什么)
      • 该项目的实际用户数量是什么级别?
      • 项目的部署,运维是如何操作的?
      • 项目的监控是怎样做的?
      • 当遇到系统故障,项目组是如何反应的?
      • 遇到的最大的挑战是什么?
      • 这个挑战是如何被解决的?
      • 如果有机会重做,你会如何考虑?

      辅助性的练习可以帮助你更好的梳理项目上学到的技能、知识,并且转换成你自己的知识

      • 记笔记
      • 写博客
      • 在办公室内演讲
      • 去社区贡献话题

      从项目上下来之后,需要深入思考并总结之前的经验,这种深入思考会帮助你建立比较完整的知识体系,也可以让你在下一项目中更加得心应手,举一反三。
      如果只是蜻蜓点水般的“经历”了若干个项目,而不进行深入的总结和思考,相当于把相同的项目用不同的技术栈做了很多遍一样,那和我们平时所痛恨的重复代码又有什么不同呢?

    • 技术人生 | 技术人如何打造个人品牌

      来自携程框架研发部高级经理魏晓军在内部活动中分享,介绍了其在撰写国内第一本React Native相关书籍《ReactNative入门与实战》时的经历和感想,从中我们或许可以一窥技术人该如何打造个人品牌。

      写书这事不比写文章,更需要花时间、花精力去琢磨。写之前罗列提纲,写之后校验几遍,还要配上简单易懂的示例。

      现在好多人写博客,我觉得这是个很好的习惯。写技术文章,对我们自身提高是很有帮助的,尤其是一些总结性文章。

      写文章,是对某个知识点梳理,而写书,是对某个技术的梳理,让你对该技术整个生态、未来方向发展非常了解,对个人是很大的提升。

      • 作为技术人,要懂得营销自己,在Github、论坛、博客上,常写总结性文章

        当你在写作的时候,是你对这个知识点的整理,不仅要理清它的来龙去脉,还要考虑要怎么写出来,被人看懂。

        通过写文章,做总结,也可以被更多圈内小伙伴、媒体、出版社关注到,逐渐打造个人品牌。

      • 常参加一些会议,做分享

        我们每个人的精力是有限的,如果你有10门技术要学,一个1年,那你要学10年;而如果10个人学习,每人学一门,大家经常一起交流、分享,这样也许1年你就把这些技术都掌握了

    • 设计模式总结

      设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性

      每个模式都描述了一个在我们的环境中不断出现的问题,然后描述了该问题的解决方案的核心,通过这种方式,我们可以无数次地重用那些已有的解决方案,无需再重复相同的工作。即模式是在特定环境中解决问题的一种方案。

      简单地说,就是从前辈们在程序设计过程中总结、抽象出来的通用优秀经验。主要目的一方面是为了增加程序的灵活性、可重用性。 另一方面也有助于程序设计的标准化和提高系统开发进度。

      设计模式分类

      • 根据其目的(模式是用来做什么的)可分为创建型(Creational),结构型(Structural)和行为型(Behavioral)三种:
        • 创建型模式主要用于创建对象
          • Singleton
          • Prototype
          • Factory Method
          • Abstract Factory
          • Builder
        • 结构型模式主要用于处理类或对象的组合
          • Composite
          • Adapter
          • Facade
          • Bridge
          • Decorator
          • Flyweight
          • Proxy
        • 行为型模式主要用于描述对类或对象怎样交互和怎样分配职责。
          • Chain of Responsibility
          • Command
          • Observer
          • Strategy
          • Interpreter
          • Iterator
          • Mediator
          • Memento
          • State
          • Template Method
          • Visitor
      • 根据范围,即模式主要是用于处理类之间关系还是处理对象之间的关系,可分为类模式和对象模式两种:
        • 类模式: 处理类和子类之间的关系,这些关系通过继承建立,在编译时刻就被确定下来,是属于静态的。
        • 对象模式:处理对象间的关系,这些关系在运行时刻变化,更具动态性。

      图片来自《设计模式:可复用面向对象软件的基础》,page8

    • 关于烂代码的那些事

      关于烂代码的那些事[上]早在班会第 12 期就已经分享过了

      中篇: 如何尽可能高效和客观的评价代码的优劣, 什么是好代码

      下篇: 如何应对这些身边的烂代码, 如何提高自己的代码质量

    • 穷人的持续集成与持续交付

      本文将使用一些免费的服务来为你的项目搭建持续交付平台,这些服务包括

      • 持续集成环境
      • 持续部署环境
      • 服务端应用托管

      周期时间(cycle time),就是一个需求从产生到最终上线所需要的时间。其中包括了需求分析,设计,编码,测试,部署,运维等活动,可能还会包含后续的监控。

      持续交付包含了自动化构建,自动化测试以及自动化部署等过程,持续改进开发流程中的问题,并促进开发人员,测试人员,运维人员之间的协作,团队可以在分钟级别将变更发布上线。

      持续交付相关技术及实践

      • 版本控制(配置管理)
      • 持续集成CI
      • 自动化测试
      • 构建工具及构建脚本
      • 部署流水线

      团队通过版本控制来进行协作,所有的代码会在持续集成环境中编译,代码静态检查/分析,自动化测试(还可能产生报告等)。除此之外,CI还还需要有自动化验收测试,自动化回归测试等。

      持续交付则更进一步,它将环境准备,持续集成,自动化部署等放在了一起。通过全自动(有些过程可以设置为手动,比如发布到产品环境)的方式,使得软件可以一键发布。如果上线后发现严重defect,还支持一键回滚的机制(其实就是将之前的一个稳定版本做一次发布,由于发布流程已经经过千锤百炼,所以发布本身就变得非常轻松,安全)

      一个前后端分离的架构,如何做到静态内容的托管,打包,部署,并和后端API集成起来

      • 持续集成(单元测试,集成测试等)
      • 持续部署/持续交付
      • 静态站点托管

      现在前后端应用完全独立,发布也互不影响。不论是服务器端新增加了API,还是添加了新数据,客户端的发布都不受影响;同样,修改样式,添加新的JavaScript也完全不会影响后端。更重要的是,所有的发布都是一键式的,开发者只需要一个git push就可以享受这些免费服务提供的自动构建,自动化测试以及自动部署的功能。

  • 产品
    • 5分钟了解Material Design

      看似平面实则3D, 在平面中具有明确的Z轴概念

      在表现元素的重叠与层次上阴影的效果功不可没

      与现实中的影子同理,阴影的表现会根据Z轴上的位置发生变化

      Material Design不能在同一个视图内使用过多的颜色

      • colorPrimary(主色)
      • colorPrimaryDark (与colorPrimary是同系色)
      • colorAccent (与colorPrimary相比较醒目的颜色,重点色)
      • windowBackground (白色或透明的黑色,与colorPrimary是同系色)

      Material Design 颜色

      舒服的变换/接触反馈/有意义的动画: 用户进行的按下按钮等操作与随后出现的动画,前后必须有紧密的关联性

    • 项目经理是大傻B吗?

      PM其实就是一个轮询器:识别所有的项目风险,然后不断跟进。项目风险可能是技术风险,比如某个技术上压根搞不定的问题。也可能资源风险,比如人手不够,或者开发者很多,但是没有足够的设计师协助,这些风险都会导致项目无法按照时间交付。

      PM的一个重要职责就是在项目之初将项目范围定下来,这个范围的划分非常依赖经验

      如何合作?

      • 理解PM的工作
      • 不要因为一个人不会某个技术而鄙视他, 就好比你不应该因为不会弹钢琴,而被一个会弹钢琴的人鄙视一样
      • 学习如何报告进度
      • 站会前自己花3分钟整理一下昨天做的工作
      • 进行合理的任务划分(tasking技能)
      • 合理估算
      • 明确告诉PM,有哪些需求是不可能按时交付的,PM会根据实际情况来重新定计划,并和客户确认
      • 明确告诉PM一些可能的风险,团队整体对交付负责,而不是PM,或者开发

      按照经验,项目从来就不会按照计划进行,在做好一个粗略的计划之后,PM的职责更多的是进行动态调整。所以团队内部至少需要保持信息的流通,虽然可能短期来看可能会影响开发速度,但是从整体上来看,可以减少很多不必要的浪费。

      简而言之,要站在别人的角度考虑问题:如果换做是你,你会怎么做?

    • Adobe Portfolio | Build your own personalized website

      Adobe 的设计每次都是极好的

    • Tilda

      Create a website for free. Introducing Tilda Publishing website builder

班会第 24 期

班会第 24 期

  • 技术
    • backend-api

      一个用于与后端交互的数据层, 即统一地调用后端接口.

      为什么需要统一调用后端接口

      这样做的好处在于对前端架构做初略的(MVC)分层: 展现层(View) -> 业务层(Controller) -> 数据层(Model)

      展现层只需要知道自己要做什么事(这个所谓的事就是业务了)就可以了, 业务层来处理这个事情涉及到的业务流程. 例如展现层做注册, 那么展现层只要调用业务层提供的注册业务就好了, 不需要关心注册涉及到的业务逻辑. 这样各层做的事情就会职责分明, 具备单一职责原则, 各层配合也就清晰明了了, 代码逻辑自然理得很顺. 分层架构其实是在应对计算机领域经典的理论, 分解复杂度, 将复杂的事情分解为一件件相对简单的事, 各个击破.

      简而言之: 展现层(视图层)只需要关注调用什么业务, 业务层负责将数据从数据层中取出来, 数据层做最底层的后端交互.

      如果是比较简单的业务, 可以只需要视图层和数据层, 此时视图层承担了业务层的事情.

      有一个统一的数据层, 即统一了数据输入和输出, 可以方便地做下面的事情

      • 方便统一处理一些公共的行为, 例如请求超时, 请求失败, 未授权等等
      • 方便知道前后端都使用了哪些接口
      • 方便扩展功能, 例如添加缓存层
      <!-- 依赖 jQuery ajax -->
      <script src="http://cdn.bootcss.com/jquery/3.1.0/jquery.min.js"></script>
      <script src="http://rawgit.com/ufologist/backend-api/master/backend-api.js"></script>
      <script>
      // 配置后端接口
      var backendApi = new BackendApi({
          'getMessageList': {
              type: 'GET',
              url: '/api/message'
          },
          'createMessage': {
              type: 'POST',
              url: '/api/message'
          }
      });
      // 设置统一的错误处理
      backendApi.setError(function() {
          console.error('backendApi error', arguments);
      });
      
      // 调用后端接口
      backendApi.invoke('getMessageList').then(function(result) {
          console.log(result);
      });
      backendApi.invoke('createMessage', { // jQuery ajax options
          data: {
              title: 'msg title',
              content: 'msg content'
          }
      }).then(function(result) {
          console.log(result);
      });
      </script>
    • range.css

      美化 input[type=range] 元素的外观 Generated Browser Compatible CSS Range Sliders

    • 前端 TOP 100

      各种热门前端框架看看是否眼熟

    • Transformicons

      各种变形图标

    • CSS 架构指南

      以命令式风格写 CSS 会很快地导致下面的结果:

      • 不够清晰 —— 那些带来了成吨混乱的东西,例如不清晰的依赖(难以删除或者增加东西),
      • 不可维护 —— 当在创建新代码或者改善现有代码的时候效率低下,
      • 重复冗余 —— 使得代码臃肿而且对性能有负面影响,
      • 大量的存在于可扩展性,一致性以及对于新开发者的问题。

      别基于他们在哪里或者他们怎么表现而是基于他们是什么来赋予样式

      命名约定

      • 基于它是什么而不是它看起来或者表现起来怎么样来命名某个事物
      • 通常来说,有更长的类名比更复杂的优先级更好

      多亏了 BEM 我们现在有了

      • 模块化 CSS 代码。这使得 CSS 很容易地转换到 React 世界,在这里中你经常希望拥有每一个组件单独的 css 文件;
      • 非常低的优先级;
      • 解耦 HTML 结构和 CSS;
      • 提高可读性(你能够在看 HTML 的时候知道更多关于 CSS 的东西);
      • 不再有命名冲突(单独的模块帮助避免了把 CSS 放在全局范围内);
      • 对于如何在一个块中命名一个新变量的清晰规则;
      • 级联继承样式不再有问题(在你不想要的地方出现意外的样式泄漏);
      • 减少类之后更小的 HTML 以及令 HTML 可重用。

      组件,模块和元素

      • 组件是模块的集合。在大多数情况下它会跟布局类处在相同的抽象层次
      • 模块是元素的集合。应该可重用而不依赖于其他模块
      • 元素是不能单独使用和需要父级实体的代码片段
    • 找到适合自己的前端发展方向

      如果从产出的代码比重来衡量这两类前端

      • 偏后的前端提交的代码主要是JS和HTML,没错,有HTML,因为套模板
      • 偏前的前端提交的代码主要是CSS和HTML,这里的HTML往往是原型

      都有哪些方向呢?

      • 界面展现用户体验和可访问性方向
      • 偏后的js/nodejs开发方向
      • audio/video音视频等富媒体方向
      • SVG/canvas/webGL动效创意表现与数据可视化方向
      • 工具建设文档管理内部站建设的前端运维方向
      • 根据客户端不同,还可以分为PC端方向,移动端方向以及物联网方向

      我该选择哪个方向呢?

      • 成长经历
      • 个人喜好
      • 和谁玩得来
      • 个人能力

      首先,偏体验前端工作需求少。虽然说,前端这个职业背后也分了很多方向,但是不同方向的人员配比和收入水平以及成长速度确是大相径庭的。众所周知,HTML和CSS入门简单,偏后的前端开发花个把月时间熟悉下,就能够从头到尾建一个网站;但是偏前的前端,很大一部分编程玩不来,想学也由于没有计算机基础而不得要领,结果,就没法从头到尾建一个网站。而放眼大**,绝大多数的企业都是中小企业,这些企业对前端的要求是帮我把功能做出来,所以,你懂的,前者1个人就可以搞定,后者需要找人配合。显然,这些公司都招那些偏后的前端,于是偏后的前端就有很多的实践和项目经验,成长更快,工作更好找。

    • LeanCloud一个全栈应用的例子

      前端主要是跑在微信上的HTML5活动页,后端数据库和逻辑分别跑在LeanCloud的数据存储和云引擎上,基于Node.js和Express开发

    • 移动应用要如何埋点上传才能收集更多数据?

      对于移动端的App来说, 分析的数据大致上都可以分为

      • 在线数据, 即App后端服务所产生的日志数据,例如服务接口的性能数据, 服务接口的调用及其参数等, 通过服务端的日志数据, 我们不但可以统计服务接口的性能指标,还可以针对具体的业务逻辑,做相关的分析,一些常见的App分析指标如新增,活跃,累计,留存等,也都可以通过服务日志来统计出来。
      • 离线数据, 即是App客户端本身产生的数据, 这种情况一般是发生在客户端不调用底层服务的情况下,需要了解用户在客户端的行为,就需要用到离线数据。 离线日志一般记录用户在客户端的具体行为,如用户在客户端的拖动,上下滚动,翻页等不涉及到后端服务的操作,以及App本身的崩溃行为产生的数据, 都可以被记录, 一般的,记录的内容包括事件类型,控件编号,控件属性及相关参数,事件时间等。

      埋点及上传

      不管是在线日志,还是离线日志,我们首先都要确认在什么地方记录日志, 于是我们就引入了埋点的概念。 通俗的讲,在正常业务代码逻辑上, 添加记录日志的代码, 都叫做埋点。 但是一般的,埋点只用来描述客户端日志记录。

      • 传统埋点:开发者直接在客户端埋点
      • 可视化埋点:用可视化交互的手段来代替写代码,将核心代码和配置,资源分开, 在App启动是通过网络更新配置和资源来实现埋点功能
      • 无埋点:所谓的无埋点,其实也就是全埋点,尽可能的收集所有控件的操作数据。 实现原理也很简单, 客户端添加扫描代码, 为每个扫描到的控件添加监听事件

      离线日志上传机制

      • 服务端提供日志记录接口,当客户端有事件时,直接调用日志记录接口将日志记录在服务器端
      • 服务端提供日志上传接口, 客户端先将日志暂存客户端本地,当达到一定的大小,网络环境允许的情况下, 通过上传接口,将日志文件打包压缩后上传
    • 性能优化的常见模式及趋势

      性能优化的价值

      • 成本降低
      • 稳定性提升
      • 用户体验体验提升

      性能优化的缺点

      • 维护成本增加:代码可能变复杂,结构可能变复杂,技术栈可能变复杂

      性能优化的两种模式

      • 单应用优化,关注单系统瓶颈,通过解决单系统瓶颈提升性能。
      • 结构型优化,通过改造链路结构和配比,进行整体性能的优化。

      优化基本思路(闭环)

      • 确定性能瓶颈/热点
      • 确定优化方案
      • 实施、反馈优化情况
    • 前端开源项目持续集成三剑客

      在 GitHub 上, README 是最先让人看到的,一些应用广泛的项目的 README ,除了非常详细的文字介绍,还常常会带有很多小徽章

      这些徽章 (badage) 展示了代码的测试覆盖率、构建状态、在各个浏览器中的运行情况,这会让项目显得更加专业和有说服力

      测试代码/持续集成/代码覆盖率/跨浏览器集成测试

      NPM Version vue

      Selenium Test Status

    • 密码逻辑漏洞小总结

      密码找回逻辑漏洞 脑图

  • 产品

班会第 16 期

  • 技术
    • node-website-scraper

      Download website to a local directory (including all css, images, js, etc.), You can try it in demo app

      var scraper = require('website-scraper');
      
      scraper.scrape({
          urls: ['http://nodejs.org/'],
          directory: './nodejs-clone'
      }, function (error, result) {
          console.log('finish', 'error', error);
          if (result) {
              result.forEach(function(resource) {
                  console.log(resource.url, resource.filename, resource.assets.length);
              });
          }
      });
    • 从网易与淘宝的font-size思考前端设计稿与工作流

      简单问题简单解决

      • 顶部与底部的bar不管分辨率怎么变,它的高度和位置都不变
      • 中间每条招聘信息不管分辨率怎么变,招聘公司的图标等信息都位于条目的左边,薪资都位于右边

      这种app是一种典型的弹性布局:关键元素高宽和位置都不变,只有容器元素在做伸缩变换。对于这类app,记住一个开发原则就好:文字流式,控件弹性,图片等比缩放。

      文字流式,控件弹性,图片等比缩放

      这个规则是一套基本的适配规则,对于这种简单app来说已经足够

      网易的做法

      随着分辨率的增大,页面的效果会发生明显变化,主要体现在各个元素的宽高与间距。375_680的比320_680的导航栏明显要高。能够达到这种效果的根本原因就是因为网易页面里除了font-size之外的其它css尺寸都使用了rem作为单位

      网易页面上html的font-size不是预先通过媒介查询在css里定义好的,而是通过js计算出来的,所以当分辨率发生变化时,html的font-size就会变

      • 先拿设计稿竖着的横向分辨率除以100得到body元素的宽度
      • 布局时,设计图标注的尺寸除以100得到css中的尺寸, 例如: 播放器高度为210px,写样式的时候css应该这么写:height: 2.1rem。之所以取一个100作为参照,就是为了这里计算rem的方便!
      • 在dom ready以后,通过以下代码设置html的font-size: document.documentElement.style.fontSize = document.documentElement.clientWidth / 6.4 + 'px'; 6.4只是举个例子,如果是750的设计稿,应该除以7.5
      • font-size可能需要额外的媒介查询,并且font-size不能使用rem

      当deviceWidth大于设计稿的横向分辨率时,html的font-size始终等于横向分辨率/body元素宽

      淘宝的做法

      淘宝的效果跟网易的效果其实是类似的,随着分辨率的变化,页面元素的尺寸和间距都相应变化,这是因为淘宝的尺寸也是使用了rem的原因

      • 动态设置viewport的scale
      • 动态计算html的font-size
      • 布局的时候,各元素的 css尺寸 = 设计稿标注尺寸 / (设计稿横向分辨率 / 10)
      • font-size可能需要额外的媒介查询,并且font-size不使用rem,这一点跟网易是一样的

      跟网易一样,淘宝也设置了一个临界点,当设备竖着时横向物理分辨率大于1080时,html的font-size就不会变化了,原因也是一样的,分辨率已经可以去访问电脑版页面了

      比较网易与淘宝的做法: 淘宝还动态设置viewport的scale;网易的做法,rem值很好计算,淘宝的做法肯定得用计算器才能用好了

      如何与设计协作

      • 视觉设计阶段,设计师按宽度750px(iPhone 6)做设计稿,除图片外所有设计元素用矢量路径来做。
      • 设计定稿后在750px的设计稿上做标注,输出标注图。同时等比放大1.5倍生成宽度1125px的设计稿,在1125px的稿子里切图。
      • 输出两个交付物给开发工程师:一个是程序用到的@3x切图资源,另一个是宽度750px的设计标注图。
      • 开发工程师拿到750px标注图和@3x切图资源,完成iPhone 6(375pt)的界面开发。此阶段不能用固定宽度的方式开发界面,得用自动布局(auto layout),方便后续适配到其它尺寸
      • 适配调试阶段,基于iPhone 6的界面效果,分别向上向下调试iPhone 6 plus(414pt)和iPhone 5S及以下(320pt)的界面效果。由此完成大中小三屏适配

      假如公司设计稿不是基于750的怎么办,其实很简单,按上图做一些相应替换即可,但是流程和方法还是一样的。解释一下为什么要在@3x的图里切,这是因为现在市面上也有不少像魅蓝note这种超高清屏幕,devicePixelRatio已经达到3了,这个切图保证在所有设备都清晰显示。

    • 微信分享的默认机制

      利用微信分享(分享到朋友圈和分享给朋友)的默认机制(不需要 JSSDK 验证配置也可以控制分享的内容), 我们可以尽量避免出现分享时出现错误的图片

      • 分享图标默认为网页中找到的第一个尺寸大于 300 * 300 的非隐藏(不能设置 display:none 或者 visibility:hidden)图片
      • 分享标题默认为网页的 title
      • 分享描述(分享给朋友时才会出现)默认为网页的域名(IP), 这个在没有启用 JSSDK 时是无法修改的

      因此我们可以尝试在页面中添加一个"隐藏"的图片来达到这个目的, 例如: 网站首页则隐藏一个网站的 LOGO, 商品页面则因此一个商品的图片

      <img src="http://placeholder.qiniudn.com/300x300" width="0" height="0" style="position:absolute"> 
    • ng-bind-html

      如何在 angular 中绑定一段 HTML 代码

      • ngSanitize 模块(Attempting to use an unsafe value in a safe context)
      • ng-bind-html="someHtml"
    • fiddler使用实践

      禁用缓存

      在进行调试的过程中,我们希望可以立即显示出效果,所以不希望有缓存,我们可以在fiddler里面设置禁用缓存:Rules->Performance->Disable Caching

      伪造数据请求

      如果参数有规律,我们还可以序列化多次伪造请求。通过Composer工具,在parsed面板中,在需要伪造的参数处写成#,然后执行:分别填入起始数据,和结束数据。

      设置断点修改返回结果

      如果我们需要某个请求/响应的HTTP头的话,则通过:bpu url 来设置断点(在 fiddler 界面左下方 QuickExec 输入框中输入命令)

      例如 bpu http://yourdomain.com/index.html

      然后刷新页面,会看见该请求会被一个红色图标标识出来, 选中这个请求, 会看见 Breakpoint hit, 点击一下 Break on Response 即拦截响应, 此时可随意修改响应的头(选中 Headers 标签, 右键某个 header 可以修改删除添加)或者整个响应的内容(在 TextView 标签或者 Raw 标签中修改), 修改完成后点击一下 Run to Completion 即恢复响应

      最后再在 QuickExec 中输入 bpu 即可取消所有断点, 更多的 QuickExec 命令请参考 Using QuickExec

    • 让console充满情怀

      // 第一个参数有五个占位符(%s),第二~六个参数会依次替换掉占位符。
      console.log("%c Look %o and %O , it %s and %d and %f","color: #6190e8;", document.body, document.body, "CC", 123.1, 123.1);
    • 移动端全兼容的flexbox速成班

      .flex-cont {
          display: -webkit-box;
          display: -webkit-flex;
          display: flex;
      }
      • 做提示icon
      • 做列表元素
      • 做tab/增加或删减tab数量, 只需要增减DOM结构即可, 无需样式的修改
      • 做导航(只适合三个布局)
      • 做搜索条
      • 做垂直居中(单/多)
      • 做垂直弹性布局

      全DEMO的合集<<移动端属性全兼容自查表>>

    • eviltransform

      Transport coordinate between earth(WGS-84) and mars in china(GCJ-02)

      WGS84坐标系:即地球坐标系,国际上通用的坐标系。设备一般包含GPS芯片或者北斗芯片获取的经纬度为WGS84地理坐标系,

      谷歌地图采用的是WGS84地理坐标系(**范围除外);

      GCJ02坐标系:即火星坐标系,是由**国家测绘局制订的地理信息系统的坐标系统。由WGS84坐标系经加密后的坐标系。

      谷歌**地图和搜搜**地图采用的是GCJ02地理坐标系; BD09坐标系:即百度坐标系,GCJ02坐标系经加密后的坐标系;

      搜狗坐标系、图吧坐标系等,估计也是在GCJ02基础上加密而成的。

      WGS84,GCJ02, BD09坐标转换

    • awesome-pure-css-no-javascript

      纯 CSS + HTML,不使用 JavaScript,能实现怎样的视觉效果?

    • Pisual Mouse

      粒子效果 + 卡片菜单效果

    • Vue.js 例子

    • 传统企业的移动电商平台实践

      传统企业移动电商平台分类

      • 销售自产商品
      • 积分商场。针对自己的客户/用户的积分商场
      • 销售非自产商品

      移动电商平台的技术选型

      从2014年下半年以来,移动前端技术发生了一些重大的变化,之前大讲特讲的Hybrid(原生代码+HTML),突然演进到了驱动原生的方式。

      这种方案的大致思路是,在运行态的时候,通过调用操作提供的接口,对UI进行渲染,而不是把渲染交给浏览器内核。这种技术流派(我这里说的流派,因各家虽然出了各自的不同名字的框架,但思路是一致的),2015年一来,从天猫开始互联网企业也采用了,后来阿里出了Weex,携程使用了React Mix框架。无论从用户体验、跨平台、性能、以及热更(hotfix)方案,都得到了广泛的认可。 React Native 无论从内存、CPU、响应时间都全面超越Webkit作为渲染器的HTML;

      • 传统的Hybrid:其大致的思路是采用HTML(或者很多人说的H5)作为UI,通过嵌入或者系统的浏览器作为渲染(通常采用Webkit),当需要本地能力的时候,采用原生语言的方式编写,并提供接口给UI端调用。因其UI的渲染采用浏览器的方式,难免会影响到用户的体验。
      • 驱动原生:在运行态的时候,通过调用操作提供的接口,对UI进行渲染,而不是把渲染交给浏览器内核。

      对于操作系统来讲,前者不无法获取到具体的控件;而后者,因操作系统负责渲染,它势必会形成一个控件树。针对这个特点,我们可以据此判断到底浏览器渲染还是操作系统渲染。而驱动原生就是采用操作系统进行渲染的,我称其为原生渲染。

      如何判断一个App是通过操作系统进行渲染的,还是通过webkit进行渲染?

      在 Android 手机上打开“开发者选项”的“显示布局边界”

      如何判断一个App是通过操作系统进行渲染的,还是通过webkit进行渲染

      如果一个界面上,被Android划出框框来,就是原生渲染(当然这有两种方式实现,一种是原因语言开发的,一种是驱动原生的方式)。如果明明是个Button,却没有被识别出来(如上图的右侧),那就是Webkit做渲染。其原理大致是,操作系统渲染的UI,都会以一个UI树的方式进行维护,而非其渲染的UI,它不负责维护,也就无法识别到了。通过研究你会发现:天猫、淘宝、京东、携程等App的主要操作的界面已经采用原生渲染了(要相信自己的眼睛哦),而不是使用webkit做渲染了。

      采用HTML/CSS/JS传统的技术实现驱动原生

      我们选择开发期让工程师编写HTML/CSS/javascript的代码,在编译期编译成驱动原生的代码. 在打包期,将编译后的代码带入安装包(ipa、apk)中

      采用HTML/CSS/JS传统的技术实现驱动原生

      传统的方式,为了让用户感知到新功能,基本上要做两件事情:AppStore 通过审核/用户主动去下载新App安装

      为了解决这个问题,我们采用了动态更新技术。确保用户在使用App时,可以及时容易获取到功能。可以不用等待App Store审核,甚至可以做到在用户无感知的情况下,新的业务已经在使用了

      问:通过什么将HTML5与JAVASCRIPT写的代码转化为驱动原生的代码?

      答:这个是我们自己实现的,原理上是针对原生控件的特点,选取了HTML的子集,并且扩展了它的属性。

    • 你了解你和代码的生存环境吗

      这里说的生存环境主要是三部分:技术,团队,业务。

      • 微观代码环境

        了解你所编写代码的环境,上下文。然后去用那些能够复用的连接、函数、工具,而不是自己造一个。如果觉得别人的写的有问题,gitblame是个好工具,跟他沟通. 有两个理论需要知道,一个是破窗理论,另外一个就是童子军军规——让营地比你来的时候更加干净。另外值得不断警醒的是不要生下代码猴子。参见《代码整洁之道》

      • 技术栈

        一般我们新到一个公司,前几天肯定是需要做的就是熟悉环境。这里的熟悉环境一般都是指技术上的,首先需要做的就是了解新公司用到了哪些技术,比如你之前的公司都是用SVN管理代码,现在大家都用git,那你肯定需要尽快熟悉,再比如说你之前打包都是用grunt,但是新公司都用glup了,这也需要熟悉。在此之上才是业务层面的熟悉,这个业务是指跟你编写代码紧密相关的业务(功能)。

        所谓的生存环境并不是固定的,它是随着你的认知的不断的扩大而扩大,就像是一个圆,内部标记为已知,外部是未知,你已知的东西越多,未知的东西就越多。因此要是时刻有更深层次的考虑,对于如何跳出舒适区的最好的办法就是保持警惕心。在感觉一切尽在掌握之中的情况下,考虑到出现什么情况会导致你无法把控——无论是项目进度还是问题修复。单纯的就局部环境来说,只是能够熟练的运用JS,CSS解决问题是不行的,对于现在已经工程化的前端来说,只会这些会让你丢掉饭碗——迟早。因此有必要精通你的技术栈。大部分情况你只熟悉了外围的技术点,不妨碍你做一些Normal或者是Easy模式的业务。但是如果始终停留在这个模式,那你也只能留在这个模式。一般我们派活给同事时,都会考虑他的技术能力在什么水平,不会上来就给一个Hard模式的业务,这必然会导致一个问题,只能解决Easy模式问题的人,一般来说不会得到重视,如果能够及时自省,自己奋发的好还好

      • 团队

        对于团队来说,任何一个新人到新团队第一件要做的事就是尽快让大家都认识你,同时你也要尽快的熟悉每个成员. 了解每个人的技术点,技术偏好(或者到底对技术有没有热爱),然后看他们目前所处的层级。这里需要了解的是,了解你所掌握的技术在这个团队中能够到怎么样的层级,任何地方都是会有阶梯的. 从团队中能够了解到的一个重要的状况是你离目前团队的天花板还有多远,你需要花多少时间才能到达。现有团队是否有成长氛围,技术氛围如何。

      • 业务

        首先要认识的一点是,所有技术的存在都是为了业务服务。如果你觉得自己技术够牛,为啥不会对业务产生好的影响?尤其是当你进入一个不错的公司,觉得可以施展才华,首先要做的可能是了解业务特点,有哪些是除了现有技术支持之外,需要改进的地方

        你了解的东西如果没上过生产环境,这个对你来说除了是知识之外,没什么用处(知识和经验是有很大差别的)

        技术是支持业务的脊梁,业务是滋养技术的环境。贴合业务的技术不仅仅能让你在技术上更为精进,也会让你在业务有所贡献. 除了从技术角度看业务,还要从行业角度看业务. 你必须了解你公司的成长情况,收益情况,行业地位。据此不停的调整自己的方向。让自己无论是在上升还是下降的公司中都能够往上成长。

    • 没有花招、直面人生的架构经验总结

      架构师承担什么样的责任

      唯有了解,才会关心,唯有关心,才会采取行动,唯有行动,才会有结果

      按照架构师所从内容侧重点不同架构师可以分为

      • 业务架构师(Business Architect)
      • 技术专项领域架构师(Domain Architect)
      • 技术架构师(Technology Architect)
      • 企业总体架构师(Enterprise Architect)
      • 项目层面的技术架构师(JAVA架构师、 .NET架构师)

      架构师的核心能力

      架构师的经验很重要,因为只有经历过才能更深入的理解痛点以及表面繁华背后需要填的坑,比经验更重要的是要具备深入思考的能力,时常对从事的专题领域的进行经验总结,才能跳出本位看全局,不断提升自己的判断和分析的能力。

      在做分析或经验总结时,一般采用结构化思维方法,首先梳理目标,清理目标与自己或将来发展的关系;其次做现状分析,知道自己有什么、缺什么以及分析与目标的差距,眼下首要的任务是什么;再次是路线与措施分析,并制定保证有效执行的方案;最后是下定决心以较高的执行力来实践。当然沟能力也很重要,在执行决策前,先与分析相关干系人的诉求,并协调其合作要比单纯的编程能力更为重要。架构师也需要具备一定的商业头脑,只有这样才能很好地理解企业战略目标,制定能够赢的技术路线与之匹配。

      架构师的知识管理

      架构师的知识面很广,需要快速的学习知识、快速的掌握并运用、经常将知识沉淀为经验并分享给伙伴、督导团队执行并创新

      • 保持好奇心和阅读习惯坚持做笔记
      • 深入思考问题背后根源,学习和掌握方法论
      • 经常与人交流或查看牛人博客
      • 经常总结并分类管理与分享

      架构师的问题解决能力

      你所在的项目接到一个新的接口开发需要,作为架构师你如何处理?

      建议的思维方式:要不要做、应该谁来做(涉及到系统边界问题)、如何做、什么时候做合适、做了对将来有什么影响……等。作为技术管理者,架构师应在不同的场景内跳入、逃出,大格局着眼,细节入手,并时时总结,尽量规避先入为主的执行思维(如:首先考虑使用协议、接口规范、如何执行、要多久才能完成、如何规避风险……等)。

  • 产品
    • 电商列表信息展示,你真的懂吗?

      用户基于产品列表里关于这些产品的有效信息来选择是否购买这些商品。因此在我们经过大规模的产品列表和筛选可用性学习后毫不奇怪地发现贫乏的列表项信息是关于产品列表导航的最严重的可用性问题。

      通过测试,我们发现信息过少或信息相关性过低的列表项很有问题,因为用户在缺少这些商品的基本信息的情况下是无法进行适当评估的。这会导致受测对象完完全全地误解了相关产品,并导致他们在产品页和列表页之间不必要的来回跳转 – 他们不得不返回继续一遍刚才的操作, 打开列表页的每个产品只是为了了解它的基本属性和核心特征; 这个令人不快的实践经常导致受测对象放弃访问站点,因为简单地定位相关产品的矛盾太突出了。 显而易见,在每个列表页展示正确的数量和正确的类型信息对提升用户的产品查找体验是至关重要的。

      在列表项中获得一个好的信噪比对提升用户找到他们想要找到商品的能力至关重要. 有两组属性应该被包含在列表项中:通用属性和特有种类属性

    • 一款产品的从0到1之旅

      全栈开发的体验. 全栈开发就是需要对前后端技术都了解的人,同时可以把产品设计界面转化成代码。总之就是对开发产品涉及的领域什么都需要了解的人。

      全栈开发为什么越来越流行?我认为这是因为技术本身的进步带来的,技术发展已经越来越开放并且模块化了,很多产品完全可以用现有的模块去重新组合二次开发,很多关键技术和算法都已经不是什么阻碍了

      个体的影响力正在被不断的放大,反而企业的影响力会降低,未来的社会中远程工作和独立工作者的数量会越来越多。社会对群体聚集进行生产产品的模式需求在降低。

      首先让我来解释下我理解的全栈思维:它应该是一种解决问题的能力。让我们假想两种思维模式就可以看出这个定义的有趣之处了。A是你要打造一款产品,然后你需要了解制作这款产品需要的资源、技术和流程。B是你需要学习一门流行的技术来找工作,然后你利用这个技术来做一个Demo产品。A和B的区别在于A需要解决各领域的问题,A是一种全栈思维,以目的为驱动的。为了完善这款产品你也许需要了解产品的各个方面

      那么全栈开发的好处和坏处有哪些呢?我认为好处是沟通成本为0, 那坏处就是什么工作都需要你来做,当然你可以外包一些不重要的部分出去,但是一定要注意沟通成本的增加

      产品设计/项目管理/产品开发/系统模块设计/数据库设计/REST API 设计/UI/UX 设计/服务器运维/APP开发/WEB开发/系统测试/域名/产品反馈/寻求帮助/运营推广/产品文案/运营/推广

    • 苹果AppStore被拒理由大全

      苹果AppStore被拒理由大全

班会第 28 期

  • 技术
    • 一个用Vue.js开发微信app界面(ios风格)的demo

      线上地址: vue-wechat.github.io

    • URLSearchParams

      Chrome 49+ 可用, 其他浏览器可以用 URLSearchParams polyfill

      The URLSearchParams interface defines utility methods to work with the query string of a URL.

      var paramsString = "q=URLUtils.searchParams&topic=api"
      var searchParams = new URLSearchParams(paramsString);
      
      //Iterate the search parameters.
      for (let p of searchParams) {
          console.log(p);
      }
      
      searchParams.has("topic") === true; // true
      searchParams.get("topic") === "api"; // true
      searchParams.getAll("topic"); // ["api"]
      searchParams.get("foo") === null; // true
      searchParams.append("topic", "webdev");
      searchParams.toString(); // "q=URLUtils.searchParams&topic=api&topic=webdev"
      searchParams.set("topic", "More webdev");
      searchParams.toString(); // "q=URLUtils.searchParams&topic=More+webdev"
      searchParams.delete("topic");
      searchParams.toString(); // "q=URLUtils.searchParams"
    • 写给js沾边工程师的《精简HTTP》

      只要大家是js沾边工程师,http是无法躲过的、必须掌握的技能

      精解http

      • 三层架构
      • 二个核心:req和res
      • 一个记住:无状态
      • Chrome调试与http
      • http基础:GET/POST/上传
      • 表单
      • 异步:ajax
      • 使用Node.js实现服务端
      • 工具postman
      • 命令行cUrl
    • 前端重构成长指南 | 首届TGDC-前端专场

      前端重构应该关注自己哪些能力的提升,在繁重的业务压力下怎么提升自己的能力,如何让专业能力有更好的呈现,个人影响力怎么加强,如何成为一个小团队里面的骨干?

      说到前端重构的职业成长,我觉得应该重点关注三个方向

      • 专业能力: 职业技能(一专) + 辅助技能(多长)
        • 职业技能
        • 辅助技能
      • 通用能力: 通用能力带动专业能力
        • 项目管理的能力
        • 解决问题的能力
        • 主动沟通的能力
      • 团队影响力: 每个人能力的提升促进整个团队发展壮大
        • 文档的输出
        • 知识的分享

      TGIDEAS 整体 WEB 解决方案

      • 基础规范: 为了增强团队的协作和高效开发,提升代码质量,TGideas团队一起制订的代码规范。主要包括五部分内容:PC规范、移动端规范、性能优化、CP规范、
      • SEO指南: 团队在SEO方面的经验沉淀,SEO小组多年经验实践总结,主要包括四部分内容:基本规范、PC与移动端差异化、产品侧SEO、SEO白皮书
      • 组件: 主要包括五部分内容:移动端组件、PC功能类组件、PC效果类组件、3D效果类组件、PC样式组件
      • 工具: 工作中常用的工具,包含TGideas团队开发的及收集的外部工具
      • 前端推荐: 这是有一些资源,如推荐书籍介绍、PDF文档下载、前端博客链接、前端分享资源、工作参考手册
    • What、Why、How?解读Webpack官方文档

      我理解的Webpack,就是一个更出色的前端自动化构建工具、模块化工具、资源管理工具。

      为什么选择Webpack,两点原因。

      • 前端需要模块化:JS模块化不仅仅为了提高代码复用性,更是为了让资源文件更合理地进行缓存
      • AMD与CMD规范日渐衰弱:原因?ES6带来了很强的模块化语法糖

      Why Webpack

      • 模块化前端项目的发布打包问题

      • 代码切分: 抽取多个页面公用模块,打包成commonjs,便于缓存

        两大重要概念:切分点(split point)与代码块(Chunk)

      • 版本控制: 对于静态资源的版本控制

        如果将版本号作为请求参数,版本号为发布日期,有两个问题:

        • 更新版本时,CDN不能及时更新
        • 没有发生变更的文件也被赋上新版本

        Webpack的做法是,生成hash,区分文件

    • 技术团队风格指南

      如何做技术,每个做 ( 过 ) 技术的都有自己的经验,而总结起来无非是影响自己、影响团队、影响业界,影响世界。

      • 无码无坑,写好代码,提升手速是影响自己
      • 抽象、共用帮其他人省时间是影响团队
      • 开源源码、把**带给业界,让昨天的优秀项目成为明天的基础设施是影响业界
      • 通过程序让一个方水平的人甚至多方水土的人能更方便地做某件事,是改变世界
      • 古训总是简炼地为我们总结这些罗嗦的话「修身,齐家,治国平天下」

      一线程序员,团队最重要的成员。这群人做了最多的事,产出了最重要的结果。如果每个人产出的质量和速度都增长,那么客户将更乐意把口袋的钱放到公司的账户。这里的关键是质量和速度。

      • 良好的入门指南
      • 导师
      • 榜样
      • 提供工具
      • 鼓励成长
      • 提供机会

      主管、经理,团队的中坚力量. 总监、部门负责人,团队的资源池

      最好的管理不是当团队的保姆,而是当团队的资源池. 如果每个人都能很好的自我驱动,在缺什么的时候就向资源池去拿,那么世界一定是和平的

      • 雇主心态
      • 放权与资源
      • 设定好目标和方向
      • 提升团队影响力
    • 大话程序猿眼里的高并发架构

      业务从发展的初期到逐渐成熟,服务器架构也是从相对单一到集群,再到分布式服务。
      一个可以支持高并发的服务少不了好的服务器架构,需要有均衡负载,数据库需要主从集群,nosql缓存需要主从集群,静态文件需要上传cdn,这些都是能让业务程序流畅运行的强大后盾。

      • 通用方案(缓存): 日用户流量大,但是比较分散,偶尔会有用户高聚的情况;
      • 消息队列: 秒杀、秒抢等活动业务,用户在瞬间涌入产生高并发请求
      • 一级缓存: 使用站点服务器缓存去存储数据
      • 静态化数据: 对于更新频繁度不高,并且数据允许短时间内的延迟,可以通过数据静态化成JSON,XML,HTML等数据文件上传CDN,在拉取数据的时候优先到CDN拉取
    • 谈谈PhxSQL的设计和实现哲学 | 来源于微信后台团队

      PhxSQL是一个建立在Paxos的一致性和MySQL的binlog流水基础上, 提供 Zookeeper 级别强一致和高可用的MySQL集群

      PhxSQL完全兼容MySQL,建立在简单可逻辑证明的一致性模型之上,架构、部署、运维简单

      主要原理简单来说

      • Paxos选出主机
      • 主机把本机MySQL设置成可写的MySQL主机,在MySQL写binlog流程中拦截binlog流水、发送到Paxos,形成全局的binlog流水
      • 备机把本机的MySQL设置成只读的MySQL备机,MySQL备机从全局binlog中拉取流水,重放和执行,从而主备MySQL一致
      • 针对常见的业务场景,PhxSQL提供两个服务端口:强一致读写端口(ReadWritePort)和只读端口(ReadonlyPort);对数据要求强一致的业务,通过ReadWritePort来读写;只要求能读取但不要求最新数据的读请求(比如一些定时对账业务),可以通过ReadonlyPort来读取
        PhxSQL架构

      看这张图让我想起了 EVA 动画片中的MAGI

      在EVA中,由赤木直子博士开发的三台超级电脑被命名为 “三贤人超级计算机系统”(MAGI System)简称“三贤人”(MAGI)。MAGI相当于NERV的大脑,由三大系统组成:MELCHIOR-1,BALTHASAR-2,CASPER-3。

      Eva-Magi

      在数据库事务隔离方面,PhxSQL支持最高级别的serializable。在性能方面,PhxSQL提供明显优于MySQL半同步的写性能和几乎相同的读性能

      MySQL传统主备同步方案仍然具备很多新系统难以企及的优点。MySQL主备在主机上支持完整SQL、全局事务、以repeatable read和serializable级别的事务隔离,在金融、帐号等关键业务中有巨大的价值。同时,现有复杂MySQL应用迁移到新的非兼容系统成本也很高。

      但是MySQL传统主备方案也有其缺点。最明显的就是主机故障后的自动换主和新旧主数据一致性(以及衍生的换主后主备一致性、各个备机之间一致性,这里就不详加讨论了),即所谓的一致性和可用性。

      为了解决这个问题,有传统流派:用Zookeeper、etcd、或者其它第三方来检测心跳、选主、和切换。改造MySQL client让其能感知新的主机。或者为了能让传统MySQL client不加修改就能感知新的主机,部署MySQL代理服务器,让其将连到自身的MySQL client请求透明转发给新的主机。为了减少主备间数据的落后,从而降低旧主机故障、某台备机被提升成新主机时,新旧主机之间、新主机和其它备机之间的差异,很多方案在主备同步机制上做了很多有益的工作

      如果主备间任何时刻都完全一致,那么任何时刻换主都是强一致的。这句话的另外一个意思是,如果无法保证主备间任何时刻完全一致,那么当有持续不断的更新时,任何时刻的换主都是无法保证强一致的。

      PhxSQL的设计原则是什么?

      • 简单可逻辑证明的一致性模型

        各个MySQL的binlog流水一致,则各个MySQL机器之间数据“一致”
        对于PhxSQL来说,切换主机是一件很平常和容易的操作,就像往MySQL里插入一条数据一样平常和容易

      • 最小侵入MySQL原则

      • 简单的架构、部署、和运维

        PhxSQL只有3+1个模块

        • MySQL是必须的
        • PhxBinlogSvr负责全局binlog存储和同步、选主、集群成员管理等关键功能
        • PhxSQLProxy则作为传统MySQL client访问PhxSQL中MySQL服务的代理,使得PhxSQL的换主操作对于传统MySQL client透明
        • 可选模块是PhxSQL client lib,它修改了MySQL client库中的连接初始化函数,允许传入一个集群的PhxSQLProxy列表,从而在一个PhxSQLProxy没有响应时、自动访问其它可用PhxSQLProxy,进一步提高可用性。开发人员可以直接链接PhxSQL client lib。

      开源是整个互联网的基石,为全世界提供许多关键不可或缺的基础服务

      PhxSQL的局限性

      • MySQL主机在执行SQL DDL命令(例如建库和建表命令)时可能存在一致性风险。
      • 在写入请求量很大的系统中,MySQL备机流水可能落后较多;如果这个时候主机死机,备机暂时无法提升成新主机,造成系统在一段时间内不可写
    • 回顾过去用过的 Web 框架

      没有什么框架是银弹,可以搞定所有问题,只有最适合你当前业务的框架和语言。

      片面的信仰任何一种技术都是不负责任的,目的不是比谁最牛逼,而是谈谈这些框架都好玩在什么地方

      • Ruby on Rails 是效率的极致

        Rails 最大的魅力就是 Convention over configuration 约定优于配置这种敏捷开发的理念. 说白了就是提供了一套规范和默认配置, 如果你按照规范来, 你基本上就不需要配置了, 一路顺风顺水, 如果团队和业界都采用相同的规范, 那么效率必然得到提高.

        举个例子来说,你要买一个包子,如果你不说你要什么馅的,那么包子店就随便给你一个包子,因为此时的重点不是包子馅,而是包子本身,一个由皮,馅构成,由蒸这种加工工艺做成的点心,这就是约定。而当你指定要什么馅的时候,就成了配置。

      • Node.js

        在 Node.js 上,我最终学到的一件事情是,语言速度快这些特性并不能解决高并发这种场景,因为在那个时候,服务器的性能瓶颈不是语言,而是数据库。

      • elixir on Erlang VM

        Erlang 是 1987 年爱立信发布的针对电信手机通讯的语言,天生支持高并发和高 uptime,在移动互联网的著名成功案例就是 Whatsapp,单个机器可以支持 200 万连接。

      • Go

        Go 不光编译的快,运行起来也是非常快

      • Swift

        他有像 Rails 一样强大的社区,有像 Ruby 一样有趣的语言,有像 Go 一样编译语言的优秀特性

  • 产品
    • 半分钟内就能看透问题本质的人,是如何思考的?

      工作中有一个高效的逻辑思维能力无比重要。它能立刻让你找到问题的关键,让问题引刃而解。

      我对逻辑思维的理解。逻辑思维的过程,是化繁为简,目的,是找到解决方法。因此,所有和“寻求解决方法”无关的信息,都是无用信息,都需要剔除。

      花半秒钟就看透事物本质的人,和花一辈子都看不清事物本质的人,注定是截然不同的命运。

      Be MECE: 取自“Mutually Exclusive Collectively Exhaustive”,中文意思是相互独立,完全穷尽,发音读作“Me See”

      实际运用中你只用不停问自己两个问题:

      • 我是不是把所有的可能因素都考虑到了,有没有遗漏的?如果有,再去找。
      • 这些因素之间有没有互相重叠的部分?如果有,进行去重。

      归纳和演绎

      这是两条基本的认知事物和思考的逻辑法则

      • 归纳,是把具备某种相同属性的事物,一一列举出来,然后寻找共通点。
      • 演绎,是把互相之间形成影响的因素,按照事物因果顺序、时间先后顺序,重要程度顺序排列出来,再寻找突破口。

      工作中所有的问题,你都可以把它用演绎或者归纳的形式进行拆分。我喜欢把这个过程称为“解构”。归纳演绎和前面提到的 MECE 经常会搭配使用,在归纳演绎的过程中,坚持 MECE 的原则,能把复杂的问题分解成多种单一的因素,这个过程犹如抽丝剥茧,将一团乱麻理地条条顺顺。

      下面是我思考问题时会遵循的一个思维提纲,大家可以参考:

      • 核心问题是什么?(只能有一个,如果有很多,找到最重要的那个)
      • 这个问题的背景是什么?(来龙去脉,历史原因)
      • 和现在这个问题有关的人物和因素有哪些?(记住MECE法则,用归纳法,一一并列出来)
      • 哪些是导致这个问题的关键原因?
      • 哪些是次要原因?
      • 解决这个问题有哪些方法?(用归纳法,写出所有可能。用演绎法,找到每种方法实施的具体步骤)
      • 解决这个问题,你现在欠缺哪些条件或者资源?
      • 如何去弥补这些条件上的欠缺?
      • 你的时间规划是怎样的,先做什么,再做什么,然后做什么?
      • 最后一步,just do it.

      先说结论

      先讲结论,把你要阐述的观点一开始就抛出来,这能节省所有人的时间. 因此第一句话就要把自己的核心观点传递出来:我们的方案是什么,以及,它为什么是最佳的选择。

      记住按照总分总的原则,首先抛出核心观点,即“我们应该做什么”。接下来需要进行解释,即“为什么这么做”。

      演绎归纳和 MECE”,是你的分析思考过程;“先讲结论”,是你思考完以后的表述方法。

      先讲结论的人,能够在一开始就抓住别人的注意力,接下来通过层层递进的方式论证结论的正确性,听众就不会迷失方向。

      当你给领导汇报工作的时候,他们绝不可能听你长篇累牍的解释分析,他们只会听你的结论,或者解决方法。当他们有兴趣的时候,会追问细节,当他们很忙的时候,他们只需要听到最重要的东西。

      培养洞察

      事物的原因,原因的原因,原因的原因的原因。你需要洞察的,就是事物的本质。在平时生活中养成勤于思考的习惯。

    • 致敬 G20:这 17 张 PPT 里,有关于**命运的 30 个大胆思考

      **正在通过G20开启世界下一个世界开端,读懂**,就读懂了世界。

      **未来产业

      • 1 维的传统产业
      • 2 维的互联网产业
      • 3 维的智能科技产业
      • 一维世界正在推倒重建,二维世界被划分完毕(BAT掌控),三维世界正在形成,高维挑战低维总有优势。所以网店可以冲散实体店,而微信的对手一定在智能领域诞生。

      **当下的企业

      • 三等企业做服务
      • 二等企业做产品
      • 一等企业做平台
      • 今后企业的出路唯有升级成平台,平台化的本质就是给创造者提供创造价值的机会!

      **互联网进化论

      • PC互联网
      • 移动互联网
      • 物联网
      • PC互联网解决了信息对称,移动互联网解决了效率对接,未来的物联网需要解决万物互联:数据自由共享、价值按需分配

      **经济结构进化论

      • 计划经济
      • 市场经济
      • 共享经济
      • 共产经济
      • 从“按计划生产、按计划消费”,到“按市场生产,按利润分配”,再到“按消费生产,按价值分配”

      **产业链的流向正在逆袭

      • 以前先生产再消费, 未来一定是先消费再生产
      • 传统经销商这个群体将消失,而能够根据消费者想法而转化成产品的设计师将大量出现

      **广告业态的进化论

      • 媒介为王
      • 技术为王
      • 内容为王
      • 产品为王
      • 未来最好的广告一定产品本身,最好的产品也一定具备广告效应。

      **商业角逐的核心

      • 地段
      • 流量
      • 粉丝
      • 房地产经营的就是地段,传统互联网经营的就是流量,自媒体经营的是粉丝。而未来是“影响力”和“号召力”之争,“核心粉丝”的瞬间联动是未来商业的“引力波”。

      **媒体的进化论

      • 传统媒体
      • 新媒体
      • 自媒体
      • 信息流

      **社会的组织结构从公司+员工,变成平台+个人. 未来每一个人都是一个独立的经济体。

      当你有一个想法时,你可以先表达出来,然后在平台上进行展示(这样的平台会越来越多),然后吸引喜欢的人去下单,拿到订单后可以找工厂生产(不用担心量太少,今后的生产一定会精细化和定制化),然后再送到消费者手里。

      **商业未来十年内的主题都将离不开,“跨界互联”. 以互联网+为基础,不同行业之间互相渗透、兼并、联合,从而构成了商业新的上层建筑

      **未来只有三种角色,自下而上依次是

      • 价值提供者
      • 价值整合者
      • 价值放大者
    • 离职后,我整理出了阿里运营的一招半式

      我认可的是运营就是经营,但这同样是个很大的词,而经营就是得用心、用脑慢慢去做的一件事。

      运营太大了,运营又太细了,运营什么都会,但运营又什么都不会。运营会什么,想创意、写文案、选商品、填页面、做推广、跟进度、看数据,设计师资源不够自己上,前端资源不够自己切页面。但按让专业的人做专业的事来说,运营又什么都不会,只会提需求,提需求,提需求。

      所以运营是最直接接触和把控业务的人,运营做得好,你可以甚至当CEO,运营做不好,当一颗螺丝钉,你也会最先被踢掉。阿里为什么运营牛?阿里的核心业务就是电商,电商就得靠运营,用心用脑研究出来的。

      有几项特质是做好运营(前提是做好)必不可少的,足够细致、有耐性、爱思考、主观能动性强。

      • 不要纠结,先去做

        做事情是要先思考,但不要纠结在选择,如果实在想不清楚也不用纠结,先去做,试试看,或许就有思路了。

      • 站在一定的高度上,要有格局

        “你做的可是产品运营,运营的是啥?是整个APP呢,你要站在CEO的高度想问题”. 站得越高,想得越多,能考虑到的就越全面,埋头只做自己的事常常会迷失方向,不知对错。就像开车时,教练说眼睛看着最远的地方

      • 不看你怎么想,要看你怎么做

      • 心要大,皮要糙

班会第 23 期

  • 技术
    • jQuery 数字渐增动画

      // 借用 jQuery 让自定义属性有动画, 可以实现一个简单的数字递增动画
      // as well as custom properties, can be animated.
      var $el = $('.js-anim-num');
      $el.animate({
          _number: 1024
      }, {
          duration: 600,
          step: function(value) {
              // $el.text(Math.ceil(value));
              // 可以在这里处理要显示的小数位
              $el.text(value.toFixed(2));
          }
      });

      如果需要更多的控制, 可以使用 jquery-animateNumber

    • HTTP 协议入门

      HTTP 是基于 TCP/IP 协议的应用层协议。它不涉及数据包(packet)传输,主要规定了客户端和服务器之间的通信格式,默认使用80端口。

      • 1991 HTTP/0.9

        只有一个命令GET

      • 1996 HTTP/1.0

        HTTP/1.0 版的主要缺点是,每个TCP连接只能发送一个请求。发送数据完毕,连接就关闭,如果还要请求其他资源,就必须再新建一个连接。

        TCP连接的新建成本很高,因为需要客户端和服务器三次握手,并且开始时发送速率较慢(slow start)。所以,HTTP 1.0版本的性能比较差。随着网页加载的外部资源越来越多,这个问题就愈发突出了。

      • 1997 HTTP/1.1

        一直用到了20年后的今天,直到现在还是最流行的版本。

        持久连接/管道机制/分块传输

        客户端请求的头信息新增了Host字段,用来指定服务器的域名,有了Host字段,就可以将请求发往同一台服务器上的不同网站,为虚拟主机的兴起打下了基础。

      • 2009 SPDY 协议

      • 2015 HTTP/2

        它不叫 HTTP/2.0,是因为标准委员会不打算再发布子版本了,下一个新版本将是 HTTP/3

        二进制协议/多工/数据流/头信息压缩/服务器推送

    • 移动 WEB 通用优化策略介绍

      移动 WEB 要做好图片优化,无外乎两点:控制图片大小和控制图片加载。

      • 按需加载图片
      • 顺序加载图片
      • 不要在页面滚定时加载图片

      重要的 CSS、JS、JSON 数据直接内联在 HTML 中,头部禁止出现任何外链资源。同时,尽可能减少页面传输体积。

      如何解决用户后续访问,内联导致的无法利用 HTTP 缓存机制的问题呢?

      我们引入了 localStorage 方案:用户首次访问时,服务端输出包含内联 CSS、JS 和 JSON 数据的页面,并通过 JS 将这些数据存入 localStorage;用户后续访问时,服务端只需要输出从 localStorage 读取并执行代码的 JS 片段即可。这样,后续访问的页面体积就小很多了。
      可以看到,这个方案的难点在于

      • 服务端如何得知用户本地存有 localStorage
      • 服务端如何得知用户本地存的 localStorage 中的某个具体文件的版本是否最新

      用户首次访问时,将以这样的形式输出:

      <style id="css_1">‍‍/* the content of 1.css... */</style>
      <script>LS.html2ls("css_1");LS.updateVersion('cookie_name','0','0')</script>

      用户再次访问时,服务端会分析 Cookie,找出对应文件在 Map 配置中的版本号,与 Cookie 中的版本进行比较,如果都没有变化,则只会输出这样少量的代码:

      <script>LS.ls2html("css_1","style","cookie_name")</script>

      这样,浏览器就会从 localStorage 中取出之前存储的内容,创建相应的标签并执行。

    • 移动端开发者眼中的前端开发流程变迁与前后端分离

      从前端开发的最初流程开始,讨论开发流程的演变过程,希望能覆盖一部分前端开发技术栈,从而对前端开发的相关概念形成初步的认识。

      网页可以分为静态、动态两种,前者就是一个 HTML 文件,后者可能只是一份模板,在请求时动态的计算出数据,最后拼接成 HTML 格式的字符串,这个过程就被称为渲染。

      前端与移动端开发另一个显著差异是: 虽然可以在本地调试 HTML,但实际上这些 HTML 的内容需要部署在服务端,这样才能在用户发起 HTTP 请求时返回 HTML 格式的文本

      • 前端开发的混沌时代

        把 UI 和业务逻辑写在一起是一种非常强的耦合,不利于项目日后的拓展

      • 后端 MVC

        使用了 MVC 架构(比如大名鼎鼎的 Struts)后,似乎职责变清晰了,前端开发者负责写 JSP,后端开发者负责写 Controller 和 Model

      • 前端只写 Demo

        一种解决方案是前端开发者只写 Demo,也就是提供静态的 HTML 效果给后端开发者,由后端开发者去完成视图层(比如 JSP)的开发。这样前端开发者就完全不需要了解后端知识了。

      • HTML 模板

        数据 + 模板 = HTML 源码. 利用工具强行禁止前端开发者在视图层写业务逻辑

        总的来说,采用服务端 MVC 方案时,HTML 在后端渲染,整体开发流程也全部基于后端环境。因此前端工程师不可避免的需要依赖于后端(虽然使用模板后情况已经大大改善)。

      • AJAX 与前端 MVC

        这就是我们常说的 前后端分离 的基本概念,即前端负责展现,后端负责数据输出。
        淘宝前后端分离实践

    • 趣店前端团队基于 koajs 的前后端分离实践

      现在我们的开发模式就可以优化为:前后端确定接口→前后端同时开发→联调提测上线

      前后端分离模式下的,数据代理主要有这两种使命:

      • 拼装一个和多个数据结果,给模板渲染数据或者给Ajax接口
      • 接受用户的数据请求,将结果交给一个后端接口

      内网访问的情况下,nodejs代理耗时不超过10ms

      proxy的性能与接口响应时间无关,与接口响应content大小有密切关系:接口响应内容越大,proxy性能越差。

      生产环境的部署与大多数服务部署类似:经过SLB之后到nginx进行反向代理,走到nodejs服务响应请求;可以在nginx层进行负载均衡和监控;如果需要用到缓存,可以在nginx和nodejs之间再加一层Varnish。

      无论前端怎么玩、无论技术怎么发展,任何架构最终都是为了服务于产品。减少技术成本,提升迭代效率和产品体验是Web技术的核心诉求

      koa-grace

    • 我们为什么要尝试前后端分离

      分享在前后端分离路上收获的点点滴滴,以此来为准备尝试前后端分离或者想了解前后端分离的童鞋做一个大体的讲解。

      把流程从

      • PM:“我要这个功能”
      • 后端:“这个先找前端做个模板”
      • 前端:“模板做完了”
      • 后端:“我来对接一下,这里样式不对”
      • 前端:“我改完了”
      • 后端:“功能交付”
      • PM:“春节要加这个活动”
      • 后端:“这个先找前端改个模板”
      • 前端:“模板做完了”
      • 后端:“我来对接一下,这里样式不对”
      • 前端:“我改完了”
      • 后端:“功能交付”

      变成

      • PM:“我要这个功能”
      • 前端:“我要接口”
      • 后端:“接口完成了”
      • 前端:“我来对接一下,功能交付”
      • PM:“春节要加这个活动”
      • 前端:“需要增加接口”
      • 后端:“接口完成了”
      • 前端:“我来对接一下,功能交付”

      由此可见,前后端分离的主要概念就是:后台只需提供API接口,前端调用AJAX实现数据呈现。

      前后端分离的实现对技术人员尤其是前端人员的要求会上升一个层次,前端的工作不只是切页面写模板或是处理一些简单的js逻辑,前端需要处理服务器返回的各种数据格式,还需要掌握一系列的数据处理逻辑、MVC**和各种主流框架。

      优势与意义

      • 彻底解放前端, 前端不再需要向后台提供模板或是后台在前端html中嵌入后台代码
      • 提高工作效率,分工更加明确
    • 好码如文档,不言自明

      • 好代码像好的段子,不需要多余的解释。
      • 好代码就像一本好的教科书
      • 简单易懂。
      • 很精巧的分成章节,每章每节都有不同的意义。
      • 可读性 —— 对你与所有读你代码的人。
      • 可维护性 —— 保持你的代码易于修改。
      • 简单 —— 不要带来不必要的复杂性。
      • 清晰 —— 方法与属性的命名要说得通。把大段代码分割成小的模块。
      • 找一个从没看过你的代码的同伙读一遍并向你解释每一模块是干什么的。你越想插嘴解释几句,你的代码可能就越烂。如果你能很安静的闭嘴坐着,而你的同伙不需要问太多问题,那么你的代码很可能不错。
      • 该重用的都重用了,没重用的随时可以重用。
      • 方法都不长,都能单独完成一项任务。
      • 当你调用一个方法时不需要进去看代码。
      • 你的每个类都有一个单独的、清晰的职责(单一职责原则)。并与其它职责不同的类分离。
    • 漫谈项目设计&重构&性能优化

      项目之初只做必要的设计。随着项目的变更,软件结构需要重新调整。通过重构可以改良最初的设计,使得项目符合最新的需求。

      重构的手法可能会使得软件性能有所下降,也应该往下执行。性能优化属于另外一个关注点,等重构完成后,项目设计良好,此时再去做性能优化也更容易。首先写出可运行的软件,然后调整它以求获得更快的速度。

      注意一定要将重构和添加功能的两种状态进行划分,在重构的时候不要添加功能。否则你不知道BUG是重构时导致还是添加功能时导致,增加重构的难度。

    • 这多年来我一直在钻研的技术

      知识广度是深度的副产品

      我只在专心研究一个事——如何做出一个性能高稳定性好的大规模的系统. 因为,只有技术、工具、工程、运维、人员这几个方面搞好了,才可能出现一个性能高且稳定性好的系统. 在残缺的环境下,能让用户不改一行代码,不动任何的架构,不改变用户很糟糕的软件开发的习惯,也不让用户作任何管理上的调整,能提升用户的软件系统的性能和稳定性。

  • 产品
    • 一般列表类( 表格, 列表)展现形式的通用状态

      • 初始状态(init)
        • 使用模版 + 空数据来渲染, 让用户尽早看到界面
      • 数据加载中(loading)
        • 提示用户正在获取数据
      • 数据加载完成(done)
        • 空数据提示(例如搜索的结果为空)
        • 有数据的情况(正常展现)
        • 加载失败(提示用户重试)
    • 交互细节!确定按钮到底该放在左边还是右边?

      这个结论,无法轻易得出。因为影响人们使用习惯的因素很多,例如设备(本实验使用平板)、系统(本实验使用IOS)和载体(本实验使用网页)等。尤其是本实验使用iPad,而包括iPad在内的苹果设备都是把确定按钮放在右边的。因此无法判断被测试者在右边寻找确定按钮的习惯是出于本能还是对IOS系统的适应。

我的微信公众号小程序之旅

最近微信公众号小程序实在太火爆了, 前面几天才开始内测, 各种尝鲜的文章已经遍布互联网了

带着强烈的好奇心, 我也玩了一把, 将小程序开发文档翻了个遍.

下面就是阅读后的一些摘要和记录


框架

小程序开发框架的目标是通过尽可能简单、高效的方式让开发者可以在微信中开发具有原生 APP 体验的服务

框架提供了自己的视图层描述语言 WXML 和 WXSS,以及基于 JavaScript 的逻辑层框架,并在视图层与逻辑层间提供了数据传输和事件系统,可以让开发者可以方便的聚焦于数据与逻辑上。

  • 响应的数据绑定
  • 页面管理
  • 基础组件
  • 丰富的 API

文件结构

框架程序包含一个描述整体程序的 app 和多个描述各自页面的 page。

一个框架程序主体部分由三个文件组成,必须放在项目的根目录,如下:

文件 必需 作用
app.js 小程序逻辑
app.json 小程序公共设置
app.wxss 小程序公共样式表

一个框架页面由四个文件组成,分别是:

文件类型 必须 作用
wxml(WeiXin Markup language 用于描述页面的结构) 页面结构
wxss(WeiXin Style Sheet 用于描述页面的样式) 页面样式表
js 页面逻辑
json 页面配置

注意:为了方便开发者减少配置项,我们规定描述页面的这四个文件必须具有相同的路径与文件名。

wxml 让我想起了 Adobe Flex 中的 MXML, 知道的人应该都老了

逻辑层(App Service)

小程序开发框架的逻辑层是由JavaScript编写

逻辑层将数据进行处理后发送给视图层,同时接受视图层的事件反馈。 在 JavaScript 的基础上,我们做了一些修改,以方便地开发小程序。

  • 增加 App 和 Page 方法,进行程序和页面的注册
  • 提供丰富的 API,如扫一扫,支付等微信特有能力
  • 每个页面有独立的作用域,并提供模块化能力
  • 由于框架并非运行在浏览器中,所以 JavaScript 在 web 中一些能力都无法使用,如 document,window 等
  • 开发者写的所有代码最终将会打包成一份 JavaScript,并在小程序启动的时候运行,直到小程序销毁。类似 ServiceWorker,所以逻辑层也称之为 App Service

API

框架提供丰富的微信原生API,可以方便的调起微信提供的能力,如获取用户信息,本地存储,支付功能等。

  • 网络
  • 媒体
  • 数据
  • 位置
  • 设备
  • 界面
  • 开放接口

视图层

视图层由 WXML 与 WXSS 编写,由组件来进行展示。将逻辑层的数据反应成视图,同时将视图层的事件发送给逻辑层。

为了适应广大的前端开发者,我们的 WXSS 具有 CSS 大部分特性。 同时为了更适合开发微信小程序,我们对 CSS 进行了扩充以及修改。

  • 尺寸单位(rpx, rem)
  • 样式导入(@import)

全局样式与局部样式: 定义在 app.wxss 中的样式为全局样式,作用于每一个页面。在 page 的 wxss 文件中定义的样式为局部样式,只作用在对应的页面,并会覆盖 app.wxss 中相同的选择器。

组件

组件(Component)是视图的基本组成单元

框架为开发者提供了一系列基础组件,自带一些功能与微信风格的样式,开发者可以通过组合这些基础组件进行快速开发。

  • 视图容器
  • 基础内容
  • 表单组件
  • 操作反馈
  • 导航
  • 媒体组件
  • 地图
  • 画布

最后上点图片尝尝鲜

wxa-editor.png

wxa-console.png

wxa-sources.png

wxa-network.png

wxa-storage.png

wxa-appdata.png

wxa-wxml.png

我的 ThinkJS 之旅 - 从前端向后端迈进

简单介绍下 ThinkJS 是用来做什么的

ThinkJS 是奇舞团开源的一款 Node.js 框架

借助 Babel 编译, 可以大胆使用 ES6/7 特性开发 Web 项目, 是一款后端 MVC 全功能框架. 使用 async & await 让异步执行以同步的方式来书写, 这个 feel 倍爽...

与其他框架的对比

  • 与 express/koa 对比

    express/koa 是 2 个比较简单的框架,框架本身提供的功能比较简单,项目中需要借助大量的第三方插件才能完成项目的开发,所以灵活度比较高

  • 与 sails 对比

    sails 也是一个提供整套解决方案的 Node.js 框架,对数据库、REST API、安全方面也很多封装,使用起来比较方便。但 sails 对异步回调的问题还没有优化,还是使用 callback 的方式,给开发带来很大的不便,导致项目中无法较好的使用 ES6/7 特性。

如果你还是有点蒙, 那么提下与 ThinkJS 同类型(Node.js web application framework)的框架 Express, Koa, Sails, 你是不是就大概了解 ThinkJS 的作用了呢.

与 Express 和 Koa 相比, ThinkJS 更符合一个全功能的 Web 开发框架, 你可以使用 Express/Koa + xx 插件 + xx 模块 + ... 来达到和 ThinkJS 类似的功能, 但其中充满了诸多选择, 需要灵活搭配才能满足所有的需求, 也就是说由于经验的不足, 保不准你就掉坑里了. 而 ThinkJS 自带了 Web 开发的常用模块, 让你开箱即用, 省力省心.

ThinkJS 与 Sails 相比, 就差不多是同一个重量级别的框架了, 类似 Ruby on Rails.

我们列一下 ThinkJS 更多的特性

以提升我们学习使用 TA 的兴趣

  • 支持 ES6/7 特性

    可以直接在项目里使用 ES6/7(Generator Function, Class, Async & Await)等特性,借助 Babel 编译,可稳定运行在 Node.js 环境上

  • 支持丰富的数据库

    支持 Mysql、SQLite、MongoDB 等常见的数据库,提供了很多简单易用、高度封装的方法,自动防止 SQL 注入

  • REST API

    自动生成 REST API,而无需写任何的代码。也可以根据接口定制,隐藏部分数据和进行权限控制

  • 丰富的 Adapter

    快速切换 Cache、Store、Session、Template 等功能,而无需关心具体使用哪种方式

  • 支持 WebSocket

    支持 socket.io、SockJS 等常见的 WebSocket 客户端,而服务端代码始终保持一致

  • 命令行调用

    支持命令行方式调用 Action,方便执行定时任务

  • 自动更新

    开发模式下,文件修改后立即生效,无需重启 Node.js 服务

  • Hook & Middleware

    系统提供了大量的钩子和中间件,可以方便地对请求进行控制和修改, 还有更多插件包含 Middleware 和 Adapter

  • 支持多种项目环境

  • 丰富的路由机制

  • 详细的日志,如:请求日志、错误日志、性能日志

  • 支持国际化多主题

  • 支持自定义多种错误页面,如:400,404,500,503

  • 单元测试

看看 ThinkJS 的版本历程

  • 2.2.15 2016.12.01
  • 2.0.0 2015.10.30
  • 1.0.0 2014.09.22

让我们试用一把尝尝鲜

大概了解下使用 ThinkJS 开发一个 Web 项目, TA 能提供什么功能, 能给我们带来什么好处, 是不是提高了我们的工作效率.

安装和创建新项目的细节大家请参考官网创建项目的文档, 我这里只是列下重要的命令和注意事项.

npm install thinkjs@2 -g

thinkjs new thinkjs-demo
cd thinkjs-demo
npm install

npm start

注意事项

  • 需要 Node.js 的版本 >=0.12.0, 建议将 Node.js 版本升级到 4.2.1 或更高版本
  • 是要安装 [email protected] 的版本, 以下实践都是基于 2.2.15 的版本
  • 2.2.12 版本开始, 创建的项目默认为 ES6 模式
  • 使用 ES6 模式创建的项目, 项目启动时会自动将 src 目录下的文件编译到 app 目录下

最后打开浏览器, 访问 http://127.0.0.1:8360/ 即可

深入了解 ThinkJS 的各个功能模块

项目算是跑起来了, 但要真正的使用, 还需理解下 ThinkJS 的项目结构, 看下其中各个目录和文件的作用, 以便知道如何新增或者修改某些功能.

首先打开 src 目录, 看见项目目录是按照模块来划分的, 新创建的项目提供了两个模块

  • common 通用模块, 用来放通用逻辑和配置信息的
  • home 一个业务模块(默认模块), 要添加一个新的模块: thinkjs module xxx
    • controller 控制器, 一个 URL 对应一个 controller 下的一个 action
    • config 模块下的配置信息
    • model 模型, 数据库相关操作, 创建模型: thinkjs model home/user
    • logic 逻辑处理, 每个 controller action 执行前可以先进行逻辑校验, 可以包含: 参数是否合法、提交的数据是否正常、当前用户是否已经登录、当前用户是否有权限等, 这样可以降低 controller 里的 action 的复杂度. logic 里的 action 和控制器里的 action 一一对应, 系统在调用控制器里的 action 之前会自动调用 logic 里的 action

另外, view 为视图目录, 放置对应的模版文件, 支持国际化和多主题. www/static 用于放置静态资源文件. www/development.js, www/testing.js, www/production.js 分别为三套项目环境(开发/测试/生产)对应的入口启动文件.

路由

这些目录大概都搞清楚后, 接下来就是重点内容了: 一个 HTTP 请求过来最终是由哪段代码负责处理的呢?

例如: http://127.0.0.1:8360/test/index.html

这就是路由的工作了, 当用户访问一个 URL 时, 最终执行哪个模块下哪个控制器的哪个操作, 这是由路由来解析后决定的.

  • 首先路由会将 URL 解析为 pathname

    例如: http://127.0.0.1:8360/test/index.html, 将 URL 进行解析(去除 host 信息)得到的 pathname 为 /test/index.html

  • 然后会对 pathname 过滤

    因为有时候为了搜索引擎优化或者一些其他的原因, URL 上会多加一些东西. 比如: 当前页面是一个动态页面, 但 URL 最后加了 .html, 这样对搜索引擎更加友好. 但这些在后续的路由解析中是无用的, 需要去除.

    默认会去除配置的 pathname 前缀和后缀内容, 以及自动去除左右的 /

    // src/common/config/config.js
    pathname_prefix: "",
    pathname_suffix: ".html"

因此经过路由处理后, 会拿到干净的 pathname, 我们就可以根据这个 pathname 来判断执行哪个模块下哪个控制器的哪个操作了.

例如

  • http://127.0.0.1:8360/test/index.html URL

  • /test/index.html 解析

  • test/index 过滤

  • 路由识别默认根据 模块/控制器/操作/参数1/参数1值/参数2/参数2值 来识别过滤后的 pathname

  • 当解析 pathname 没有对应的值时, 便使用对应的默认值

    其中模块默认值为 home, controller 默认值为 index, action 默认值为 index, 这些值可以在 src/common/config/config.js 中进行修改

    默认模块为 home 模块, 当解析用户的请求找不到模块时会自动对应到 home 下, 可以通过配 default_module 来修改默认模块

    关于大小写转化

    路由识别后, module、controller 和 action 值都会自动转为小写, 如果 action 值里有 _, 会作一些转化, 如: 假设识别后的 controller 值为 index, action 值为 user_add, 那么对应的 action 方法名为 userAddAction, 但模版名还是 index_user_add.html

  • 因此我们得知上面的 URL 会调用 test 模块(module)的 index 控制器(controller)的 index 操作(action)

  • 即: src/test/controller/index.js#indexAction

  • 默认的视图文件路径为 view/[module]/[controller]_[action].html模块/控制器_操作.html

  • 因此 display() 时对应的视图为: view/test/index_index.html

如果项目里并没有这个模块或者这个模块被禁用了, 就会识别为默认模块. 例如: http://127.0.0.1:8360/foo/bar.html, 会识别为 src/home/controller/foo.js#barAction

另外我们还可以自定义路由

默认的路由虽然看起来清晰明了, 解析起来也很简单, 但看起来不够简洁. 有时候需要更加简洁的路由, 这时候就需要使用自定义路由解析了, 路由配置文件为: src/common/config/route.js

  • 正则路由
  • 规则路由
  • 静态路由
  • 按模块来配置路由, 使用这种方式后, 通用模块里的路由配置不再配置具体的路由规则, 而是配置哪些规则命中到哪个模块, 再在对应模块下配置具体的路由规则

控制器

错误处理

扩展错误类型: 添加完错误后, 需要在对应地方调用显示错误才能让用户看到, 可以通过 think.statusAction 方法实现 return think.statusAction(600, this.http)

REST API Controller

可以用很便捷的方式来创建 REST API, 创建后无需额外的代码即可响应 REST API 的处理, 同时也可以通过定制响应额外的需求

thinkjs controller home/ticket --rest

上面的命令表示在 home 模块下创建了一个 ticket 的 Rest Controller,该 Controller 用来处理资源 ticket 的请求, 资源名称和数据表名称是一一对应的. 注意继承的类是: think.controller.rest

多级控制器

对于很复杂的项目, 一层控制器有时候不能满足需求, 这个时候可以创建多级控制器, 如:src/test/controller/group/article.js, 这时解析到的控制器为二级, 具体为 group/article, Logic 和 View 的目录与此相同. 例如: http://127.0.0.1:8360/test/group/article/index.html

下面是一个完整的 controller 示例, 列举了一般开发中所需要的功能

// src/foo/controller/bar.js
// 控制器是一类操作的集合, 用来响应用户同一类的请求
export default class extends think.controller.base {
    // 前置操作: 在 action 调用之前自动调用
    // 推荐放在一个 base controller 类中, 其他 controller 继承 base controller
    __before() {
        // 如果想在前置操作里阻止后续 action 代码继续执行
        // 可以用 return this.end('__before') 之类的操作提前结束请求
        console.log('controller __before');
    }

    // 后置操作: 在 action 调用之后自动调用
    __after() {
        // 如果 action 里阻止了后续的代码继续执行(用了 return), 则后置操作不会调用
        console.log('controller __after');
    }

    // 空操作: 当解析后的 URL 对应的控制器存在, 但 action 不存在时调用
    // 一般不需要使用
    __call() {
        console.log('controller __call');
        return this.end('404');
    }

    // 不指定 action 时默认用 indexAction 来处理这个请求
    // http://127.0.0.1:8360/foo/bar/a/%E4%B8%AD%E6%96%87/b/2?c=123
    indexAction() {
        // 获取 URL
        console.log('url', this.http.method, this.http.host, this.http.url);
        console.log('module/controller/action', this.http.module + '/' + this.http.controller + '.js#' + this.http.action + 'Action');

        // 获取请求参数
        console.log('pathparam-a', this.get('a'));
        console.log('pathparam-b', this.get('b'));
        console.log('urlparam-c', this.get('c'));
        console.log('GET param', this.get());
        // 当上传文件时, 包含 form 表单中除开 file 类型的其他字段的值
        console.log('POST param', this.post());
        console.log('param', this.param());
        // 上传的文件保存在临时目录(runtime/upload)中, 可以通过 path 属性看到
        // 使用时需要将其移动到项目里的目录, 否则请求结束时会被删除
        console.log('file', this.file());

        // 获取模型数据
        // 项目开发中, 经常要操作数据库, 如: 增删改查等操作.
        // 模型就是为了方便操作数据库进行的封装, 一个模型对应数据库中的一个数据表.
        // 模型文件不是必须存在, 如果没有自定义方法可以不创建模型文件, 实例化时会取模型基类的实例
        let model = this.model('city');
        // 操作模型
        model.where({name: 'Kabul'}).select().then(function(rs) {
            console.log('model', model.name, model.schema, rs);
        });
        // 指定 SQL 语句执行查询
        this.model().query("SELECT * FROM city WHERE name = '%s'", 'Kabul').then(function(rs) {
            console.log(rs);
        });

        // 变量赋值和模版渲染
        this.assign({
            title: '我们一起来学习 ThinkJS',
            author: 'Sun'
        });
        // 默认模版变量: 框架自动向模版里注册了 http, controller, config
        // 例如 <%- http.url %> <%- controller.ip() %> <%- config.port %> <%- config.db.type %>
        return this.display();
        // return this.end('随便输出点什么内容');

        // 返回 JSON/JSONP
        // return this.json({a: 1});
        // return this.jsonp({a: 1});

        // 返回格式化的正常数据, 一般是操作成功后输出
        // return this.success({a: 1});
        // 返回格式化的异常数据, 一般是操作失败后输出
        // return this.fail(1000, 'error...', {e: 1});

        // 跳转页面
        // return this.redirect('https://thinkjs.org');
    }

    // http://127.0.0.1:8360/foo/bar/baz?callback=abc
    // http://127.0.0.1:8360/模块/控制器/操作
    bazAction() {
        return this.jsonp({baz: 'hello thinkjs'});
    }
}

Logic

支持的数据类型有: booleanstringintfloatarrayobject, 默认为 string. 内置了很多校验类型

扩展校验类型

如果默认支持的校验类型不能满足需求, 可以在 src/common/bootstrap/validate.js 中通过 think.validate 方法对校验类型进行扩展

下面是一个完整的 logic 示例, 列举了一般开发中所需要的功能

// src/foo/logic/bar.js
// Logic 用于校验类(例如请求类型, 请求参数数据校验)的逻辑处理
// 与控制器里的 action 一一对应
// 系统在调用控制器里的 action 之前会自动调用 Logic 里的 action
export default class extends think.logic.base {
    indexAction() {
        // 验证请求类型
        this.allowMethods = 'get,post';
        // 自动校验, 如果有错误则直接输出 JSON 格式的错误信息
        // this.rules = {};

        let rules = {
            field1: {
                required: true, // 要去掉这个属性才能让参数变成不是必要的
                int: [10, 20], // 多个参数以数组形式传入
                // default: 20,
                post: true // 指定获取数据的方式
            }
        };

        // 验证请求参数
        let flag = this.validate(rules);
        // 验证通过返回 true
        if(!flag) {
            return this.fail('validate error', this.errors());
            // 在模版中显示错误
            // return this.display();
        }
    }
}

视图

视图配置可以在 src/common/config/view.js 中修改, 如果想每个模块有独立的视图目录,将配置 root_path 修改为空即可.

那么 http://127.0.0.1:8360/foo/bar.html 会去找 src/foo/view/bar_index.html

修改连接符

默认控制器和操作之间的连接符是 _, 文件名类似为 index_index.html, 如果想将控制器作为一层目录的话, 如: index/index.html, 可以将连接符修改为 file_depr: "/".

断点调试

在 VS Code(v1.7+)下断点调试, 设置调试配置后, 在源码中直接添加断点即可调试

配置

可以在不同的模块和不同的项目环境下使用不同的配置, 且这些配置在服务启动时就已经生效

可以在每个模块下定义不同的配置. 其中 common 模块下定义一些通用的配置, 其他模块下配置会继承 common 下的配置. 如: home 模块下的最终配置是将 commonhome 模块下配置合并的结果.

支持多种级别的配置文件, 会按如下顺序进行读取: 框架默认的配置 -> 项目模式下框架配置 -> 项目公共配置 -> 项目模式下的公共配置 -> 模块下的配置

默认支持 3 种项目环境, 可以根据不同的环境进行配置, 以满足不同情况下的配置需要. 项目里也可以扩展其他的环境, 当前使用哪种环境可以在 入口文件 中设置, 设置 env 值即可.

不同项目环境差异化配置一般不是很多, 所以放在一个文件中定义. 这时候如果要修改一个独立功能的配置, 就需要将独立功能对应的 key 带上. 如修改数据库配置需要将数据库对应的名称 db 带上.

扩展配置

项目里可以根据需要扩展配置, 扩展配置只需在 src/common/config/ 建立对应的文件即可, 例如: src/common/config/foo.js, 这样就可以通过 think.config('foo') 来获取对应的配置了

模型

数据库配置和常用的CRUD 操作以及关联模型查询缓存

代码规范

  • 文件路径必须小写, 因为有些操作系统对文件路径不区分大小写, 有些又区分大小写, 因此统一必须小写
  • 不要使用 constrcutor 方法, 而是统一使用 init
  • 使用 async/await
  • 通过 Babel 编译来使用 ES6 语法开发

线上部署

上线前执行 npm run compile 命令,将 src/ 目录编译到 app/ 目录,然后将 app/ 目录下的文件上线

  • 使用 PM2 管理服务

    注意 pm2.json 中的 "cwd": "F:/tmp/thinkjs-demo" 路径必须使用 / 来分隔, 否则 PM2 启动会报错: Error: ENOENT: no such file or directory, uv_chdir

  • 使用 nginx 做反向代理

    同时最好设置 ThinkJS 禁止端口访问和关闭 ThinkJS 本身的静态资源处理

默认使用的 www/development.js 作为启动脚本, 因此你会发现通过 PM2 启动项目后, 修改 src 中的源码自动编译到 app 目录了, 就相对于代码已经重新部署生效了.

因此当你运行了 pm2 startOrReload pm2.json 后, 想修改为 www/production.js 作为启动脚本, 需要先 pm2 stop pm2.jsonpm2 delete pm2.json, 再修改 pm2.json 中的 script, 最后 pm2 startOrReload pm2.json 来重新启动, 否则你会发现修改了 script 没有效果, 还是用的以前的那份配置.

这样当你再修改 src 中的源码时, 需要手动 npm run compile, 然后还需要 pm2 startOrReload pm2.json 来重新部署.

Adapter

用来解决一类功能的多种实现, 如: 支持多种数据库,支持多种模版引擎等. 系统默认支持的 Adapter 有: Cache, Session, WebSocket, DB, Template.

Middleware

在请求处理中埋很多 hook, 每个 hook 串行执行一系列的 middleware, 最终完成一个请求的逻辑处理

建议使用追加的方式配置 middleware, 系统的 middleware 名称可能在后续的版本中有所修改

路径常量

系统提供了很多常量供项目里使用, 利用这些常量可以方便的访问对应的文件, 还可以通过入口文件启动文件在项目里定义额外的路径常量

常见问题

  • 如何修改服务监听的端口

    默认监听的端口为 8360, 可以通过配置文件 src/common/config/config.js 来修改: port: 1234

  • 并行处理

    使用 async/await 来处理异步时, 是串行执行的, 但很多场景下我们需要并行处理, 此时可以结合 Promise.all 来处理

  • 如何在不同的环境下使用不同的配置/如何跨模块调用/如何请求其他接口数据/如何输出图片/修改请求超时时间/如何捕获异常/如何忽略异常/如何开启 cluster/如何让 Action 只允许命令行调用/设置跨域头信息(CORS)/如何让用户登录后才能访问

更多资源

总结

ThinkJS 这么玩了一圈下来, 我们发现其实对于前端来说, 后端也没有想象中的那么难, 还能将 ES6/7 这样的新技术运用到项目中, 而不像在浏览器上随便用个什么新特性都畏畏缩缩, 担心兼容性问题, 何乐而不为呢?

如果你以前感觉前后端跨界似鸿沟般难以逾越, 现在借助 ThinkJS 这么智能的框架, 前端也可以很块上手做后端的开发, 什么接口, 什么访问数据库都是小 case. 况且基于 Node.js 平台从开发到上线到运维都已经很成熟了, 工具和生态圈都很完善而且很活跃, 大型互联网公司早就用于生产环境了, 这方面没有什么后顾之忧.

前端向后端迈进地主要的难点还是在于模型这一块, 对数据库比较陌生的前端多补补课, 把各种关联模型搞清楚, 不出几日已然就是全栈工程师了.

俗话说万事开头难, 最后我只想告诉大家: Node.js 已经彻底改变了前端, 扩大了前端的圈子, 每一个前端工程师都应该拿起这个有力的武器, 在这个前端最好的时代, 实现自己的理想.

班会第 33 期

  • 技术
    • 如何看待B站 (bilibili) 开源 HTML5 播放器内核 flv.js @Monine

      An HTML5 Flash Video (FLV) Player written in pure JavaScript without Flash.

      flv.js works by transmuxing FLV file stream into ISO BMFF (Fragmented MP4) segments, followed by feeding mp4 segments into an HTML5 <video> element through Media Source Extensions API.

      flv.js 做了三件事:

      • HTML5 原生仅支持播放 mp4/webm 格式,flv.js 实现了在 HTML5 上播放 FLV 格式视频
      • 使 Bilibili 网页端平滑过度到 HTML5 播放器,历史遗留不再是障碍
      • 对于视频直播,在 HTML5 上支持了延迟极低 HTTP FLV 播放,解开网页端直播对 Flash 的依赖
    • React 初学者教程

      • React 简介
      • 创建第一个 React 应用
      • React 中的组件
      • 在 React 中设置样式
      • 创建复杂的组件
      • 传递属性
      • 深入 JSX
      • 处理状态
      • 从数据到 UI
      • React 中的事件
      • 组件的生命周期
      • 在 React 中用 React Router 创建单页应用
      • 用 React 创建一个简单的 Todo List 应用
      • 在 React 中访问 DOM 元素
      • 设置 React 开发环境
  • 产品

如何写出一个好的 Web 页面

结合我自己的经验和体会, 总结了一些大方向上的指导意见, 主要是考虑一个页面做好后, 要方便以后的开发和维护工作

  • 命名

    主要是文件命名, class 命名, 变量命名, 可以先根据他们的职责, 取中文名, 再翻译成英文

    例如: 图片的取名最好不要用什么 img_09.png, 应该取个更有意义的名字, 不然以后连自己都不知道这个图片是用来做什么的了

    class 命名最好也不要用什么 div1 div2, 这样的名字太萌了, 会让人懵掉的

  • 模块

    应该将页面多个部分的样式分别写在多个 css 中, js 也是一样的, 这样每个文件的职责就会很清晰, 方便大家重用和维护

    例如: header.css/nav.css/banner.css... header.js/nav.js/banner.js...

    那么我们一般如何组织一个网站各个页面中的前端资源呢? 核心**其实很简单:

    • 一个网站一个全局的 CSS/JS 以及全局的基础库
    • 每个页面一个独立的文件夹用于放置页面特有的 CSS/JS/资源(图片字体等等)
    • 每个公共组件一个独有的 CSS/JS/资源

    至于为什么要这样组织前端资源, 关键在于代码的维护和共用, 大家协作的时候可以相对放心地修改页面的样式(CSS)或者逻辑(JS), 因为各个资源都限制在一定的作用域下, 不必害怕改动会产生预料之外的结果(例如修改了页面A的样式却影响到了页面B). 详细内容请参考网站项目目录结构规范

  • 组件

    如果需要用到通用组件, 先找开源的成熟组件, 基础样式最好基于开源的框架来做(例如使用 Bootstrap)

    例如: 焦点图/幻灯片组件, 就可以使用 swiper.js, 而非自己实现一个

    因为自己实现的可能有很多情况没有考虑在内, 使用起来不够灵活, 你写的这个组件就有可能变成一次性投入, 不利于大家重复使用

    因此关于组件的使用, 一般为先找已有的, 如果找到了但细节不满足, 可以考虑扩展, 最后还不满足, 才自己来实现

  • 细节

    注意细节, 严格要求每个页面的界面和交互, 站在用户的角度思考, 前端工程师应该是最具产品意识的

    一个页面做完后, 一定要反复测试反复检查, 考虑以下几个问题

    • 切图追求"像素完美", 可以参考前端工程师必备的PS技能——切图篇
    • 语义化, 最简单的办法就是看一个页面没有任何样式时是什么样子的, 是否结构清晰
    • 多分辨率下有问题吗? 做了响应式布局吗? 移动端适配吗? 在 PC 端和移动端显示都 OK 吗?
    • 页面加载的速度怎样? 是否需要优化? 常规的性能优化都做了吗? 让 PageSpeed 和 YSlow 给你一些优化建议
    • 页面有哪些公共部分, 是否可以提取出来作为组件, 又或是写一个通用组件让大家都可以使用
    • 精简最终实现的代码, 越少越好(但是不要走极端, 以便于维护扩展为准)
    • 如果需要与后端交互, 最好自己做好测试接口, 预先完成前端的逻辑
    • 考虑用自己的电脑做服务器, 发布出页面来让大家评审(code review), 以此相互学习
    • 考虑前端工程问题(例如如何发布到正式服务器上), 可以参考大公司里怎样开发和部署前端代码?
  • 规范

    HTML/CSS/JS 都有相应的成熟规范, 可以理解为多年实践中形成的最佳指南, 应该多参考这些规范, 最终形成自己的编码习惯

    最重要的莫过于 CSS 规范了, 推荐使用 BEM 规范 .block-name__elem-name--mod-name 来书写 CSS

    请参考我的前端之旅中的编码规范

  • 监控

    做完一个页面后, 不要以为工作就完成了, 大家应该学会用事实说话, 用数据说话, 确保我们的工作是有效果的(PV/UV 等指标), 因此需要在每个页面中添加统计代码(例如x度统计). 最好再加上事件跟踪代码, 用以评估功能的价值(例如某个按钮被用户点击了多少次).

欢迎大家聊一聊自己写页面的一些经验, 力求写出一个"完美"的页面

金星"完美"表情

班会第 2 期

  • 技术
    • AngularJS中scope基于原型链的继承

      A "child scope" (prototypically) inherits properties from its parent scope.

    • 用$scope还是用controller as

    • 抛开 React 学习 React

      • 更新整个应用的 state
      • 更新 DOM(根据应用当前的 state 来调用 render 函数)
      • state 作为中间媒介,简化了事件和 DOM 元素之间的交互, 而不是通过事件来直接操作 DOM
      • 简单的单向数据流(one-way data flow)的原则
    • Web 应用架构指南 | 5分钟学会五个前端框架

      辣么多的前端框架?!怎么学得过来

      • Backbone.js 2010.10
      • React 2013.03
      • Vue 2014.03
      • Angular 2 2016
      • Knockout 2010.06
      • Ember.js 2011.12

      万变不离其宗

      • 第一式: 学会编写组件

        相比较 Angular1 庞杂的概念而言, React 提出的组件模式简单, 但也很强大. React 的流行, 影响了整个前端框架所提供的开发模式 -- 倾向于提供组件化开发的方式

        将应用中的任何 UI 相关的部分都看成了一个个组件, 就如 HTML 标签一样

        按照 MVC 的思路解构组件!

        • M 绑定到 V: 数据更新, View 自动更新
        • V 绑定到 C: 绑定 DOM 事件
        • C 更新到 M
      • 第二式: 用组件搭积木

        • 小组件组合大组件, 分而治之
        • 子组件存在关联关系, 可以通过大组件来处理
        • 大组件通过属性, 注入配置和事件回调, 来控制小组件的行为, 响应小组件的事件
      • 第三式:把模块的 Template、Style、JavaScript、Images 放到一个目录下!

        • 使用组件名作为样式的命名空间
        • 样式使用预处理器, 采用嵌套的方式编写
        • 业务复杂时,按照业务切分为多个独立的单页应用
    • Web Animation 制作指南

    • 聊聊职场规划那些事儿

      • 尽量选择快速发展的平台,尽量选择行业的领头羊
      • 争取在自己的专业领域有所积累,然后再做扩展
      • 优秀说白了就是一种习惯一种坚持
      • 把工作当成是创业,不但要保质保量完成自己的份内之事,还要争取再多干一点事情
      • 永远不要把自己的幸福完全建立在自己的事业是否成功,赚的钱是否比别人多的基础之上,要逐渐接受多元化的幸福观。你的健康,你的家庭,你的亲人,你的好朋友,你的知识,你的品味,这些都是你获取幸福的地方,职场只是其中之一而已,保持心态平和很重要
    • 滚动条君请别来挤我的界面

    • 简约而不简单的蒙板展开动画

  • 产品

班会第 25 期

  • 技术
    • The elements of HTML

      A list of HTML and XHTML elements, past and present

    • Pano2VR 3D

      Create virtual tours and interactive 360º panoramas

    • 高效jQuery的奥秘

      • 缓存变量
      • 使用匈牙利命名法, 在jQuery对象前加$前缀
      • 请使用’on’
      • 精简javascript
      • 链式操作
      • 繁重的操作中分离元素 detach()
      • 使用子查询缓存的父元素
      • 必要时组合jQuery和javascript原生代码

      jQuery并非不可或缺,仅是一种选择。思考为什么要使用它。DOM操作?ajax?模版?css动画?还是选择符引擎?或许javascript微型框架或jQuery的定制版是更好的选择。

    • 聊聊JavaScript中的二进制数

      !~location.href.search('***')

      !~x的逻辑就是判断x是否为-1

      my god这逻辑真是逆天了,我还是劝大家直接写成 x !== -1多好啊

    • 知道这20个正则表达式,能让你少写1,000行代码

      • 校验密码强度
      • 校验中文
      • 由数字、26个英文字母或下划线组成的字符串
      • 校验E-Mail 地址
      • 校验身份证号码
      • 校验日期
      • 校验金额
      • 校验手机号
      • 判断IE的版本
      • 校验IP-v4地址
      • 校验IP-v6地址
      • 检查URL的前缀
      • 提取URL链接
      • 文件路径及扩展名校验
      • 提取Color Hex Codes
      • 提取网页图片
      • 提取页面超链接
      • 查找CSS属性
      • 抽取注释
      • 匹配HTML标签
    • WEB前端知识体系脑图

      • 2015-2016前端知识体系
      • [Web前端工程师]学习路径
      • [前端工程师]需要涉及的知识
      • 前端知识脑图
      • 前端测试工具
    • 论版本号的正确打开方式

      Consider a version format of X.Y.Z (Major.Minor.Patch).

      版本格式:主版本号.次版本号.修订号,版本号递增规则如下:

      • 主版本号:当你做了不兼容的 API 修改, 当主版本号递增时, 次版本号和修订号必须归零
      • 次版本号:当你做了向下兼容的功能性新增, 当次版本号递增时, 修订号必须归零
      •     修订号:当你做了向下兼容的问题修正

      注意事项

      • 进行新的项目开发时, 版本号从 0.1.0 开始
      • 主版本号为 0(0.y.z) 的软件处于开发初始阶段, 一切都可能随时被改变. 这样的公共 API 不应该被视为稳定版
      • 1.0.0 的版本号用于界定公共 API 的形成. 这一版本之后所有的版本号更新都基于公共 API 及其修改内容

      先行版本号(pre-release)及版本编译信息(build metadata)可以加到"主版本号.次版本号.修订号"的后面作为延伸

      • pre-release: 表示当前版本是一个不稳定的版本, 使用它时需要注意风险
      • 建议使用这种 <major>.<minor>.<patch>-<stage>.<num> 的形式, 其中 <stage> 一般选用: alpha、beta、rc, 对于标记部分的比较, 是根据 ASCII 字母表中的顺序来进行的

      一个典型的版本号发展示例

      • 0.1.0
      • 0.1.1
      • 0.1.2
      • ......
      • 0.16.0
      • 1.0.0-alpha.1
      • 1.0.0-alpha.2
      • 1.0.0-beta.1
      • 1.0.0-rc.1
      • 1.0.0
      • 1.0.1
      • ......
      • 1.1.0-alpha.1
      • ......
      • 1.1.0
      • ......

      版本号范围标记, 建议在写法上采用"通配符的写法"跟进每个小版本更新, 即书写为 1.x 表达的版本号范围 2.0.0 > 1.x >= 1.0.0

    • Node.js与io.js那些事儿

      Node.js创始人Ryan Dahl

      Ryan Dahl的经历比较奇特,他并非科班出身的开发者,在2004年的时候他还在纽约的罗彻斯特大学数学系读博士,期间有研究一些分形、分类以及p-adic分析,这些都跟开源和编程没啥关系。

      Ryan Dahl的生活方式就是接项目,然后去客户的地方工作,在他眼中,拿工资和上班其实就是去那里旅行。此后他去过很多地方,如阿根廷的布宜诺斯艾利斯、德国的科隆、奥地利的维也纳。

      Ryan Dahl经过两年的工作后,成为了高性能Web服务器的专家,从接开发应用到变成专门帮客户解决性能问题的专家。Ryan Dahl大致的感觉到了解决问题的关键是要通过事件驱动和异步I/O来达成目的。

      在他快绝望的时候,V8引擎来了。V8满足他关于高性能Web服务器的想象:

      • 没有历史包袱,没有同步I/O。不会出现一个同步I/O导致事件循环性能急剧降低的情况。
      • V8性能足够好,远远比Python、Ruby等其他脚本语言的引擎快。
      • JavaScript语言的闭包特性非常方便,比C中的回调函数好用。
      • 于是在2009年的2月,按新的想法他提交了项目的第一行代码,这个项目的名字最终被定名为“node”。
      • 2009年5月,Ryan Dahl正式向外界宣布他做的这个项目。2009年底,Ryan Dahl在柏林举行的JSConf EU会议上发表关于Node.js的演讲,之后Node.js逐渐流行于世。
    • 少写代码少填坑

      你应该只完成你真正需要的东西 —— 即你的用户真正需要的东西。在按钮上加一道光?别说道光,加康熙也不干。为了加社交按钮引入一堆第三方代码,同时破坏掉你的页面设计?将它们一脚踹开。用 JavaScript 定制用户的鼠标右键来显示一个自定义的模态对话菜单?代表月亮消灭它们

      这不仅仅是关于你引入代码来破坏 UX 设计的问题,你自己写的代码也必须要尽量减少。这里我提供一些观点会有帮助。我曾经写过一些不用写的代码,用在无障碍和响应式设计方面。结果却让我明白一个道理,灵活的、无障碍的 Web 正需要我们尽可能少去人为控制。只有不写的代码才永远都不需要重写

    • 99%的人都理解错了HTTP中GET与POST的区别

      GET和POST本质上就是TCP链接,并无差别。但是由于HTTP的规定和浏览器/服务器的限制,导致他们在应用过程中体现出一些不同。

    • 程序员福利:各大平台免费接口,非常实用

      • 快递接口
      • 多米音乐接口
      • soso接口
      • 阿里云根据地区名获取经纬度接口
      • 阿里云根据经纬度获取地区名接口
      • IP接口
    • 微信上最近很火很炫的广告是怎么实现的

      很明显,这个是一个原生开发的页面,而并不是HTML;但作为一个为广告主使用的页面,那就要能够根据需求灵活展示各种元素,必然需要较好的订制化特性。
      我脑子里一下想到了React Native,weex,微信是不是也是和这些一样的,通过javascript代码来渲染翻译原生页面展示的呢?

      fromAdXml — 一段xml,最最关键的信息来了,整个页面的meta data都在这里面!

      客户端订好若干模板,tableview的每一个cell是一个模板,广告主去组合这个即可

      无论如何,这种广告方式都是一个非常了不起的发明,可以确信,app端广告将正式进入原生时代!

      <?xml version="1.0" encoding="utf-8"?>
      
      <adxml>
        <adCanvasInfo>
          <pageID>1700002364</pageID>
          <id>2566</id>
          <canvasName>nike其他城市</canvasName>
          <sizeType>1</sizeType>
          <basicWidth>750</basicWidth>
          <basicRootFontSize>1</basicRootFontSize>
          <shareTitle>嘿,今天该你上场了!</shareTitle>
          <shareDesc>没错,就是你!立即一探究竟</shareDesc>
          <shareThumbUrl>http://mmsns.qpic.cn/mmsns/gFuZJlqxR6dJFiccZHiagg9l2ibIPClbic4wrylT8DKZaj06bg9sbRzSbw/0</shareThumbUrl>
          <shareWebUrl>http://mp.weixin.qq.com/tp/ad_detail_info?page_key=5b6cddf2c33149ccf8692fb1a3dde13a63e56cd068fd9d5e65c22f692fb134f3fbc37fb96e77abbf502ec59ca87ddfc4</shareWebUrl>
          <PageList>
            <Page>
              <backgroundCover/>
              <backgroundColor>#ffffff</backgroundColor>
              <componentItemList>
                <componentItem>
                  <pureImageUrl>http://mmsns.qpic.cn/mmsns/gFuZJlqxR6dJFiccZHiagg9l2ibIPClbic4wpEw5ySjbksLJiaAqcdeWicXw/0</pureImageUrl>
                  <imageHeight>750</imageHeight>
                  <imageWidth>750</imageWidth>
                  <paddingTop>0</paddingTop>
                  <paddingBottom>0</paddingBottom>
                  <paddingRight>0</paddingRight>
                  <paddingLeft>0</paddingLeft>
                  <type>41</type>
                  <name>头图</name>
                  <id>2566_2832_41</id>
                </componentItem>
                <componentItem>
                  <streamVideoUrl>http://wxsnsdy.tc.qq.com/105/20210/snsdyvideodownload?filekey=30280201010421301f02016904025348041022c56408ca857868ae7e28d5ca2457f50204011d47340400&amp;bizid=1023&amp;hy=SH&amp;fileparam=302c020101042530230204136ffd93020457a4387102024ef202031e8d7f02030f42400204045a320a0201000400</streamVideoUrl>
                  <streamDisplayType>1</streamDisplayType>
                  <streamVideoThumb>http://vweixinthumb.tc.qq.com/150/20250/snsvideodownload?filekey=30270201010420301e02020096040253480410ee035de565a944eabf9145f8098ecc7a020231130400&amp;bizid=1023&amp;hy=SH&amp;fileparam=302c020101042530230204136ffd93020457a4387102024f1a02031e8d7f02030f42400204045a320a0201000400</streamVideoThumb>
                  <streamDisplayWidth>750</streamDisplayWidth>
                  <streamDisplayHeight>421.875</streamDisplayHeight>
                  <paddingTop>0</paddingTop>
                  <paddingBottom>0</paddingBottom>
                  <paddingRight>0</paddingRight>
                  <paddingLeft>0</paddingLeft>
                  <type>62</type>
                  <name>流媒体视频</name>
                  <id>2566_2834_62</id>
                </componentItem>
                <componentItem>
                  <btnTitle>立即上场</btnTitle>
                  <fontSize>30</fontSize>
                  <fontColor>#000000</fontColor>
                  <btnJumpUrl>http://m.nike.com/cn/zh_cn/c/justdoit/national?cp=cn_brom_080616_u_GEN_AL_OLP_nwc_LM_02_SP_GC</btnJumpUrl>
                  <btnType>0</btnType>
                  <borderSize>2</borderSize>
                  <btnHeight>80</btnHeight>
                  <btnBgColorTheme>#ffffff</btnBgColorTheme>
                  <btnBorderColorTheme>#000000</btnBorderColorTheme>
                  <btnFontType>1</btnFontType>
                  <paddingTop>0</paddingTop>
                  <paddingBottom>20</paddingBottom>
                  <paddingRight>150</paddingRight>
                  <paddingLeft>150</paddingLeft>
                  <type>21</type>
                  <name>按钮</name>
                  <id>2566_2844_21</id>
                </componentItem>
              </componentItemList>
            </Page>
          </PageList>
        </adCanvasInfo>
      </adxml>
  • 产品

班会第 6 期

班会第 34 期

  • 技术

    • 我的 React Native 之旅 - 从前端到全栈和全端

      要想学好用好 React Native, 使用 React Native 来开发 App, 必须学会 Android 开发(Java) + iOS 开发(Objective-C/Swift) + React + Web 开发的部分技能(主要是 ES6/7 和 CSS Flex)

      因此你最好有如下的项目经验才能事半功倍

      • Web 前端, 使用 React 开发过至少一个项目
      • 会 Java, 开发过至少一个 Android 原生 App, 并上线到应用市场
      • 会 Objective-C/Swift, 开发过至少一个 iOS 原生 App, 并上线到应用市场

      想想是不是有点小激动呢, 这条路应该会很有趣, 但必然是一场艰难的冒险之旅.

    • interact.js

      drag and drop, resizing and multi-touch gestures

      • Dragging
      • Drag and drop
      • Snapping
      • Resizing
      • Multi-touch Rotation
      • Pinch-to-zoom
      • Use in SVG files
      • Tap, doubletap and hold
    • Fabric.js

      a powerful and simple Javascript HTML5 canvas library.

      Fabric provides interactive object model on top of canvas element, also has SVG-to-canvas (and canvas-to-SVG) parser

      You can then scale, move, and rotate these objects with the mouse

    • lining.js

      DOWN-TO-THE-LINE control for radical web typography

      In CSS we already have the selector ::first-line to apply style on the first line of element. But there is no selector like ::nth-line(), ::nth-last-line() or even ::last-line.

      即可以控制每一行文字的样式, 并可以使用动画, 让文字一行行显示出来

    • Tether

      A positioning engine to make overlays, tooltips and dropdowns better

      defining and managing the position of user interface (UI) elements in relation to one another on a web page. It is a tool for web developers building features that require certain UI elements to be precisely positioned based on the location of another UI element.

      如果你想让一个元素「贴住」另一个元素,那么用这个库吧。
      Bootstrap 的 Tooltip 依赖了这个库。

    • 构建可靠的前端异常监控服务-采集篇

      可采集的异常

      • 全局错误
      • Ajax 上下文
      • 操作上下文
      • 页面依赖
      • 浏览器数据

      理想美好,现实残酷,困难重重

      • 同源策略 & ‘Script error.’
      • (uglifyjs + combo) vs sourcemap
      • 节流
      • 跨域上报

      flextracker 是我基于上面所讲内容的一个简单实现,你可以根据自己的需求来重新封装。

    • 轻氧 - 聚焦知名互联网公司、团队或站点的专业资讯APP | Aotu.io「凹凸实验室」

      轻氧 是 凹凸实验室 一不留神上架了的一款互联网技术资讯APP,它囊括了众多知名互联网公司、团队及网站的资讯,让你能一口气把业界最优质的文章读完,只要你愿意。

      众多知名互联网公司、团队及网站的资讯

      做轻氧的『初心』本来就不是超越,而是在积累和探索

      • 从业务的层面来看,是为团队积累和探索一款APP从零到设计到上架的整个流程,为下一次(如果有的话)APP研发需求做好流程和技术上的准备。
      • 从专业技术的层面来看,我们是在努力拓宽自己的专业范畴,要知道凹凸这个团队的前身是前端团队,相对匮乏原生应用开发经验,如果团队技术的努力方向是多终端技术体系,是全栈,那末轻氧APP则是印证我们朝这个方向发展、具备全栈开发综合能力的结果。

      我们没有忘记O2的口号是:Open Oriented,所以「轻氧」年后将会开源,并配套一本总结整个APP项目从零到上架的书籍,记录着轻氧从无到有的套路和心法。希望能帮助到那些想了解和掌握Swift编程、Sketch设计、以及数据库架构及设计相关技能的同学们。

      两三个技术工程师包揽了从产品构思、基于 Flinto 的原型交互、基于 Sketch 的视觉设计(除了LOGO为一个视觉美眉支持外)、基于 Swift3.x 的编码实现,当然还有 LeanCloud 数据服务的应用,Linux 服务器运维,以及应用上架部署的所有工作。

    • Box2d – 用 JavaScript构建物理世界

      物理引擎 - Box2D box2dweb

      • 空间( world )
      • 刚体(body)
      • 材质(fixture)
      • 形状(shape)

      总之: 刚体=形状+材质。

      例如: 铅球=圆形 + 铁 ,书=方形 + 纸

  • 产品

我是一只小小的"爬虫"

互联网充满了丰富的数据, 如何将这些数据收集起来是门技术活. "爬虫"就是这门技术活的代名词, 一提到 TA, 你可能就想到了搜索引擎, 搜索引擎就是靠 TA 来发家致富的.

如果你也需要抓取数据, 就让我这只小小的"爬虫"来说点抓数据的实现思路吧, 主要针对 Web 页面和 APP 这两种类型.

实现思路

  • Web
    • 前端调用后端接口做渲染的页面, 通过浏览器 DevTools 来查看 Network, 分析前端代码的逻辑, 看你所需的数据是通过哪些关键的后端接口来提供的, 从而得知如何自动抓取数据
    • 后端直接渲染的页面, 则分析页面的 DOM 结构, 看如何解析出你所需的数据, 可以通过 headless browser(例如 PhantomJS) 或者类似 cheerioNode.js 库来解析页面的 DOM 结构
    • 微信中的一些页面不能直接在浏览器中打开, 需要先经过微信授权, 因此需要综合运用 Web 和 APP 中提到的方法, 也许还需要模拟下 User Agent
  • APP
    • 通过 Fiddler 代理机制嗅探出 APP 调用了哪些后端接口, 猜解数据
    • 如果涉及到请求参数做了签名(例如 signature=xxxx), 后端有签名验证, 则需要反编译 APP 提取出签名算法, 才能写自动化程序来抓取数据

参考实现

班会第 35 期

  • 技术

    • 我的 Flexbox 之旅

      借着通关了Flexbox Froggy 游戏, 让我们再稍稍了解下关于 Flexbox 布局的一些细节和要点.

      • Flexbox 布局的由来
      • Flexbox 的基础概念
      • Flexbox 相关属性速记
    • JavaScript 全栈工程师培训教程 @Monine

      我现在的技术方向,前端是 React,后端是 Node,时间都投入在这两方面。

      阮一峰老师整理的一份技术清单, 涵盖前端开发的历史和趋势, React 技术栈, Node 应用开发, 前端工程简介. 特别推荐《前端开发的历史和趋势》

      • 什么是前端(前端:针对浏览器的开发,代码在浏览器运行/后端:针对服务器的开发,代码在服务器运行)
      • 前端开发的历史演变(前后端不分 -> 前后端分离 -> 全栈工程师)
      • 前端MVC框架的兴起(Backbone -> Angular -> React)
      • 全栈工程师和全栈技能(单个程序员的生产力要求越来越高)
      • 前端开发的未来(现在基于 Web 的前端技术,将演变为未来所有软件的通用的 GUI 解决方案)
    • 前端技术体系大局观

      前后端分离的含义不只是前后端代码的分离,而是系统级的分离。

      前后端分离不是说前端工程师只需要关注浏览器或者App内的部分,由于系统级分离的需要,反而要更有全局意识,关注各种支撑系统的建设与发展。

      前端要有一整套独立的开发、线上服务与周边保障体系,从而更全面地支撑用户端业务的快速发展,并且实现跨业务线的技术资源横向复用。

      技术体系的线下层重点关注开发效率,基础设施层重点关注稳定性,保障层重点关注质量与可用性,业务层重点关注服务的全面性和可复用性。

    • Cordova 好久不见

      做过前端又做过 App 的, 大概都听过或者用过 Cordova, 知道通过 TA 可以让前端使用 Web 技术来开发 App, 而且是跨平台的, 只要开发一次, 就可以出来 iOS 版和 Android 版的 Hybrid App.

      就让我们一起入门下 Cordova 开发 App 的 Hello World.

    • ionic react-native和native开发移动app那个好

      • 跨平台特性

      • 开发方式

      • 功能支持

      • 性能对比

        开发水平很重要,html开发的app可能比原生的更快。主要还看开发人员的水平以及会不会优化

      • 优劣对比

        • ionic: 纯web思维,开发速度快,简单方便,一次编码,到处运行,如果熟悉web开发,则开发难度较低。
        • react-native: 开发人员要求较高,不是懂点web技术就行的. 从Native到Web,要做很多概念转换,学习曲线偏高
    • React 技术栈系列教程

      • ES6
      • Babel
      • React
      • Webpack
      • React 项目脚手架
      • Flex 布局
      • CSS Modules
      • React-Router
      • Flux 架构
      • Redux 架构
      • Mocha 测试框架
      • Istanbul 覆盖率框架
      • React 单元测试
    • 双十一特辑 · 买买买的背后,电商如何做好前端优化? @Monine

      天猫前端 2015年双十一总结

      • 活动页面的性能优化

      • 天猫双11页面服务容灾方案大揭秘

      • 浅谈 React Native与双11

      • 大规模 Node.js 应用

      • 解密2015狂欢城

      • 大规模 Node.js 应用(续)

      • 如何精确识别终端

      • 双11密令红包的前端技术方案

      • vue+webpack在“双十一”导购产品的技术实践

        • 一套完整的图片工作方案

          图片的工作流程
          切图、测量(开发阶段)/上传和替换地址(打包阶段)/图片自动优化(代码运行阶段)

          一套完整的图片工作方案

      • 如何为用户省电

      • H5性能最佳实践

        班会第 15 期 的时候我们分享的就是这个 15年双11手淘前端技术巡演 - H5性能最佳实践

    • 在线JSON校验格式化工具和其他前端各种常用在线工具

      • JSON相关
      • 编码/加密
      • 格式化
      • 网络
      • 前端
      • 转换
      • 其他
      • 接口API
      • 文档
      • 平台工具
    • Content Security Policy 入门教程

      跨域脚本攻击 XSS 是最常见、危害最大的网页安全漏洞。为了防止它们,要采取很多编程措施,非常麻烦。很多人提出,能不能根本上解决问题,浏览器自动禁止外部注入恶意脚本?

      这就是"网页安全政策"(Content Security Policy,缩写 CSP)的来历,使用 CSP 防止 XSS 攻击。

      CSP 的实质就是白名单制度,开发者明确告诉客户端,哪些外部资源可以加载和执行,等同于提供白名单。它的实现和执行全部由浏览器完成,开发者只需提供配置。CSP 大大增强了网页的安全性。攻击者即使发现了漏洞,也没法注入脚本,除非还控制了一台列入了白名单的可信主机。

      两种方法可以启用 CSP

      • 一种是通过 HTTP 头信息的 Content-Security-Policy 的字段

      • 另一种是通过网页的 <meta> 标签

        <meta http-equiv="Content-Security-Policy" content="script-src 'self'; object-src 'none'; style-src cdn.example.org third-party.org; child-src https:">
    • 软件架构入门

      • 分层架构(layered architecture)
        • 表现层(presentation):用户界面,负责视觉和用户互动
        • 业务层(business):实现业务逻辑
        • 持久层(persistence):提供数据,SQL 语句就放在这一层
        • 数据库(database) :保存数据
      • 事件驱动架构(event-driven architecture)
      • 微核架构(microkernel architecture, plug-in architecture)
      • 微服务架构(microservices architecture, service-oriented architecture SOA)
      • 云架构(space-based architecture)
    • Android 4.4 沉浸式透明状态栏与导航栏

      android:theme="@android:style/Theme.DeviceDefault.Light.NoActionBar.TranslucentDecor"

  • 产品

    • 要聊天,先付费

      "今年下半年,我就要毕业了。这个行业里,谁也不认识。到了新城市上班以后,估计平时也没有时间和渠道,拓宽社交圈。如果可以让我多认识一些行业内人士,我愿意付费加入。"

      人需要社交,我们需要有机会接触其他人。面对面地交谈是一种社交方式,互联网聊天又何尝不是呢。如果软件可以提供或营造一个高质量的社交渠道,当然可以收费。真实世界中,高档会所的会员费高达十万甚至几十万,还不是照样有不少人加入,他们是为了享受会所的服务吗,恐怕更多的还是看中会所提供的社交圈。

      因此,收费群的商业模式是可行的,背后有真实需求。而且,网络社交比传统社交更便宜。线下的社交活动,比如吃饭、出游、娱乐的成本都不低(考虑进时间成本就更是如此),相比之下,收费群的会员费并不贵,当然前提是提供良好的社交体验。

      人类的日常生活主要分布于三个空间:

      • 第一空间是居住空间(也就是家)
      • 第二空间是工作空间
      • 第三空间是休闲娱乐空间,在那里会见朋友、喝啤酒、谈天说地,享受人际交往的乐趣。典型的第三空间是咖啡馆、酒吧、美发店、露天啤酒店、桌球房、俱乐部这一类地方。"

      人的生活质量与这三个空间都相关。其中,第三空间的质量和逗留时间长短,决定了你的生活是否丰富多彩。当代社会的问题是,第三空间正在逐渐丧失。

      此前第三空间只被当作实体空间,现在我们终于可以说,网络也是第三空间,聊天群就是最好的例子。一个运行良好的聊天群,也可以对参与者的生活质量产生重大影响。

      我现在的认识是,社交需求是一个极大的市场,网络社交才刚刚起步,潜力无限,现有软件根本没有很好地满足这些需求。收费的聊天群,只是一个非常初级的应用,各方面都还很简陋。将来付费的网络社交将是常态,那些高质量社交群的会员费,一定是很贵的。

    • 时间管理的七句话

      • 进程切换非常昂贵,避免多任务,保持单进程。不要同时做多件事,结果可能都没做好,还拖长了工作时间。
      • 划分任务的优先级,不要把'急切'当作'重要'。你的时间有限,不可能做所有事。最重要的事,应该首先做。先做重要且紧急的, 再做重要不紧急的, 而且重心要放在重要不紧急的事情, 因为那就是未来的事情, 它们迟早会变成重要且紧急的, 如果你不保持关注, 往往会措手不及.
      • 早晨精力最充沛, 因此早点起床来做重要的事
      • 你没空时不会做的事情,有空了也不会做。那些没有时间也会去做的事,才是你应该全力以赴的人生方向
    • 什么是重要的事情?

      • 不要只盯着钱

        钱本身并不是生活的目的,你自己想干的事才是。钱就好比汽油,生活的目的不是为了获得汽油,而是为了让汽车加满油之后,去那些你想去的地方。

      • 创造更多的价值

        不要去想你怎样才能赚到钱,而要去想你对他人、对社会的价值在哪里。你要相信,如果你对社会是有价值的,你就一定能够赚到钱,虽然未必很多。

        任何真正成功的人生,都是为他人创造价值的人生;任何真正成功的企业,都是为客户创造价值的企业。

        我们的人生通过不断与他人进行双赢的价值交换,达到壮大自己和发展自己的目的;整个社会通过这样的交换,实现了繁荣和进步。

        紧盯着创造价值,并不意味盈利是不重要的。相反,它是非常重要的。如果赚不到钱,我们就无法满足生存的基本需要。这里面存在一个平衡问题。我们必须经常自省:我们得到了什么?我们又创造了什么?

      • 符合长期利益和整体利益

        你个人的成功是建立在你对集体的价值之上的,所以对你来说重要的事,往往对其他人也是重要的。除了你自己的立场,你还必须站在其他人的立场,判断某件事是否重要。

班会第 3 期

  • 技术
    • 淘宝首页性能优化实践

    • 了解HTML/HTML5中的download属性

    • JS函数式编程指南

    • CSS Filter Blend

    • 烤 Promise 串

    • 2016年的前端技术栈展望 @Monine

      React/Redux/ES6/npm/Webpack/测试/Lodash/Fetch/CSS 模块/JavaScript 同构/Electron

    • Houdini:也许是你从未听过的在CSS领域最令人兴奋的发展

      Houdini是一个新的W3C工作组,他们致力于让这些问题永远消失。他们计划通过引入一整套API来让开发者首次拥有扩展CSS的权利,并且会提供出一套工具来与浏览器的渲染引擎的样式与布局进行挂钩.

      每次我为一些全新的CSS特征编写文章或者构建一个demo,必然会有人在评论或者推特上说,“这真的很棒!不过我们可能未来十年都不会用到它们。”

      你并不能控制你的浏览器如何解析HTML和CSS也不能控制他如何把HTML和CSS转化成DOM和CSS对象模型(CSSOM)。你无法控制级联。你无法掌控浏览器如何在DOM里布局元素,如何在屏幕上绘制元素。你也无法控制合成器。唯一一个你可以全部控制的进程就是DOM。CSSOM部分开放

      想像一下如果你可以使用任何CSS属性,并且知道他们一定会生效,在每个浏览器里面表现都是一样,那么你的开发工作会变得多轻松。如果你今天就可以使用它们并且它们的性能表现的就像原生的CSS功能一样。而你所有需要做的就是从Github上面获取代码。这就是Houdini的梦想。这就是他们期望的未来。

      • CSS解析器API
      • CSS属性和值API
      • CSS Typed OM
      • CSS布局API
      • CSS绘制API
    • GitHub **区前 100 名到底是什么样的人?

      来认识下明星程序员是什么样子的, 认个脸熟, 面试的时候用得上 :)

    • 这些年,我们知道的那些pages平台

      如何选择代码托管平台托付你的博客

  • 产品
    • 为什么有些设计初衷很好,结果却很糟糕

      如何处理"会话已过期"的问题

    • UI动效的必备原则总结 @liuchuanfeng1

      • 功能性
        • 优化用户对界面的感知,使其感到更轻快更全面。
        • 引起用户的注意。
        • 提供(用户操作后的)视觉(功能)反馈,并为下一步的跳转做准备。
      • 物理性
        • 在一致的动画原则和物理的(符合物理定律的)UI模型基础上构建动画。
        • 定义屏幕和UI元件之间的空间相对关系,他们的相对高度,权重以及速度。
      • 趣味性
        • 在上面两个部分都满足的情况下,加入一些有趣的动画。
        • 使它感觉独特,能在诸多动画中能让人眼前一亮。
        • 娱乐用户,并让他们一想到动画就能想到该产品或者反之。

      cta.js animate any element ("action") onto any other element ("effect") on the page.

班会第 17 期

  • 技术
    • javascript实用代码片段

      • 元素是否位于当前视窗
      • 转义
      • 按字节截取字符串
      • 删除数组中指定值的项
      • for循环简写
      • 构造函数
      • 面向模块
      • 单例模式
      • 动画: 平移/正弦曲线/抛物线/圆周运动/矩形运动/弹动的小球
    • 浏览器跨域问题解决办法

      Cookie跨域/iframe跨域/ajax跨域

      • 片段标示符
      • window.name
      • 跨文档通信API - window.postMessage
      • JSONP
      • WebSocket
      • CORS
    • 数据类型和JSON格式

      从结构上看,所有的数据(data)最终都可以分解成三种类型:

      • 标量(scalar),也就是一个单独的字符串(string)或数字(numbers),比如"北京"这个单独的词。
      • 序列(sequence),也就是若干个相关的数据按照一定顺序并列在一起,又叫做数组(array)或列表(List),比如"北京,上海"。
      • 映射(mapping),也就是一个名/值对(Name/value),即数据有一个名称,还有一个与之相对应的值,这又称作散列(hash)或字典(dictionary),比如"首都:北京"。

      数据构成的最小单位原来如此简单!难怪在编程语言中,只要有了数组(array)和对象(object)就能够储存一切数据了。

      JSON的规格非常简单,只用一个页面几百个字就能说清楚,而且Douglas Crockford声称这个规格永远不必升级,因为该规定的都规定了。

      • 并列的数据之间用逗号(", ")分隔。
      • 映射用冒号(": ")表示。
      • 并列数据的集合(数组)用方括号("[]")表示。
      • 映射的集合(对象)用大括号("{}")表示。
    • 《javascript框架设计》

      之前人家写过的弹出层,富文本编辑器,语法高亮插件……你一个个的自己实现,这样你才能接触到之前碰不到的原生API与知识点。如弹出层有关垂直居中的CSS知识点,select穿透问题,富文本编辑器用到的iframe知识点,Range与Selection对象的知识点,语法高亮则是你正则的大检验!

    • 唯快不破:Web 应用的 13 个优化步骤

      优化 Web 应用是一项费劲的工作。Web 应用不仅处于客户端和服务器端的两部分组件当中,通常来说也是由多种多样的技术栈构建而成:数据库,后端组件(一般也是搭建在不同技术架构之上的),以及前端(HTML + JavaScript + CSS + 转译器)。运行时也是变化多端的:iOS,Android,Chrome,Firefox,Edge。

      优化最难的地方就是如何在开发生命周期中最适当的时候去做优化。Donald Knuth 有一句名言:「过早优化乃万恶之源」. 因为一不小心就会浪费时间去优化某个 1% 的地方,但是结果却并不会对性能造成什么重大影响。与此同时,一些优化还妨碍了可读性或者是可维护性,甚至还会引入新的 Bug。

      优化不应当被认为是「意味着得到应用程序的最佳性能」,而是「探索优化应用的正确的方式,并得到最大的效益」

      盲目的优化可能会导致效率的丢失,而收益却很小。

      你最好的朋友就是分析工具:找到你可以进行通过优化获得最大程度改善的性能点,而不用损害应用开发的进程或者可维护性。

      程序员们浪费了大量时间来思考,或者说是担忧,他们的程序中非关键部分的运行速度。并且他们对于性能的这些尝试,实际上却对代码的调试和维护有着非常消极的影响。我们应当忘记那些不重要的性能影响

      • JavaScript 压缩和模块打包
      • 按需加载资源
      • 在使用 DOM 操作库时用上 array-ids
      • 缓存
      • 启用 HTTP/2
      • 应用性能分析
      • 使用负载均衡方案
      • 为了更快的启动时间考虑一下同构 JavaScript
      • 使用索引加速数据库查询
      • 使用更快的转译方案
      • 避免或最小化 JavaScript 和 CSS 的使用而阻塞渲染
      • 用于未来的一个建议:使用 service workers + 流
      • 更新:图片编码优化
    • 世界顶级Web性能专家教你优化出高性能网站

      邀请专家团回答了下面两个问题:

      • 如果只能选择一个方面进行Web优化,您会选择哪个方面?
      • 就Web性能而言,您看到哪些错误最常见?
    • 浏览器缓存知识小结及应用

      它分为强缓存协商缓存

      1)浏览器在加载资源时,先根据这个资源的一些http header判断它是否命中强缓存,强缓存如果命中,浏览器直接从自己的缓存中读取资源,不会发请求到服务器。比如某个css文件,如果浏览器在加载它所在的网页时,这个css文件的缓存配置命中了强缓存,浏览器就直接从缓存中加载这个css,连请求都不会发送到网页所在服务器;

      2)当强缓存没有命中的时候,浏览器一定会发送一个请求到服务器,通过服务器端依据资源的另外一些http header验证这个资源是否命中协商缓存,如果协商缓存命中,服务器会将这个请求返回,但是不会返回这个资源的数据,而是告诉客户端可以直接从缓存中加载这个资源,于是浏览器就又会从自己的缓存中去加载这个资源;

      3)强缓存与协商缓存的共同点是:如果命中,都是从客户端缓存中加载资源,而不是从服务器加载资源数据;区别是:强缓存不发请求到服务器,协商缓存会发请求到服务器。

      4)当协商缓存也没有命中的时候,浏览器直接从服务器加载资源数据。

    • 输入url到页面返回的全过程

      结合DNS、TCP和HTTP来详细地说一下输入url到页面返回的全过程

    • 非微信内置浏览器中的网页调起微信支付的方案研究

      ios内置浏览器中只要输入相关协议都可以调起相关app的, 比如:输入 weixin:// 可以调起微信, 输入 alipay:// 可以调起支付宝

      H5支付是基于公众号基础开发的一种非微信内浏览器支付方式

      微信给了一个官方的测试链接:http://wxpay.weixin.qq.com/pub_v2/pay/wap.v2.php,在手机浏览器中打开该页面,点击“立即购买”,就可以调起微信支付

      协议是这样的:weixin://wap/pay?appid%3Dwx2421b1c4370ec43b%26noncestr%3D3e84679af4efab5f32ee9ea01b2ec290%26package%3DWAP%26prepayid%3Dwx20160504154919fdacd7bc0d0127918780%26timestamp%3D1462348159%26sign%3DC40DC4BB970049D6830BA567189B463B

      上述a链接里的协议就是app支付里面的各种参数,因此可以得到结论,weixin://wap/pay 是微信定义的一种支付协议,用于网页端支付,微信app必定设置了名为weixin://的scheme,因此可以在网页上唤起微信app,在通过约定的参数名称,获取各种参数,从而可以完成支付,具体机制跟app支付是相同的

      至于上面一系列参数,是第三方网页端调用微信的统一下单接口那边获取的,均由第三方服务端处理,客户端不必关心。

      可以发现H5的支付协议中唯独少了partnerId,partnerId指商户ID,在注册微信支付时都会有。至于为什么没有商户id,猜测一是为了安全,另外第三方自家的网页,当然已知partnerId了(如京东的网页,京东在微信的商户id当然知道的),就没必要放到协议中去。

    • 我为何放弃Gulp与Grunt,转投npm scripts //

      随着时间的流逝,我发现诸如Gulp与Grunt等任务运行器都存在以下3个核心问题:

      • 对插件作者的依赖
      • 令人沮丧的调试
      • 脱节的文档

      在构建时我们为何会忽略掉npm-scripts

      • 认为npm scripts需要强大的命令行技巧
      • 认为npm scripts不够强大
      • 认为Gulp的流对于快速构建来说是不可或缺的
      • 认为npm scripts无法实现跨平台运行

      使用跨平台的命令

      && 链式任务(一个任务接着一个任务运行)
      < 将文件内容输入到一个命令
      > 将命令输出重定向到文件
      | 将一个命令的输出重定向到另一个命令
      
    • nginx 初入者手册

      翻译自: http://nginx.org/en/docs/beginners_guide.html

      • 启动,停止与重新加载配置
      • 配置文件的结构
      • 作静态内容服务器
      • 设置简单的代理服务
      • 设置 FastCGI 代理
    • 百度旅游预测

    • Clean Code: Writing Code for Humans

  • 产品
    • 马化腾内部讲座:我们希望的产品经理是从技术晋升而来的

      一:产品设计:核心能力要做到极致.

      关键词:核心能力、口碑

      核心能力不仅仅是功能,也包括性能。

      做产品要做到口碑就要关注高端用户、意见领袖关注的方向。

      每个功能不一定要用得多才是好,而是用了的人都觉得好才是真正的好。

      二:运营式管理:敏感才能找到不足

      关键词:天天用

      天天用你的产品, 要关注多个方面,经常去看看运营

      三:交互设计:做最挑剔的用户

      关键词:细致

      不强迫用户/操作便利/淡淡的美术/重点要突出

    • 移动互联网原罪:颠覆还是堕落

      互联网,特别是移动互联网已经融入我们的生活。我们通过网络来消费信息、社交、娱乐,发泄或产生情绪,组成我们的精神世界。同时,缺失的安全感和生活的不确定,也传递到互联网,利用着我们的「贪嗔痴」进行着各种网络行为构建。

      我们太多时候在互联网行业内,听惯了各种「时髦」的行业词汇,反而忘记了最原始的形态、本质的模式,以及底层的行为。浮躁的行业氛围也让我们更多的望着台上聚光灯下的辉煌,而却很少有人反过来看看台下的观众的情绪,以及他们的状态。

      移动社交流量:是分享还是传销

      从PC互联网到移动互联网,网络、服务、用户三者的关系在改变,移动互联网逐步的成为一种生活方式,而传统的生活场景在不断的转移到线上,并与线下相互影响。这种形态和PC互联网时代是有较大区别的,不仅仅从流量资源形态上(从入口型到去中心化类型),在用户行为与认知上也有较大的改变。

      移动流量生态变得更加复杂,以用户为节点的再分发模型,让社交流量成为主体形态。

    • 月入百万:移动互联网背后的罪与罚

      前言:这个故事通过对大量不同人物的经历的拼接和重构,来合成和展现小刘这个虚拟人物的互联网历程,其中的很多描述和操作,已经省略核心部分,同时几乎都已经完全失效,不管是为了法律和良心,还是就实际的成功率来讲,我都不得不说一句,请勿效仿。

班会第 29 期

  • 技术
    • JavaScript奇技淫巧44招

      • 首次为变量赋值时务必使用var关键字

      • 从数组中随机获取成员

        var items = [12, 548 , 'a' , 2 , 5478 , 'foo' , 8852, , 'Doe' , 2145 , 119];
        var randomItem = items[Math.floor(Math.random() * items.length)];
      • 获取指定范围内的随机数

        Math.floor(Math.random() * (max - min + 1)) + min;
      • 生成随机的字母数字字符串

        function generateRandomAlphaNum(len) {
            var rdmString = "";
            for( ; rdmString.length < len; rdmString  += Math.random().toString(36).substr(2));
            return  rdmString.substr(0, len);
        }
      • 打乱数字数组的顺序

        var numbers = [5, 458 , 120 , -215 , 228 , 400 , 122205, -85411];
        numbers = numbers.sort(function(){ return Math.random() - 0.5});
      • 数组之间追加

        var array1 = [12 , "foo" , {name "Joe"} , -2458];
        var array2 = ["Doe" , 555 , 100];
        Array.prototype.push.apply(array1, array2);
      • 类数组对象(例如 arguments)转换为真正的数组

        var argArray = Array.prototype.slice.call(arguments);
      • 验证是否是数字

        function isNumber(n){
            return !isNaN(parseFloat(n)) && isFinite(n);
        }
      • 获取数组中的最大值和最小值

        var  numbers = [5, 458 , 120 , -215 , 228 , 400 , 122205, -85411]; 
        var maxInNumbers = Math.max.apply(Math, numbers); 
        var minInNumbers = Math.min.apply(Math, numbers);
      • length = 0 清空数组

      • splice 删除数组元素

      • 使用 length 属性截断数组

      • 在条件中使用逻辑与或,逻辑或还可用来设置默认值,比如函数参数的默认值。

        foo == 10 && doSomething();
        foo == 5 || doSomething();
        arg1 = arg1 || 10;
      • 使用 map() 函数方法对数组循环

      • toFixed 保留指定小数位数

      • 浮点计算的问题

      • 通过 for-in 循环检查对象的属性

      • 提前检查传入 isFinite() 的参数

        isFinite(0/0) ;      // false
        isFinite("foo");     // false
        isFinite("10");      // true
        isFinite(10);        // true
        isFinite(undefined); // false
        isFinite();          // false
        isFinite(null);      // true,这点当特别注意
      • 避免在数组中使用负数做索引

    • 我是一只小小的"爬虫"

      抓数据的实现思路, 主要针对 Web 页面和 APP 这两种类型.

    • NodeJS 写的 csv 文件 Excel 打开是乱码

      在使用 Node.js 写一个包含中文内容的 csv 文件时, 用 UltraEdit 打开是正常的, 没有乱码. 但使用 Microsoft Excel 打开时, 就是一坨乱码.

    • 程序员、技术主管和架构师

      一个技术主管的 60% ~ 70% 的时间可能花在了开发任务分解分配、开发实践、代码审核和风险识别上,而余下的 30% ~ 40% 的时间则花在为了保障系统按时交付所需的各种计划、协作、沟通、管理上。

      技术主管即使在日常的开发实现中,重点的内容一般也不是放在某个具体的功能实现上。在完成了具体的开发任务评估、分解并分配后,技术主管应该负责设计整体代码的结构和规范、必要时引入能提高整个团队生产力的新工具,推广代码模板,总结最佳实践。

      优秀的程序员转入技术主管这个角色后,就很容易尝试控制设计和代码的实现,他们很难接受代码不按照他们希望的方式去编写,这个是他们作为优秀程序员一直以来的工作习惯,长此以往他们自身很容易变成整个开发团队的瓶颈,而团队里的其他成员却未能得到足够的锻炼和成长。

      最后,我们总结下技术主管的职责要求:

      • 技术职责
        • 代码规范制定和推广
        • 生产力工具研发和推广
        • 最佳实践总结和推广
        • 工作量评估
        • 任务分解、分配
        • 代码审核
        • 风险识别
        • 研发任务管理
        • 技术能力提升
        • 关键代码实现
      • 组织职责
        • 协调沟通
        • 招聘面试
        • 教练指导
        • 复盘总结

      架构师的能力模型

      架构师的能力模型

      除了技术主管的技术职责之外,架构师还需要站在更高的纬度去做关于软件系统的抽象和封装。如果技术主管的抽象和封装层次更多考虑的是语言函数、设计模式、代码结构等这一类的事务,那么架构师是站在整体软件系统高度,考虑不同子系统之间的交互关系、技术的合理性、需求的完整性、未来的演进可能性,技术体系发展与组织、产品商业诉求的匹配度。

      架构师还承担着在技术团队和非技术团队(例如:产品设计等团队)之间的接口作用,明确产品的边界,勾勒技术蓝图,协调不同技能的技术团队协作,完成最终的软件系统交付。这时架构师的角色就像服务化架构中的 API,定义了协作规范、交互协议和方式,但并不会聚焦在具体的实现上。

      最后,我们还是总结下架构师的职责要求:

      • 技术职责
        • 继承技术主管的职责
        • 高纬度的系统设计、抽象和封装
        • 产品技术蓝图绘制与关键技术决策
      • 组织职责
        • 继承技术主管的职责
        • 跨技术和非技术团队的接口协作

      舍得,舍得,没有舍就没有得。成为架构师会拥有一个更立体的知识、技能矩阵,这是你的得。获得了一个面,在某些点上必然面临被超越的结局。如果成为一名架构师好几年后,你居然还是团队里面编码最多,编程能力最强的人,其实这是一个失败的架构师,在教练和指导这个职责上已经完全的失败了。

    • 程序员不可不知的版权协议

      如何选择合适的开源协议?

      由于开源协议种类众多,作为普通人很难搞懂它们之间的区别,即便是常见的协议大家也不完全知道协议的内容,那么如何快速的选择一款适合自己的协议呢?

      帮助你选择一个合适的开源共享协议

      quick_choose

      知识共享协议(Creative Commons,也称为CC协议)也属于版权协议的一种,常用于数据、多媒体、网站、文章等内容,是作者保障自己权益的一道屏障。

      选择一个知识共享协议

      我的文章、原创图片等其他非代码内容一般会采用 知识共享 署名-非商业性使用-禁止演绎 4.0 国际 许可协议

      • 保持原文,不作修改
      • 明确署名,即至少注明
      • 商业用途可以联系本人,需要征得本人同意。
    • 用Node.js的CTO是写代码的,想看看他的经历么?

      我开始把眼光放的更长远,我不再把自己仅仅定位成一个前端工程师,而是会开始关心互联网的发展趋势与整体格局,关心产品从 0 到 1 诞生过程中的盈利模式,关心在产品迭代中工程师与运营多方参与的角度和结合的效率,关心工作流程和团队文化

      那么对于技术这个领域,我也开始去关注更多非前端的生态,不求精通只求通,我逐渐意识到自己可以创造的价值不再是仅仅前端页面的输出,这个价值不单单是指可以一己之力搭建一个完整的网站,而是有了前后的动手经验,能从更高的一个层次上去把握一个项目以什么样的形式去设计,以什么样的思路去迭代会更加的省时省力,这个省时省力其实能更好的促成产品,拿到商业目标,而有了这个意识,就能更好的配合产品经理实现他脑海中的想法,如果你认为是不切实际海阔天空的想法,没关系,来小成本验证一下,验证之后说不定就真的是海阔天空,自己的技术面和技术深度也得到了很大的拓展。

    • 携程数据库访问框架 Ctrip DAL by 携程技术中心

      随着企业规模扩张和业务量的急剧增加,作为系统核心的数据库相关开发也会经历一个由单一团队发展为多团队;由单机扩张到集群;由单数据库发展为多数据库;由采用单一数据库产品到多种数据库产品并存的过程。

      Ctrip DAL 支持流行的分库分表操作,支持Java和C#,支持Mysql和MSSqlServer。使用该框架可以在有效地保护企业已有数据库投资的同时,迅速,可靠地为企业提供数据库访问层的横向扩展能力。

      整个框架包括代码生成器和客户端。工作模式是使用代码生成器在线生成代码,通过DAL客户端完成数据库操作。生成器具有丰富的向导指引,操作简单清晰,既可以批量生成标准DAO,也可以在方法级别定制数据库访问。客户端则可以简单地通过标准的maven方式添加依赖。

      Ctrip DAL

    • iOS审核总被拒?腾讯教你提升iOS审核通过率!

      苹果在官网给出了截至2016年6月份应用被拒绝的十大条款(其中63%以上的应用被拒绝都是因为这10个条款)

      • 分析《苹果应用商店审核指南》的条款,结合过往提审被拒的案例,进行系统的测试设计,并输出成可落地的测试用例;
      • 在以上步骤的基础上,进行自动化分析,抽离出可自动化的模块(开发对应的自动扫描工具);
      • 将剩余的部分用例,组建专项的测试人员来进行验收;
      • App每次版本提审,通过以上测试验收后,才会正式提交给苹果审核;

      腾讯预审的探秘

      • ipa包的检查

        主要是确保ipa中info.plist、包/文件大小、icon规格、私有API、第三方SDK、64位等内容符合苹果要求,此部分的验收,腾讯预审团队已开发出自动化工具,通过自动扫描来完成;

      • 提审资源的检查

        主要是确保提交的应用截图、视频、AppIcon、应用描述等资源是符合苹果要求的,其中资源规格属性的验收,预审团队已开发出自动化工具,通过自动扫描来完成;但资源的内容、文案等部分内容的验收,还需要人工来审查;

      • 应用内容和功能的检查

        确保应用的内容满足苹果审核审核指南中安全、性能、设计、法律等章节的条款,通常需要覆盖安装、登录、IAP支付、公告、活动、邮件、icloud文件存储、美国VPN网络连通性、IPv6网络连通性等应用场景内容和功能,此部分的验收,全需要人工来审查;

      为了提高IEG苹果审核通过率,腾讯专门成立了苹果审核测试团队,打造出iOS预审工具这款产品。经过1年半的内部运营,腾讯内部应用的iOS审核通过率从平均35%提升到90%+。

      【一键扫描】只需提供ipa包、审核图片、审核视频、应用描述,即可在4小时内拿到一份完整的检测报告,定位问题的同时提供解决方案,助您成功通过审核。

  • 产品
    • 1分钟了解微信这5年是如何过来的

      微信团队的成员啃饼在他的公众号里分享了《微信,是怎么过来的(2010-2015)》,以较长的篇幅阐述了微信这5年的变化和成功之道。可能是**互联网近年来最好的「小成本测试」-->「寻找突破点」-->「大规模扩散」-->「谨慎商业化」的案例。

      微信商业化的三层架构

      • 最底层是微信的社交平台,它聚集了海量的用户,这是商业化的养分;
      • 第二层是开放公众平台,它连接所有的主体(服务和内容提供方),这是商业化的土壤;
      • 第三层是业务,包括游戏、支付业务、广告、O2O、电商、企业、硬件等,这是商业化的收成。

      产品逻辑始终保持

      连接一切,是微信一直以来的产品逻辑,不管是人与人的连接,还是人与公众号、与信息等对象。微信最早的版本,分别有4个功能:对话、通讯录、找朋友和设置,这4个核心功能,一直没有变过。

    • PPT装逼指南

      设计原则
      无论PPT怎么创新,也离不开最基本的设计原则:重复、对齐、对比、亲密。这四条原则出自美国设计师Robin Williams的科普书籍《写给大家看的设计书》

      色彩搭配
      一份美观的PPT,应该选取的柔和而不刺眼的颜色作为同一章节甚至整个PPT的主色调。同时,颜色搭配要有一定反差以便区分、辨识。另外,颜色要与内容主题相契合

      字体选择
      一个好的字体可以迅速的提高PPT的逼格,如果没有字体用,用微软雅黑也绝对强过宋体。通常来说无衬线字体(无笔锋,比如雅黑、黑体)比较扁平化,风格轻快,而衬线字体(有笔锋,比如“字体选择”所采用的字体)更加保守与古雅一些。

      内容排版
      PPT要大胆留白,当然,留白不是说不去设计,而是要在看上去内容很少的同时,让人感到更加舒服。同时,留白可以逼迫你去精简PPT页面内容。要知道,PPT不是让你在做演讲时去对着朗读的。

    • 有哪些 PPT 设计软件堪称神器,却不为大家所知道?

      有哪些软件堪称「神器」,却不为大众所知? | 知乎

班会第 37 期

  • 技术

    • 饿了么基于Vue 2.0的通用组件库开发之路

      Element 是由饿了么UED设计、饿了么大前端开发的一套基于 Vue 2.0 的桌面端组件库, 提供了非常多的基础组件, 适合 PC 端后台系统

      随着公司的业务发展,内部开始衍生出很多后台系统,UED 部门也接到越来越多的设计需求

      • 日渐增多的后台产品设计需求

      • 设计资源有限,没办法支持所有业务线

      • 公司内部诸多后台产品使用体验不一致

      • 设计一套后台支撑框架,提升后台系统的可用性和一致性

      • 套用此框架,即使没有设计师参与,也能让产品或开发设计出一套好用的后台系统

      Element 开发团队有一颗独苗啊...

    • blur-admin

      Angular Bootstrap Admin Panel Framework

      Mint version demo

    • 激发灵感! 26个令人印象深刻的纯CSS构建的Web项目

      • CSS 3D太阳系
      • 纯CSS实现的蒙娜丽莎画像
      • STAR WARS AT-AT步行者
      • CSS实现的3D 飞行器 X-wing
      • CSS实现的Pip-Boy游戏《辐射4》
      • 纯CSS泰姬陵
      • Alex制作的CSS雪橇犬
      • 500行纯CSS代码制作的一个平行停车应用
      • CSS实现的城市中正在行驶汽车的效果
      • CSS 3D Hartwig国际象棋(完全可玩版)
      • CSS 行走大象先生动画
      • 纯CSS Coffee App界面
      • 纯CSS实现的冰沙机APP
      • 零行JS代码实现的飞行游戏
      • CSS 月光之下
      • 900行CSS代码制作的狼动画
      • 纯CSS实现的韩国烧烤之夜。没有图像,没有任何的JavaScript
      • CSS实现的任天堂游戏机
      • 纯CSS实现的Ken Burns全屏效果
      • 纯CSS实现的快乐人物的动画效果
      • 纯CSS实现的理发店
      • 打开汽车后备箱的丰田钥匙
      • CSS实现的日历APP
      • CSS实现的复仇者联盟
      • CSS实现的图标动画悬停效果
      • 纯CSS实现的一只鸟
    • 既然写CSS很容易,那为什么大家还是把CSS写的那么烂呢?

      后端开发工程师:“虽然我已经完成新功能的开发,但是我弄乱了前端,不过你放心,我已经修好绝大部分,所以你前端只需要对细节进行微调,时间应该不会超过 30 分钟”

      于是我打开HTML文件,(吃惊地)发现到处都是弃用的HTML标签,而且丝毫没有考虑过响应式设计。深呼吸,(暗示自己),他们写的CSS肯定会稍微好点。然而在我打开CSS文件之后,发现(同样)到处都是类似固定(fixed)定位、清除左浮动、右浮动以及!important的代码,于是我慢慢的把鼠标绕在脖子上。(别拦我,让我死)

      (安慰自己),也许他们写出的代码不会一直这么糟糕,但是(在现实中)我几乎没见过后端工程师写出能用的前端代码的。也还好啦,写前端代码本来就不是后端工程师的职责所在。但是请后端工程师不要随便写一堆前端代码,然后指望前端工程师帮你擦屁股。

    • Sass: Directory Structures To Maintain Your Code

      介绍了多种文件夹结构来组织文件

    • multi-picker

      『为移动端而生』的自定义多级联动选择器,可处理各种类型的多级联动,例如城市联动,时间联动

    • 自定义微信中的域名提示

      我们在微信中打开网页时, 往下拉网页, 会在底部显示出网页的域名

      wechat-domain-tip

      那么问题来了, 是不是可以通过某种手段来自定义这个内容呢?

      研究发现, 通过限制内层元素滚动条的位置, 我们可以变向地达到"自定义微信中往下拉网页时显示的域名提示信息", 让用户看见我们覆盖的那一层内容, 而非微信原本显示的内容.

      overscroll-wechat-custom

      overscroll.html

      overscroll-wechat-qrcode

    • 前后端分离开发模式的 mock 平台预研

      前后端分离

      • 前后端仅仅通过异步接口(AJAX/JSONP)来编程
      • 前后端都各自有自己的开发流程,构建工具,测试集合
      • 关注点分离,前后端变得相对独立并松耦合

      开发流程

      • 后台编写和维护接口文档,在 API 变化时更新接口文档
      • 后台根据接口文档进行接口开发
      • 前端根据接口文档进行开发
      • 开发完成后联调和提交测试

      面临问题

      • 没有统一的文档编写规范,导致文档越来越乱,无法维护和阅读
      • 开发中的接口增删改等变动,需要较大的沟通成本
      • 对于一个新需求,前端开发的接口调用和自测依赖后台开发完毕
      • 将接口的风险后置,耽误项目时间

      解决方法

      • 接口文档服务器 -- 解决接口文档编辑和维护的问题
      • mock 数据 -- 解决前端开发依赖真实后台接口的问题

      前端 mock 方法回顾

      • 硬编码数据
      • 请求拦截 & mock 数据
      • 本地 mock 服务器
      • 代理服务器

      mock服务器

    • node爬虫之gbk网页中文乱码解决方案

      中文乱码具体是指用 node 请求 gbk 编码的网页,无法正确获取网页中的中文(需要转码)

      • 使用 superagent-charset 模块

        superagent-charset 模块包括了 superAgent 模块以及 iconv-lite 模块

      • 直接用 iconv-lite 模块进行转码

        是一个进行编码转换的模块(node 默认编码 utf-8)。需要 decode 的编码必须是 Buffer 类型。

        • 在 http 模块中使用
        • request 模块中使用

        iconv-lite 模块能配合 http 模块以及 request 模块使用,却不能直接和 superAgent 模块使用。因为 superAgent 是以 utf8 去取数据,然后再用 iconv 转也是不行的。页面是 gbk 编码的,res.text 已经是 decode 过了的结果,也就是说它已经被转换成 utf8 了,再转换成 buffer 出来的结果必然是不正确的。

    • 跟着老司机玩转Node命令行

      • commander 命令行输入和参数解析
      • inquirer 命令行进行交互,提供了用户界面和查询会话流程
      • chalk 美化命令行
    • 一道 JS 面试题引发的思考 @Monine

      ECMAScript 标准

      • 变量对象(variable object)
      • 活动对象(activation object)
      • 执行环境和作用域链(execution context and scope chain)
    • 是什么使一名好程序员变得伟大

      • 好程序员测试她的代码来确保它能正常工作

      • 伟大的程序员测试她的代码来确保它不会不工作

      • 好程序员积极协助设置代码约定

      • 伟大的程序员遵守代码约定,即使它们与她自己的习惯不符

      • 好程序员写简洁的代码

      • 伟大的程序员写简洁的代码,最后再整理一遍并为它撰写文档

      • 好程序员能独立解决问题

      • 伟大的程序员认识到她所在团队的专业知识的价值并在需要的时候充分挖掘团队的力量

      • 好程序员学习效率工具并将它们有效地用于简化她的工作流

      • 伟大的程序员自己定制工作来提高效率并改进她的工作环境和工作流

      • 好程序员评审她团队成员的代码来保证质量

      • 伟大的程序员在代码评审中给出详细的,合理的,建设性的评论来帮助与她一起共事的程序员,让他们在知识和专业领域上有所成长

    • 使用开源项目的正确姿势,都是血和泪的总结!

      简单来说:如果你的业务要求1000 TPS,那么一个20000 TPS 和50000 TPS的方案是没有区别的。有的人可能会担心我TPS不断上涨怎么办?其实不用担心,我们的架构会不断演进的,等到真的需要这么高的时候我们再来架构重构,记住:不要过早优化,过早优化是万恶之源 —— 《UNIX编程哲学》

      • 选:如何选择一个开源项目
        • 是否满足业务
        • 是否成熟
        • 运维能力
      • 用:如何使用开源方案
        • 深入研究,仔细测试
        • 小心应用,灰度发布
        • 做好应急,以防万一
      • 改:如何基于开源项目做二次开发
        • 保持纯洁,加以包装
        • 发明你要的轮子
        • 其实选与不选开源项目,核心还是一个成本和收益的问题,并不是说选择开源项目就一定是最优的方案,最主要的问题是:没有完全适合你的轮子!
    • 一起动手写一个 JavaScript 太空船游戏!

      • 需求确认
      • 功能探索
      • 分解任务
        • 制作原型图
        • 绘制事件列表
        • 画出组件图
        • 规定数据结构
      • 概念学习
        • 什么是 Canvas
        • 为什么不用 SVG
        • Flash 不高兴了
      • DEMO预研
      • 功能实现
      • 反馈
        • 注重功能,不要过于追求完美
    • 程序员提交代码的 emoji 指南——原来表情文字不能乱用

      程序员都爱 github,而许多程序员喜欢在 github 提交代码时加入 emoji 表情。 并不是程序员喜欢故意卖萌,而是添加了 emoji 表情的提交记录真的能包含很多有用信息,阅读体验非常棒。

      但是,emoji 表情在提交代码的时候也不能乱用,否则容易造成误解。因此开源项目 gitmoji 专门规定了在 github 提交代码时应当遵循的 emoji 规范

    • GraphQL

      A query language for your API

      graphql

      REST API 暴露多个 REST 路由,每个路由让你可以访问一个预定义的数据集(比如,/api/post、/api/comments 等等)。而 GraphQL 只暴露一个端点,让客户端可以通过这一个端点查询它所需的数据。

      就好像你要买很多东西,REST API 就是多次来回肉店、面包店、小卖部,而 GraphQL 就是给某人一个购物清单,然后把他送到这三个地方。

      GraphiQL

    • 值得订阅的 12 份优质前端期刊

  • 产品

    • 互联网盈利模式研习笔记1:流量变现

      流量是产生消费的重要因素。一般来讲,流量越大,可能产生的消费越多。

      • banner广告(典型案例:门户网站)

      • 匹配广告(典型案例:Google搜索、淘宝直通车)

        Google的搜索广告一般按照CPC(Cost Per Click,每次点击价格)的方式计价,也即,展现免费,产生有效点击才会收费。在Google的结果页面上,广告位数量是有限的,当有多个广告竞争同一广告位的时候,Google会通过广告本身的一些属性进行排名,排名的一个重要依据,是广告的出价。也即,在同等条件下,愿意花越多价钱的广告,被展现在结果页中的概率越大,从而获得有效点击的概率也就越大。这个机制强有力的放大了关键词匹配广告的盈利能力。

      • 社交广告(典型案例:Facebook、广点通)

      • 流量分发(典型案例:导航网站、各种“互联网入口”)

        除了广告之外,直接把流量导入某些网站,也是一个赚钱的好方法。国内最经典的案例,应该是导航网站hao123了。

      总结:流量变现模式的典型闭环, 流量变现模式的逻辑是:先获得大量的流量,然后在此基础上通过广告、流量分发等方式赚钱

      我们以360为例来说明一下这种模式的典型闭环。

      • 首先,大前提是国内的计算机用户普遍技术水平不高,网络环境又比较恶劣。
      • 其次,360通过免费的手段(当年瑞星怎么也想不通,杀毒软件免费?那还赚什么钱?)和“安全”的概念,用“360安全卫士”、“360杀毒”等产品积累了大量的用户,获取了强大的互联网入口,并且其入口足够的前置(直接安装在用户计算机上,且常驻)。
      • 然后,这些用户会产生大量的流量,360将它们导给360浏览器等产品(内置导航网站),然后通过广告和流量分发链接获利。

      最后,补充一下国内常见的使用“流量变现模式”盈利,或者辅助其他产品盈利的互联网产品:

      • 百度搜索广告、网盟广告
      • 去哪儿网搜机票酒店时看到的广告(很多与目的地有关)
      • hao123等导航网站
      • 360浏览器等各种浏览器
      • 豌豆荚、91助手等手机管理软件
      • 机锋市场等各种Android市场
      • 各种Android ROM

班会第 1 期

今天, 我们的学前班成立了.

各位学前班的同学们, 很高兴能和大家一起聊聊前端, 聊聊技术, 聊聊产品.

我们的班会时间定为: 每周五下午(16:00 - 16:30), 欢迎大家踊跃分享发表意(tu)见(cao).


班会第 11 期

  • 技术
    • AlloyTeam/Rosin

      Fiddler插件,协助开发者进行移动端页面开发调试,是移动端web开发、调试利器

      • 拦截 console, 支持复杂对象的 JSON 解析

        对于复杂对象,双击Object字符区域选中,然后右键, 复杂对象都会被转为JSON对象,生成一个JSON View

      • 脚本运行错误捕获

        javascript运行时错误信息捕获,并且支持跨域情况下的捕获

    • 解决 html2canvas 截取非视野内元素得到一片空白的问题

    • 移动端页面性能优化

      移动端页面性能优化总结

    • 移动端坑你没商量系列

    • 鲜有人知的css事实

      • The color Property Isn’t Just for Text
      • The visibility Property Can Be Set to “collapse”
      • The background Shorthand Property Has New Values
      • The clip Property Works Only on Absolutely Positioned Elements
      • Vertical Percentages are Relative to Container Width, Not Height
      • The border Property is Kind of Like Inception
      • The text-decoration Property is Now a Shorthand
      • The border-width Property Accepts Keyword Values
      • Nobody Uses border-image
      • There’s an empty-cells Property
      • The font-style Property Accepts a Value of “oblique”
      • word-wrap is the Same as overflow-wrap
      • border-radius属性可以使用'/'(斜杠)标签
      • 使用bolder、lighter相关关键字进行font-weight属性的定义
      • 关于outline-offset属性
      • 关于table-layout属性
      • vertical-align属性用在表格跟非表格中的时候表现不一样
      • 伪元素::first-letter比你想象中更灵活
      • 你可以在HTML class列表中使用无效字符作为分隔符
      • 动画重复的次数可以是带小数的值
      • 动画名称会在动画的简写方式中影响动画的使用
      • 使用样式选取元素列表中元素的范围
      • 伪元素也适用于一些空元素
      • 有些属性值在选择器中是不区分大小写的
    • Can I use webp?

      <img data-src="1.png" data-webp="1.png.webp" src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7">
      // 如何判断浏览器是否支持webp?
      var img = new Image();
        img.src = "data:image/webp;base64,UklGRjoAAABXRUJQVlA4IC4AAACyAgCdASoCAAIALmk0mk0iIiIiIgBoSygABc6WWgAA/veff/0PP8bA//LwYAAA";
        img.onload = img.onerror = function() {
          if(img.width === 2 && img.height === 2){
              //支持webp    
          }else{
              //不支持webp
          };
        };
    • HEAD

      A list of everything that could go in the of your document

    • 技术成长四个阶段需要的架构知识

      1. 从接受训练成为圣斗士,就像刚刚入门的初级工程师
      2. 到获得青铜圣衣打败暗黑圣斗士,就像中/高级工程师
      3. 到击败白银圣斗士,就像架构师
      4. 再到战胜十二黄金圣斗士救出自由女神雅典娜
    • 如何看待前端如此迅猛的发展态势?自己的技术栈又该如何选择?

      1. 保持对社区的关注
      2. 动手去解决实际问题
      3. 尝试寻找问题的本质
    • StuQ 专访|前端架构师CSS魔法:畅聊前端人生

      我在百姓网的日常工作包括:

      • 调研新技术、新工具,适时应用到团队中。
      • 制定代码规范,并通过工具来确保规范的执行。
      • 填补基础类库和业务开发之间的断层,提供工具库和 UI 框架,并编写文档,提升业务开发效率。
      • 优化构建流程和开发环境,提升业务工程师的开发体验。
      • 组织定期的技术交流会和不定期的技术分享……
    • Webrebuild主题演讲《十年》现场实录

      回首互娱重构的十年,大致分为四个阶段,网页制作,网页重构,技术指标探索,技能多元化。

      • 一专多长,专精重构的技能,根据所处环境培养其他的能力
      • 设计还原,充分沟通,挖掘深层次的意图,并关注理念还原,从而提升体验。
      • 结果导向,或者可以理解为数据导向,通过数据分析和用户调研来验证我们的工作价值
      • 识别重点,因为我们的工作应该以找到最能体现自我价值的工作为出发点的
      • 沉淀&分享,通过将经验沉淀为文档进行分享,提升个人影响力和团队能力
        五点收获与项目周期
    • 如何优雅地修改前同事的混乱代码?

      编程的本质是控制复杂性。 毫无疑问,混乱的代码增加了复杂性。如果对混乱的代码置之不理,直接在上面修改或者增加新功能,复杂性往往会与日俱增。因此,当发现项目代码开始变得混乱时,就应当保持警觉并采取措施,把混乱扼杀在萌芽阶段。混乱的代码是技术债务,即使不碰它也会产生利息。因为随着时间的推移,你会对这些混乱感觉越来越陌生。为了不让债务越来越多,你就应该及时去消除技术债务。消除混乱的方法通常有两种选择:重构(Refactoring)和重写(Rewrite)。

      重构和重写的共同目的是让混乱变得有序。 但它们有一些区别,下面我从几个方面来对比一下这些区别。这些区别不一定对所有系统都准确,但对大部分软件项目都是适用的。

      • 重构是渐进式的行为,每次只改变局部;而重写是侵入式的行为,一切都从头开始;
      • 由于重构每次只改变局部,可以更好控制混乱;而重写一开始就改变整体,更难控制;
      • 由于重构更好控制混乱,周期更短;而重写往往周期更长。
    • Deco IDE

    • Adobe Spark试用手记

      它包括三部分功能:Post(海报制作)、Page(页面制作)以及Video(视频制作),三者之间其实是相互独立的,在PC端可以通过统一的Web应用入口spark.adobe.com访问使用,每部分功能对应一个独立的可视化编辑器,但各自又有单独的IOS APP客户端。看上去更像是一个可视化媒体内容创作的套装,哪天说不定会增加其他的独立功能,例如Slide(幻灯片)。

    • 2015 年度新增开源软件排名 TOP 100

  • 产品

班会第 27 期

  • 技术
    • WeUI 1.0 正式发布

      WeUI 是一套同微信原生视觉体验一致的基础样式库,由微信官方设计团队为微信内网页和微信小程序量身设计,令用户的使用感知更加统一。

      经过半年的打磨,WeUI 1.0 正式发布,主要是新增了一些常用组件,并使用 BEM 命名,为接下来的微信小程序开发做好准备

    • 微信公众号 · 小程序

      • 我的微信公众号小程序之旅
        最近微信公众号小程序实在太火爆了, 前面几天才开始内测, 各种尝鲜的文章已经遍布互联网了. 带着强烈的好奇心, 我也玩了一把, 将小程序开发文档翻了个遍.

      • 微信小程序开发环境搭建

        微信已于9月23号晚发布了最新微信公众号 | 小程序文档/工具下载,新版开发工具支持无appid登录开发者工具,所以可去官网直接下载使用。

      • 关于微信小程序(应用号)的全部看法

        张小龙在朋友圈这样说:

        什么是小程序:小程序是一种不需要下载安装即可使用的应用,它实现了应用“触手可及”的梦想,用户扫一扫或者搜一下即可打开应用。也体现了“用完即走”的理念,用户不用关心是否安装太多应用的问题。应用将无处不在,随时可用,但又无需安装卸载。

        我曾经将微信的发展阶段分为三个阶段:IM阶段浏览器阶段OS阶段。IM阶段的大招是语音通信和摇一摇,浏览器阶段的大招是订阅号,OS阶段的大招可能就是小程序

      • awesome-wechat-weapp

        微信小程序开发资源汇总

    • CSS 3D Panorama - 淘宝造物节技术剖析

      想象一下,当我们站在十字路口中间,身体不动,头部旋转 360°,这个过程中所看到的画面就形成了一幅以你为中心的全景图了。其实,当焦距不变时,我们就等同于站在一个圆柱体的中心。

      但是,虚拟世界与现实的最大不同是:没有东西是连续的,即所有东西都是离散的。例如,你无法在屏幕上显示一个完美的圆。你只能以一个正多边形表示圆:边越多,圆就越“完美”。

      同理,在三维空间,每个 3D 模型都等同于一个多面体(即 3D 模型只能由不弯曲的平面组成)。当我们讨论一个本身就是多面体(如立方体)的模型时并不足以为奇,但当我们想展示其它模型时,如球体时,就需要记住这个原理了。

      三维环境的球体

      全景图素材的制作分为设计类与实景类

    • paipaimo-base

      拍拍无线基础库

      • Zepto

      • Module

        • 模块加载器用于实现代码的模块化,打下工程化基础,在模块化以前,我们的代码结构松散,变量污染严重,非常不便于管理,因此我们需要借助一些工具来帮助我们规范我们的代码。
        • 类生成器主要是为了解决原始的构建类的方式太过简陋,缺乏一定的规范的问题,通过一个合理约束方法,可以统一我们实现类的方式,统一我们的风格。
      • Util

      • Components

        在我们平时开发的过程中会发现有很多的功能是通用的,为了实现同样的功能我们可能会到处去找之前的代码,引用或是直接拷贝,这就会造成代码冗余、结构混乱。所以我们需要将这些通用功能进行梳理,基于统一的规范,构建出一个能持续发展的组件库,在降低我们的开发时间、提升我们的开发效率之余为我们的开发工作提供更流畅的开发体验。

        分为UI组件和功能性组件两部分

        • cache
        • cookie
        • dialog
        • go_top
        • lazyload
        • mvvm(mvvm简易版)
        • overlay
        • pager
        • tab
        • toast
        • uri
        • validator
    • HaloJS

      HaloJS 是一款基于 Zepto 并采用 CMD 规范面向移动端提供各种实用工具的组件库

      • 基础模块
      • UI模块
      • 翻页模块
    • web font 终极解决方案

      • 中文字库

      • 下载字体

      • 字体转换(ttf -> woff)

      • fontmin

        第一个纯 JavaScript 字体子集化方案

      • 字体精简与压缩

    • 第一届前端体验大会 | 物勒工名

      春秋时期,对于工匠的要求极其严格,每件器具均需要刻上工匠的名字。更留下了“物勒工名,以考其诚,工有不当,必行其罪。”的要求,并在唐朝归入法典。后面也相继出现“工程师之戒”与“鸟巢留名”等事迹,都是人们对工匠精神最好的阐释。

      2007年由来自各大互联网企业的技术负责人创办WebRebuild协会。往后由相关的技术志愿者相继推动了九届分享大会。 2015年出于对科技未来的发展以及业界对于“重构”的认可度,组委会特此更名为前端体验大会。并继续秉承WebRebuild的宗旨,为技术人而生。

    • MAC全栈开发环境搭建指南

      目的只有一个:带你用MAC带你装逼带你飞!

      • 通用环境

        MAC通用开发环境秒搭,Homebrew、iTerm2、Sublime Text、oh-my-zsh...

      • 交互与设计

        其实内涵党的我们是不是只需要PS和Sketch是不是已经足够了呢

      • 前端开发

        Sublime Text的前端插件、Node-Static本地服务器、Gulp的各类常用前端插件...

      • 后台与部署

        Nginx、Mongodb、Strongloop、PM2

      • Markdown手册

      • 网络抓包

      • Nginx

      Awesome Mac 收集非常好用的Mac应用程序、软件以及工具,主要面向开发者和设计师

  • 产品
    • 大话程序猿VS产品狗

      总结产品的几大宗罪

      • 动不动就修改需求
      • 需求内容不够详细
      • 需求考虑不周全
      • 需求缺少数据依据
      • 项目流程不熟悉
      • 需求内容没有创新,跟着竞品的脚步
    • 简单梳理一下,如何确定产品的商业模式

      商业模式能够决定产品的一生,且在产品一出生时,它就设定好了。探索新世界的年轻产品人,花些时间研究它,就等于是在救产品的命。对产品来说,商业模式可以扮演成败萧何的角色。

      为产品定航向→为产品规划业务→积累自身资源→制定产品盈利模式→争取自由现金流→衡量产品投资价值

      商业模式的本质:“连接各利益相关者的价值”;

      为产品定航向是起点,为产品规划业务是核心,积累自身资源是关键,制定产品盈利模式和争取自由现金流是中间,衡量产品投资价值是归宿。

      其中产品业务以产品航向为目标导向,决定产品要进行的活动;自身资源支撑产品业务系统高效运行;产品盈利模式直接影响自由现金流能力;自由现金流能力可以体现产品价值,同时间接影响产品投资规模、收益持续增长能力。

班会第 9 期

  • 技术
    • 常用gulp插件介绍

    • 百万级访问量网站的技术准备工作

      • 开发语言
      • 代码版本管理
      • 服务器硬件
      • 机房
      • 架构
      • 服务器软件
      • 数据库
      • 文件存储
      • 程序
    • CDN缓存那些事

      CDN是什么?

      谈到CDN的作用,可以用8年买火车票的经历来形象比喻:

      8年前,还没有火车票代售点一说,12306.cn更是无从说起。那时候火车票还只能在火车站的售票大厅购买,而我所住的小县城并不通火车,火车票都要去市里的火车站购买,而从县城到市里,来回就是4个小时车程,简直就是浪费生命。后来就好了,小县城里出现了火车票代售点,可以直接在代售点购买火车,方便了不少,全市人民再也不用在一个点苦逼的排队买票了。

      CDN就可以理解为分布在每个县城的火车票代售点,用户在浏览网站的时候,CDN会选择一个离用户最近的CDN边缘节点来响应用户的请求,这样海南移动用户的请求就不会千里迢迢跑到北京电信机房的服务器(假设源站部署在北京电信机房)上了。

      HTTP Request and Response with CDN

      CDN的优势很明显:

      • CDN节点解决了跨运营商和跨地域访问的问题,访问延时大大降低;
      • 大部分请求在CDN边缘节点完成,CDN起到了分流作用,减轻了源站的负载。

      CDN缓存的缺点

      CDN的分流作用不仅减少了用户的访问延时,也减少的源站的负载。但其缺点也很明显:当网站更新时,如果CDN节点上数据没有及时更新,即便用户再浏览器使用Ctrl +F5的方式使浏览器端的缓存失效,也会因为CDN边缘节点没有同步最新数据而导致用户访问异常。

    • Choosing an HTTP Status Code — Stop Making It Hard

      HTTP-Status-Codes

    • Postman 调后端接口必备神器

      Postman

    • Android安全开发之浅谈密钥硬编码

      信息安全的基础在于密码学,而常用的密码学算法都是公开的,加密内容的保密依靠的是密钥的保密,密钥如果泄露,对于对称密码算法,根据用到的密钥算法和加密后的密文,很容易得到加密前的明文;对于非对称密码算法或者签名算法,根据密钥和要加密的明文,很容易获得计算出签名值,从而伪造签名。

    • 乐视秒杀:每秒十万笔交易的数据架构解读

      • 分库分表
      • 订单ID
      • 最终一致性
      • 数据库高可用
      • 数据分级
      • 粗细管道
  • 产品
    • 初创公司如何打造百万级用户产品?Teambition 的 Growth Hacking Ways

      Growth Hacking: 用探索的方式来做技术套利的事情, 即依靠技术和数据的力量,来完成各种营销目标,低成本或者零成本地让产品和用户获得有效增长

      数据分析是衡量一切后续产品改进或者 Growth Hacking 结果的指标。这也正符合管理学大师彼得·格鲁克说过的:「If you can’t measure it,you can’t improve it.」

      海盗模型-AARRR

      • 获客(Acquisition):从网站等渠道获得到访的流量;
      • 激活(Activation):让用户真正理解产品,体会到产品迭代创新值并且愿意回来用;
      • 留存(Retention):用户再次使用,并多次回访;
      • 推荐(Referal):让用户把产品传播给其他人;
      • 收益(Revenue):用户产生了付费行为,给产品带来收益。

      Growth Model 漏斗

      增长是最好的管理,许多公司都在做增长的事情,对增长的理解或许不尽相同,但核心永远都离不开:通过数据发现和创造更大的价值。

      优步总结自己最核心关注的数据是:乘客打车时手按下去后,专车到乘客面前的时间,这和滴滴关心的定单量截然不同。

      优化了这样一个很小的数据,就体现了这家公司的价值:优步让整个世界的交通效率提高了。

      所以,一家公司,特别是初创公司对数据的理解,是做好一切增长的前提,我们应该想明白公司最关注的数据是什么。

      因此,理解 Growth hacking 是基础,追逐前沿是投机,数据分析的种种方法均是手段,站在自己公司的角度,思量增长的核心,认清关键数据,把握产品价值,才是一家公司在着手做增长之前,更应该深入思考的问题。

    • 设计的7条心理学原则和定律

      • 冯·雷斯托夫效应: 某个元素越是违反常理,就越引人注目、令人难忘
      • 色彩心理学: 颜色可以影响情绪
      • 马斯洛需求层次理论

      马斯洛需求金字塔

      • 席克定律: 一人需要多久来做出决定。如果人们有更多选择,就需要更长的时间做出抉择
      • 面部辨识: 人们天生会被面部吸引——甚至我们能在没有人脸的地方看出人脸来
      • 费茨定律: 点击区域越大,就越容易被点到
      • 奥卡姆剃刀原理: 最简单的解决方法往往是最好的
    • 用户体验设计中的分步导航

我的 Flexbox 之旅

班会第 32 期中我们通过Flexbox Froggy 游戏对 Flexbox 布局有了一些了解, 感觉用起来确实很方便, 就是属性有些多, 而且需要相互配合, 如果不仔细体会每个属性的含义和作用, 就很容易搞混了.

因此借着通关了Flexbox Froggy 游戏, 让我们再稍稍了解下关于 Flexbox 布局的一些细节和要点.

flexboxfroggy-level-24


CSS Flexbox 布局是一种新的布局方式, 全称是 CSS Flexible Box Layout, W3C 标准文档 CSS Flexible Box Layout Module Level 1 中给出的介绍如下

CSS 2.1 defined four layout modes — algorithms which determine the size and position of boxes based on their relationships with their sibling and ancestor boxes:

  • block layout, designed for laying out documents
  • inline layout, designed for laying out text
  • table layout, designed for laying out 2D data in a tabular format
  • positioned layout, designed for very explicit positioning without much regard for other elements in the document

This module introduces a new layout mode, flex layout, which is designed for laying out more complex applications and webpages.


CSS3 Flexbox属性可视化指南

flex布局由被称为 flex container(flex容器) 的父容器和被称为 flex item(flex项) 的直接子元素构成

每个flex子元素沿着 主轴(main axis) 依次相互排列。 交叉轴(cross axis) 垂直于主轴。

  • 属性 flex-direction 定义主轴方向
  • 属性 justify-content 定义了flex子元素如何沿着主轴排列
  • 属性 align-items 定义了flex子元素如何沿着交叉轴排列
  • 属性 align-self 覆盖父元素的 align-items 属性,定义了单独的flex子元素如何沿着交叉轴排列

CSS Flexbox 相关属性速记

.flex-container {
    /* 主轴方向 row(水平横向)/column(垂直纵向) */
    flex-direction: row | row-reverse | column | column-reverse;
    /* 单行还是换行成多行 */
    flex-wrap:      nowrap | wrap | wrap-reverse;

    /* 主轴(main axis) */
    justify-content: flex-start | flex-end | center | space-between | space-around;
    /* 交叉轴(cross axis) */
    align-items:     flex-start | flex-end | center | baseline | stretch;

    /* 交叉轴存在多行时多余的空间 */
    align-content:   flex-start | flex-end | center | space-between | space-around | stretch;
}

.flex-item {
    /* 单个 flex item 覆盖 align-items 的值 */
    align-self:      flex-start | flex-end | center | baseline | stretch;
    /* 单个 flex item 的排列顺序 */
    order: ...-1 | 0 | 1...;
    /* 单个 flex item 占据多少空间 */
    flex: 1;
}

班会第 36 期

  • 技术

    • 前端工程模版

      通用规范

      注意事项

      • 所有的后端接口必须使用 backend-api.js 来调用
      • 所有的 APP 接口必须使用 ponto.js 来调用
    • Codelf(变量命名神器)

      There are only two hard things in Computer Science: cache invalidation and naming things.-- Phil Karlton

      twohardtings

      Search over projects from GitHub, Bitbucket, Google Code, Codeplex, Sourceforge, Fedora Project to find real-world usage variable names. API powerd by searchcode & youdao

      search2

      并提供 Codelf Chrome App, Codelf for Atom, Codelf for Sublime Text 插件

    • BEM — Block Element Modifier

      BEM is a highly useful, powerful, and simple naming convention that makes your front-end code easier to read and understand

    • 一套基于jquery或javascript的插件库

      包含轮播、标签页、滚动条、下拉框、对话框、搜索提示、城市选择(城市三级联动)、日历等组件

      jquerywidget

    • 腾讯 AlloyTeam 移动 Web 裁剪组件 AlloyCrop @px0078

      裁剪图片的应用场景有头像编辑、图像编辑,在移动端要配合手势以及进行触摸反馈来进行变形以确认用户的选区进行裁剪。AlloyCrop就是专注于裁剪图像的组件,目前服务于QQ相关的Web业务,今日正式对外开源

      在线Demo演示

    • Tesseract.js @Monine

      Pure Javascript OCR for 62 Languages(包括中文), 测试过识别图片手机号码和验证码, 识别率还是蛮高的

      Demo

      <canvas id="input_overlay" style="position: absolute;"></canvas>
      <img id="input">
      <p id="resultText"></p>
      <script src='http://cdn.rawgit.com/naptha/tesseract.js/1.0.10/dist/tesseract.js'></script>
      <script>
      input.onload = function() {
          // 第一次运行需要加载一个很大的语言样本训练包, 需耐心等待
          // 例如: eng.traineddata.gz 有 9M
          Tesseract.recognize(input)
                   .then(function(result) {
                       console.log('OCR', result.text, result);
                       // resultText.textContent = result.text;
                       resultText.innerHTML = result.html;
      
                       // 绘制识别结果中每个字的区域
                       // 参考: http://tesseract.projectnaptha.com/demo.js
                       input_overlay.width = input.naturalWidth;
                       input_overlay.height = input.naturalHeight;
                       var ioctx = input_overlay.getContext('2d');
      
                       result.words.forEach(function(w){
                           var b = w.bbox;
      
                           ioctx.strokeWidth = 2
      
                           ioctx.strokeStyle = 'red';
                           ioctx.strokeRect(b.x0, b.y0, b.x1-b.x0, b.y1-b.y0);
                           ioctx.beginPath();
                           ioctx.moveTo(w.baseline.x0, w.baseline.y0);
                           ioctx.lineTo(w.baseline.x1, w.baseline.y1);
                           ioctx.strokeStyle = 'green';
                           ioctx.stroke();
                       });
                   });
      };
      // 注意图片不能跨域, 否则需要做跨域设置
      // 如果直接加载跨域图片, 会报错
      // Uncaught SecurityError: Failed to execute 'getImageData' on 'CanvasRenderingContext2D': The canvas has been tainted by cross-origin data.
      input.src = 'ocr.gif';
      </script>
    • 2016 JavaScript 发展现状大调查 @Monine

      The State Of JavaScript

      • 代码风格(JS预编译语言): ES6成为了新的标准
      • 前端框架: 选择React准儿没错, Vue越来越火
      • 状态管理: Redux 是最火的
      • API层: GraphQL 看起来比较有前途, REST APIs 仍然是最广泛适用的
      • 全栈框架: 最主流的是Meteor和MEAN, 火起来的还有用React-Redux替代AngularJS的MERN框架。
      • 测试框架: 最主流的是Mocha和Jasmine
      • CSS 构建工具/预处理器: SASS/SCSS是主导, CSS Modules 值得一试
      • 构建工具: Webpack 和 Gulp最受欢迎, Grunt 已经过气了
      • 移动端框架: 原生应用还是最主流的解决方案, React Native 证明了它自己

      观点

      • 现在开发JavaScript有些过于复杂了
      • JavaScript的发展变化实在是太快了
      • JavaScript前途一片大好
    • 自学前端开发:代码之外需要关注的问题

      • 学好英语
      • 学会搜索/谷歌
      • 学会提问
      • 学习方式
      • 动手实践: 学而不练则忘
    • GraphQL,你准备好了么

      一个多月前,facebook 将其开源了一年多的 GraphQL 标记为 production ready,几乎同一时间,github 开放了其 GraphQL API 的 early access。两颗重磅炸弹先后落地,是否意味着已有五年多历史,和 facebook 的 news feed 几乎同时诞生的 GraphQL 将在接下来的日子里大放异彩,逐渐取代 REST API 的地位?

      • GraphQL 定义了一套完整的类型系统。服务器通过定义数据的类型告知客户端服务器的 capability,所以它也是一份 contract
      • REST API 体系本身及其各个 framework 都没有定义一套合适的类型系统,这就催生了很多零散的,不完善的实现,或者依托于类似于 swagger 这样的工具的实现。
      • GraphQL 定义了一套严谨的查询语言
      • REST API 在此毫无建树,基本上 API 的 querystring / body 没有太多章法可循,大家随遇而安

      由此,GraphQL 可以很容易地通过类型系统和用户定义的 schema 生成强大的验证工具,保证 query 是正确的,且满足服务器的 capability。

      GraphQL 很适合作为一层薄薄的 API gateway,成为客户端和各种内部系统(包括 REST API)的一个桥梁

    • 如何通过手机号初始化所属地区

      使用《中华人民共和国行政区划代码》国家标准(GB/T2260). 这部分可分为三个层次,从左到右的含义分别是:

      • 第一、二位表示省(自治区、直辖市、特别行政区)
      • 第三、四位表示市(地区、自治州、盟及国家直辖市所属市辖区和县的汇总码)
      • 第五、六位表示县(市辖区、县级市、旗).

      比如厦门市思明区的区划代码为:350203,可以通过简单的运算得出其省级代码为:350000(福建),市级代码为:350200(厦门)

    • SwitchHosts!

      管理、切换多个 hosts 方案的工具

      SwitchHosts capture

    • 还在用Android自带的WebView组件?太Out了!

      • 为何不直接使用内置的WebView组件?
        • 内存泄漏的问题
        • 在4.4以前的版本是WebKit的内核,4.4以后才换成chromium的内核,要考虑兼容以前的版本
      • 第三方可靠的WebView组件
        • Crosswalk

          Include the Crosswalk Project web runtime with your hybrid Android or Cordova / PhoneGap app, and users will consistently see it through a predictable, powerful WebView based on Google Chromium.

        • TBS腾讯浏览服务

          由腾讯QQ浏览器团队出品。支持“共享X5内核模式”和“独立下载X5内核模式”, TBS Android SDK(完整版)285KB 可独立下载x5内核,也可共享使用微信或手Q的x5内核, TBS Android SDK(精简版)194KB 不可独立下载x5内核,只能共享使用微信或手Q的x5内核

      • 最终我还是选择了TBS服务
        • 因为我不希望最终的APP体积突然增多了20M(Crosswalk需要整体打包进APP)
        • 小马哥的微信、手机QQ等APP在国内的装机量实在是太高了,而且能够支持以共享X5内核的方式,在自己的APP里面直接调用微信或手机QQ的浏览服务,我认为未尝不是一种好的解决方案。

      如何判断已经成功接入了腾讯的X5内核浏览服务呢?辨别是否使用x5webview的方法:

      显示网页文字时,可通过长按选择文字的标识判断,如下水滴状选择效果就是 x5webview 的标志

    • 如何在微信6.0.2+版本不接入微信API的情况下设置自定义分享内容(图片、链接、标题)

      微信在6.0.2及以上版本已经回收客户端自定分享的权限,而是以授权api的形式开放出来。有时候我们只想简单地自定义分享的title,分享的图片以及分享的链接时,而不想或者缺乏资源去接入微信api的时候该怎么实现呢?以下方法即可在微信6.0.2+版本自定义分享内容,不需额外引入微信的js文件

      • 设置分享title

        修改 document.title 值即可

      • 设置分享图片

        在页面隐藏一张尺寸大于290*290的图(图片需要容器包裹,设置容器css属性display:none即可)

      • 设置分享的链接

        修改 document.documentURI 的值即可(safari下,document.documentURI为只读属性,可借助history.pushState, 但此方法有一个弊端:就是复制当前页面url时,页面的链接就会是pushState设置的链接了)

      • 我们不能自定分享的描述内容(desc),默认使用了document.documentURI

      通过解压微信app(android),分析js源代码来了解微信api的运行原理

    • 如何开发一个App(Android)

      从整个大局去把握如何去构思一个app的开发,让你对独立开发一款app的时候有个理解

      这里只是提供一个如何开发一个app的思路, 从整个大局去把握如何去构思一个app的开发, 整个app开发流程是怎样的, 并不会介绍很多技术上的细节,但理解app流程对自己把握产品很有益处,虽然我们只是一个小小的开发者,但如果你有追求,哪天轮到你去负责一个产品的时候,你就应该对开发的每一个环节都了如指掌,因为出了问题,你也知道怎么针对性的去解决。笔者虽然只是一个小小的开发者,但也乐于思考,很多时候不太愿意被别人牵着鼻子走,因为我们的人生就应该把握在自己手里。

      • 开发环境
      • 开发工具
      • 模拟器
      • 产品开发流程
        • 产品规划,定产品方向
        • 需求调研,产出需求文档
        • 需求评审,修订需求文档
        • 产品经理(狗)画app线框图提供给设计(射鸡)师
        • 设计(射鸡)师根据线框图设计视觉稿
        • 程序(猿)根据视觉稿搭建UI框架
        • 程序(猿)根据需求文档开发功能
        • 测试(媛)编写测试用例,根据排期进行测试
        • 程序(猿)修复回归测试反馈的bug,提交beta版
        • 测试通过,提交给运营(喵)发布到渠道上线
      • 快速搭建项目
        • 定开发规范
        • 搭建UI框架
        • 选用开发库集成(或自造轮子)
        • 第三方服务集成(视情况而定)
    • StatusBarUtil 状态栏工具类(实现沉浸式状态栏/变色状态栏)

      这是一个为Android App 设置状态栏的工具类, 可以在4.4及其以上系统中实现 沉浸式状态栏/状态栏变色,支持设置状态栏透明度,满足你司设计师的各种要求

    • Android 启动页 (Splash) 的实现

      • 先显示一个界面,停留1~2s,然后跳转到另一个界面

      • 只显示一次启动页( App 没被 kill 的情况下)
        微信打开之后,按下返回键回到桌面,再打开微信,并不会再看到启动页(除非你手动清了微信的后台或者被系统 kill 了),这个是怎么实现的呢?其实很简单,只需要重写一下 MainActivity 的 onBackPressed() 方法就行

      • 全屏页面切换到非全屏页面的问题

        由于启动页一般是全屏显示的,而主页则不是,因此从全屏切换到非全屏就存在一个卡顿的问题. Android 全屏界面切换到非全屏界面的问题

    • iOS App上架流程(2016详细版)

      • 前言
      • 准备
      • 检查
      • 生成发布证书
      • 创建App IDs和绑定你的App的Bundle Identifier
      • 生成描述文件(描述文件的作用就是把证书和Bundle Identifier关联起来)
      • 在App Store开辟空间
      • 在Xcode中打包工程

      最后我只想说, 上架 iOS App 看样子非常费劲的说... :(

  • 产品

    • 我们现在能手把手帮您做Material Design设计了

      Material Design

      • Gallery ,您不妨把它理解成是设计师版的 GitHub 。有了它,人们就可以更轻松地上传、分享、评论设计方案
      • Remixer ,应用开发者可以用它来快速完成程序的可动原型
    • 打字速度

      两个目标

      • 盲打:常用字母和字符不需要看键盘就能打,减少编程时由于视线切换而造成的思路被打断
      • 快速:在盲打的前提下,打字速度快,这样在编程过程中思路更流畅,效率更高

      三个阶段

      • 初级:盲打每分钟超过20个单词
      • 中级:盲打每分钟超过40个单词
      • 高级:盲打每分钟超过60个单词

      我做的一分钟打字测试的结果

      1-minute-typing-test

班会第 5 期

我的 React Native 之旅 - 从前端到全栈和全端

Hello React Native, 我们终于见面了

首先我们来简单了解下什么是 React Native.

Build Native Mobile Apps using JavaScript and React

A React Native App is a Real Mobile App

With React Native, you don't build a “mobile web app”, an “HTML5 app”, or a “hybrid app”. You build a real mobile app that's indistinguishable from an app built using Objective-C or Java. React Native uses the same fundamental UI building blocks as regular iOS and Android apps. You just put those building blocks together using JavaScript and React.

  • React Native ScrollView
    • On iOS, a React Native ScrollView uses a native UIScrollView.
    • On Android, it uses a native ScrollView.
  • React Native Image
    • On iOS, a React Native Image uses a native UIImageView.
    • On Android, it uses a native ImageView.

React Native wraps the fundamental native components, giving you the performance of a native app, plus the clean design of React.

接下来我们要搭建 react-native android 的开发环境

以下所有尝试都是基于当时的最新版本: [email protected], [email protected], [email protected]

参考React Native Getting Started, 选择 Mobile OS 为 Android, Development OS 为 Windows, 按照教程一步步来操作即可完成开发环境的搭建.

主要需要安装的环境有

  • Node.js
  • Python2
  • react-native-cli
  • Android Studio

注意 Android SDK 可能还需要下载 API Level 23, 否则可能报错找不到对应版本的 Android SDK.

环境安装好后, 执行下面的命令来生成一个项目模版并运行 App

react-native init AwesomeProject
cd AwesomeProject
react-native run-android

React Native projects are essentially made up of an Android project, an iOS project and a JavaScript project, all combined under an npm package.

在搭建环境的过程中, 主要碰到了如下问题

  • failed to find Build Tools revision 23.0.1

    React Native on Android failed to find Build Tools

    要解决这个问题, 可以下载对应版本的 Build Tools, 或者修改 android/app/build.gradle 设置成你对应版本的 buildToolsVersion

  • Could not connect to development server

    React-native Could not connect to Development Server on android device

    由于我没有使用 Android 模拟器来运行 App, 直接使用的真机(Lenovo K50-t5/Android 6.0)来调试, 好像就会连接不上 react packager server.

    要解决这个问题主要参考GUIDES (ANDROID) - Running On Device.

    If you get a "bridge configuration isn't available" error, see the Using adb reverse section below.

    cd android/sdk/platform-tools
    adb reverse tcp:8081 tcp:8081
    

    在红屏错误界面摇动(Shake or press menu button for dev menu)下手机唤起开发者菜单, 选择 Reload, 终于成功看见 Welcome to React Native!

  • 修改 JS 代码后 reload 界面没有刷新

    [Windows] packager not update when change js file content

    you should increase "MAX_WAIT_TIME" variable (example : 360000) ;

    For the benefit of future Googlers, MAX_WAIT_TIME is located here :

    node_modules/react-native/packager/react-packager/src/node-haste/FileWatcher/index.js

    修改了 MAX_WAIT_TIME 后重启 react packager(在项目目录下执行 npm start)即可.

    最好在开发菜单中选择 Enable Hot Reloading, 这样每次修改代码后就会自动刷新界面了.

  • 如何给 Image 设置本地图片

    示例中看见, 一句话就搞定了, 但我 copy 过来却一直报错!

    <Image source={require('./img/favicon.png')} />

    搜索了下才明白, 好像只能 Restart the packager

    Error on load image on React-native: Unexpected character

    Images - Static Image Resources

    On Windows, you might need to restart the packager if you add new images to your project.

最后按照惯例, 我们将官方的 Doc 文档全部刷一遍

State

There are two types of data that control a component: props and state. props are set by the parent and they are fixed throughout the lifetime of a component. For data that is going to change, we have to use state.

Style

With React Native, you don't use a special language or syntax for defining styles. You just style your application using JavaScript. All of the core components accept a prop named style. The style names and values usually match how CSS works on the web, except names are written like backgroundColor instead of like background-color.

The style prop can be a plain old JavaScript object. You can also pass an array of styles - the last style in the array has precedence, so you can use this to inherit styles.

One common pattern is to make your component accept a style prop which in turn is used to style subcomponents. You can use this to make styles "cascade" the way they do in CSS.

React Native 的样式真心难写, 没有像 CSS 那样级联继承, 而且不是所有的组件都可以随便设置某个样式的, 例如 fontSize, 所以如果你需要设置字体样式, 就要给每个 <Text> 都设置一下才行, 好麻烦啊.

Height and Width

All dimensions in React Native are unitless, and represent density-independent pixels.

Layout with Flexbox

A component can specify the layout of its children using the flexbox algorithm. Flexbox is designed to provide a consistent layout on different screen sizes.

Flexbox works the same way in React Native as it does in CSS on the web.

Using a ScrollView

ScrollView works best to present a small amount of things of a limited size. All the elements and views of a ScrollView are rendered, even if they are not currently shown on the screen. If you have a long list of more items that can fit on the screen, you should use a ListView instead.

Networking

React Native provides the Fetch API for your networking needs.

You can also use the proposed ES2017 async/await syntax in a React Native app.

By default, iOS will block any request that's not encrypted using SSL. If you need to fetch from a cleartext URL (one that begins with http) you will first need to add an App Transport Security exception.

The XMLHttpRequest API is built in to React Native, you can use the XMLHttpRequest API directly if you prefer.

The security model for XMLHttpRequest is different than on web as there is no concept of CORS in native apps.

React Native also supports WebSockets.

Using Navigators

Navigator provides a JavaScript implementation of a navigation stack, so it works on both iOS and Android and is easy to customize.

A scene is nothing other than a React component that is typically rendered full screen.

More Resources

Awesome React Native

  • Example Apps
  • Development Tools

Colors

  • supported formats
  • supported named colors

Images

As of 0.14 release, React Native provides a unified way of managing images in your iOS and Android apps.

Here are some benefits that you get:

  • Same system on iOS and Android.

  • Images live in the same folder as your JS code. Components are self-contained.

  • No global namespace, i.e. you don't have worry about name collisions.

  • Only the images that are actually used will be packaged into your app.

  • Adding and changing images doesn't require app recompilation, just refresh the simulator as you normally do.

  • The packager knows the image dimensions, no need to duplicate it in the code.

  • the image name in require has to be known statically.

  • Static Image Resources

  • Images From Hybrid App's Resources

    you can still use images that are already bundled into the app (via Xcode asset catalogs or Android drawable folder)

Background Image via Nesting

A common feature request from developers familiar with the web is background-image. To handle this use case, simply create a normal component and add whatever children to it you would like to layer on top of it.

Handling Touches

Tappable Components

  • TouchableHighlight
  • TouchableOpacity
  • TouchableNativeFeedback
  • TouchableWithoutFeedback

You can use "Touchable" components when you want to capture a tapping gesture. They take a function through the onPress props which will be called when the touch begins and ends within the bounds of the component.

Timers

  • setTimeout, clearTimeout

  • setInterval, clearInterval

  • setImmediate, clearImmediate

  • requestAnimationFrame, cancelAnimationFrame

  • requestAnimationFrame(): for code that animates a view over time.

  • setImmediate/setTimeout/setInterval(): run code later, note this may delay animations.

  • runAfterInteractions(): run code later, without delaying active animations.

Direct Manipulation

It is sometimes necessary to make changes directly to a component without using state/props to trigger a re-render of the entire subtree. When using React in the browser for example, you sometimes need to directly modify a DOM node, and the same is true for views in mobile apps. setNativeProps is the React Native equivalent to setting properties directly on a DOM node.

Debugging

In-app errors are displayed in a full screen alert with a red background inside your app. This screen is known as a RedBox. You can use console.error() to manually trigger one.

Warnings will be displayed on screen with a yellow background. These alerts are known as YellowBoxes. Click on the alerts to show more information or to dismiss them. You can use console.warn() to trigger a YellowBox.

debugging-warning

You can display the console logs for an iOS or Android app by using the following commands in a terminal while the app is running:

$ react-native log-ios
$ react-native log-android

To debug the JavaScript code in Chrome, select "Debug JS Remotely" from the Developer Menu. Than open a new tab at http://localhost:8081/debugger-ui in Chrome.

我们可以在 Chrome DevTools 的控制台中看见 console 信息

chrome developer tools

还能够像 Web 中那样下断点调试 JavaScript 代码

chrome developer tools js break

JavaScript Environment

  • ES6
  • ES7

Performance

iOS devices display 60 frames per second, which gives you and the UI system about 16.67ms to do all of the work needed to generate the static image (frame) that the user will see on the screen for that interval. If you are unable to do the work necessary to generate that frame within the allotted 16.67ms, then you will "drop a frame" and the UI will appear unresponsive.

For most React Native applications, your business logic will run on the JavaScript thread. This is where your React application lives, API calls are made, touch events are processed, etc... Updates to native-backed views are batched and sent over to the native side at the end of each iteration of the event loop, before the frame deadline (if all goes well).

  • Main thread (aka UI thread) frame rate
  • JavaScript thread frame rate

When running a bundled app, console.log statements can cause a big bottleneck in the JavaScript thread. So make sure to remove them before bundling.

There is a babel plugin that can remove all console.* calls. You need to install it first using npm install babel-plugin-transform-remove-console --save, and then edit (or create) .babelrc. Then it will automatically remove all console.* calls in a release (production) version of your project.

Each frame during this transition, the JavaScript thread needs to send a new x-offset to the main thread. If the JavaScript thread is locked up, it cannot do this and so no update occurs on that frame and the animation stutters.

Platform Specific Code

React Native provides two ways to easily organize your code and separate it by platform:

  • Using the Platform module: Platform.OS, Platform.Version, Platform.select()
  • Using platform-specific file extensions: BigButton.ios.js, BigButton.android.js

参考

  • React Native Android入门与实践

    GUIDES (ANDROID) - Native Modules

    由于官方文档举例使用的 ToastAndroid 本身就是一个已经存在的内置模块, 因此需要设置 canOverrideExistingModule

    @Override
    public boolean canOverrideExistingModule() {
        return true;
    }
  • React Native Express

    • Modern JavaScript
      • ES6
      • ES7
    • React Components
      • Component API
      • Lifecycle API
    • Core Components
      • View
      • Flexbox
      • Text
      • Image
      • ScrollView
      • ListView
    • Data Management
      • Component State
      • Redux
      • Realm
    • Persistence
      • AsyncStorage
      • Redux Persist
    • Networking
    • Animation
      • Animated
      • RN Animatable
      • Gestures
    • Boilerplates
    • Exercises
      • Todo List
      • Reddit
      • Uber

最后的感受是: 要想学好用好 React Native, 使用 React Native 来开发 App, 必须学会 Android 开发(Java) + iOS 开发(Objective-C/Swift) + React + Web 开发的部分技能(主要是 ES6/7 和 CSS Flex)

因此你最好有如下的项目经验才能事半功倍

  • Web 前端, 使用 React 开发过至少一个项目
  • 会 Java, 开发过至少一个 Android 原生 App, 并上线到应用市场
  • 会 Objective-C/Swift, 开发过至少一个 iOS 原生 App, 并上线到应用市场

从前端到全栈和全端

┏━━━━━━━━━━┓     ┏━━━━┓
┃Web 前端           ┃  → ┃ 后端   ┃
┃(HTML/CSS/JS)     ┃     ┃(Node.js)┃
┗━━━━━━━━━━┛     ┗━━━━┛
          ↓
┏━━━━━━━━━━┓
┃App 端             ┃↗  iOS
┃(React Native/Weex)┃↘  Android
┗━━━━━━━━━━┛

想想是不是有点小激动呢, 这条路应该会很有趣, 但必然是一场艰难的冒险之旅.

不用多久, 我就会升职加薪, 当上总经理, 出任CEO, 迎娶白富美, 走上人生巅峰.

班会第 26 期

  • 技术
    • Monine's blog

      @Monine 同学纯手工打造的 Vue Blog, 和学前班一样也是借用 github issues 做为博客系统

    • Angular 2.0 Final Release Now Live!

      2.0.0 (2016-09-14)

    • 图解7种耦合关系

      高内聚与低耦合

      内聚是从功能角度来度量模块内的联系,一个好的内聚模块应当恰好做一件事。它描述的是模块内的功能联系。

      耦合是软件结构中各模块之间相互连接的一种度量,耦合强弱取决于模块间接口的复杂程度、进入或访问一个模块的点以及通过接口的数据。

      要实现的功能。m1和m2是两个独立的模块,其中m2种会显示m1的输入,m1会显示m2的输入。很显然,m1和m2两个模块之间会有一些联系(耦合)

      根据耦合程度可以分为7种,耦合度依次变低。

      • 内容耦合: 最紧的耦合程度,一个模块直接访问另一模块的内容
      • 公共耦合: 一组模块都访问同一个全局数据结构
      • 外部耦合: 一组模块都访问同一全局简单变量,而且不通过参数表传递该全局变量的信息。外部耦合和公共耦合很像,区别就是一个是简单变量,一个是复杂数据结构。
      • 控制耦合: 模块之间传递的不是数据信息,而是控制信息例如标志、开关量等,一个模块控制了另一个模块的功能. 从控制耦合开始,模块的数据就放在自己内部了,不同模块之间通过接口互相调用
      • 标记耦合: 调用模块和被调用模块之间传递数据结构而不是简单数据
      • 数据耦合: 调用模块和被调用模块之间只传递简单的数据项参数。相当于高级语言中的值传递
      • 非直接耦合: 两个模块之间没有直接关系,它们之间的联系完全是通过主模块的控制和调用来实现的。耦合度最弱,模块独立性最强。子模块无需知道对方的存在,子模块之间的联系,全部变成子模块和主模块之间的联系。

      内聚也分很多种

      • 偶然内聚
      • 逻辑内聚
      • 时间内聚
      • 通信内聚
      • 顺序内聚
      • 功能内聚
    • 为什么我不喜欢「前后端分离」

      在 v2ex 引起了热烈的讨论

      前后端分离大概的意思就是后端只给前端提供数据,前端负责 HTML 渲染(可以在服务器渲染,也可以在浏览器渲染)和用户交互。

      为什么做前后端分离?

      • 如果不分离,前端对网站的控制力太弱,没有话语权。
      • 前端想要扩大势力范围。扩大了势力范围才有晋升的机会。
      • 当时前端能控制的,就是 CSS 和 JS 文件。连 HTML 都是放在后端的仓库的。因为 HTML 是由服务器输出的,用到的模板语言就是后端的。

      我认同的是「全栈工程师」

    • Web 开发不应该这么复杂

      回顾下从 2004 年开始, Web 开发经历了怎样的过程。

      我们对服务器渲染 HTML 的性能不是很满意,同时浏览器的性能进一步提高了,所以我们觉得可以把渲染放到浏览器上来做。

      浏览器从服务器得到一个空的页面,然后用 JS 启动这个页面。 JS 发起很多 API 请求。服务器接收 JSON ,输出 JSON 。所有的 HTML 渲染,由浏览器完成。

      但是呢,有两个问题:

      • 所以这些 JS 代码和 API 请求,让首页渲染,非常非常非常慢。
      • 所有内容,都无法被搜索引擎检索到。

      所以我们决定不用浏览器来渲染首屏了,让服务器来(回到老路子)。但是由于渲染逻辑我们不想做两遍,所以我们需要在服务器添加一个 JS runtime 来执行 JS 才行,这样浏览器端的渲染逻辑在服务器上也能跑起来了。

      康威定律说,软件产品的结构就是其创造团队的组织结构的镜像。

    • 不依赖 Gulp、Babel、WebPack,还能优雅地写代码吗?

      • 前端打包

      • 框架的兴起

        MVC 框架(如 Backbone.js) -> MVVM 框架(AngularJS), 此时的库都是不需要额外用 Grunt 做转译的。直到 React 的出现。需要把 JSX 翻译成 JS。此时 Grunt 大概也因为性能太低被 Gulp 取代了。

      • ECMAScript 的发展

        前端开始追新,一定要第一时间用上最新版的 JS 语法。但是即便是 Chrome 和 Firefox 也不可能那么快就支持最新语法。于是前端说,不过就是在 Gulp 里再加一道转译嘛,用 Babel 把 ES 2016 的语法转译成 ES 5 就好了。

      • DOM 不好用,换成虚拟 DOM

      • CSS 不好用,换成 CSS in JS

      • 浏览器支持的 JS 不好用,换成 ES 最新版语法,然后转译为浏览器支持的 JS

      • DOM Event 不用了,去新造一个 Event 机制。

      • Gulp 用得太多了 watch 很慢,于是加上了 hot module replacement

      实际上这些变化非常适合复杂的 Web 应用,然而 90% 的页面根本不是单页面应用好吗!

      能不能让我写一个 CSS 一个 JS 刷新一下就能看到效果!为什么我要花那么多时间来学习转译工具,以及解决转译过程中的各种问题。

      总感觉『弊大于利』。甚至有的时候觉得这是『没有问题,创造问题也要上』。

    • Hybrid APP架构设计思路

      Native(以Android为例)和H5通讯,基本原理:

      • Android调用H5:通过webview类的loadUrl方法可以直接执行js代码,类似浏览器地址栏输入一段js一样的效果

        webview.loadUrl("javascript: alert('hello world')");
      • H5调用Android:webview可以拦截H5发起的任意url请求,webview通过约定的规则对拦截到的url进行处理(消费),即可实现H5调用Android

        var ifm = document.createElement('iframe');
        ifm.src = 'jsbridge://namespace.method?[...args]';

      JSBridge即我们通常说的桥协议

      由于JavaScript语言自身的特殊性(单进程),为了不阻塞主进程并且保证H5调用的有序性,与Native通讯时对于需要获取结果的接口(GET类),采用类似于JSONP的设计理念:

      类比HTTP的request和response对象,调用方会将调用的api、参数、以及请求签名(由调用方生成)带上传给被调用方,被调用方处理完之后会吧结果以及请求签名回传调用方,调用方再根据请求签名找到本次请求对应的回调函数并执行,至此完成了一次通讯闭环。

      界面与交互(Native与H5职责划分)哪些由Native负责哪些由H5负责?

      这个回到原始的问题上来:我们为什么要采用hybrid模式开发?简而言之就是同时利用H5的跨平台、快速迭代能力以及Native的流畅性、系统API调用能力。

      • 总的原则是H5提供内容,Native提供容器

      • 关键界面、安全性要求比较高的界面、交互性强的的界面、UI变更的频率也不高的界面使用Native

      • 导航组件采用Native

        导航组件,就是页面的头组件,左上角一般都是一个back键,中间一般都是界面的标题,右边的话有时是一个隐藏的悬浮菜单触发按钮有时则什么也没有。

        再者,也是最重要的一点,如果整个界面都是H5的,在H5加载过程中界面将是白屏,在弱网络下用户可能会很疑惑。

        所以基于这两点,打开的界面都是Native的导航组件+webview来组成,这样即使H5加载失败或者太慢用户可以选择直接关闭。

      • 系统级UI组件采用Native

      • 默认界面采用Native

      设计H5容器

      • H5离线访问: 顾名思义就是将H5预先放到用户手机,这样访问时就不会再走网络从而做到看起来和Native APP一样的快了。

      • H5离线动态更新机制: 将H5资源放置到本地离线访问,最大的挑战就是本地资源的动态更新如何设计

      • Local Url Router

        对于H5的请求,线上和离线采用相同的url访问,这就需要H5容器对H5的资源请求进行拦截“映射”到本地,即Local Url Router

    • 哪个蠢蛋写的烂代码?

      你既可能是那个吐槽别人给你留下了麻烦,也可能是别人嘴里那个制造麻烦的人。

      最难的不是自己写代码,而是维护别人写的代码,在复杂的逻辑中找到某一个隐藏得很深的bug,或者在某个(些)位置添加一些代码以实现新的功能。你需要按照最初实现者的思路去理解,这往往是最难的,这个过程中非常让人容易产生挫败感和不良情绪。

      • 设计太复杂
      • 性能不好
      • 各种无法理解的逻辑

      其实有时候我们不理解的,不是人家用的差,而是我们的格调低。我开始收起我的傲慢,不会一上来就指责别人,对不甚了解的领域保持敬畏,以免看起来像个小丑。

      好的代码是什么样子的呢?

      Bjarne Stroustrup(C++之父)说:

      • 逻辑应该是清晰的,bug难以隐藏。
      • 依赖最少,易于维护。
      • 错误处理完全根据一个明确的策略。
      • 性能接近最佳,避免代码混乱和无原则的优化。
      • 整洁的代码只做一件事。

      Michael Feathers(《修改代码的艺术》作者)说:

      • 整洁的代码看起来总是像很在乎代码质量的人写的。
      • 没有明显的需要改善的地方。
      • 代码的作者似乎考虑到了所有的事情。

      可以感受到,对好的代码的理解有很多共通的地方:

      • 代码简单,代码意图明确,其他人才容易与你协作。
      • 可读性和可维护性要高。
      • 以最合适的方式解决问题。

      程序员有三种

      • 拿钱干活,不爽就换 - 程序员只是一份工作。
      • 只要能实现功能就好,学习进步太累了。
      • 热爱程序本身的人, 这些人可能只有1%, 他们有目标的写程序, 他们愿意思考, 愿意听取正确地/更好的方法, 他们会热爱学习新的东西。优秀的工程师在思考、重构

      明年的今天「其他」工程师还写一样的代码, 唯一不一样的是Ta老了一岁。

      进阶的经验

      • 多看书,多读其他人的博客,阅读优秀的开源项目的代码甚至语言本身的源代码. 看代码要思考别人为什么这样写
      • 想好了再开始写
      • 给自己提要求。实现过程中不断的提高要求,这个要求就是比你现有的能力要高一点点
      • 选择更强的队友。遇见什么样的人,就会变成什么样子的人
      • 对别人吐槽狠

      可能有一天, 看到一段代码,骂了句「哪个蠢蛋写的烂代码?」 结果git blame一看原来是自己写的。恭喜你,你进阶了!

    • 一家初创公司的 CTO 应当做什么

      像是技术问题,但是当你深入分析问题的本质时,你会发现它们实际上是人的问题

      主要工作是确保公司的技术策略服务于它的商业策略

      将它分解为五个特定的技能

      • 平台选择与技术方案设计

      • 把控全局(包括一些关键细节)

        CTO 是整个项目中能够了解整套技术方案能做什么不能做什么的人。这意味着了解什么可行,什么不可行,当前架构能支持什么,做不到什么,以及构建一个新功能在先有架构下要多长时间

      • 提供选择

        从不说 “这是不可能的” 或 “我们永远别这样做”。相反找到可选方案并且能够就这些方案与其他人沟通

      • 80/20原则

        找到一个获得 80% 好处而只要消耗 20% 成本的折衷方案

      • 培养技术 leader

  • 产品

我的 Vue.js 之旅

我的 Vue.js 之旅

写在 Vue.js 2.0 版本发布之后, 关于 Vue.js 2.x, 在实例的生命周期上我们就可以看出关键的不同点了: Virtual DOM

在底层的实现上, Vue 将模板编译成虚拟 DOM 渲染函数。结合响应系统,在应用状态改变时, Vue 能够智能地计算出重新渲染组件的最小代价并应用到 DOM 操作上

实例的生命周期

从 Vue 1.x 迁移

  • Vue 2.0 几乎 90% 的 API 和核心概念都没有变
  • 单向数据流(父 -> 子): props 现在只能单向传递. 父组件是使用 props 传递数据给子组件, 但如果子组件要把数据传递回去, 为了对父组件产生反向影响, 子组件需要显式地传递一个自定义事件而不是依赖于隐式地双向绑定.
  • 组件内修改 prop 是反模式(不推荐的)的, 因为根据渲染机制, 当父组件重新渲染时, 子组件的内部 prop 值也将被覆盖. 所以改变 prop 值可以用以下选项替代: 通过 data 属性, 用prop去设置一个data属性的默认值; 通过 computed 属性
  • 现在在组件上使用 v-on 只会监听自定义事件(组件用 $emit 触发的事件). 如果要监听根元素的原生事件, 可以使用 .native 修饰符
  • $dispatch 和 $broadcast 已经被弃用, 替代手段是通过使用事件中心, 允许组件自由交流, 无论组件处于组件树的哪一层. 由于 Vue 实例实现了一个事件分发接口, 你可以通过实例化一个空的 Vue 实例来实现这个目的
  • 移除了插入文本之外的过滤器: 现在过滤器只能用在插入文本中 ({{ }} tags)
  • 现在组件总是会替换掉他们被绑定的元素, 为了模仿 replace: false 的行为, 可以用一个和将要替换元素类似的元素将根组件包裹起来
  • 最佳实践: 使用 Vue.js 开发版, 多看控制台的警告信息 [Vue warn]

vue.js logo

数据驱动的组件,为现代化的 Web 界面而生

推荐先看下官网首页的 10 秒钟看懂 Vue.js, 是不是有点小兴奋了?

<div id="demo">
  <p>{{message}}</p>
  <input v-model="message">
</div>
var demo = new Vue({
  el: '#demo',
  data: {
    message: 'Hello Vue.js!'
  }
})

俗话说好记性不如烂笔头, 以下记录为我浏览了一遍 Vue.js 教程 1.0 后学习的笔记.

需要重点理解的章节有: 概述Vue 实例指令组件深入响应式原理, 过渡动画这一章非常实用.

概述

Vue.js(读音 /vjuː/, 类似于 view)是一个构建数据驱动的 web 界面的库。需要 IE9+ 及其他支持 ECMAScript 5 的浏览器

Vue.js 不是一个全能框架——它只聚焦于视图层。目标是通过尽可能简单的 API 实现响应的数据绑定组合的视图组件

Vue.js 拥抱数据驱动的视图概念。
通俗地讲,它意味着我们在普通 HTML 模板中使用特殊的语法将 DOM “绑定”到底层数据。
一旦创建了绑定,DOM 将与数据保持同步。每当修改了数据,DOM 便相应地更新。
这样我们应用中的逻辑就几乎都是直接修改数据了,不必与 DOM 更新搅在一起。
这让我们的代码更容易撰写、理解与维护。

MVVM

组件系统是 Vue.js 构建大型应用的基础,因为它提供了一种抽象,让我们可以用独立可复用的小组件来构建大型应用。
如果我们考虑到这点,几乎任意类型的应用的界面都可以抽象为一个组件树:

<div id="app">
  <app-nav></app-nav>
  <app-view>
    <app-sidebar></app-sidebar>
    <app-content></app-content>
  </app-view>
</div>

Component Tree

使用 vue-devtools Chrome 开发者工具扩展,可以更方便地调试 Vue.js 应用。

vue-devtools screenshot

Vue 实例

每个 Vue.js 应用的起步都是通过构造函数 Vue 创建一个 Vue 的根实例

一个 Vue 实例其实正是一个 MVVM 模式中所描述的 ViewModel - 因此在文档中经常会使用 vm 这个变量名

// vue 根实例
var vm = new Vue({
  // 选项
})

// 在实例化 Vue 时,需要传入一个选项对象,它可以包含数据、模板、挂载元素、方法、生命周期钩子等选项
// 可以扩展 Vue 构造器,从而用预定义选项创建可复用的组件构造器:
var MyComponent = Vue.extend({
  // 扩展选项
})
// 所有的 `MyComponent` 实例都将以预定义的扩展选项被创建
var myComponentInstance = new MyComponent()

更多的选项/数据

var data = { a: 1 }
var vm = new Vue({
  data: data
})

// 每个 Vue 实例都会代理其 data 对象里所有的属性
vm.a === data.a // -> true

// 设置属性也会影响到原始数据
vm.a = 2
data.a // -> 2

// ... 反之亦然
data.a = 3
vm.a // -> 3

注意只有这些被代理的属性是响应的。如果在实例创建之后添加新的属性到实例上,它不会触发视图更新。

受 ES5 的限制,Vue.js 不能检测到对象属性的添加或删除。因为 Vue.js 在初始化实例时将属性转为 getter/setter,所以属性必须在 data 对象上才能让 Vue.js 转换它,才能让它是响应的
在实例创建之后添加属性可以通过 $set(key, value) 实例方法让它是响应的。对于普通数据对象,可以使用全局方法 Vue.set(object, key, value)

var data = { a: 1 }
var vm = new Vue({
  el: '#example',
  data: data
})

// Vue 实例暴露了一些有用的实例属性与方法。这些属性与方法都有前缀 $,以便与代理的数据属性区分。
vm.$data === data // -> true
vm.$el === document.getElementById('example') // -> true

// $watch 是一个实例方法
vm.$watch('a', function (newVal, oldVal) {
  // 这个回调将在 `vm.a`  改变后调用
})

更多 Vue 实例属性

实例的生命周期 created/beforeCompile/compiled/ready/beforeDestroy/destroyed

Lifecycle

更多 Vue 全局 API

数据绑定语法

Vue.js 的模板是基于 DOM 实现的。这意味着所有的 Vue.js 模板都是可解析的有效的 HTML,且通过一些特殊的特性做了增强。

数据绑定最基础的形式是文本插值,使用 “Mustache” 语法(双大括号)。放在 Mustache 标签内的文本称为绑定表达式,由一个简单的 JavaScript 表达式和可选的一个或多个过滤器(以“管道符”指示)构成。

<!-- 插值 -->
<span>Message: {{ msg }}</span>
<!-- 过滤器 -->
<span>{{ msg | filterA 'arg1' arg2 | filterB }}</span>

<!-- 单次插值 -->
<span>Message: {{* msg }}</span>

<!-- 原始HTML -->
<span>Message: {{{ rawHtml }}}</span>

复用模板片断 partials

// 注册 partial
Vue.partial('my-partial', '<p>This is a partial! {{msg}}</p>')

<div><partial name="my-partial"></partial></div>

指令

指令的职责就是当其表达式的值改变时把某些特殊的行为应用到 DOM 上。

指令可以在其名称后面带一个“参数” (Argument),中间放一个冒号隔开。

修饰符 (Modifiers) 是以半角句号 . 开始的特殊后缀,用于表示指令应当以特殊方式绑定。

例如: v-bind:href.literal="/a/b/c" .literal 修饰符告诉指令将它的值解析为一个字面字符串而不是一个表达式。

更多 Vue 内置指令

v-bind

用于响应地更新 HTML 特性

例如: <a v-bind:href="url">link</a>

缩写: <a :href="url">link</a>

v-bind:class="{ 'class-a': isA, 'class-b': isB }"

v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"

当 v-bind:style 使用需要厂商前缀的 CSS 属性时,如 transform,Vue.js 会自动侦测并添加相应的前缀。

v-on

用于监听 DOM 事件

例如: <a v-on:click="doSomething">link</a>

缩写: <a @click="doSomething($event)">link</a>

<!-- 阻止单击事件冒泡 -->
<a v-on:click.stop="doThis"></a>
<!-- 提交事件不再重载页面 -->
<form v-on:submit.prevent="onSubmit"></form>
<!-- 修饰符可以串联 -->
<a v-on:click.stop.prevent="doThat"></a>

<!-- 添加事件侦听器时使用 capture 模式 -->
<div v-on:click.capture="doThis"></div>
<!-- 只当事件在该元素本身(而不是子元素)触发时触发回调 -->
<div v-on:click.self="doThat"></div>

<!-- 在监听键盘事件时,我们经常需要检测 keyCode。Vue.js 允许为 v-on 添加按键修饰符: -->
<!-- 只有在 keyCode 是 13 时调用 vm.submit() -->
<input v-on:keyup.13="submit">
<!-- 记住所有的 keyCode 比较困难,Vue.js 为最常用的按键提供别名: -->
<input v-on:keyup.enter="submit">
<!-- 全部的按键别名 enter/tab/delete/esc/space/up/down/left/right/单字母按键/自定义按键别名 -->
// 自定义按键别名, 可以使用 @keyup.f1
Vue.directive('on').keyCodes.f1 = 112

为什么在 HTML 中监听事件?
你可能注意到这种事件监听的方式违背了传统理念 “separation of concern”。
不必担心,因为所有的 Vue.js 事件处理方法和表达式都严格绑定在当前视图的 ViewModel 上,它不会导致任何维护困难。

实际上,使用 v-on 有几个好处:

  • 扫一眼 HTML 模板便能轻松定位在 JavaScript 代码里对应的方法。
  • 因为你无须在 JavaScript 里手动绑定事件,你的 ViewModel 代码可以是非常纯粹的逻辑,和 DOM 完全解耦,更易于测试。
  • 当一个 ViewModel 被销毁时,所有的事件处理器都会自动被删除。你无须担心如何自己清理它们。

v-if/v-for

v-if/v-show/v-else/<template v-if="ok">

<!-- 默认可以 $index 变量来获取索引 -->
v-for="item in items"
<!-- 自定义索引变量名 -->
v-for="(index, item) in items"

<!-- of 语法更接近 JavaScript 遍历器语法 -->
v-for="item of items"

<!-- 多个元素 -->
<template v-for="item in items">

<!-- 使用 track-by 特性给 Vue.js 一个提示,Vue.js 因而能尽可能地复用已有实例 -->
v-for="item in items" track-by="_uid"

<!-- 也可以使用 v-for 遍历对象。除了 `$index` 之外,作用域内还可以访问另外一个特殊变量 `$key` -->
v-for="(key, value) in object"
<!-- v-for 也可以接收一个整数,此时它将重复模板数次 -->
v-for="n in 10"

如果没有唯一的键供追踪,可以使用 track-by="$index",它强制让 v-for 进入原位更新模式:片断不会被移动,而是简单地以对应索引的新值刷新。这种模式也能处理数据数组中重复的值。

这让数据替换非常高效,但是也会付出一定的代价。因为这时 DOM 节点不再映射数组元素顺序的改变,不能同步临时状态(比如 <input> 元素的值)以及组件的私有状态。
因此,如果 v-for 块包含 <input> 元素或子组件,要小心使用 track-by="$index"

v-model

在表单控件元素上创建双向数据绑定。根据控件类型它自动选取正确的方法更新元素。

尽管有点神奇,v-model 不过是语法糖,在用户输入事件中更新数据

<!-- 表单控件绑定 -->
<input type="text" v-model="message" placeholder="edit me">

<!-- 在默认情况下,v-model 在 input 事件中同步输入框值与数据,可以添加一个特性 lazy,从而改到在 change 事件中同步 -->
<!-- 在 "change" 而不是 "input" 事件中更新 -->
<input v-model="msg" lazy>

<!-- 如果想自动将用户的输入保持为数字,可以添加一个特性 number -->
<!-- checkbox/radio/select 同样适用 -->
<input v-model="age" number>

<!-- debounce 设置一个最小的延时,在每次敲击之后延时同步输入框的值与数据。如果每次更新都要进行高耗操作(例如在输入提示中 Ajax 请求),它较为有用。 -->
<input v-model="msg" debounce="500">
<!-- 注意 debounce 参数不会延迟 input 事件:它延迟“写入”底层数据。因此在使用 debounce 时应当用 vm.$watch() 响应数据的变化。 -->
<!-- 若想延迟 DOM 事件,应当使用 debounce 过滤器。 -->
<input v-model="msg" v-on:keydown="doSomething | debounce 500">

<!-- 单个勾选框,逻辑值: -->
<input type="checkbox" id="checkbox" v-model="checked">
<!-- true/false -->
<label for="checkbox">{{ checked }}</label>

<!-- 多个勾选框,绑定到同一个数组: -->
<input type="checkbox" id="jack" value="1" v-model="checkedNames"><label for="jack">Jack</label>
<input type="checkbox" id="john" value="2" v-model="checkedNames"><label for="john">John</label>
<br>
<!-- 默认多个 checkbox 绑定到数组时, 数据类型为字符串(checkedNames: ['1', '2']), 如果需要数字类型, 应该添加 number 特性(checkedNames: [1, 2]) -->
<span>Checked names: {{ checkedNames | json }}</span>

<input type="radio" id="one" value="1" v-model="picked"><label for="one">One</label>
<input type="radio" id="two" value="2" v-model="picked"><label for="two">Two</label>
<br>
<!-- picked: 1 或者 picked: '1' 都可以 -->
<span>Picked: {{ picked }}</span>

<!-- select 单选 -->
<!-- answer: 2 或者 answer: '2' 都可以 -->
<select v-model="answer">
    <option value="1">A</option>
    <option value="2">B</option>
</select>

<!-- 多选(绑定到一个数组) -->
<select v-model="answer" multiple>
    <option value="1">A</option>
    <option value="2">B</option>
</select>
<br>
<!-- answer: [1, 2] 或者 answer: ['1', '2'] 都可以 -->
<span>Selected: {{ selected | json }}</span>

<!-- 值绑定 -->
<!-- 有时我们想绑定值到 Vue 实例一个动态属性上。可以用 v-bind 做到, 而且允许绑定输入框的值到非字符串值 -->
<input type="checkbox"
    v-model="toggle"
    v-bind:true-value="a"
    v-bind:false-value="b">
<!-- 当选中时,picked 为动态属性 a 的值, 而非字符串 "a" -->
<input type="radio" v-model="pick" v-bind:value="a">
<select v-model="selected">
    <!-- 对象字面量 -->
    <option v-bind:value="{ number: 123 }">123</option>
</select>

数组变动检测

Vue.js 包装了被观察数组的变异方法(修改了原始数组),故它们能触发视图更新
push/pop/unshift/shift/splice/sort/reverse

在使用非变异方法(filter/concat/slice)时, 可以直接用新数组替换旧数组

因为 JavaScript 的限制,Vue.js 不能检测到下面数组变化

  1. 直接用索引设置元素,如 vm.items[0] = {}
// 为了解决问题 (1),Vue.js 扩展了观察数组,为它添加了一个 $set() 方法
// 与 `example1.items[0] = ...` 相同,但是能触发视图更新
example1.items.$set(0, { childMsg: 'Changed!'})
  1. 修改数据的长度,如 vm.items.length = 0。

    至于问题 (2),只需用一个空数组替换 items。

除了 $set(), Vue.js 也为观察数组添加了 $remove() 方法,用于从目标数组中查找并删除元素,在内部它调用 splice()

有时我们想显示过滤/排序过的数组,同时不实际修改或重置原始数据。有两个办法:

  1. 创建一个计算属性,返回过滤/排序过的数组;
  2. 使用内置的过滤器 filterBy 和 orderBy。

计算属性有更好的控制力,也更灵活,因为它是全功能 JavaScript,但是通常过滤器更方便。

更多 Vue 内置过滤器

计算属性

模板是为了描述视图的结构。在模板中放入太多的逻辑会让模板过重且难以维护。这就是为什么 Vue.js 将绑定表达式限制为一个表达式。如果需要多于一个表达式的逻辑,应当使用计算属性。

computed: {
    b: function() {
        return this.a + 1
    },
    fullName: { // getter/setter
        get: function () {
            return this.firstName + ' ' + this.lastName
        },
        set: function (newValue) {
            var names = newValue.split(' ')
            this.firstName = names[0]
            this.lastName = names[names.length - 1]
        }
    }
}

计算属性不是简单的 getter。计算属性持续追踪它的响应依赖。
在计算一个计算属性时,Vue.js 更新它的依赖列表并缓存结果,只有当其中一个依赖发生了变化,缓存的结果才无效。
因此,只要依赖不发生变化,访问计算属性会直接返回缓存的结果,而不是调用 getter。

computed: {
    example: {
       // 由于计算属性被缓存了,在访问它时 getter 不总是被调用
       // 有时希望 getter 不改变原有的行为,每次访问 vm.example 时都调用 getter
       // 这时可以为指定的计算属性关闭缓存
        cache: false,
        get: function () {
            return Date.now() + this.msg
        }
    }
}

过渡

通过 Vue.js 的过渡系统,可以在元素从 DOM 中插入或移除时自动应用过渡效果。
Vue.js 会在适当的时机为你触发 CSS 过渡或动画,你也可以提供相应的 JavaScript 钩子函数在过渡过程中执行自定义的 DOM 操作。

<div v-if="show" transition="my-transition"></div>

transition 特性可以与下面资源一起用:

  • v-if
  • v-show
  • v-for (只为插入和删除触发)
  • 动态组件 (介绍见组件)
  • 在组件的根节点上,并且被 Vue 实例 DOM 方法(如 vm.$appendTo(el))触发

当插入或删除带有过渡的元素时,Vue 将:

  1. 尝试以 ID "my-transition" 查找 JavaScript 过渡钩子对象——通过 Vue.transition(id, hooks) 或 transitions 选项注册。如果找到了,将在过渡的不同阶段调用相应的钩子。
  2. 自动嗅探目标元素是否有 CSS 过渡或动画,并在合适时添加/删除 CSS 类名。
  3. 如果没有找到 JavaScript 钩子并且也没有检测到 CSS 过渡/动画,DOM 操作(插入/删除)在下一帧中立即执行。

CSS 过渡

<div v-if="show" transition="expand">hello</div>

<!-- 可以通过动态绑定过渡  -->
<div v-if="show" :transition="transitionName">hello</div>

类名的添加和切换取决于 transition 特性的值。比如 transition="expand",会有三个 CSS 类名:
.expand-transition, .expand-enter, .expand-leave。如果 transition 特性没有值,类名默认是 .v-transition, .v-enter 和 .v-leave。

  1. .expand-transition 始终保留在元素上。
  2. .expand-enter 定义进入过渡的开始状态。只应用一帧然后立即删除。
  3. .expand-leave 定义离开过渡的结束状态。在离开过渡开始时生效,在它结束后删除。

我们可以在过渡的 JavaScript 定义中声明自定义的 CSS 过渡类名。
这些自定义类名会覆盖默认的类名。当需要和第三方的 CSS 动画库,比如 Animate.css 配合时会非常有用:

<div v-show="ok" class="animated" transition="bounce">Watch me bounce</div>

Vue.transition('bounce', {
  enterClass: 'bounceInLeft',
  leaveClass: 'bounceOutRight'
})

Vue.js 需要给过渡元素添加事件侦听器来侦听过渡何时结束
基于所使用的 CSS,该事件要么是 transitionend,要么是 animationend。
如果你只使用了两者中的一种,那么 Vue.js 将能够根据生效的 CSS 规则自动推测出对应的事件类型。
但是,有些情况下一个元素可能需要同时带有两种类型的动画。
比如你可能希望让 Vue 来触发一个 CSS animation,同时该元素在鼠标悬浮时又有 CSS transition 效果。
这样的情况下,你需要显式地声明你希望 Vue 处理的动画类型 (animation 或是 transition):

Vue.transition('bounce', {
  // 该过渡效果将只侦听 `animationend` 事件
  type: 'animation'
})

JavaScript 过渡

可以只使用 JavaScript 钩子,不用定义任何 CSS 规则。
当只使用 JavaScript 过渡时,enter 和 leave 钩子需要调用 done 回调,否则它们将被同步调用,过渡将立即结束。

Vue.transition('expand', {
  // 为 JavaScript 过渡显式声明 css: false 是个好主意,Vue.js 将跳过 CSS 检测。这样也会阻止无意间让 CSS 规则干扰过渡
  css: false,

  beforeEnter: function (el) {},
  enter: function (el) {},
  afterEnter: function (el) {},
  enterCancelled: function (el) {},

  beforeLeave: function (el) {},
  leave: function (el) {},
  afterLeave: function (el) {},
  leaveCancelled: function (el) {}
})

渐近过渡

transition 与 v-for 一起用时可以创建近渐过渡。给过渡元素添加一个特性 stagger, enter-stagger 或 leave-stagger。
或者,提供一个钩子 stagger, enter-stagger 或 leave-stagger,以更好的控制:

<div v-for="item in list" transition="stagger" stagger="100"></div>

Vue.transition('stagger', {
  stagger: function (index) {
    // 每个过渡项目增加 50ms 延时
    // 但是最大延时限制为 300ms
    return Math.min(300, index * 50)
  }
})

组件

组件(Component)是 Vue.js 最强大的功能之一。
组件可以扩展 HTML 元素,封装可重用的代码。
在较高层面上,组件是自定义元素,Vue.js 的编译器为它添加特殊功能

var MyComponent = Vue.extend({
  // 在使用 template 选项时,模板的内容将替换实例的挂载元素。因而推荐模板的顶级元素始终是单个元素
  // 片断实例: 有未知数量的顶级元素,它将把它的 DOM 内容当作片断
  // 片断实例仍然会正确地渲染内容。不过,它没有一个根节点,它的 $el 指向一个锚节点,即一个空的文本节点
  // 片断实例组件元素上的非流程控制指令,非 prop 特性和过渡将被忽略,因为没有根元素供绑定
  template: '<div>A custom component!</div>',
  // 传入 Vue 构造器的多数选项也可以用在 Vue.extend() 中,不过有两个特例: data, el
  data: function() {
    return {a: 1};
  }
})

// 要把这个构造器用作组件,需要用 Vue.component(tag, constructor) 注册
// 全局注册组件,tag 为 my-component
Vue.component('my-component', MyComponent)

注意组件的模板替换了自定义元素,自定义元素的作用只是作为一个挂载点。这可以用实例选项 replace 改变。

不需要全局注册每个组件。可以让组件只能用在其它组件内,用实例选项 components 注册。这种封装也适用于其它资源,如指令(directives)、过滤器(filters)、过渡(transitions)和模板片断(partials)。

var Child = Vue.extend({ /* ... */ })

var Parent = Vue.extend({
  template: '...',
  components: {
    // <my-component> 只能用在父组件模板内
    'my-component': Child
  }
})

为了让事件更简单,可以直接传入选项对象而不是构造器给 Vue.component() 和 component 选项。Vue.js 在背后自动调用 Vue.extend():

// 在一个步骤中扩展与注册
Vue.component('my-component', {
  template: '<div>A custom component!</div>'
})

// 局部注册也可以这么做
var Parent = Vue.extend({
  components: {
    'my-component': {
      template: '<div>A custom component!</div>'
    }
  }
})

一些 HTML 元素对什么元素可以放在它里面有限制。常见的限制:

  • a 不能包含其它的交互元素(如按钮,链接)
  • ul 和 ol 只能直接包含 li
  • select 只能包含 option 和 optgroup
  • table 只能直接包含 thead, tbody, tfoot, tr, caption, col, colgroup
  • tr 只能直接包含 th 和 td

另一个结果是,自定义标签(包括自定义元素和特殊标签,如 <component>、<template>、 <partial> )不能用在 ul, select, table 等对内部元素有限制的标签内。
放在这些元素内部的自定义标签将被提到元素的外面,因而渲染不正确。对于自定义元素,应当使用 is 特性:

<table>
  <tr is="my-component"></tr>
</table>

使用 props 传递数据

组件实例的作用域是孤立的。这意味着不能并且不应该在子组件的模板内直接引用父组件的数据。

应该使用 props 把数据传给子组件。“prop” 是组件数据的一个字段,期望从父组件传下来。子组件需要显式地用 props 选项声明 props。

HTML 特性不区分大小写。名字形式为 camelCase 的 prop 用作特性时,需要转为 kebab-case(短横线隔开)

Vue.component('child', {
  // 声明 props
  props: ['msg'],
  // prop 可以用在模板内
  // 代码中可以用 `this.msg` 来获取
  template: '<span>{{ msg }}</span>'
})
<!-- 普通字符串, 传递了一个字符串 "1" -->
<child msg="1"></child>
<!-- 传递实际的数字  -->
<child :msg="1"></child>
<!-- 动态 props -->
<child v-bind:msg="msg"></child>
<child v-bind:msg="'hello!'"></child>

prop 默认是单向绑定:当父组件的属性变化时,将传导给子组件,但是反过来不会。
这是为了防止子组件无意修改了父组件的状态——这会让应用的数据流难以理解。

不过,也可以使用 .sync 或 .once 绑定修饰符显式地强制双向或单次绑定。
双向绑定会把子组件的 msg 属性同步回父组件的 parentMsg 属性。
单次绑定在建立之后不会同步之后的变化。
注意如果 prop 是一个对象或数组,是按引用传递。在子组件内修改它会影响父组件的状态,不管是使用哪种绑定类型。

<!-- 双向绑定 -->
<child :msg.sync="parentMsg"></child>
<!-- 单次绑定 -->
<child :msg.once="parentMsg"></child>

组件可以为 props 指定验证要求。当组件给其他人使用时这很有用,因为这些验证要求构成了组件的 API,确保其他人正确地使用组件。
此时 props 的值是一个对象,包含验证要求:

Vue.component('example', {
  props: {
    // 基础类型检测 (`null` 意思是任何类型都可以)
    propA: Number,
    // 必需且是字符串
    propB: {
      type: String,
      required: true
    }
  }
}

父子组件通信
子组件可以用 this.$parent 访问它的父组件。
根实例的后代可以用 this.$root 访问它。
父组件有一个数组 this.$children,包含它所有的子元素。
尽管可以访问父链上任意的实例,不过子组件应当避免直接依赖父组件的数据,尽量显式地使用 props 传递数据

另外,在子组件中修改父组件的状态是非常糟糕的做法,因为:

  1. 这让父组件与子组件紧密地耦合;
  2. 只看父组件,很难理解父组件的状态。因为它可能被任意子组件修改!理想情况下,只有组件自己能修改它的状态

Vue 实例实现了一个自定义事件接口,用于在组件树中通信
每个 Vue 实例都是一个事件触发器:

  • 使用 $on() 监听事件;
  • 使用 $emit() 在它上面触发事件;
  • 使用 $dispatch() 派发事件,事件沿着父链冒泡;
  • 使用 $broadcast() 广播事件,事件向下传导给所有的后代。
    不同于 DOM 事件,Vue 事件在冒泡过程中第一次触发回调之后自动停止冒泡,除非回调明确返回 true

我们在使用子组件的地方使用 v-on 绑定自定义事件会更好

<child v-on:child-msg="handleIt"></child>

这让事情非常清晰:当子组件触发了 "child-msg" 事件,父组件的 handleIt 方法将被调用。
所有影响父组件状态的代码放到父组件的 handleIt 方法中;子组件只关注触发事件。

有时仍然需要在 JavaScript 中直接访问子组件。为此可以使用 v-ref 为子组件指定一个索引 ID(子组件索引)

<div id="parent">
  <user-profile v-ref:profile></user-profile>
</div>
var parent = new Vue({ el: '#parent' })
// 访问子组件
var child = parent.$refs.profile

使用 slot 分发内容

为了让组件可以组合,我们需要一种方式来混合父组件的内容与子组件自己的模板,这个处理称为内容分发(或 “transclusion”,如果你熟悉 Angular)。
Vue.js 实现了一个内容分发 API,参照了当前 Web 组件规范草稿,使用特殊的 <slot> 元素作为原始内容的插槽。

我们先明确内容的编译作用域。假定模板为:

<child>{{ msg }}</child>

msg 应该绑定到父组件的数据,还是绑定到子组件的数据?答案是父组件。组件作用域简单地说是:
父组件模板的内容在父组件作用域内编译;子组件模板的内容在子组件作用域内编译

一个常见错误是试图在父组件模板内将一个指令绑定到子组件属性/方法:

<!-- 无效 -->
<child v-show="someChildProperty"></child>

假定 someChildProperty 是子组件的属性,上例不能如预期工作。父组件模板不知道子组件的状态

如果要绑定子组件内的指令到一个组件的根节点,应当在它的模板内这么做:

Vue.component('child-component', {
  // 有效,因为是在正确的作用域内
  template: '<div v-show="someChildProperty">Child</div>',
  data: function () {
    return {
      someChildProperty: true
    }
  }
})

类似地,分发内容是在父组件作用域内编译

<slot> 元素有一个特殊特性 name,用于配置如何分发内容。
多个 slot 可以有不同的名字。
命名 slot 将匹配有对应 slot 特性的内容片断。
也可以有一个未命名 slot,它是默认 slot,作为找不到匹配内容的回退插槽。
如果没有默认的 slot,不匹配内容将被抛弃。

假定我们有一个 multi-insertion 组件,它的模板为

<div>
  <slot name="one"></slot>
  <slot></slot>
  <slot name="two"></slot>
</div>

父组件模板:

<multi-insertion>
  <p slot="one">One</p>
  <p slot="two">Two</p>
  <p>Default A</p>
</multi-insertion>

渲染结果为:

<div>
  <p slot="one">One</p>
  <p>Default A</p>
  <p slot="two">Two</p>
</div>

动态组件

多个组件可以使用同一个挂载点,然后动态地在它们之间切换。
使用保留的 <component> 元素,动态地绑定到它的 is 特性。

如果把切换出去的组件保留在内存中(例如保留 input 输入框中输入的值),可以保留它的状态或避免重新渲染。为此可以添加一个 keep-alive 指令参数:

<component :is="currentView" keep-alive></component>

在切换组件时,切入组件在切入前可能需要进行一些异步操作。为了控制组件切换时长,给切入组件添加 activate 钩子。
注意 activate 钩子只作用于动态组件切换或静态组件初始化渲染的过程中,不作用于使用实例方法手工插入的过程中。

transition-mode 特性用于指定两个动态组件之间如何过渡。
在默认情况下,进入与离开平滑地过渡。这个特性可以指定另外两种模式:

  • in-out:新组件先过渡进入,等它的过渡完成之后当前组件过渡出去。
  • out-in:当前组件先过渡出去,等它的过渡完成之后新组件过渡进入。
<component :is="view" transition="fade" transition-mode="out-in"></component>

编写可复用组件

一次性组件跟其它组件紧密耦合没关系,但是可复用组件应当定义一个清晰的公开接口。
Vue.js 组件 API 来自三部分——prop事件slot

  • prop 允许外部环境传递数据给组件;
  • 事件 允许组件触发外部环境的 action;
  • slot 允许外部环境插入内容到组件的视图结构内。
<my-component
  :foo="baz"
  :bar="qux"
  @event-a="doThis"
  @event-b="doThat">
  <!-- content -->
  <img slot="icon" src="...">
  <p slot="main-text">Hello!</p>
</my-component>

在大型应用中,我们可能需要将应用拆分为小块,只在需要时才从服务器下载。
为了让事情更简单,Vue.js 允许将组件定义为一个工厂函数,动态地解析组件的定义。
Vue.js 只在组件需要渲染时触发工厂函数,并且把结果缓存起来,用于后面的再次渲染。

Vue.component('async-example', function (resolve, reject) {
  setTimeout(function () {
    // 异步组件
    resolve({
      template: '<div>I am async!</div>'
    })
  }, 1000)
})

如果子组件有 inline-template 特性,组件将把它的内容当作它的模板,而不是把它当作分发内容。这让模板更灵活。

<my-component inline-template>
  <p>These are compiled as the component's own template</p>
  <p>Not parent's transclusion content.</p>
</my-component>

但是 inline-template 让模板的作用域难以理解,并且不能缓存模板编译结果。最佳实践是使用 template 选项在组件内定义模板。

深入响应式原理

把一个普通对象传给 Vue 实例作为它的 data 选项,Vue.js 将遍历它的属性,用 Object.defineProperty 将它们转为 getter/setter。这是 ES5 特性。
用户看不到 getter/setters,但是在内部它们让 Vue.js 追踪依赖,在属性被访问和修改时通知变化。一个问题是在浏览器控制台打印数据对象时 getter/setter 的格式化不同,使用 vm.$log() 实例方法可以得到更友好的输出。
模板中每个指令/数据绑定都有一个对应的 watcher 对象,在计算过程中它把属性记录为依赖。之后当依赖的 setter 被调用时,会触发 watcher 重新计算 ,也就会导致它的关联指令更新 DOM。

尽管 Vue.js 提供了 API 动态地添加响应属性,还是推荐在 data 对象上声明所有的响应属性

  1. data 对象就像组件状态的模式(schema)。在它上面声明所有的属性让组件代码更易于理解
  2. 添加一个顶级响应属性会强制所有的 watcher 重新计算,因为它之前不存在,没有 watcher 追踪它。这么做性能通常是可以接受的(特别是对比 Angular 的脏检查),但是可以在初始化时避免。

Vue.js 默认异步更新 DOM。每当观察到数据变化时,Vue 就开始一个队列,将同一事件循环内所有的数据变化缓存起来
如果一个 watcher 被多次触发,只会推入一次到队列中。等到下一次事件循环,Vue 将清空队列,只进行必要的 DOM 更新。
在内部异步队列优先使用 MutationObserver,如果不支持则使用 setTimeout(fn, 0) 。

例如,设置了 vm.someData = 'new value',DOM 不会立即更新,而是在下一次事件循环清空队列时更新。
为了在数据变化之后等待 Vue.js 完成更新 DOM,可以在数据变化之后立即使用 Vue.nextTick(callback) ,回调会在 DOM 更新完成后调用。

var vm = new Vue({
  el: '#example',
  data: {
    msg: '123'
  }
})
vm.msg = 'new message' // 修改数据
// 异步更新 DOM
vm.$el.textContent === 'new message' // false
// vm.$nextTick() 这个实例方法比较方便,因为它不需要全局 Vue,它的回调的 this 自动绑定到当前 Vue 实例。
Vue.nextTick(function () {
  vm.$el.textContent === 'new message' // true
})

自定义指令

自定义指令提供一种机制将数据的变化映射为 DOM 行为。

可以用 Vue.directive(id, definition) 方法注册一个全局自定义指令,它接收两个参数指令 ID 与定义对象。
也可以用组件的 directives 选项注册一个局部自定义指令。

定义对象可以提供几个钩子函数(都是可选的):

  • bind:只调用一次,在指令第一次绑定到元素上时调用。
  • update: 在 bind 之后立即以初始值为参数第一次调用,之后每当绑定值变化时调用,参数为新值与旧值。
  • unbind:只调用一次,在指令从元素上解绑时调用。
Vue.directive('my-directive', {
  // 所有的钩子函数将被复制到实际的指令对象中,钩子内 this 指向这个指令对象。
  // 这个对象暴露了一些有用的属性:
  // el: 指令绑定的元素。
  // vm: 拥有该指令的上下文 ViewModel。
  // expression: 指令的表达式,不包括参数和过滤器。
  // arg: 指令的参数。
  // name: 指令的名字,不包含前缀。
  // modifiers: 一个对象,包含指令的修饰符。
  // descriptor: 一个对象,包含指令的解析结果。
  // 
  // 你应当将这些属性视为只读的,不要修改它们。
  // 你也可以给指令对象添加自定义属性,但是注意不要覆盖已有的内部属性。
  bind: function () {
    // 准备工作
    // 例如,添加事件处理器或只需要运行一次的高耗任务
  },
  // 当指令使用了字面修饰符,它的值将按普通字符串处理并传递给 update 方法。
  // update 方法将只调用一次,因为普通字符串不能响应数据变化。
  update: function (newValue, oldValue) {
    // 值更新时的工作
    // 也会以初始值为参数调用一次
  },
  unbind: function () {
    // 清理工作
    // 例如,删除 bind() 添加的事件监听器
  }
})

在注册之后,便可以在 Vue.js 模板中这样用(记着添加前缀 v-):

<div v-my-directive="someValue"></div>

当只需要 update 函数时,可以传入一个函数替代定义对象:

Vue.directive('my-directive', function (value) {
  // 这个函数用作 update()
})

有时我们想以自定义元素的形式使用指令,而不是以特性的形式。这与 Angular 的 “E” 指令非常相似。
元素指令可以看做是一个轻量组件。

元素指令不能接受参数或表达式,但是它可以读取元素的特性从而决定它的行为。
迥异于普通指令,元素指令是终结性的,这意味着,一旦 Vue 遇到一个元素指令,它将跳过该元素及其子元素——只有该元素指令本身可以操作该元素及其子元素。

Vue.elementDirective('my-directive', {
  // API 同普通指令
  bind: function () {
    // 操作 this.el...
  }
})
<my-directive></my-directive>

高级选项

  • params

    指定一个特性列表,Vue 编译器将自动提取绑定元素的这些特性

  • deep

    如果指令用在一个对象上,当对象内部属性变化时要触发 update

  • twoWay

    如果指令想向 Vue 实例写回数据

  • acceptStatement

    如果指令想接受内联语句

  • terminal

    Vue 通过递归遍历 DOM 树来编译模块。但是当它遇到 terminal 指令时会停止遍历这个元素的后代元素。这个指令将接管编译这个元素及其后代元素的任务。v-if 和 v-for 都是 terminal 指令。

  • priority

    可以给指令指定一个优先级。如果没有指定,普通指令默认是 1000, terminal 指令默认是 2000。同一个元素上优先级高的指令会比其它指令处理得早一些。优先级一样的指令按照它在元素特性列表中出现的顺序依次处理,但是不能保证这个顺序在不同的浏览器中是一致的。

自定义过滤器

可以用全局方法 Vue.filter() 注册一个自定义过滤器,它接收两个参数:过滤器 ID 和过滤器函数。

// 过滤器函数以值为参数, 之后可接收任意数量的参数
Vue.filter('wrap', function (value, begin, end) {
  // 过滤器函数的 this 始终指向调用它的 vm
  // 返回转换后的值
  return begin + value + end + this.a
})

一般我们使用过滤器都是在把来自模型的值显示在视图之前转换它。
不过也可以定义一个过滤器,在把来自视图(<input> 元素)的值写回模型之前转化它:

Vue.filter('currencyDisplay', {
  // model -> view
  // 在更新 `<input>` 元素之前格式化值
  read: function(val) {
    return '$'+val.toFixed(2)
  },
  // view -> model
  // 在写回数据之前格式化值
  write: function(val, oldVal) {
    var number = +val.replace(/[^\d.]/g, '')
    return isNaN(number) ? 0 : parseFloat(number.toFixed(2))
  }
})

混合

混合以一种灵活的方式为组件提供分布复用功能。
混合对象可以包含任意的组件选项。当组件使用了混合对象时,混合对象的所有选项将被“混入”组件自己的选项中。

// 定义一个混合对象
var myMixin = {
  created: function () {
    this.hello()
  },
  methods: {
    hello: function () {
      console.log('hello from mixin!')
    }
  }
}

// 定义一个组件,使用这个混合对象
var Component = Vue.extend({
  mixins: [myMixin]
})

var component = new Component() // -> "hello from mixin!"

当混合对象与组件包含同名选项时,这些选项将以适当的策略合并。
例如,同名钩子函数被并入一个数组,因而都会被调用。
另外,混合的钩子将在组件自己的钩子之前调用。

值为对象的选项,如 methods, components 和 directives 将合并到同一个对象内。如果键冲突则组件的选项优先。

可以全局注册混合。但要小心使用!因为一旦全局注册混合,它会影响所有之后创建的 Vue 实例。
如果使用恰当,可以为自定义选项注入处理逻辑。
慎用全局混合,因为它影响到每个创建的 Vue 实例,包括第三方组件。
在大多数情况下,它应当只用于自定义选项。

// 自定义选项也可以指定合并策略
// 如果想用自定义逻辑合并自定义选项,则向 Vue.config.optionMergeStrategies 添加一个函数
Vue.config.optionMergeStrategies.myOption = function (toVal, fromVal) {
  // 返回 mergedVal
}

// 对于多数值为对象的选项,可以简单地使用 methods 所用的合并策略
var strategies = Vue.config.optionMergeStrategies
strategies.myOption = strategies.methods

插件

插件通常会为 Vue 添加全局功能。
插件的范围没有限制——通常是下面几种:

  • 添加全局方法或属性,如 vue-element
  • 添加全局资源:指令/过滤器/过渡等,如 vue-touch
  • 添加 Vue 实例方法,通过把它们添加到 Vue.prototype 上实现。
  • 一个库,提供自己的 API,同时提供上面提到的一个或多个功能,如 vue-router
// Vue.js 的插件应当有一个公开方法 install
// 第一个参数是 Vue 构造器,第二个参数是一个可选的选项对象
MyPlugin.install = function (Vue, options) {
  // 1. 添加全局方法或属性
  Vue.myGlobalMethod = ...
  // 2. 添加全局资源
  Vue.directive('my-directive', {})
  // 3. 添加实例方法
  Vue.prototype.$myMethod = ...
}

// 通过 Vue.use() 全局方法使用插件, 即调用 `MyPlugin.install(Vue)`
Vue.use(MyPlugin, { someOption: true })

构建大型应用

Vue.js 生态系统提供了一系列的工具与库,用于构建大型单页应用。
这些部分会感觉开始更像一个『框架』,但是它们本质上只是一套推荐的技术栈而已 - 你依然可以对各个部分进行选择和替换。

对于大型项目,为了更好地管理代码使用模块构建系统非常必要。
推荐代码使用 CommonJS 或 ES6 模块,然后使用 Webpack 或 Browserify 打包。

单文件组件

在典型的 Vue.js 项目中,我们会把界面拆分为多个小组件,每个组件在同一地方封装它的 CSS 样式,模板和 JavaScript 定义。你可以在 Webpackbin.com 上在线尝试!

my-component.vue

my-component.vue

对于单页应用,推荐使用官方库 vue-router
如果你只需要非常简单的路由逻辑,可以这么做,监听 hashchange 事件并使用动态组件。
利用这种机制也可以非常容易地配合其它路由库,如 Page.jsDirector

<div id="app">
  <component :is="currentView"></component>
</div>
Vue.component('home', { /* ... */ })
Vue.component('page1', { /* ... */ })
var app = new Vue({
  el: '#app',
  data: {
    currentView: 'home'
  }
})
// 在路由处理器中切换页面
app.currentView = 'page1'

状态管理

在大型应用中,状态管理常常变得复杂,因为状态分散在许多组件内。如果一个状态要被多个实例共享,应避免复制它,而是共享引用:

var sourceOfTruth = {}

var vmA = new Vue({
  data: sourceOfTruth
})

var vmB = new Vue({
  data: sourceOfTruth
})
// 现在每当 sourceOfTruth 被修改后,vmA 与 vmB 将自动更新它们的视图。

// 扩展这个思路,我们可以实现 store 模式:
// 如果我们约定,组件不可以直接修改 store 的状态,而应当派发事件,通知 store 执行 action,那么我们基本上实现了 Flux 架构。
// 此约定的好处是,我们能记录 store 所有的状态变化,并且在此之上实现高级的调试帮助函数,如修改日志,快照,历史回滚等。
var store = {
  state: {
    message: 'Hello!'
  },
  actionA: function () {
    // 有一点要注意,不要在 action 中替换原始的状态对象——为了观察到变化,组件和 store 需要共享这个对象
    this.state.message = 'action A triggered'
  },
  actionB: function () {
    this.state.message = 'action B triggered'
  }
}

// 我们把所有的 action 放在 store 内,action 修改 store 的状态。
// 集中管理状态更易于理解状态将怎样变化。组件仍然可以拥有和管理它的私有状态。
var vmA = new Vue({
  data: {
    privateState: {},
    sharedState: store.state
  }
})

var vmB = new Vue({
  data: {
    privateState: {},
    sharedState: store.state
  }
})

状态管理

生产发布

为了更小的文件体积,Vue.js 的压缩版本删除所有的警告,但是在使用 Browserify 或 Webpack 等工具构建 Vue.js 应用时,压缩需要一些配置。

对比其它框架

  • Angular

    比 Angular 简单得多,Angular 使用双向绑定,Vue 也支持双向绑定,不过默认为单向绑定,数据从父组件单向传给子组件。在大型应用中使用单向绑定让数据流易于理解。

  • React

    React 的渲染建立在 Virtual DOM 上——一种在内存中描述 DOM 树状态的数据结构。当状态发生变化时,React 重新渲染 Virtual DOM,比较计算之后给真实 DOM 打补丁。

    因为它不使用数据观察机制,每次更新都会重新渲染整个应用,因此从定义上保证了视图与数据的同步。它也开辟了 JavaScript 同构应用的可能性。

    React 团队雄心勃勃,计划让 React 成为通用平台的 UI 开发工具。

    React 的开发趋势是将所有东西都放在 JavaScript 中,包括 CSS。

  • Polymer

    Vue.js 的组件可以类比为 Polymer 中的自定义元素,它们提供类似的开发体验。最大的不同在于,Polymer 依赖最新的 Web 组件特性,在不支持的浏览器中,需要加载笨重的 polyfill,性能也会受到影响。

  • Riot

    尽管比 Riot 重一点,Vue 提供了一些显著优处。

  • Ember

班会第 21 期

班会主题: 那些年我们手机上用过的 App


  • 技术
    • 有用的 CSS 代码片段

      • 垂直对齐
      • 伸展一个元素到窗口高度
      • 基于文件格式使用不同的样式
      • 创建跨浏览器的图像灰度
      • 背景渐变动画
      • CSS:表格列宽自适用
      • 只在一边或两边显示盒子阴影
      • 包裹长文本
      • 制造模糊文本
      • 用CSS动画实现省略号动画
      • 样式重置
      • 清除浮动
      • 跨浏览器的透明
      • CSS引用模板
      • 个性圆角
      • 通用媒体查询
      • 现代字体栈
      • 自定义文本选择
      • 为logo隐藏H1
      • 图片边框偏光
      • 锚链接伪类
      • 奇特的CSS引用
      • CSS3:全屏背景
      • 内容垂直居中
      • 强制出现垂直滚动条
      • CSS3渐变模板
      • @font-face模板
      • 缝合CSS3元素
      • CSS3 斑马线
      • 有趣的&
      • 大字段落
      • 内部CSS3 盒阴影
      • 外部CSS3 盒阴影
      • 三角形列表项目符号
      • 固定宽度的居中布局
      • CSS3 列文本
      • CSS固定页脚
      • 跨浏览器设置最小高度
      • CSS3 鲜艳的输入
      • 强制换行
      • 在可点击的项目上强制手型
      • 网页顶部盒阴影
      • CSS3对话气泡
      • H1-H5默认样式
      • 纯CSS背景噪音
      • 持久的列表排序
      • CSS悬浮提示文本
      • 深灰色的圆形按钮
      • 在可打印的网页中显示URLs
      • 禁用移动Webkit的选择高亮
      • CSS3 圆点图案
      • CSS3 方格图案
      • Github的fork色带
      • CSS font属性缩写
      • 论文页面的卷曲效果
      • 鲜艳的锚链接
      • 带CSS3特色的横幅显示
    • 我的 React 之旅

      • 介绍 create-react-app 工具
      • React Tutorial 学习笔记
    • 使用 gulp.dest 复制目录结构

      复制文件到另外一个目录时保持原有文件的目录结构

    • gulp-oss-upload

      上传文件到阿里云 OSS 的 gulp 插件

    • 静态资源自动化发布方案

      • 全量发布
      • 增量发布
    • 使用 layer 组件打开多个弹层

      // 注意: 如果要同时打开两个以上的弹窗, type 参数必须是 1 或者 2
      // 因为 type 默认值是 0, 会造成无法同时创建两个以上的弹窗
      layer.open({
          type: 1,
          title: 'title',
          area: ['390px', '330px'],
          content: 'content',
          btn: '再弹一个',
          yes: function(){
              // 这里再使用 layer.open 或者其他内置方法都可以
              layer.confirm('a');
          }
      });
    • 什么鬼,又不知道怎么命名class了

      相信写css的人都会遇到下面的问题:

      • 糟糕,怎么命名这个class,好像不太贴切,要是冲突了怎么办,要不要设计成通用一点...
      • 而改别人css代码的时候则会一直有个疑问:这个class到底是只在这个地方用了,还是其他地方都用了?

      于是就有了下面的做法:

      • 最后终于被逼出了个class,简洁也好,中英混搭也罢,看着一头雾水也没关系,反正最后页面显示出来的。
      • 这个class应该是只有这个地方用到,我可以放心写。上线之后。如果没问题,则暗自自我欣赏,看吧问题就这么简单,分分钟搞定呀;如果冲突了,则无限感慨,哎,改的时候我就隐隐不安啊,妈蛋,深坑,这是谁写的,谁写的!!!
      • 不好,这个class说不定其他地方也用到了,我得加个限制范围,加个父元素?要不重新再命名个class吧,比较保险。最后如果没问题则表示还好比较机智,怎么说哥也是混过的,还是有几斤几两的;如果有问题则表示防不慎防啊,这也太太太坑了吧。

      也许你花了十分钟设计定义的一个class样式,人家分分钟就给你干掉了,这得多恼火;也许这个页面好好的,跑到另一个页面就跟原先的样式有了冲突。

      所以class命名的难就难在既要重复利用,又要避免样式的冲突。如果要重复利用,那么当然是越简单越好,越抽象可用的地方越大,太具体了就完蛋了。而如果要避免样式冲突。BEM的方式最简单,class都唯一了,那还冲突个毛线;其次就是通过父元素限定作用域,可以搞几个层级,而不是单独一个class定义样式;还有就是追加class,来实现差异化;最后不同的页面不同的文件,你用你的我用我的。

      class命名的发展历程

      • 混沌阶段,没有规则就是最好的规则(大概每个人都是从这个阶段一路走过来的, @liangmiao930617 同学对吧)
      • 原子类阶段,聚集神龙现身手
      • 模块阶段,以职能划分,添加前缀
      • BEM阶段,规则有序

      其实每个命名的发展经历都有其特定的历史意义,也当然有其价值。所以吸取之长,弃之短缺就很好了。

      常见class关键词

      • 布局类:header, footer, container, main, content, aside, page, section
      • 包裹类:wrap, inner
      • 区块类:region, block, box
      • 结构类:hd, bd, ft, top, bottom, left, right, middle, col, row, grid, span
      • 列表类:list, item, field
      • 主次类:primary, secondary, sub, minor
      • 大小类:s, m, l, xl, large, small
      • 状态类:active, current, checked, hover, fail, success, warn, error, on, off
      • 导航类:nav, prev, next, breadcrumb, forward, back, indicator, paging, first, last
      • 交互类:tips, alert, modal, pop, panel, tabs, accordion, slide, scroll, overlay,
      • 星级类:rate, star
      • 分割类:group, seperate, divider
      • 等分类:full, half, third, quarter
      • 表格类:table, tr, td, cell, row
      • 图片类:img, thumbnail, original, album, gallery
      • 语言类:cn, en
      • 论坛类:forum, bbs, topic, post
      • 方向类:up, down, left, right
      • 其他语义类:btn, close, ok, cancel, switch; link, title, info, intro, more, icon; form, label, search, contact, phone, date, email, user; view, loading...
    • 聊一聊iconfont那些事儿

      css3中,新增了一种样式规则,@font-face,这个规则可以用来引入自定义的字体,到客户端
      上面的自已个h1中使用的,正是我们存在服务端的字体。由于各个浏览器的兼容性问题,

      • IE浏览器:EOT
      • Mozilla浏览器:OTF,TTF
      • Safari浏览器:OTF,TTF,SVG
      • 歌剧:OTF,TTF,SVG
      • Chrome浏览器:TTF,SVG
      @font-face {
          font-family: 'icons';
          src: url(../font/curiconfont.eot#iefix) format('embedded-opentype'),
               url(../font/curiconfont.woff) format('woff'),
               url(../font/curiconfont.ttf) format('truetype'),
               url(../font/curiconfont.svg?#iconfont) format('svg');
          font-weight: normal;
          font-style: normal;
      }

      既然font-face可以指定字体文件,那么字体长成什么样,不就是开发者说的算了么. 文字不就是图像么。人类最早发明文字的时候就是按照图像来发明的。所以,我们可以把一些字符,描述成图像。在我们的网页上,当成图像来使用。这就是iconfont了。把一些零散的icon做成字体。我们调用文字的时候,渲染出来的就是icon图像了。

      iconfont的利与弊

      • iconfont图像放大后,不会失真

        相信读者们没有见过文字在网页上放大的时候会失真的状况吧,因为字体是矢量的,字体的描绘只记录绘制的路径。而图片不是,我们如果把一张小图放大若干倍之后,会发现图像变得模糊了。因为图像是基于像素点的描述,放大后,之前图像的一个像素,被放大为多个像素。自然是会失真的

      • iconfont节省流量

        在图片清晰度要求越高的情况下,我们的图片本身就会越大。这样非常耗费资源,而且,图像需要的色彩值信息,也会存储。这样也极大的浪费了空间。iconfont颜色由css决定,尺寸要求变大的话,则适应性的变大。传输的大小不会变大。

      • iconfont在颜色变幻方面很简单

      • iconfont不能支持一个图像里面混入多重颜色

        作为文字,是不会出现左边是红色右边是绿色的状况的。一个文字,是一个整体,统一的颜色。这个颜色就取决于css的color了。所以使用iconfont做图标的话,最好使用纯色的图标。

      • iconfont的使用没有使用图片那么直接,简单

    • 聊一聊前端模板与渲染那些事儿

      在刚有web的时候,前端与后端的交互,非常直白,浏览器端发出URL,后端返回一张拼好了的HTML串。浏览器对其进行渲染。html中可能会混有一些php(或者php中混有一些html)。在服务端将数据与模板进行拼装,生成要返回浏览器端的html串。

      这与我们现在做一个普通网页没什么区别。只不过现在,我们更常使用模板技术来解决前后端耦合的问题。

      前端使用模板引擎,在html中写一些标签,与数据与逻辑基本无关。后端在渲染的时候,解析这些标签,生成HTML串,如smarty。其实前端与后端的交互在服务端就已经有一次了。

      // ajax获取字符串直接渲染方式
      //
      // 如果这种模板的拼装会发生多次。是一个非常频繁的行为,且模板基本一致,只是数据变动的话,最好是一开始采用客户端拼装的方法。
      // 因为,同样的模板没有必要被传到客户端好几次。这样,我们可以剩下传输同样模板的流量,请求更快
      // 不过,这种做法也有问题,就是用户同步刷新的时候,需要等页面渲染完,再发一个请求,去请求第一屏的数据,才能开始渲染。
      // 这个过程相当于发了两次请求,等待的时候还是有所感知的
      document.querySelector('.blankPlace').innerHTML = xhr.responseText;
      // ajax获取数据,前端进行拼装的方式
      //
      // 同步的时候,就将一段渲染好的HTML,直接输出到页面,而在异步的时候,请求的也是这段HTML,直接将请求回的HTML往页面上一塞就完成了。
      // 这样就可以达到同步页面的时候,直接输出
      var res = JSON.parse(xhr.responseText);
      document.querySelector('.blankPlace').innerHTML = ''
          +'<h2>'+
             '我是模板'+
          '</h2>'+
          '<div>'+
             res.data+
          '</div>';

      如果前端的js里写一份模板,后端的html(jsp/asp/smarty)中也写一份模板呢?这样,同步的时候,直接用后端HTML(jsp/asp/smarty)中的模板。异步拉取数据的时候,每次使用js中的模板进行拼装 。同步也能保证首屏的速度,异步也能保证传输量的限制与速度。可是这样,也会面临问题,那就是,你的模板需要维护两份。如果那天产品和你说,我要改一下页面的结构。你不得不改动HTML的时候。js中与jsp/asp/smarty中的模板都需要同样的更改两次

      smartyMonkey 用js解析smarty语法的模板,达到服务端smarty与客户端共享同一套模板的目的

      前端解析模板的引擎的语法,与后端j解析模板引擎语法一致。这样就达到了一份HTML前后端一起使用的效果。一改俱改,一板两用

      直接刷HTML的成本太高, 好在react给了我们一种新的思路,它用最少的开销帮我们处理模板的更新,却又不用我们维护更新时繁琐的步骤。有兴趣的读者可以了解一下react的diff算法及其应用。

    • 聊一聊前端功能统计那些事儿

      • 什么是功能统计

        比如,你想看一个功能有多少用户进行了点击,来证明用户是否喜欢这个功能,亦或是你想看看用户究竟会在你的页面停留多长时间,从而判断用户的黏性。那么,在用户点击那个功能的时候,前端发送一条日志到服务端,这样积累下去,我们就能获得,每天有多少用户在点击某一个功能了。在功能发生迭代后,我们也能根据统计,来判断用户是否喜欢新的变化。

      • 如何统计

        只要在想统计的行为发生时,发送一条请求到达服务端即可。这样我们的服务端就有了相应的记录。我们就能开心的利用记录数量来判断点击数量了。

        一般来讲我们不必为了发送请求,就在各处点击的地方加个ajax,其实有种发送请求的方式比ajax更加的简单。而且还避免了跨域问题。其实直接给一个图片、script标签赋值地址,就完成了一次GET请求。

      • 服务端如何接收并使用数据

        服务器的server都会有access日志

    • 聊一聊前端速度统计(性能统计)那些事儿

      • 网站都有哪些指标?
        • 首屏时间(包括首屏的DOM元素的渲染,展现在用户第一屏幕的所有图片都完成。)
        • 白屏时间(就是页面处于空白的时间。页面空白,用户就会焦躁,并且变得不耐心。影响白屏时间的多数是:DNS解析耗时+服务端耗时+网络传输耗时。)
        • 用户可操作时间(我们的网页用户可以使用的时间。一般来讲 domready时间,便是我们的用户可操作时间了)
        • 总下载时间(使用window.onload即可)

      如何统计自己网站的这些指标

      更建议采集用户日志,即,在自己网站的代码中,增加统计,并把统计结果发送到服务器。在服务器采集这些日志,并产生一个监控的网站。其实大可不必使用一些付费的服务,我们自己就可以轻轻松松的做一个简答的速度监控服务。

  • 产品
    • 对于没有搜索到结果的页面给与用户友好提示

      例如提示: 没有找到符合搜索条件的内容

      如果不给用户提示的话, 用户点击了搜索按钮之后会觉得系统没有反应, 类似的提示文案可以参考 QQ 中的查找功能

    • 《双11:零点之战》纪录片

      真实电影《双十一:零点之战》讲述阿里巴巴神秘技术战队的故事,是阿里巴巴首次对外公布七年双11技术备战历程的纪录大片。

班会第 32 期

  • 技术

    • 边玩游戏边学 Flexbox 布局 @Monine

      Flexbox 布局在很大程度上解决了网页布局问题。但是实际使用的时候还是有一定的难度,因为属性太多,应用非常灵活。

    • 一道常被人轻视的前端JS面试题 @Monine

      function Foo() {
          getName = function () { alert (1); };
          return this;
      }
      Foo.getName = function () { alert (2);};
      Foo.prototype.getName = function () { alert (3);};
      var getName = function () { alert (4);};
      function getName() { alert (5);}
      
      //请写出以下输出结果:
      Foo.getName();          // 静态属性
      getName();                 // 变量声明提升/函数表达式与函数声明
      Foo().getName();        // 变量作用域问题/this指向问题
      getName();
      new Foo.getName();   // 运算符优先级
      new Foo().getName(); // 运算符优先级/构造函数返回值
      new new Foo().getName();
    • JavaScript世界万物诞生记 @Monine

      JavaScript 世界最终的样子

    • 怎样实现前端裁剪上传图片功能 @Monine

      第一个是支持拖拽,第二个压缩,第三个是裁剪编辑,第四个是上传和上传进度显示

      ios系统拍摄的照片,如果不是横着拍的,展示出来的照片旋转角度会有问题

      即不管你怎么拍,ios实际存的图片都是横着放的,因此需要用户自己手动去旋转。旋转的角度放在了exif的数据结构里面

  • 产品

班会第 7 期

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.