Full Code of cnsnake11/blog for AI

master b9f6f85f0f2a cached
131 files
23.0 MB
144.2k tokens
1 requests
Download .txt
Showing preview only (581K chars total). Download the full file or copy to clipboard to get everything.
Repository: cnsnake11/blog
Branch: master
Commit: b9f6f85f0f2a
Files: 131
Total size: 23.0 MB

Directory structure:
gitextract_zekn0oua/

├── HybirdAPI/
│   ├── AudioPlayer.md
│   ├── AudioRecorder.md
│   └── index.md
├── README.md
├── ReactNative开发指导/
│   ├── CodePush.md
│   ├── ReactNative入门知识.md
│   ├── ReactNative分享.md
│   ├── ReactNative增量升级方案.md
│   ├── ReactNative安卓首屏白屏优化.md
│   ├── ReactNative导航设计与实现.md
│   ├── ReactNative开发技巧总结.md
│   ├── ReactNative打离线包-android篇.md
│   ├── ReactNative打离线包-ios篇.md
│   ├── ReactNative的ios崩溃整理分析.md
│   ├── ReactNative的架构设计.md
│   ├── ReactNative组件状态设计思考.md
│   ├── ReactNative调试菜单.md
│   ├── React的render优化框架.md
│   ├── 已有工程集成ReactNaitve-IOS.md
│   └── 淘宝d2分享-ReactNative变革无线前端.md
├── ReactNative开发规范/
│   ├── 目录与命名规范.md
│   ├── 组件、页面结构规范.md
│   └── 编码规范.md
├── ReactNative翻译/
│   ├── React Advanced Performance.md
│   ├── React PureRenderMixin.md
│   ├── React Shallow Compare.md
│   ├── ReactNative : A warning from Apple.md
│   ├── Reconciliation.md
│   ├── react-native的定时器.md
│   ├── react-native的性能.md
│   └── 导航器比较.md
├── ReactNative问题汇总/
│   ├── Immutable.js的问题.md
│   ├── ReactNative-0.14.2.md
│   ├── ReactNative-0.15.0.md
│   ├── ReactNative-0.16.0.md
│   ├── ReactNative-0.17.0.md
│   └── 总体说明.md
├── data.json
├── xmind/
│   ├── 20160125RN增量升级讨论会.xmind
│   ├── 201602Todo.xmind
│   ├── 2016规划.xmind
│   ├── RN分享议题PPT大纲.xmind
│   ├── RN安卓启动优化.xmind
│   ├── RN阶段总结-里程碑2.xmind
│   ├── react环境搭建.xmind
│   ├── web性能监控方案.xmind
│   ├── web资源缓存.xmind
│   ├── 增量升级.xmind
│   ├── 增量升级新方案.xmind
│   ├── 孕育集成能不能吃-IOS.xmind
│   ├── 已有App集成RN.xmind
│   ├── 文档编写大纲.xmind
│   └── 腾讯x5集成.xmind
├── 其它/
│   ├── 2
│   ├── Building the DOM faster: speculative parsing, async, defer and preload(part 1).md
│   ├── Building the DOM faster: speculative parsing, async, defer and preload(part 2).md
│   ├── Building the DOM faster: speculative parsing, async, defer and preload(part 3).md
│   ├── Designing Websites for iPhone X.md
│   ├── FlatList.md
│   ├── How TensorFlow Lite Brings Machine Learning to Mobile Devices.md
│   ├── PanResponder.md
│   ├── RN分享提纲.md
│   ├── Range.md
│   ├── ReactNative分享议题.md
│   ├── ReactNative分享议题PPT大纲.md
│   ├── Scrollview.md
│   ├── Selection.md
│   ├── Understanding the WebView Viewport in iOS 11 ~ 1.md
│   ├── Understanding the WebView Viewport in iOS 11 ~ 2.md
│   ├── WebAssembly(1) A cartoon intro to WebAssembly.md
│   ├── WebAssembly(2-1)A crash course in just-in-time (JIT) compilers.md
│   ├── WebAssembly(2-2)A crash course in just-in-time (JIT) compilers.md
│   ├── WebAssembly(3)A crash course in assembly.md
│   ├── WebAssembly(4-1)Creating and working with WebAssembly modules.md
│   ├── WebAssembly(4-2)Creating and working with WebAssembly modules.md
│   ├── WebAssembly(5-1)What makes WebAssembly fast?.md
│   ├── WebAssembly(5-2)What makes WebAssembly fast?.md
│   ├── WebAssembly(6-1)Where is WebAssembly now and what’s next?.md
│   ├── WebAssembly(6-2)Where is WebAssembly now and what’s next?.md
│   ├── ios11和iPhone X中Webview的适配.md
│   ├── node与shell的交互与通讯.md
│   ├── node中文件操作的简单介绍.md
│   ├── package.json中版本号的含义.md
│   ├── performance.timing.md
│   ├── rn分享5.md
│   ├── 一个类似微信群聊程序的技术方案设计过程.md
│   ├── 了解一个新概念---区块链.md
│   ├── 前端和开闭原则.md
│   ├── 前端应该掌握的一些app开发知识-android篇(1).md
│   ├── 前端应该掌握的一些app开发知识-android篇(2).md
│   ├── 前端应该掌握的一些app开发知识-ios篇(1).md
│   ├── 前端应该掌握的一些app开发知识-ios篇(2).md
│   ├── 前端监控平台.md
│   ├── 前端资源打包设计.md
│   ├── 富文本编辑器1~html转结构化数据.md
│   ├── 富文本编辑器2~复制粘贴的处理.md
│   ├── 富文本编辑器3~自定义元素.md
│   ├── 富文本编辑器4~站外图片的粘贴.md
│   ├── 富文本编辑器的命令执行.md
│   ├── 开坑机器学习?.md
│   ├── 弱特征广告方案.md
│   ├── 微信二次分享.md
│   ├── 数据结构--树型数据的处理(1).md
│   ├── 数据结构--树形数据的处理2.md
│   ├── 机器学习-入门篇(1).md
│   ├── 机器学习-入门篇(2).md
│   ├── 机器学习-入门篇(3).md
│   ├── 机器学习-入门篇(4).md
│   ├── 架构/
│   │   └── 通用组件规范.md
│   └── 模式/
│       ├── 代理模式.md
│       ├── 单例模式(1).md
│       ├── 单例模式(2).md
│       ├── 原型模式.md
│       ├── 多个工厂方法模式.md
│       ├── 建造者模式.md
│       ├── 抽象工厂模式.md
│       ├── 普通工厂模式.md
│       ├── 桥接模式.md
│       ├── 装饰器模式.md
│       ├── 门面模式.md
│       └── 静态工厂方法模式.md
└── 日常记录与计划/
    ├── 2015总结与2016畅想.md
    ├── 2016-09-13.md
    ├── todo list.md
    ├── week2015-11-23.md
    ├── week2015-11-30.md
    ├── week2015-12-07.md
    ├── week2015-12-14.md
    ├── week2016-01-04.md
    ├── 总体计划1.md
    └── 总体计划2.md

================================================
FILE CONTENTS
================================================

================================================
FILE: HybirdAPI/AudioPlayer.md
================================================
# AudioPlayer

# 概述

音频播放对象,播放本地音频。

注:网络音频请使用h5的audio标签。

# 常量

### TYPE_SPEAKER
### TYPE_EARPIECE

# 方法

### play
### pause
### stop
### setCurrentTime(long ms)
### (long)getDuration
### (long)getCurrentTime
### setType(int AudioPlayer.TYPE_*)

# 事件

### onPlay
### onPause
### onFail
### onEnded
### onTimeupdate





================================================
FILE: HybirdAPI/AudioRecorder.md
================================================
# AudioRecorder

# 概述

调用麦克风进行录音操作

# 方法

### record

filePath
samplerate
format

### stop
### getFilePath
### clear

# 事件

### onRecord
### onFail
### onEnded
### onTimeupdate






================================================
FILE: HybirdAPI/index.md
================================================
# HybirdAPI

# 概述

此系列文档是为了描述app中如何提供一套统一的原生接口,供js调用。

app中webview中的js可以调用。

app中reactnative模块可以调用。



================================================
FILE: README.md
================================================
# 文章目录

大家有问题欢迎留言issues讨论。

### [【翻译】理解ios11中的webview viewport(第一部分)](https://github.com/cnsnake11/blog/blob/master/%E5%85%B6%E5%AE%83/Understanding%20the%20WebView%20Viewport%20in%20iOS%2011%20~%201.md)

### [【翻译】让网站适配iphoneX](https://github.com/cnsnake11/blog/blob/master/%E5%85%B6%E5%AE%83/Designing%20Websites%20for%20iPhone%20X.md)

### [【原创】富文本编辑器4~站外图片的粘贴](https://github.com/cnsnake11/blog/blob/master/%E5%85%B6%E5%AE%83/%E5%AF%8C%E6%96%87%E6%9C%AC%E7%BC%96%E8%BE%91%E5%99%A84~%E7%AB%99%E5%A4%96%E5%9B%BE%E7%89%87%E7%9A%84%E7%B2%98%E8%B4%B4.md)

### [【原创】富文本编辑器3~自定义元素](https://github.com/cnsnake11/blog/blob/master/%E5%85%B6%E5%AE%83/%E5%AF%8C%E6%96%87%E6%9C%AC%E7%BC%96%E8%BE%91%E5%99%A83~%E8%87%AA%E5%AE%9A%E4%B9%89%E5%85%83%E7%B4%A0.md)

### [【原创】富文本编辑器2~复制粘贴的处理](https://github.com/cnsnake11/blog/blob/master/%E5%85%B6%E5%AE%83/%E5%AF%8C%E6%96%87%E6%9C%AC%E7%BC%96%E8%BE%91%E5%99%A82~%E5%A4%8D%E5%88%B6%E7%B2%98%E8%B4%B4%E7%9A%84%E5%A4%84%E7%90%86.md)

### [【原创】富文本编辑器1~html转结构化数据](https://github.com/cnsnake11/blog/blob/master/%E5%85%B6%E5%AE%83/%E5%AF%8C%E6%96%87%E6%9C%AC%E7%BC%96%E8%BE%91%E5%99%A81~html%E8%BD%AC%E7%BB%93%E6%9E%84%E5%8C%96%E6%95%B0%E6%8D%AE.md)

### [【翻译】ReactNative:关于苹果审核警告](https://github.com/cnsnake11/blog/blob/master/ReactNative%E7%BF%BB%E8%AF%91/ReactNative%20:%20A%20warning%20from%20Apple.md)

### [【翻译】Reconciliation React比对算法](https://github.com/cnsnake11/blog/blob/master/ReactNative%E7%BF%BB%E8%AF%91/Reconciliation.md)

### [【原创】数据结构--树形数据的处理(2)](https://github.com/cnsnake11/blog/blob/master/%E5%85%B6%E5%AE%83/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84--%E6%A0%91%E5%BD%A2%E6%95%B0%E6%8D%AE%E7%9A%84%E5%A4%84%E7%90%862.md)

### [【原创】数据结构--树形数据的处理(1)](https://github.com/cnsnake11/blog/blob/master/%E5%85%B6%E5%AE%83/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84--%E6%A0%91%E5%9E%8B%E6%95%B0%E6%8D%AE%E7%9A%84%E5%A4%84%E7%90%86(1).md)

### [【翻译】React Advanced Performance 性能进阶](https://github.com/cnsnake11/blog/blob/master/ReactNative%E7%BF%BB%E8%AF%91/React%20Advanced%20Performance.md)

### [【原创】弱特征广告方案](https://github.com/cnsnake11/blog/blob/master/%E5%85%B6%E5%AE%83/%E5%BC%B1%E7%89%B9%E5%BE%81%E5%B9%BF%E5%91%8A%E6%96%B9%E6%A1%88.md)

### [【原创】前端和开闭原则](https://github.com/cnsnake11/blog/blob/master/%E5%85%B6%E5%AE%83/%E5%89%8D%E7%AB%AF%E5%92%8C%E5%BC%80%E9%97%AD%E5%8E%9F%E5%88%99.md)

### [【原创】React的render优化通用解决方案](https://github.com/cnsnake11/blog/blob/master/ReactNative%E5%BC%80%E5%8F%91%E6%8C%87%E5%AF%BC/React%E7%9A%84render%E4%BC%98%E5%8C%96%E6%A1%86%E6%9E%B6.md)

### [【原创】一个类似微信群聊程序的技术方案设计过程](https://github.com/cnsnake11/blog/blob/master/%E5%85%B6%E5%AE%83/%E4%B8%80%E4%B8%AA%E7%B1%BB%E4%BC%BC%E5%BE%AE%E4%BF%A1%E7%BE%A4%E8%81%8A%E7%A8%8B%E5%BA%8F%E7%9A%84%E6%8A%80%E6%9C%AF%E6%96%B9%E6%A1%88%E8%AE%BE%E8%AE%A1%E8%BF%87%E7%A8%8B.md)

### [【原创】ReactNative的ios崩溃整理分析](https://github.com/cnsnake11/blog/blob/master/ReactNative%E5%BC%80%E5%8F%91%E6%8C%87%E5%AF%BC/ReactNative%E7%9A%84ios%E5%B4%A9%E6%BA%83%E6%95%B4%E7%90%86%E5%88%86%E6%9E%90.md)

### [【原创】ReactNative团队分享提纲](https://github.com/cnsnake11/blog/blob/master/ReactNative%E5%BC%80%E5%8F%91%E6%8C%87%E5%AF%BC/ReactNative%E5%88%86%E4%BA%AB.md)

### [【翻译】React PureRenderMixin](https://github.com/cnsnake11/blog/blob/master/ReactNative%E7%BF%BB%E8%AF%91/React%20PureRenderMixin.md)

### [【原创】ReactNative增量升级解决方案](https://github.com/cnsnake11/blog/blob/master/ReactNative%E5%BC%80%E5%8F%91%E6%8C%87%E5%AF%BC/ReactNative%E5%A2%9E%E9%87%8F%E5%8D%87%E7%BA%A7%E6%96%B9%E6%A1%88.md)

### [【翻译】React 浅比对 Shallow Compare](https://github.com/cnsnake11/blog/blob/master/ReactNative%E7%BF%BB%E8%AF%91/React%20Shallow%20Compare.md)

### [【原创】ReactNative安卓首屏白屏优化](https://github.com/cnsnake11/blog/blob/master/ReactNative%E5%BC%80%E5%8F%91%E6%8C%87%E5%AF%BC/ReactNative%E5%AE%89%E5%8D%93%E9%A6%96%E5%B1%8F%E7%99%BD%E5%B1%8F%E4%BC%98%E5%8C%96.md)

### [【原创】ReactNative导航设计与实现](https://github.com/cnsnake11/blog/blob/master/ReactNative%E5%BC%80%E5%8F%91%E6%8C%87%E5%AF%BC/ReactNative%E5%AF%BC%E8%88%AA%E8%AE%BE%E8%AE%A1%E4%B8%8E%E5%AE%9E%E7%8E%B0.md)

### [【原创】ReactNative打离线包-android篇](https://github.com/cnsnake11/blog/blob/master/ReactNative%E5%BC%80%E5%8F%91%E6%8C%87%E5%AF%BC/ReactNative%E6%89%93%E7%A6%BB%E7%BA%BF%E5%8C%85-android%E7%AF%87.md)

### [【原创】ReactNative打离线包-ios篇](https://github.com/cnsnake11/blog/blob/master/ReactNative%E5%BC%80%E5%8F%91%E6%8C%87%E5%AF%BC/ReactNative%E6%89%93%E7%A6%BB%E7%BA%BF%E5%8C%85-ios%E7%AF%87.md)

### [【原创】ReactNative的组件架构设计](https://github.com/cnsnake11/blog/blob/master/ReactNative%E5%BC%80%E5%8F%91%E6%8C%87%E5%AF%BC/ReactNative%E7%9A%84%E6%9E%B6%E6%9E%84%E8%AE%BE%E8%AE%A1.md)

### [【原创】ReactNative组件状态设计思考](https://github.com/cnsnake11/blog/blob/master/ReactNative%E5%BC%80%E5%8F%91%E6%8C%87%E5%AF%BC/ReactNative%E7%BB%84%E4%BB%B6%E7%8A%B6%E6%80%81%E8%AE%BE%E8%AE%A1%E6%80%9D%E8%80%83.md)

### [【翻译】ReactNative的定时器Timers](https://github.com/cnsnake11/blog/blob/master/ReactNative%E7%BF%BB%E8%AF%91/react-native%E7%9A%84%E5%AE%9A%E6%97%B6%E5%99%A8.md)

### [【原创】已有工程集成ReactNative-IOS](https://github.com/cnsnake11/blog/blob/master/ReactNative%E5%BC%80%E5%8F%91%E6%8C%87%E5%AF%BC/%E5%B7%B2%E6%9C%89%E5%B7%A5%E7%A8%8B%E9%9B%86%E6%88%90ReactNaitve-IOS.md)

### [【翻译】ReactNative的性能](https://github.com/cnsnake11/blog/blob/master/ReactNative%E7%BF%BB%E8%AF%91/react-native%E7%9A%84%E6%80%A7%E8%83%BD.md)

### [【原创】ReactNative的组件架构设计](https://github.com/cnsnake11/blog/blob/master/ReactNative%E5%BC%80%E5%8F%91%E6%8C%87%E5%AF%BC/ReactNative%E7%9A%84%E6%9E%B6%E6%9E%84%E8%AE%BE%E8%AE%A1.md)

### [【转载】ReactNative变革无线前端-淘宝d2分享](https://github.com/cnsnake11/blog/blob/master/ReactNative%E5%BC%80%E5%8F%91%E6%8C%87%E5%AF%BC/%E6%B7%98%E5%AE%9Dd2%E5%88%86%E4%BA%AB-ReactNative%E5%8F%98%E9%9D%A9%E6%97%A0%E7%BA%BF%E5%89%8D%E7%AB%AF.md)

### [【原创】CodePush](https://github.com/cnsnake11/blog/blob/master/ReactNative%E5%BC%80%E5%8F%91%E6%8C%87%E5%AF%BC/CodePush.md)

### [【原创】ReactNative开发技巧总结](https://github.com/cnsnake11/blog/blob/master/ReactNative%E5%BC%80%E5%8F%91%E6%8C%87%E5%AF%BC/ReactNative%E5%BC%80%E5%8F%91%E6%8A%80%E5%B7%A7%E6%80%BB%E7%BB%93.md)

### [【原创】ReactNative入门知识](https://github.com/cnsnake11/blog/blob/master/ReactNative%E5%BC%80%E5%8F%91%E6%8C%87%E5%AF%BC/ReactNative%E5%85%A5%E9%97%A8%E7%9F%A5%E8%AF%86.md)







================================================
FILE: ReactNative开发指导/CodePush.md
================================================
#CodePush

https://github.com/Microsoft/react-native-code-push

#重要说明

<http://microsoft.github.io/code-push/faq/index.html#3-how-should-i-interpret-the-beta-status-of-the-service>

While the service is in beta, we don’t recommend using it for doing production deployments, since we don’t currently offer any specific SLA.因为现在是beta版本,不建议用做生产版本的发布。

确实不能用于生产,目前只在美国有服务器,大陆访问非常慢。<https://github.com/Microsoft/code-push/issues/70>

所以,增量升级只能自力更生了。

#工作方式
可以只升级Rn的js和图片,不用使用二进制包升级。

通过CodePush服务器进行升级。

服务端目前没有开源,不能用自己的服务器

原生代码的改动是不能通过codepush升级的。

# 支持平台

Android (asset support coming soon!)

安卓暂不支持asset

#基本流程
1. 安装CodePush CLI
2. 创建codePush账户
3. 注册app到codepush服务器
4. app中加入codepush客户端代码,并开发升级相关代码。 
5. 发布更新到codepush服务器
6. app收到了升级推送


具体配置过程请参考官网<http://microsoft.github.io/code-push/>

网上资料参考<http://blog.csdn.net/oiken/article/details/50279871>


#下一步工作

因为codepush服务器端不开源,而且服务器还在国外的关系,不能保证服务端的稳定性,所以很遗憾不能应用于真正的项目中。

针对目前的情况,制定下一步工作如下:

1. 研读codepush客户端源码,理解android和ios在客户端下载资源文件后,如何切换到新资源的方法。
2. 设计服务端,服务端仅提供文件资源下载服务和升级信息描述服务即可,不需要较复杂的逻辑。
3. 设计自动化打包解决方案,包括升级补丁打包,完整app打包。




#源码阅读记录
1. js版本同时需要考虑对app版本的依赖问题,例如,js1.0版本必须运行在iosApp2.0,安卓app2.6上等。
2. 提供了一系列js接口,方便应用更细节的控制升级的过程。
3. 对于assets中的图片内容,可以自动计算与上一版本的差别,只下载增量部分。
4. 如果app升级了,js应自动使用app中版本。todo一个升级算法状态图。
4. 客户端应有2部分组件-codepush文档很详细,可以参考
	1. native部分,安卓和ios分别提供启动时bundle资源位置的服务
	2. js部分,提供对更新和下载的细粒度控制接口.



================================================
FILE: ReactNative开发指导/ReactNative入门知识.md
================================================
# ReactNative入门知识

本文也可以作为RN的入门知识范围,为入门RN提供了一个知识大纲。掌握这些知识帮助你快速入门RN,少走弯路。

#es6

let和const

箭头函数

类定义

解构赋值Destructuring

函数参数的默认值

函数的rest参数【形式为“...变量名”】;及其逆运算;

import export

参考地址:http://facebook.github.io/react-native/docs/javascript-environment.html#content

参考地址:http://www.ghugo.com/react-native-es6/

#Flow


#react
jsx

生命周期事件

render方法

state相关

props相关


#react-naive常用组件
view

text

touch

image

textInput

scrollview

listview

navigator


#flexbox


#Dimensions

#fetch

#console
断点

#定时任务
参考地址:https://github.com/cnsnake11/blog/blob/master/ReactNative翻译/react-native的定时器.md

#交互管理器
参考地址:https://github.com/cnsnake11/blog/blob/master/ReactNative翻译/react-native的定时器.md

#调试
console.log()

在chrome中调试js

#Immutable.js




================================================
FILE: ReactNative开发指导/ReactNative分享.md
================================================

# ReactNative分享提纲

# 分享的目的

1. 了解rn是什么,特点和使用场景
2. 本次重点是学习架构(思想)而不是学习框架(用法)
3. 学习组件化的思想及其好处,目标是能运用到工作中
4. 希望随时打断进行交流讨论

# reactnative是个啥

用js写原生app的开源框架,目前官方支持ios和android。

facebook2015年发布。社区关注度非常高。版本迭代很快,基本上2周左右一个版本。

# 安卓demo包下载

[RnDemo.apk,9MB](http://pan.baidu.com/s/1mhX6VoO)


# 优势

## 开发体验
	
1. 改代码,即时编译,即时加载
1. 兼容性好,代码可预测,各系统的模拟器、各型号的真机基本无差异
1. 组件化支撑,代码更易复用
1. flexbox布局,自适应布局更容易
1. 手势操控系统,更易开发体验佳的触屏应用
1. 支持应用内更新,自由控制发版
1. es6新特性,各种语法黑魔法
	1. 箭头函数
	1. promise
	1. 解构赋值
	1. 类定义、继承
	1. fetch
	2. 等

## 用户体验
1. 加载性能好,无白屏
2. 动画性能好,无卡顿
2. 顺畅的手势操作

# 劣势
1. 无web版,分享页等还要开发,react-web目前还不成熟
1. 无选择器的概念,定义样式很繁琐,通过开发规范部分解决
1. 尚未发布1.0

程序员首先要思考的是让用户爽,然后才是让自己爽。如果按此原则的话,劣势还是在我们接受范围内的。(用户体验和开发体验同样重要,最好是有更完美的解决方案。)

# react基本概念

## 组件化编程

### 组件化定义
组件的定义:独立的可完成某些工作的部件。可能是一个button,或者一个util类。

组件化编程的目的:复用复用复用。站在别人肩膀上可以极大的提升开发测试效率。

遇到的困难:个性化定制。通过属性、事件等扩展。

举个web组件的例子,参考此文档的前半部分:[链接](https://github.com/cnsnake11/blog/blob/master/ReactNative%E5%BC%80%E5%8F%91%E6%8C%87%E5%AF%BC/ReactNative%E7%BB%84%E4%BB%B6%E7%8A%B6%E6%80%81%E8%AE%BE%E8%AE%A1%E6%80%9D%E8%80%83.md)

### react做了什么

react是一个组件化编程的框架,提供了组件化编程的完整解决方案。[例子](http://facebook.github.io/react/)

react组件的定义。 [链接](http://facebook.github.io/react/docs/component-specs.html)

react组件生命周期及其生命周期事件。[链接](http://facebook.github.io/react/docs/component-specs.html#lifecycle-methods)

## 面向状态编程

页面中任何组件的state的改变,都会引起页面所有组件的render方法的执行。react会根据render执行的结果与当前的虚拟dom进行比对,只进行增量的更新。[链接](https://github.com/cnsnake11/blog/blob/master/ReactNative%E5%BC%80%E5%8F%91%E6%8C%87%E5%AF%BC/ReactNative%E7%BB%84%E4%BB%B6%E7%8A%B6%E6%80%81%E8%AE%BE%E8%AE%A1%E6%80%9D%E8%80%83.md#rn设计思路)

## jsx
js中的xml。[例子](http://facebook.github.io/react/)

# reactnative基本概念

## 和react的关系

1. rn使用react的组件化规范。
2. rn使用react的面向状态编程的机制。
3. rn使用react的jsx机制。
4. rn提供了一系列app开发所需要的组件。

## 常用组件
1. div View
2. span Text
3. img Image
4. input TextInput
5. button Touch*

## 样式定义
不支持选择器。不支持选择器。不支持选择器。

只能内联或者在每一个节点上声明外部css定义。所以,一般没有复用的样式使用内联,有复用的才使用外部定义。

[链接](http://reactnative.cn/docs/0.24/style.html#content)


# 开发环境

## ios

xcode+app的ios代码+js编辑器+rn开发服务器+真机or模拟器

## android

jdk+androidSdk+androidStudio+app的android代码+js编辑器+rn开发服务器+真机or模拟器

# 开发过程

1. 启动rn开发服务器
2. 启动模拟器,点开app,设置自动reload
3. 启动js代码编辑器,coding---save---看效果
4. tips:可以直接让首页显示你要开发的页面,可以快速查看效果

```
// tips用到的代码,替换index页面的最后一行
AppRegistry.registerComponent('Ask', () => require('../../../demo/demo1/animate/drag2'));
```

# 调试过程

1. console.log
2. js断点调试
3. alert
3. 页面元素检测器

# 组件设计
[链接](https://github.com/cnsnake11/blog/blob/master/ReactNative%E5%BC%80%E5%8F%91%E6%8C%87%E5%AF%BC/ReactNative%E7%9A%84%E6%9E%B6%E6%9E%84%E8%AE%BE%E8%AE%A1.md)


# 坑坑坑

1. android的textinput不能设置边框圆角
1. android的图片resizemodal=contain不好用
1. 循环依赖报错的问题
1. 安卓rn首屏白屏时间长
1. 安卓的中绝对定位元素移动出父元素会不可见,设置overflow=hidden也不好使
1. 不支持隐藏元素
1. 安卓中,使用缓存rootview,并且键盘打开情况下,直接后退出rn模块,在进入会报错
1. 魅族smartbar不占高
1. android中,设置overflow=hidden,父容器高度不能为0,至少为0.01,否则hidden无效
1. 加固后动画有掉帧现象


# 架构设计
```
业务模块
业务框架
技术框架
reactnative
android、ios操作系统
```

# 框架设计

参考技术框架和业务框架的目录结构介绍。

# 版本发布

## 全量发布

全量发布是将rn相关资源打包进app中,是无需网络下载的。

一般过程:

1. coding结束
2. 使用全量打包命令,打出android和ios全量包
3. 将包拷贝到android和ios工程约定好的位置
4. 按照android和ios原有打包方式进行打包即可

## 增量发布

[增量升级方案](https://github.com/cnsnake11/blog/blob/master/ReactNative%E5%BC%80%E5%8F%91%E6%8C%87%E5%AF%BC/ReactNative%E5%A2%9E%E9%87%8F%E5%8D%87%E7%BA%A7%E6%96%B9%E6%A1%88.md)

一般过程:

1. coding结束
2. 使用全量打包命令,打出android和ios全量包
3. 使用增量打包命令,打出android和ios增量包
4. 将增量包上传到后台管理系统,上线即可



================================================
FILE: ReactNative开发指导/ReactNative增量升级方案.md
================================================
# ReactNative增量升级方案

# 前言
facebook的react-native给我们带来了用js写出原生应用的同时,也使得使用RN编写的代码的在线升级变得可能,终于可以不通过应用市场来进行升级,极大的提升了app修bug和赋予新功能的能力。----使用h5的方式也可以做到,但是rn的用户体验可要远远超过h5啊。

一般使用RN编写的app的线上使用方式,是将react-native bundle命令打出bundle文件和assets文件夹,直接内置到app中,app在viewcontroller或者activity中直接加载app内部的bundle文件,比如下图。

![](media/14534499414604.jpg)


当修改了代码或者图片的时候,只要app使用新的bundle文件和assets文件夹,就完成了一次在线升级。

本文主要基于以上思路,讲解增量升级的解决方案。

# 何为增量?

 一个完整的RN-app程序通常包含以下几个部分:
 
 1. native代码部分-objc或者java
 2. js代码部分-rn代码、依赖的第三方库、业务代码等
 3. 图片资源部分

native代码别想了,没法在线升级,要是能大家就都不使用应用市场ota升级了。
 
能进行在线升级的是js代码部分和图片资源部分,具体到代码就是bundle文件和assets文件夹。

因为在线升级是要走网络的,我们要想办法将网络消耗降到最低,所以要使用增量升级的方式。

针对js代码部分(即bundle文件)的增量指的是,代码的改动有多少,增量patch的补丁就有多少,那些没有改动的代码部分是不在补丁的范围内的。

针对图片部分(即assets)的增量指的是,升级补丁包中只包含新增的图片和有改动的图片。

那么在app端,下载升级补丁包,只需要和现有的版本进行合并,就能计算出最新版本的全量包。

总结下流程:()中为例子

首先,计算增量包:新版本(v10) - 旧版本(v1到v9) = 增量包 (会有9个包,v1~v10.zip,v2~v10.zip,,,,,v9-v10.zip)

然后,app根据自己的当前版本(比如V6),下载对应的增量包(V6-V10.zip)。

最后,app中通过 旧版本(v6) + 增量包(v6~v10.zip) = 新版本(v10) ,计算出了新版本的全量包。

 
# 增量算法
 
 assets增量算法,比较简单,就是比对,可以很容易的比较出新增的文件,和不同的文件(使用md5)。
 
 bundle文件的增量算法,确实比较复杂,刚开始没有什么头绪,后来在leader的指引下,很幸运的找到了google写的一个开源的库,可以对大字符串进行diff和patch,并且支持java、objc、js等等语言,完全的满足了我们的需求。

只用到2个接口,具体请参考github上的文档

1. 生成增量包时候:patch_make(text1, text2) => patches 
2. app生成全量包时候:patch_apply(patches, text1) => [text2, results]

google开源库地址:https://github.com/bystep15/google-diff-match-patch


# codepush

微软的codepush也做了类似的事情,不过由于以下原因,我们团队没敢使用其作为解决方案。

1. 其增量升级仅仅是针对图片资源的 
2. 其升级服务器端程序并不开源
3. 其升级服务器在美国,国内访问很慢且不稳定

不过,codepush客户端的源码和文档也给我们提供了很多思路,在此感谢codepush团队。

codepush地址:http://microsoft.github.io/code-push/

# bundle要求的app最小版本

本文中一般用min-v或者appMinV表示。

因为js代码是依赖于native代码的,所以,jsbundle对app的版本有要求,所以有这个概念。

试想,如果bundle依赖了一个native的一个新的接口,这个接口在v3版本的app中才发布,如果v2版本的app升级了这个bundle,那么必然会报错,严重的可能会导致app的崩溃。


# 系统结构设计与各模块职责
![312313123](media/312313123.png)

# bundle仓库设计

存储全量bundle和生成增量patch


## node patch 命令

在bundle目录下放入一个符合要求【参考目录结构说明】的新版本目录,比如0.3.0,然后执行以下命令。

命令:node patch 版本号 , 示例:node patch 0.3.0

-d参数: node patch 版本号 -d ,如果加入-d参数,会先删除patch目录下的对应版本目录,然后进行patch生成

然后在patch目录中就会生成0.3.0的增量包,同时patch目录下的update.json文件也会重新生成.

## node update.json 命令

在patch目录下重新生成update.json文件

## 目录结构说明
![](media/14534529649291.jpg)

```
bundle   存放全量bundle和全量assets的目录,里面的文件基本上是使用react-native bundle命令生成的
    0.1.0
        略
    0.2.0
        android
            略,同ios
        ios
            config.json    此版本的配置信息,包含要求app的最低版本等,手动配置
            index.jsbundle    全量jsbundle文件,使用react-native bundle命令生成
            assets    全量图片目录,使用react-native bundle命令生成
    0.3.0
        略
        
patch   存放增量补丁的目录,里面文件都是命令生成的,无需手动维护    
    0.1.0
        第一版本无文件
    0.2.0
        android
                略,同ios
        ios
            0.1.0-0.2.0.zip    增量包.zip
    0.3.0
        android
                略,同ios
        ios
            0.1.0-0.3.0.zip    增量包.zip
            0.2.0-0.3.0.zip    增量包.zip
    update.json    所有的升级包信息
src    存放打包用的源码
lib    存放打包用依赖的第三方的源码
patch.js    patch命令入口
update.json.js    update.json命令入口
```
## config.json示例

```
{
  "v": "0.3.0", //版本
  "min-v": "4.0.0", //此版本要求的最小app版本
  "date": "2016-01-01", //打包日期
  "des": [
    "修复xxbug", "添加xx功能"
  ]
}

```


## update.json示例

```
[
  {
    "v": "0.1.0",
    "min-v": "4.0.0",
    "date": "2016-01-01",
    "des": [
      "修复xxbug",
      "添加xx功能"
    ],
    "iosBundleMd5": "11f82563f8fd3f22dccb80ad2297f7bc",
    "androidBundleMd5": "11f82563f8fd3f22dccb80ad2297f7bc"
  },
  {
    "v": "0.2.0",
    "min-v": "4.0.0",
    "date": "2016-01-01",
    "des": [
      "修复xxbug",
      "添加xx功能"
    ],
    "iosBundleMd5": "3ca2824b008132cee515c0ea29938ff2",
    "androidBundleMd5": "3ca2824b008132cee515c0ea29938ff2"
  },
  {
    "v": "0.3.0",
    "min-v": "4.0.0",
    "date": "2016-01-01",
    "des": [
      "修复xxbug",
      "添加xx功能"
    ],
    "iosBundleMd5": "dbb81d2383112abb50eb19970c486acd",
    "androidBundleMd5": "dbb81d2383112abb50eb19970c486acd"
  }
]

```

# 升级服务器设计

## 接口patch/query

例如:http://localhost:3000/patch/query?bundleV=0.2.0&appV=4.0.0&platform=ios

此接口会有以下4个场景的使用情况,每个场景返回的json示例已经提供在后面文档中。

### 输入参数

    ```
    bundleV : app中的bundle版本
    appV : app版本
    platform : app的平台

    ```

### 返回json各项说明


 1. status : 本次请求后台是否发生了错误
 1. msg : 给用户看的中文提示信息,静默升级时候没什么用
 1. latestBundleV : 当前的最新bundle版本
 1. latestAppMinV : 最新bundle要求的app最低版本
 1. canUpdate : 能否升级,boolean
 1. canUpdateBundleV : 能升级的bundle版本
 1. canUpdateAppMinV : 能升级的bundle要求的app最低版本
 1. patchUrl : 补丁包相对地址
 1. platform : 平台:ios or android



### 场景1

能升级,且能升级到最新版

```
{
   status: 'success',
   msg: '可以升级,bundle最新版为0.3.0',
   latestBundleV: '0.3.0',
   latestAppMinV: '4.0.0',
   canUpdate: true,
   canUpdateBundleV: '0.3.0',
   canUpdateAppMinV: '4.0.0',
   patchUrl: 'patch/0.3.0/ios/0.2.0-0.3.0.zip',
   platform: 'ios'
}
```

### 场景2
无需升级,已经是最新版本

```
{
   status: 'success',
   msg: '无需升级,已经是最新版本',
   canUpdate: false,
   platform: 'ios'
}
```

### 场景3
能升级,能升级到当前appMinV的最新bundle版本,但不是最新的bundle,想升最新bundle,必须先升app

```
{
   status: 'success',
   msg: '可以升级,但app版本3.0.0太低,只能升到bundleV0.2.0,bundleV最新为0.3.0',
   latestBundleV: '0.3.0',
   latestAppMinV: '4.0.0',
   canUpdate: true,
   canUpdateBundleV: '0.2.0',
   canUpdateAppMinV: '3.0.0',
   patchUrl: 'patch/0.2.0/ios/0.1.0-0.2.0.zip',
   platform: 'ios'
}
```

### 场景4
不能升级,已经是当前appMinV的最新bundle,但不是最新的bundle,想升最新bundle,必须先升app

```
{
   status: 'success',
   msg: '不能升级,当前已经是app3.0.0的最新bundle了,但不是最新bundle0.3.0,想升级bundle到最新,请先升级app',
   latestBundleV: '0.3.0',
   latestAppMinV: '4.0.0',
   canUpdate: false,
   platform: 'ios'
}
```

# native客户端设计

客户端的主要工作就是发请求到升级服务器询问是否能升级,然后根据返回的信息,下载升级包,解压升级包,安装升级包。

过程中要保证下载的文件是正确的(md5校验),要保证补丁安装之后的全量bundle文件是正确的(md5校验)。

整个过程用户无感知。

此部分详细设计后边会补充。

# 遗留问题
目前rn将安卓的图片放入到res目录中,导致安卓图片不能使用在线升级的解决方案,但是codepush的作者已经重构了此部分内容,并提pr到rn,rn团队也接受了这个pr,会在近期的版本中发布。

参考地址:https://github.com/facebook/react-native/pull/4527

# 近期开源
本部分内容核心的几个部分都已经完成,近期完善之后,会开源出来。





================================================
FILE: ReactNative开发指导/ReactNative安卓首屏白屏优化.md
================================================
# ReactNative安卓首屏白屏优化

#问题描述
公司现有app中部分模块使用reactnative开发,在实施的过程中,rn良好的兼容性,极佳的加载、动画性能,提升了我们的开发、测试效率,提升了用户体验。

但是,在android中,当点击某个rn模块的入口按钮,弹出rn的activity到rn的页面展现出来的过程中,会有很明显的白屏现象,不同的机型不同(cpu好的白屏时间短),大概1s到2s的时间。

注意,只有在真机上才会有此现象,在模拟器上没有此现象完全是秒开。ios上也是秒开,测试的最低版本是ios7,iphone4s。

reactnative版本0.20.0。

jsbundle文件大小717kb。

#优化效果
经过了大量的源码阅读,和网上资料查找,最终完美的解决了这个问题,无论什么机型,都可以达到秒开,如图(虽然下图是模拟器的截图,但是真机效果基本一样):

![1](media/1.gif)

#优化过程

##时间分布
一般优化速度问题,首先就是要找到时间分布,然后根据二八原则,先优化耗时最长的部分。

android集成rn都会继承官方提供的ReactActivity

```
public class MainActivity extends ReactActivity {
```
然后只在自己的activity中覆盖一些配置项。

在官方的ReactActivity中的onCreate方法中

```
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    if (getUseDeveloperSupport() && Build.VERSION.SDK_INT >= 23) {
      // Get permission to show redbox in dev builds.
      if (!Settings.canDrawOverlays(this)) {
        Intent serviceIntent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
        startActivity(serviceIntent);
        FLog.w(ReactConstants.TAG, REDBOX_PERMISSION_MESSAGE);
        Toast.makeText(this, REDBOX_PERMISSION_MESSAGE, Toast.LENGTH_LONG).show();
      }
    }

    mReactInstanceManager = createReactInstanceManager();
    ReactRootView mReactRootView = createRootView();
    mReactRootView.startReactApplication(mReactInstanceManager, getMainComponentName(), getLaunchOptions());
    setContentView(mReactRootView);
  }
```
最慢的就是这两行代码,占了90%以上的时间。

```
ReactRootView mReactRootView = createRootView();
mReactRootView.startReactApplication(mReactInstanceManager, getMainComponentName(), getLaunchOptions());
```

这两行代码就是把jsbundle文件读入到内存中,并进行执行,然后初始化各个对象。

##优化思路---内存换时间

在app启动时候,就将mReactRootView初始化出来,并缓存起来,在用的时候直接setContentView(mReactRootView),达到秒开。

###步骤1 缓存rootview管理器

缓存rootview管理器主要用于初始化和缓存rootview对象。

```
import android.app.Activity;
import android.os.Bundle;
import android.view.ViewParent;

import com.facebook.react.LifecycleState;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactPackage;
import com.facebook.react.ReactRootView;

import java.lang.reflect.Field;

/**
 * 缓存view管理
 */
public class RNCacheViewManager {

    private static ReactRootView mRootView = null;
    private static ReactInstanceManager mManager = null;
    private static AbsRnInfo mRnInfo = null;

    //初始化
    public static void init(Activity act, AbsRnInfo rnInfo) {
        init(act, rnInfo, null);
    }

    public static void init(Activity act, AbsRnInfo rnInfo, Bundle launchOptions) {
        if (mManager == null) {
            updateCache(act, rnInfo, launchOptions);
        }
    }

    public static void updateCache(Activity act, AbsRnInfo rnInfo) {
        updateCache(act, rnInfo, null);
    }

    //更新cache,适合于版本升级时候更新cache
    public static void updateCache(Activity act, AbsRnInfo rnInfo, Bundle launchOptions) {
        mRnInfo = rnInfo;
        mManager = createReactInstanceManager(act);
        mRootView = new ReactRootView(act);
        mRootView.startReactApplication(mManager, rnInfo.getMainComponentName(), launchOptions);
    }

//设置模块名称,因为是private,只能通过反射赋值
    public static void setModuleName(String moduleName) {
        try {
            Field field = ReactRootView.class.getDeclaredField("mJSModuleName");
            field.setAccessible(true);
            field.set(getReactRootView(), moduleName);
        } catch (Throwable e) {
            throw new RuntimeException(e);
        }
    }
    
//设置启动参数,因为是private,只能通过反射赋值
    public static void setLaunchOptions(Bundle launchOptions) {
        try {
            Field field = ReactRootView.class.getDeclaredField("mLaunchOptions");
            field.setAccessible(true);
            field.set(getReactRootView(), launchOptions);
        } catch (Throwable e) {
            throw new RuntimeException(e);
        }
    }

    public static ReactRootView getReactRootView() {
        if(mRootView==null){
            throw new RuntimeException("缓存view管理器尚未初始化!");
        }
        return mRootView;
    }

    public static ReactInstanceManager getReactInstanceManager() {
        if(mManager==null){
            throw new RuntimeException("缓存view管理器尚未初始化!");
        }
        return mManager;
    }

    public static AbsRnInfo getRnInfo() {
        if(mRnInfo==null){
            throw  new RuntimeException("缓存view管理器尚未初始化!");
        }
        return mRnInfo;
    }

    public static void onDestroy() {
        try {
            ViewParent parent = getReactRootView().getParent();
            if (parent != null)
                ((android.view.ViewGroup) parent).removeView(getReactRootView());
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }

    public static void clear() {
        try {
            if (mManager != null) {
                mManager.onDestroy();
                mManager = null;
            }
            if (mRootView != null) {
                onDestroy();
                mRootView = null;
            }
            mRnInfo = null;
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }

    private static ReactInstanceManager createReactInstanceManager(Activity act) {

        ReactInstanceManager.Builder builder = ReactInstanceManager.builder()
                .setApplication(act.getApplication())
                .setJSMainModuleName(getRnInfo().getJSMainModuleName())
                .setUseDeveloperSupport(getRnInfo().getUseDeveloperSupport())
                .setInitialLifecycleState(LifecycleState.BEFORE_RESUME);

        for (ReactPackage reactPackage : getRnInfo().getPackages()) {
            builder.addPackage(reactPackage);
        }

        String jsBundleFile = getRnInfo().getJSBundleFile();

        if (jsBundleFile != null) {
            builder.setJSBundleFile(jsBundleFile);
        } else {
            builder.setBundleAssetName(getRnInfo().getBundleAssetName());
        }
        return builder.build();
    }
}

```

###步骤2 重写ReactActivity
将官方的ReactActivity粘出来,重写2个方法,onCreate和onDestroy,其余代码不动。

onCreate方法中使用缓存rootview管理器来获得rootview对象,而不是重新创建。

这里曾尝试继承ReactActivity,而不是重写这个类,但是子类覆盖onCreate方法时候,必须要调用super.onCreate,否则编译会报错,但是super.onCreate方法会重新创建rootview,所以实在是绕不过去了。

```
protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        if (RNCacheViewManager.getRnInfo().getUseDeveloperSupport() && Build.VERSION.SDK_INT >= 23) {
            // Get permission to show redbox in dev builds.
            if (!Settings.canDrawOverlays(this)) {
                Intent serviceIntent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
                startActivity(serviceIntent);
                FLog.w(ReactConstants.TAG, REDBOX_PERMISSION_MESSAGE);
                Toast.makeText(this, REDBOX_PERMISSION_MESSAGE, Toast.LENGTH_LONG).show();
            }
        }

        mReactInstanceManager = RNCacheViewManager.getReactInstanceManager();
        ReactRootView mReactRootView = RNCacheViewManager.getReactRootView();
        setContentView(mReactRootView);
    }
```


onDestroy方法中,不能再调用原有的mReactInstanceManager.destroy()方法了,否则rn初始化出来的对象会被销毁,下次就用不了了。同时,要卸载掉rootview的parent对象,否则下次再setContentView时候回报错。

```
protected void onDestroy() {
        RNCacheViewManager.onDestroy();
        super.onDestroy();
    }
```    
    
RNCacheViewManager.onDestroy的方法:

```
public static void onDestroy() {
        try {
            ViewParent parent = getReactRootView().getParent();
            if (parent != null)
                ((android.view.ViewGroup) parent).removeView(getReactRootView());
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }
```


###步骤3 在app启动时候初始化缓存rootview管理器

```
RNCacheViewManager.init((Activity) context, new RnInfo(moduleName, launchOptions));
```

其中RnInfo如下:

```
public class RnInfo extends AbsRnInfo {

    private String mModuleName;
    private Bundle mLaunchOptions;

    public RnInfo(String moduleName) {
        this.mModuleName = moduleName;
    }

    public RnInfo(String moduleName, Bundle launchOptions) {
        this.mModuleName = moduleName;
        this.mLaunchOptions = launchOptions;
    }

    @Nullable
    @Override
    public Bundle getLaunchOptions() {
        return mLaunchOptions;
    }

    @Override
    public String getMainComponentName() {
        return mModuleName;
    }

    @Override
    public String getJSMainModuleName() {
        return RNKeys.Default.DEf_JS_MAIN_MODULE_NAME;
    }

    @Nullable
    @Override
    public String getJSBundleFile() {
        return RNManager.getJsBundlePath();
    }

    @Override
    public boolean getUseDeveloperSupport() {
        return true;
    }

    @Override
    public List<ReactPackage> getPackages() {
        return Arrays.asList(
                new MainReactPackage(),
                new BBReactPackage()
        );
    }
}
```

#结语
希望本篇文档能帮助遇到类似问题的小伙伴们。

reactnative虽然不是银弹,但是在目前移动端浏览器兼容性弱爆了的情况下,还是能极大的提升开发测试效率的,性能也是极佳的,看好rn的未来。


#参考文章
http://zhuanlan.zhihu.com/magilu/20587485

http://zhuanlan.zhihu.com/magilu/20259704

https://yq.aliyun.com/articles/3208?spm=5176.100239.yqblog1.39.t2g49u&utm_source=tuicool&utm_medium=referral




================================================
FILE: ReactNative开发指导/ReactNative导航设计与实现.md
================================================
# ReactNative导航设计与实现

# 前言

关于reactnaitve的导航,官方提供了2个组件,NavigatorIOS和Navigator,其中官方并不推荐使用NavigatorIOS,它不是官方维护的,不能保证及时的更新和维护。

所以本文中是以Navigator组件为基础,进行导航的设计和实现。

Navigator的劣势:Navigator组件是纯js的实现,所以在页面进行转场动画的过程中,如果js不能保证在16ms内完成其它操作的话,转场动画会有卡顿现象,后面会介绍优化的方案。

官方的Navigator组件使用方式较为灵活,本文的目的是选取一种最佳用法,并提取出通用功能应对常用场景,规范和设计项目中导航的使用。

# 定义

rn应用:全站rn应用,简称rn应用。

rn模块:部分模块使用rn,简称rn模块。

rn首页:无论是rn应用还是rn模块,进入rn页面的第一屏,简称rn首页。

nav:Navigator组件对象的简称,注意是实例化好的对象,不是类。页面间传递的导航对象统一使用此命名。

Header:自定义的导航栏组件。

# 体系结构、设计原则

一个rn应用或者一个rn模块,有且只有一个Navigator组件被定义。

在rn首页定义Navigator组件。

各个子页面统一使用首页定义的Navigator组件对象nav。

不要使用Navigator的navigationBar,请自定义导航栏组件,例如Header组件。


# Navigator组件的定义和初始化

在rn首页中的render方法中,定义一个Navigator组件,并做好以下几件事:

1. 实现好通用的renderScene方法,
2. 实现好android的物理返回按键
3. 初始化真正的rn首页

## 实现统一路由函数renderScene

renderScene函数是Navigator组件的必填函数,入参是route对象和当前的nav对象,返回值是jsx。

此函数的意思是根据传入的route,返回一个作为新页面的jsx,也就是说所有的路由算法都是在此函数中实现的。

其中route对象是一个自定义的对象,是nav.push方法中传入的对象。

此函数设计相当于门面模式,此函数是路由的统一处理器,所有的页面跳转请求都会通过此函数的计算来获得具体的jsx页面。

既然是统一的路由处理器,必然要求传入的route对象要满足统一的规则,否则无法实现统一的算法。

在此,设计route对象如下:

```
{
	name: 'page2', //名字用来做上下文判断和日志输出
	page: <Page2 />, //jsx形式的page,作为新页面的jsx
	// page: () => <Page2 />, //或者函数形式的page,此函数必须返回jsx,此jsx作为新页面的jsx
}
```
根据route对象设计,设计统一的renderScene方法如下:

```
_renderPage(route, nav) {

        if (!route.page) {
            console.error('页面导航请求没有传入page参数.');
            return null;
        }

        let page;

        if (typeof route.page === 'function') {
            page = route.page();
        } else {
            page = route.page;
        }


        let name = route.name;
        if (!name) {
            if (page) {
                name = page.type.name;
            }
        }
        console.log(`in render page ${name}`);

        return page;
    }
```

业务代码中,页面跳转的时候,只需要如下代码

```
nav.push({
	name: 'page2',
	page: <Page2 nav={nav}/>,
});
```

## android物理返回按键的处理
如果你的应用需要支持android的话,那就要实现andorid的物理返回按键的对应处理。

一般按物理返回按键要么是返回上一页面,要么是返回页面的上一状态【例如,有打开的弹窗,按返回是关闭这个弹窗】。

返回上一页面因为有通用路由器的存在,所以可以通用处理,直接使用nav.pop()即可。

但是返回页面上一状态,并不容易统一处理,所以使用基于事件扩展的方式,交给业务代码自行实现。

在此重构route对象的规则,添加事件onHardwareBackPress,如下

```
{
	name: 'page2', //名字用来做上下文判断和日志输出
	page: <Page2 />, //jsx形式的page,作为新页面的jsx
	// page: () => <Page2 />, //或者函数形式的page,此函数必须返回jsx,此jsx作为新页面的jsx
	onHardwareBackPress: () => alert('点物理按键会触发我'), // 返回false就终止统一路由器的默认动作,即终止页面返回动作,可以在此方法中实现返回页面上一状态的相关实现
}
```

android物理返回按键的统一处理代码如下,

```
componentWillMount() {

        BackAndroid.addEventListener('hardwareBackPress', () => {

            if (this.refs.nav) {

                let routes = this.refs.nav.getCurrentRoutes();
                let lastRoute = routes[routes.length - 1]; // 当前页面对应的route对象

                if (lastRoute.onHardwareBackPress) {// 先执行route注册的事件
                    let flag = lastRoute.onHardwareBackPress();
                    if (flag === false) {// 返回值为false就终止后续操作
                        return true;
                    }
                }


                if (routes.length === 1) {// 在第一页了

                    // 此处可以根据情况实现 点2次就退出应用,或者弹出rn视图等
                    
                } else {
                    
                    this.refs.nav.pop();
                    
                }
            }

            return true;
        });
    }
    
```


## 初始化真正的rn首页

此处较为简单,直接使用Navigator组件的initialRoute属性来指定初始化的route对象。

```
<Navigator initialRoute={{
           page: <Home />, // Home为伪代码,自定义的首页组件
           name: 'home',
       }} />
```

# 页面跳转

根据前面设计好的renderScene方法,直接使用如下代码,即可跳转到Page2,并将nav对象传递给了Page2.

```
nav.push({
	name: 'page2',
	page: <Page2 nav={nav}/>,
});
```

# 页面返回

页面返回直接使用

```
nav.pop();
```

# 页面转场优化

前面提到,Navigator组件完全使用js实现,由于js的单线程特点,如果在页面转场动画过程中,js干其他事情【比如渲染个某个jsx】超过了16ms,那么转场动画将不足60帧,给用户的感觉就是动画有卡顿。

为了避免这种情况,一种简单粗暴的办法就是在转场动画中不要让js来干别的事情。

那么我们如何知道转场动画什么时候结束呢,官方提供了动画交互管理器InteractionManager,示例伪代码如下:

```
InteractionManager.runAfterInteractions(() => {
      alert('哈哈 转场动画结束了!');
    });
```

大多数的场景:点击page1的某个按钮,要跳转到page2,并且page2要和服务器请求数据,根据返回的数据来渲染page2的部分or全部内容。

针对上述场景,解决方案如下,用伪代码描述:

1. page2的state至少有2个值,转场动画进行中=true,服务器查询=true
1. page2的componentWillMount方法中发起异步服务器交互请求,当请求结束setState:服务器查询=false
2. page2的componentWillMount方法中注册InteractionManager.runAfterInteractions事件,当转场结束setState:转场动画进行中=false
3. page2的render方法中,先判断(转场动画进行中=true || 服务器查询=true)就返回一个loading的提示,否则返回真正的jsx,并且此时,服务器返回的数据已经可用了

也可以参考官方文档: http://reactnative.cn/docs/0.22/performance.html#content

# 刷新的实现

目标:实现类似于html中window.reload的方法。

由于我们对route的规则限定,所以我们可以做到统一的刷新页面的逻辑。

思路是,

1. 首先获得当前页面对应的route对象
2. 然后获取route中的page属性,page属性可能是当前页面的jsx,也可能是可以产生当前页面jsx的方法
3. 最后使用官方Navigator组件提供的replace方法,来用新的route替换掉原有的route

示例参考代码如下:

```
/**
     * 刷新页面,route可以为空,会刷新当前页面
     * @param nav
     * @param route
     */
   refresh(nav, route) {

        if (!route) {
            let routes = nav.getCurrentRoutes();
            let length = routes.length;
            route = routes[length - 1]; // 使用当前页对应的route
        }

        // todo 最好的方式是直接使用route.page,但是不好使,这种写法只支持一层节点,如果有多层会有问题
        // todo 暂时未处理page是function的情况
        let Tag = route.page.type;
        nav.replace({
            page: <Tag {...route.page.props} />,
        });

    }
```

然后业务代码中这样调用,当前页面就被刷新了。

```
Util.refresh(nav); //Util是伪代码,是你定义refresh方法的对应对象

```


# rn首页直接跳转子页面

如果你开发的是rn模块【rn模块嵌入到已有app中,定义可以参考前面定义一节】,可能进入rn模块的入口会很多,比如,用rn开发一个论坛模块,正常入口进来是直接展现帖子列表,也可能会有点击某个其它按钮【此按钮是不是rn的】会直接跳转到某个帖子的详情页。

使用官方Navigator组件提供的initialRouteStack属性,可以完美的解决此问题,官方文档对此属性的说明如下:提供一个路由集合用来初始化。如果没有设置初始路由的话则必须设置该属性。如果没有提供该属性,它将被默认设置成一个只含有initialRoute的数组。

说白了就是,initialRouteStack要定义一个数组,里面是很多route对象,然后Navigator对象会展现到最后一个,而且数组中的其他route也都被初始化过了,你想返回到任何一个route都是可以的,是不是爽歪歪了。

给个示例代码吧,这是我项目中真正的代码,请当伪代码来阅读:

```
getInitialRouteStack() {

        let props = this.getProps();

        let detailId = props.detailId;
        if (detailId) { // 如果传入了详情id,那么跳转到详情页
            return [{name: 'home', },
            {
                page: <AskDetail data={{id: detailId, }}/>,
                backIsClose: true,
            }];
        }


        let wantAsk = props.wantAsk;
        if (wantAsk === true || wantAsk === 'true') { // 如果传入了提问属性=true,那么直接跳转到提问页面
            return [{name: 'home', },
            {
                page: <WantAsk backIsClose={true}/>,
                backIsClose: true,
            }];
        }

        // 跳转到首页
        return [{name: 'home', }];

    }
```

# 实现代码参考:
根据以上设计思路,笔者封装了一个Navigator组件,是对官方的navigator组件进行了一层封装,供大家参考:

```
import React from "react-native";

const {
    Platform,
    Animated,
    View,
    DeviceEventEmitter,
    Dimensions,
    Navigator,
    BackAndroid,
    } = React;

class Navigator2 extends React.Component {

    componentWillMount() {

        BackAndroid.addEventListener('hardwareBackPress', () => {

            if (this.refs.nav) {

                let routes = this.refs.nav.getCurrentRoutes();
                let lastRoute = routes[routes.length - 1];

                if (lastRoute.onHardwareBackPress) {// 先执行route注册的事件
                    let flag = lastRoute.onHardwareBackPress();
                    if (flag === false) {// 返回值为false就终止后续操作
                        return true;
                    }
                }


                if (routes.length === 1) {// 在第一页了

                    if (this.props.nav) {// 父页面仍有nav
                        this.props.nav.pop();
                    }

                    if (this.props.onHardwareBackPressInFirstPage) {
                        this.props.onHardwareBackPressInFirstPage();
                    }

                } else {

                    if (lastRoute.backIsClose === true) {
                        if (this.props.onHardwareBackPressInFirstPage) {
                            this.props.onHardwareBackPressInFirstPage();
                        }
                    } else {
                        this.refs.nav.pop();
                    }
                }
            }

            return true;
        });
    }


    getLastRoute() {
        if (this.refs.nav) {
            let routes = this.getCurrentRoutes();
            let lastRoute = routes[routes.length - 1];
            return lastRoute;
        }

        return null;
    }

    render() {
        return <Navigator renderScene={this._renderPage.bind(this)}
                          {...this.props}
                          ref='nav'
            />;
    }


    _renderPage(route, nav) {

        if (!route.page) {
            console.error('页面导航请求没有传入page参数.');
            return null;
        }

        let page;

        if (typeof route.page === 'function') {
            page = route.page();
        } else {
            page = route.page;
        }


        let name = route.name;
        if (!name) {
            if (page) {
                name = page.type.name;
            }
        }
        console.log(`in render page ${name}`);

        return page;
    }

    // todo 以下的方法为实现原版navigator的方法,这样做不好,但是没想到其它好办法
    getCurrentRoutes() {
        return this.refs.nav.getCurrentRoutes(...arguments);
    }
    jumpBack() {
        return this.refs.nav.jumpBack(...arguments);
    }
    jumpForward() {
        return this.refs.nav.jumpForward(...arguments);
    }
    jumpTo(route) {
        return this.refs.nav.jumpTo(...arguments);
    }
    push(route) {
        return this.refs.nav.push(...arguments);
    }
    pop() {
        return this.refs.nav.pop(...arguments);
    }
    replace(route) {
        return this.refs.nav.replace(...arguments);
    }
    replaceAtIndex(route, index) {
        return this.refs.nav.replaceAtIndex(...arguments);
    }
    replacePrevious(route) {
        return this.refs.nav.replacePrevious(...arguments);
    }
    immediatelyResetRouteStack(routeStack) {
        return this.refs.nav.immediatelyResetRouteStack(...arguments);
    }
    popToRoute(route) {
        return this.refs.nav.popToRoute(...arguments);
    }
    popToTop() {
        return this.refs.nav.popToTop(...arguments);
    }

}

module.exports = Navigator2;

```

#参考地址

http://reactnative.cn/docs/0.21/navigator.html#content

http://reactnative.cn/docs/0.22/performance.html#content




================================================
FILE: ReactNative开发指导/ReactNative开发技巧总结.md
================================================
# ReactNative开发技巧总结

#样式
不支持选择器

无复用就尽量用行内,避免命名难题

不支持position=fixed,利用flexbox可以搞定。<https://medium.com/@Nayflix/building-a-soundcloud-app-with-react-native-1144b6d3773a#.n6bzcbm43>

		
RN样式没有提供类似于display=none的方式,使用BaseCss提供的hidden样式,原理是绝对定位,left=-9999
	
总结的较好:http://segmentfault.com/a/1190000002658374


#调试
在系统首页调试可以极大的提供效率,系统首页直接使用你要调试的组件作为app
	
js可以用chrome来调试

css和结构就靠刷新了,官方给的结构查看器不是很好用

在一些重要逻辑部分多用console.log,特别是在触摸事件中,有时候还可以发现隐藏问题,习惯用console.log代替一些注释


#touch系列
一般包裹在view的外面,margin写在touch上,不要写在view上,否则margin会有动画效果,padding写在view上。
	
一般使用touchOpacity,不使用touchHeighlight



#text
一定不要有padding margin,如果要有请在外面套一个view,写在view上

#listview,scrollview
必须有高,否则不能滚动,flex=1也可以,相当于给了高




================================================
FILE: ReactNative开发指导/ReactNative打离线包-android篇.md
================================================
# ReactNative打离线包-android篇


官方文档:<http://facebook.github.io/react-native/docs/running-on-device-android.html#content>

官方文档2:<http://facebook.github.io/react-native/docs/signed-apk-android.html#content>

离线包就是把RN和你写的js图片等资源都打包放入app,不需要走网络下载。

#打包命令说明

react-native bundle

Options:

  --entry-file        Path to the root JS file, either absolute or relative to JS root                                   [required]
  
  --platform          Either "ios" or "android"         
                                                                 
  --transformer       Specify a custom transformer to be used (absolute path)                                            [default: "/Users/babytree-mbp13/projects/xcodeProjects/AwesomeProject/node_modules/react-native/packager/transformer.js"]
  
  --dev               If false, warnings are disabled and the bundle is minified                                         [default: true]
  
  --prepack           If true, the output bundle will use the Prepack format.                                            [default: false]
  
  --bridge-config     File name of a a JSON export of __fbBatchedBridgeConfig. Used by Prepack. Ex. ./bridgeconfig.json
  
  --bundle-output     File name where to store the resulting bundle, ex. /tmp/groups.bundle                              [required]
  
  --bundle-encoding   Encoding the bundle should be written in (https://nodejs.org/api/buffer.html#buffer_buffer).       [default: "utf8"]
  
  --sourcemap-output  File name where to store the sourcemap file for resulting bundle, ex. /tmp/groups.map       
       
  --assets-dest       Directory name where to store assets referenced in the bundle                     
                 
  --verbose           Enables logging                                                                                    [default: false]


#安卓打包步骤

1. 在工程根目录下执行打包命令,比如``` react-native bundle --entry-file demo/index.js --bundle-output ./android/app/src/main/assets/index.android.jsbundle --platform android --assets-dest ./android/app/src/main/res/ --dev false ```请参考上面命令说明,根据自己的情况进行修改再执行。注意要先保证[./android/app/src/main/assets/]文件夹存在。
2. ps:增量升级的话不要把图片资源直接打包到res中,脚本如下:```  react-native bundle --entry-file demo/index.js --bundle-output ./bundle/androidBundle/index.android.jsbundle --platform android --assets-dest ./bundle/androidBundle --dev false  ```
1. 命令执行完生成资源如图![2015-12-24 11.05.31](media/2015-12-24%2011.05.31.png)

1. 保证MainActivity.java中的setBundleAssetName与你的jsbundle文件名一致,比如`.setBundleAssetName("index.android.jsbundle")`就与我生成的资源名一致
2. 一切OK 打包测试吧



#To disable the developer menu for production builds:

For iOS open your project in Xcode and select Product → Scheme → Edit Scheme... (or press ⌘ + <). Next, select Run from the menu on the left and change the Build Configuration to Release.


For Android, by default, developer menu will be disabled in release builds done by gradle (e.g with gradle assembleRelease task). Although this behavior can be customized by passing proper value to ReactInstanceManager#setUseDeveloperSupport.




================================================
FILE: ReactNative开发指导/ReactNative打离线包-ios篇.md
================================================
# ReactNative打离线包-ios篇

官方文档,内容很旧:<http://facebook.github.io/react-native/docs/running-on-device-ios.html#content>

相关链接:<https://github.com/facebook/react-native/issues/4084>

离线包就是把RN和你写的js图片等资源都打包放入app,不需要走网络下载。

升级服务器的使用方法:
在mobile-rn/bbt-rn-update-server目录中,执行命令npm start,然后访问http://localhost:3000/

#打包命令说明

react-native bundle

Options:

  --entry-file        Path to the root JS file, either absolute or relative to JS root                                   [required]
  
  --platform          Either "ios" or "android"         
                                                                 
  --transformer       Specify a custom transformer to be used (absolute path)                                            [default: "/Users/babytree-mbp13/projects/xcodeProjects/AwesomeProject/node_modules/react-native/packager/transformer.js"]
  
  --dev               If false, warnings are disabled and the bundle is minified                                         [default: true]
  
  --prepack           If true, the output bundle will use the Prepack format.                                            [default: false]
  
  --bridge-config     File name of a a JSON export of __fbBatchedBridgeConfig. Used by Prepack. Ex. ./bridgeconfig.json
  
  --bundle-output     File name where to store the resulting bundle, ex. /tmp/groups.bundle                              [required]
  
  --bundle-encoding   Encoding the bundle should be written in (https://nodejs.org/api/buffer.html#buffer_buffer).       [default: "utf8"]
  
  --sourcemap-output  File name where to store the sourcemap file for resulting bundle, ex. /tmp/groups.map       
       
  --assets-dest       Directory name where to store assets referenced in the bundle                     
                 
  --verbose           Enables logging                                                                                    [default: false]


 
#ios打包步骤
1. 在工程根目录下执行打包命令,比如``` react-native bundle --entry-file demo/index.js --bundle-output ./bundle/iosBundle/index.ios.jsbundle --platform ios --assets-dest ./bundle/iosBundle --dev false ```请参考上面命令说明,根据自己的情况进行修改再执行。注意要先保证bundle文件夹存在。
2. 命令执行完生成如下资源 ![323424sf](media/323424sf-1.png)




2. 在xcode中添加assets【必须用Create folder references的方式,添加完是蓝色文件夹图标】和index.ios.jsbundle,如图![2015-12-23 17.35.50](media/2015-12-23%2017.35.50.png)
3. 参考官方文档,修改AppDelegate.m文件,使用OPTION 2处的代码
	```
	jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"index.ios" withExtension:@"jsbundle"];
	```
4. 一切OK 运行模拟器看效果吧
 
#ios打包遇到的问题
1. 离线包如果开启了chrome调试,会访问调试服务器,而且会一直loading出不来。 
2. 如果bundle的名字是main.jsbundle,app会一直读取旧的,改名就好了。。。非常奇葩的问题,我重新删了app,clean工程都没用,就是不能用main.jsbundle这个名字。
3. 必须用Create folder references【蓝色文件夹图标】的方式引入图片的assets,否则引用不到图片
4. 执行bundle命令之前,要保证相关的文件夹都存在


#To disable the developer menu for production builds:

For iOS open your project in Xcode and select Product → Scheme → Edit Scheme... (or press ⌘ + <). Next, select Run from the menu on the left and change the Build Configuration to Release.


For Android, by default, developer menu will be disabled in release builds done by gradle (e.g with gradle assembleRelease task). Although this behavior can be customized by passing proper value to ReactInstanceManager#setUseDeveloperSupport.



================================================
FILE: ReactNative开发指导/ReactNative的ios崩溃整理分析.md
================================================
# ReactNative的ios崩溃整理分析

共12种异常,如下:

```
wanghonglu  18:14
>---------------------- Row   1 -----------------------<
=> Start Unable to execute JS call: __fbBatchedBridge is undefined 
	-> translating『 0x100ac2b60x100aa8004 』=> RCTFatal /Users/kevin/Code/pregnancy-rn/mobile-rn/node_modules/react-native/React/Base/RCTAssert.m: line 120
	-> translating『 0x100ac2b60 』=> -[RCTBatchedBridge stopLoadingWithError:] /Users/kevin/Code/pregnancy-rn/mobile-rn/node_modules/react-native/React/Base/RCTBatchedBridge.m: line 476
	-> translating『 0x1006d72fc 』=> main /Users/wanghonglu/Desktop/project/pregnancy-v2-ios/pregnancy/pregnancy/main.m: line 13
=> End Unable to execute JS call: __fbBatchedBridge is undefined 
>------------------------------------------------------<


>---------------------- Row   2 -----------------------<
=> Start Application received signal SIGSEGV 
	-> translating『 0x1012891bc 』=> 
	-> translating『 0x100abf734 』=> __64-[RCTJSCExecutor executeApplicationScript:sourceURL:onComplete:]_block_invoke /Users/kevin/Code/pregnancy-rn/mobile-rn/node_modules/react-native/React/Executors/RCTJSCExecutor.m: line 515
	-> translating『 0x100abf944 』=> -[RCTJSCExecutor executeBlockOnJavaScriptQueue:] /Users/kevin/Code/pregnancy-rn/mobile-rn/node_modules/react-native/React/Executors/RCTJSCExecutor.m: line 547
	-> translating『 0x100abdc3c 』=> +[RCTJSCExecutor runRunLoopThread] /Users/kevin/Code/pregnancy-rn/mobile-rn/node_modules/react-native/React/Executors/RCTJSCExecutor.m: line 151
=> End Application received signal SIGSEGV 
>------------------------------------------------------<
wanghonglu  18:14
>---------------------- Row   4 -----------------------<
=> Start Application received signal SIGSEGV 
	-> translating『 0x1012891bc 』=> 
	-> translating『 0x100abf734 』=> __64-[RCTJSCExecutor executeApplicationScript:sourceURL:onComplete:]_block_invoke /Users/kevin/Code/pregnancy-rn/mobile-rn/node_modules/react-native/React/Executors/RCTJSCExecutor.m: line 515
	-> translating『 0x100abf944 』=> -[RCTJSCExecutor executeBlockOnJavaScriptQueue:] /Users/kevin/Code/pregnancy-rn/mobile-rn/node_modules/react-native/React/Executors/RCTJSCExecutor.m: line 547
	-> translating『 0x100abdc3c 』=> +[RCTJSCExecutor runRunLoopThread] /Users/kevin/Code/pregnancy-rn/mobile-rn/node_modules/react-native/React/Executors/RCTJSCExecutor.m: line 151
=> End Application received signal SIGSEGV
wanghonglu  18:14
>---------------------- Row   7 -----------------------<
=> Start SyntaxError: Unexpected end of script 
	-> translating『 0x100aa8004 』=> RCTFatal /Users/kevin/Code/pregnancy-rn/mobile-rn/node_modules/react-native/React/Base/RCTAssert.m: line 120
	-> translating『 0x100ac2b60 』=> -[RCTBatchedBridge stopLoadingWithError:] /Users/kevin/Code/pregnancy-rn/mobile-rn/node_modules/react-native/React/Base/RCTBatchedBridge.m: line 476
	-> translating『 0x1006d72fc 』=> main /Users/wanghonglu/Desktop/project/pregnancy-v2-ios/pregnancy/pregnancy/main.m: line 13
=> End SyntaxError: Unexpected end of script 
>------------------------------------------------------<


>---------------------- Row   8 -----------------------<
=> Start Unable to execute JS call: __fbBatchedBridge is undefined 
	-> translating『 0x100aa8004 』=> RCTFatal /Users/kevin/Code/pregnancy-rn/mobile-rn/node_modules/react-native/React/Base/RCTAssert.m: line 120
	-> translating『 0x100ac2b60 』=> -[RCTBatchedBridge stopLoadingWithError:] /Users/kevin/Code/pregnancy-rn/mobile-rn/node_modules/react-native/React/Base/RCTBatchedBridge.m: line 476
	-> translating『 0x1006d72fc 』=> main /Users/wanghonglu/Desktop/project/pregnancy-v2-ios/pregnancy/pregnancy/main.m: line 13
=> End Unable to execute JS call: __fbBatchedBridge is undefined 
>------------------------------------------------------<
wanghonglu  18:14
>---------------------- Row  11 -----------------------<
=> Start Application received signal SIGSEGV 
	-> translating『 0x1012891bc 』=> 
	-> translating『 0x100a92140 』=> __46-[RCTNetworking buildRequest:completionBlock:]_block_invoke /Users/kevin/Code/pregnancy-rn/mobile-rn/node_modules/react-native/Libraries/Network/RCTNetworking.m: line 215
	-> translating『 0x100a923bc 』=> -[RCTNetworking processDataForHTTPQuery:callback:] /Users/kevin/Code/pregnancy-rn/mobile-rn/node_modules/react-native/Libraries/Network/RCTNetworking.m: line 264
	-> translating『 0x100a91e2c 』=> -[RCTNetworking buildRequest:completionBlock:] /Users/kevin/Code/pregnancy-rn/mobile-rn/node_modules/react-native/Libraries/Network/RCTNetworking.m: line 204
	-> translating『 0x100a940a8 』=> -[RCTNetworking sendRequest:responseSender:] /Users/kevin/Code/pregnancy-rn/mobile-rn/node_modules/react-native/Libraries/Network/RCTNetworking.m: line 442
	-> translating『 0x100aa67ec 』=> -[RCTModuleMethod invokeWithBridge:module:arguments:] /Users/kevin/Code/pregnancy-rn/mobile-rn/node_modules/react-native/React/Base/RCTModuleMethod.m: line 426
	-> translating『 0x100ac53f0 』=> -[RCTBatchedBridge _handleRequestNumber:moduleID:methodID:params:] /Users/kevin/Code/pregnancy-rn/mobile-rn/node_modules/react-native/React/Base/RCTBatchedBridge.m: line 899
	-> translating『 0x100ac4de0 』=> __33-[RCTBatchedBridge handleBuffer:]_block_invoke.383 /Users/kevin/Code/pregnancy-rn/mobile-rn/node_modules/react-native/React/Base/RCTBatchedBridge.m: line 848
=> End Application received signal SIGSEGV 
>------------------------------------------------------<
wanghonglu  18:15
>---------------------- Row  16 -----------------------<
=> Start Unable to execute JS call: __fbBatchedBridge is undefined 
	-> translating『 0xa3b4ef 』=> RCTFatal /Users/kevin/Code/pregnancy-rn/mobile-rn/node_modules/react-native/React/Base/RCTAssert.m: line 120
	-> translating『 0xa52b37 』=> -[RCTBatchedBridge stopLoadingWithError:] /Users/kevin/Code/pregnancy-rn/mobile-rn/node_modules/react-native/React/Base/RCTBatchedBridge.m: line 476
	-> translating『 0x68b883 』=> main /Users/wanghonglu/Desktop/project/pregnancy-v2-ios/pregnancy/pregnancy/main.m: line 13
=> End Unable to execute JS call: __fbBatchedBridge is undefined 
>------------------------------------------------------<
wanghonglu  18:15
>---------------------- Row  22 -----------------------<
=> Start Application received signal SIGSEGV 
	-> translating『 0x1012891bc 』=> 
	-> translating『 0x100ac1c30 』=> -[RCTBatchedBridge registerModuleForFrameUpdates:withModuleData:] /Users/kevin/Code/pregnancy-rn/mobile-rn/node_modules/react-native/React/Base/RCTBatchedBridge.m: line 357
	-> translating『 0x100ac707c 』=> -[RCTModuleData finishSetupForInstance] /Users/kevin/Code/pregnancy-rn/mobile-rn/node_modules/react-native/React/Base/RCTModuleData.m: line 73
	-> translating『 0x100ac1a74 』=> -[RCTBatchedBridge initModules] /Users/kevin/Code/pregnancy-rn/mobile-rn/node_modules/react-native/React/Base/RCTBatchedBridge.m: line 249
	-> translating『 0x100ac02a8 』=> -[RCTBatchedBridge start] /Users/kevin/Code/pregnancy-rn/mobile-rn/node_modules/react-native/React/Base/RCTBatchedBridge.m: line 99
	-> translating『 0x100ac016c 』=> -[RCTBatchedBridge initWithParentBridge:] /Users/kevin/Code/pregnancy-rn/mobile-rn/node_modules/react-native/React/Base/RCTBatchedBridge.m: line 68
	-> translating『 0x100ad5648 』=> -[RCTBridge setUp] /Users/kevin/Code/pregnancy-rn/mobile-rn/node_modules/react-native/React/Base/RCTBridge.m: line 257
	-> translating『 0x100ad5068 』=> -[RCTBridge initWithDelegate:launchOptions:] /Users/kevin/Code/pregnancy-rn/mobile-rn/node_modules/react-native/React/Base/RCTBridge.m: line 156
	-> translating『 0x100071c60 』=> __36-[BBRNManager reactNativeBridgeInit]_block_invoke /Users/wanghonglu/Desktop/project/pregnancy-v2-ios/pregnancy/pregnancy/ReactNative/Utils/BBRNManager.m: line 56
	-> translating『 0x1006d72fc 』=> main /Users/wanghonglu/Desktop/project/pregnancy-v2-ios/pregnancy/pregnancy/main.m: line 13
=> End Application received signal SIGSEGV 
>------------------------------------------------------<
wanghonglu  18:15
>---------------------- Row  24 -----------------------<
=> Start Application received signal SIGABRT 
	-> translating『 0x1012891bc 』=> 
	-> translating『 0x100abf290 』=> __52-[RCTJSCExecutor _executeJSCall:arguments:callback:]_block_invoke /Users/kevin/Code/pregnancy-rn/mobile-rn/node_modules/react-native/React/Executors/RCTJSCExecutor.m: line 391
	-> translating『 0x100abf944 』=> -[RCTJSCExecutor executeBlockOnJavaScriptQueue:] /Users/kevin/Code/pregnancy-rn/mobile-rn/node_modules/react-native/React/Executors/RCTJSCExecutor.m: line 547
	-> translating『 0x100abeda4 』=> -[RCTJSCExecutor _executeJSCall:arguments:callback:] /Users/kevin/Code/pregnancy-rn/mobile-rn/node_modules/react-native/React/Executors/RCTJSCExecutor.m: line 385
	-> translating『 0x100abeb7c 』=> -[RCTJSCExecutor callFunctionOnModule:method:arguments:callback:] /Users/kevin/Code/pregnancy-rn/mobile-rn/node_modules/react-native/React/Executors/RCTJSCExecutor.m: line 368
	-> translating『 0x100ac43b0 』=> -[RCTBatchedBridge _actuallyInvokeAndProcessModule:method:arguments:] /Users/kevin/Code/pregnancy-rn/mobile-rn/node_modules/react-native/React/Base/RCTBatchedBridge.m: line 747
	-> translating『 0x100ac3774 』=> __39-[RCTBatchedBridge enqueueJSCall:args:]_block_invoke /Users/kevin/Code/pregnancy-rn/mobile-rn/node_modules/react-native/React/Base/RCTBatchedBridge.m: line 642
	-> translating『 0x100abf944 』=> -[RCTJSCExecutor executeBlockOnJavaScriptQueue:] /Users/kevin/Code/pregnancy-rn/mobile-rn/node_modules/react-native/React/Executors/RCTJSCExecutor.m: line 547
	-> translating『 0x100abdc3c 』=> +[RCTJSCExecutor runRunLoopThread] /Users/kevin/Code/pregnancy-rn/mobile-rn/node_modules/react-native/React/Executors/RCTJSCExecutor.m: line 151
=> End Application received signal SIGABRT 
>------------------------------------------------------<
wanghonglu  18:15
>---------------------- Row  25 -----------------------<
=> Start Application received signal SIGABRT 
	-> translating『 0x1012891bc 』=> 
	-> translating『 0x100ace79c 』=> _RCTJSONStringifyNoRetry /Users/kevin/Code/pregnancy-rn/mobile-rn/node_modules/react-native/React/Base/RCTUtils.m: line 26
	-> translating『 0x100ace5bc 』=> RCTJSONStringify /Users/kevin/Code/pregnancy-rn/mobile-rn/node_modules/react-native/React/Base/RCTUtils.m: line 71
	-> translating『 0x100abeeec 』=> __52-[RCTJSCExecutor _executeJSCall:arguments:callback:]_block_invoke /Users/kevin/Code/pregnancy-rn/mobile-rn/node_modules/react-native/React/Executors/RCTJSCExecutor.m: line 391
	-> translating『 0x100abf944 』=> -[RCTJSCExecutor executeBlockOnJavaScriptQueue:] /Users/kevin/Code/pregnancy-rn/mobile-rn/node_modules/react-native/React/Executors/RCTJSCExecutor.m: line 547
	-> translating『 0x100abeda4 』=> -[RCTJSCExecutor _executeJSCall:arguments:callback:] /Users/kevin/Code/pregnancy-rn/mobile-rn/node_modules/react-native/React/Executors/RCTJSCExecutor.m: line 385
	-> translating『 0x100abeb7c 』=> -[RCTJSCExecutor callFunctionOnModule:method:arguments:callback:] /Users/kevin/Code/pregnancy-rn/mobile-rn/node_modules/react-native/React/Executors/RCTJSCExecutor.m: line 368
	-> translating『 0x100ac43b0 』=> -[RCTBatchedBridge _actuallyInvokeAndProcessModule:method:arguments:] /Users/kevin/Code/pregnancy-rn/mobile-rn/node_modules/react-native/React/Base/RCTBatchedBridge.m: line 747
	-> translating『 0x100ac3774 』=> __39-[RCTBatchedBridge enqueueJSCall:args:]_block_invoke /Users/kevin/Code/pregnancy-rn/mobile-rn/node_modules/react-native/React/Base/RCTBatchedBridge.m: line 642
	-> translating『 0x100abf944 』=> -[RCTJSCExecutor executeBlockOnJavaScriptQueue:] /Users/kevin/Code/pregnancy-rn/mobile-rn/node_modules/react-native/React/Executors/RCTJSCExecutor.m: line 547
	-> translating『 0x100abdc3c 』=> +[RCTJSCExecutor runRunLoopThread] /Users/kevin/Code/pregnancy-rn/mobile-rn/node_modules/react-native/React/Executors/RCTJSCExecutor.m: line 151
=> End Application received signal SIGABRT 
>------------------------------------------------------<
wanghonglu  18:16
>---------------------- Row  26 -----------------------<
=> Start Application received signal SIGSEGV 
	-> translating『 0x1012891bc 』=> 
	-> translating『 0x100ac1c30 』=> -[RCTBatchedBridge registerModuleForFrameUpdates:withModuleData:] /Users/kevin/Code/pregnancy-rn/mobile-rn/node_modules/react-native/React/Base/RCTBatchedBridge.m: line 357
	-> translating『 0x100ac707c 』=> -[RCTModuleData finishSetupForInstance] /Users/kevin/Code/pregnancy-rn/mobile-rn/node_modules/react-native/React/Base/RCTModuleData.m: line 73
	-> translating『 0x100ac7400 』=> -[RCTModuleData instance] /Users/kevin/Code/pregnancy-rn/mobile-rn/node_modules/react-native/React/Base/RCTModuleData.m: line 122
	-> translating『 0x100ac113c 』=> -[RCTBatchedBridge moduleForName:] /Users/kevin/Code/pregnancy-rn/mobile-rn/node_modules/react-native/React/Base/RCTBatchedBridge.m: line 231
	-> translating『 0x100ad540c 』=> -[RCTBridge moduleForClass:] /Users/kevin/Code/pregnancy-rn/mobile-rn/node_modules/react-native/React/Base/RCTBridge.m: line 236
	-> translating『 0x100ae16d4 』=> -[RCTUIManager setBridge:] /Users/kevin/Code/pregnancy-rn/mobile-rn/node_modules/react-native/React/Modules/RCTUIManager.m: line 270
	-> translating『 0x100ac6f2c 』=> -[RCTModuleData setBridgeForInstance] /Users/kevin/Code/pregnancy-rn/mobile-rn/node_modules/react-native/React/Base/RCTModuleData.m: line 58
	-> translating『 0x100ac19b0 』=> -[RCTBatchedBridge initModules] /Users/kevin/Code/pregnancy-rn/mobile-rn/node_modules/react-native/React/Base/RCTBatchedBridge.m: line 249
	-> translating『 0x100ac02a8 』=> -[RCTBatchedBridge start] /Users/kevin/Code/pregnancy-rn/mobile-rn/node_modules/react-native/React/Base/RCTBatchedBridge.m: line 99
	-> translating『 0x100ac016c 』=> -[RCTBatchedBridge initWithParentBridge:] /Users/kevin/Code/pregnancy-rn/mobile-rn/node_modules/react-native/React/Base/RCTBatchedBridge.m: line 68
	-> translating『 0x100ad5648 』=> -[RCTBridge setUp] /Users/kevin/Code/pregnancy-rn/mobile-rn/node_modules/react-native/React/Base/RCTBridge.m: line 257
	-> translating『 0x100ad5068 』=> -[RCTBridge initWithDelegate:launchOptions:] /Users/kevin/Code/pregnancy-rn/mobile-rn/node_modules/react-native/React/Base/RCTBridge.m: line 156
	-> translating『 0x100071c60 』=> __36-[BBRNManager reactNativeBridgeInit]_block_invoke /Users/wanghonglu/Desktop/project/pregnancy-v2-ios/pregnancy/pregnancy/ReactNative/Utils/BBRNManager.m: line 56
	-> translating『 0x1006d72fc 』=> main /Users/wanghonglu/Desktop/project/pregnancy-v2-ios/pregnancy/pregnancy/main.m: line 13
=> End Application received signal SIGSEGV 
>------------------------------------------------------<
wanghonglu  18:16
>---------------------- Row  27 -----------------------<
=> Start SyntaxError: Unexpected EOF 
	-> translating『 0x100aa8004 』=> RCTFatal /Users/kevin/Code/pregnancy-rn/mobile-rn/node_modules/react-native/React/Base/RCTAssert.m: line 120
	-> translating『 0x100ac2b60 』=> -[RCTBatchedBridge stopLoadingWithError:] /Users/kevin/Code/pregnancy-rn/mobile-rn/node_modules/react-native/React/Base/RCTBatchedBridge.m: line 476
	-> translating『 0x1006d72fc 』=> main /Users/wanghonglu/Desktop/project/pregnancy-v2-ios/pregnancy/pregnancy/main.m: line 13
=> End SyntaxError: Unexpected EOF 
>------------------------------------------------------<
```

# __fbBatchedBridge is undefined 3次;Unexpected end of script 1次;Unexpected EOF 1次;

场景:异常从RCTBatchedBridge stopLoadingWithError方法【此方法是当jsbundle加载出现异常时就会执行】抛出,应为加载的jsbundle文件有问题,有可能是文件下载不对或存储空间不足等,建议加载前,使用md5进行校验。

解决:建议加载前,使用md5进行校验。校验不通过的不进行加载,尝试回退or重新下载补丁等动作。

android端也出现了__fbBatchedBridge is undefined的异常,解法也是使用md5来校验jsbundle。

参考链接:http://www.jianshu.com/p/3db03c8c4ae7


# Start Application received signal SIGSEGV

## [RCTJSCExecutor executeApplicationScript:sourceURL:onComplete:]2次

-> translating『 0x1012891bc 』=> 

最根的没有转换出来

RCTJSCExecutor executeApplicationScrip

RCTJSCExecutor executeBlockOnJavaScriptQueue

场景:暂时没有线索

解决: todo


## [RCTNetworking buildRequest:completionBlock:] 1次

-> translating『 0x1012891bc 』=> 

最根的没有转换出来

场景:js调用原生,发送网络请求

解决:todo

## [RCTBatchedBridge registerModuleForFrameUpdates:withModuleData:] 2次

-> translating『 0x1012891bc 』=> 

最根的没有转换出来

场景:初始化bridge的过程,[BBRNManager reactNativeBridgeInit]中调用[RCTBridge initWithDelegate:launchOptions:]的时候。

解决:todo

# Start Application received signal SIGABRT

## [RCTJSCExecutor _executeJSCall:arguments:callback:] 1次

-> translating『 0x1012891bc 』=> 

最根的没有转换出来

场景:是由RCTBatchedBridge enqueueJSCall调用,是native调用js。

解决:todo

## RCTUtils.m 中的 _RCTJSONStringifyNoRetry 1次

-> translating『 0x1012891bc 』=> 

最根的没有转换出来

场景:将json对象转换为json字符串。也是由[RCTJSCExecutor _executeJSCall:arguments:callback:]调用造成的。是由RCTBatchedBridge enqueueJSCall调用,是native调用js。

解决:todo



================================================
FILE: ReactNative开发指导/ReactNative的架构设计.md
================================================
# ReactNative的组件架构设计

还有一篇较早的文章,也是分析的过程,可以对本篇文章进行一个补全:RN组件状态设计思考:http://segmentfault.com/a/1190000004180955 

请注意,本篇写的是react native的架构设计,如果你用react来开发web程序,本篇文章只能仅供参考,问题都没有在web上去考虑过。

本篇较长,前面是目前flux开源框架的一些分析,后面是架构设计过程。您可以直奔主题。

用RN最大的难题是设计思想的转变,以前的设计方法论已经不太适用了。而RN仅仅提供了view的框架,构建完整app的架构并没有直接提供。

考虑目前遇到的如下问题,希望架构给出解决方案。

1. **交互**:如何解决组件间通信【父子、子父、兄弟等,特别是跨层or反向数据流动等】;用state还是接口操作组件;
3. **职责**:组件状态放哪,业务逻辑放哪,数据放哪,因为太灵活了,怎么做都可以实现功能,但是怎么做才是最好的,才是最正确的呢?

*todo一个问题:由于react是面向状态编程,相当于react的组件只关注数据的最终状态,数据是怎么产生的并不关心,但是某些场景下,数据如何产生的是会影响到组件的一些行为的【比如一个新增行要求有动画效果,查询出的行就不需要等】,这在RN中很难描述。。。。。*

RN架构就是为解决上述问题提供的指导和方法论,是通盘考虑整个开发、测试、运维的状况,做出的考虑最全面的抉择,或者为抉择提供依据。

目前为react服务的架构也有一些了,如Flux,Reflux,Redux,Relay,Marty。

##Flux
flux是官方提供的架构,目的是分层解耦,职责划分清晰,谁负责干啥很明确。具体描述可以参考官方文档,这里不详述。

1. action 封装请求
2. dispatcher 注册处理器、分发请求
3. store 是处理器,处理业务逻辑,保存数据
4. view 根据store提供的数据进行展现;接受用户的输入并发出action请求。


![](media/14500845993004.jpg)


数据流动:
Action-> Dispatcher -> Store -> Component

但我觉得解耦的太细了,干一个事,要做太多太多的额外工作了。

光注册监听动作就2次,一次是store注册到dispatcher,一次是view注册到store中。

而且,注册到dispatcher的监听应该都不叫注册,架构完全没有提供任何封装,直接暴露一个统一的回调方法,里面自行if else路由不同的store。


##Reflux
结构上与flux架构基本一致,去掉了flux的一些冗余操作【比如没有了dispatcher】,架构更加简洁和紧凑,用到了一些约定大于配置的理念。

基本上将flux的架构冗余都简化了,可以说是flux的去冗余提升版,但是没有本质的变化。

```
╔═════════╗       ╔════════╗       ╔═════════════════╗
║ Actions ║──────>║ Stores ║──────>║ View Components ║
╚═════════╝       ╚════════╝       ╚═════════════════╝
     ^                                      │
     └──────────────────────────────────────┘

```

1. 更容易的监听。listenables和约定以on开头的方法。等。
2. 去掉了dispatcher。
3. action可以进行aop编程。
4. 去掉了waitfor。store可以监听store。
5. component提供了一系列mixin,方便注册\卸载到store的监听和与store交互等。

##Redux

社区内比较受推崇,因为用起来相对比较简单


![](media/14502335830493.jpg)


特性:

1. 分层设计,职责清晰。
2. 要求store reducer都是页面单例,易于管理。
2. action为请求dto对象,是请求类型,请求数据的载体。
3. reducer是处理请求的方法。不允许有状态,必须是纯方法。必须严格遵守输入输出,中间不允许有异步调用。不允许对state直接进行修改,要想修改必须返回新对象。
4. store
	5. 维持应用的state;
	1. 提供 getState() 方法获取 state;
	2. 提供 dispatch(action) 方法分发请求来更新 state;门面模式,要求所有的请求满足统一的格式【可以进行路由、监控、日志等】,统一的调用方式。
	1. 通过 subscribe(listener) 注册监听器监听state的变化。
1. 官方文档写的较为详细,从设计到开发都有,比flux要好

痛处如下,看能否接受或者解决:

1. redux的原则1:state不能被修改。 
	4. 其实这个用react的state也会有同样的问题,最好把state设计的没有冗余,尽量少出这种情况
	4. **解决方案:**参考官方:因为我们不能直接修改却要更新数组中指定的一项数据,这里需要先把前面和后面都切开。如果经常需要这类的操作,可以选择使用帮助类 React.addons.update,updeep,或者使用原生支持深度更新的库 Immutable。最后,时刻谨记永远不要在克隆 state 前修改它。
4. 单一的庞大的reducer的拆分
	5. 这块设计也不好做,会让人疑惑
	6. 官方给的demo中直接按state的内容区分,我觉得这样做不好,如果后期有跨内容的情况,就比较奇怪了。官方给的combineReducers方案,也只是减少代码量,本质没有变化,state还是拆分处理,路由还是业务逻辑自己来做。
	7. **解决方案**:还是处理一整个state,可以按照约定写reducer类而不是方法,类里按照actionType建方法,架构自动路由并调用。
	8. 以前做java架构,路由一定是架构来调用的,目前感觉各大flux框架都是解决问题不彻底。
1. 官方建议设计模式:顶层容器组件才对redux有依赖,组件间通过props来传递数据。按照这样设计还是没有解决组件间交互和数据传递的问题。官方react设计建议:react的设计建议:http://camsong.github.io/redux-in-chinese/docs/basics/UsageWithReact.htm
2. 使用connect将state绑定到component。此处有些黑盒了。
2. 异步action用来请求服务端数据,利用middleware增强createStore的dispatch后即支持。

##Relay
没有时间,没做研究
##Marty
没有时间,没做研究

##结论

开源架构封装的简单的flux会产生较多的冗余代码。

开源架构封装的复杂的redux,其和RN绑定封装了一些东西,是一个黑盒,不易理解和维护。

介于上述两者之间的开源架构reflux,文档较上述2个少,不知道其可持续性如何。如果一定要用开源架构的话,我觉得他稍加封装是一个较为推荐的选择。

不是特复杂的程序【一般spa的程序会更复杂一些,而RN并不是spa】,这些概念只会增加你的开发难度,并且对后面维护的人要求更高。

我们继续头脑风暴,继续抽象总结一下flux系列框架, flux系列框架干了什么,没干什么,针对开篇提出的问题。

2. 【解决职责】flux系列框架都做到了解耦,分层,谁该干什么就干什么,不许干别的,让代码读起来更有预测性和一致性,方便维护
3. 【解决通信】继续解耦,flux系列框架采用事件机制解决各层之间通信,采用props传递解决各组件之间通信。


####事件系统是关键

flux系列架构解决通信问题的方法是使用事件系统,事件系统中的回调函数是业务逻辑,redux是【store action reducer】,flux是【action dispacher store】。

我们真的需要事件系统吗?

事件系统的好处: 

1. 一个事件可以注册多个回调函数
2. 各回调函数间没有耦合。

关于1

需要注册多个的这种情况并不多见,不信你去翻看你已经写好的代码,是不是大部分都是注册一个。

关于2 

解耦确实很彻底,但是当我需要控制执行顺序,需要等a执行完在执行b,怎么办?ok你可以先注册a在注册b啊。那a要是一个fetch或ajax操作呢?这时候只能乖乖的在a的请求结束回调函数中进行调用b了。又变成a依赖b了。当然,你可以继续dispatch(b),这就没有耦合了。但是你要知道注册一个事件是要有成本的,要写action,而且这种dispatch的方式,真的不太适合人类的阅读,dispatch一下,下一步都有谁来执行都不知道,这哪有直接调用来的爽快。


好吧说到这,最后的结论也出来了,不使用开源架构,借助其好的思想,替换其事件系统为面向对象结构,自行封装架构。


## 架构设计

再次强调:目前仅考虑如何应用于react native

###先扣题,针对开篇问题的解决方案如下

####交互
1. 组件对外发布:组件对外只允许使用props来暴露功能,不允许使用接口及其它一切方式
2. 父子组件间:组件的子组件通过父组件传递的接口来与父组件通信
3. 兄弟组件间:
	4. 方案1:假设a要调用b,参考第一条的话,其实就是a要改变b的props,那么a只要改b的props的来源即可,b的props的来源一般就是根组件的state。那么根组件就要有组织和协调的能力。
	5. 方案2:利用事件机制,基本同flux架构。略复杂,且我们并不需要事件的特性,本架构设计不推荐。	
#### 职责

1. root-存放state,组织子view组件,组织业务逻辑对象等
2. 子view组件-根据this.props渲染view。
3. 业务逻辑对象-提供业务逻辑方法



根据以上推导,我将其命名为面向对象的ReactNative组件架构设计,它与flux系列架构的最大的不同之处在于,用业务逻辑对象来代替了【store action dispatcher】or【store reducer】的事件系统。业务逻辑对象就是一组对象,用面向对象的设计理念设计出的n个对象,其负责处理整个页面的业务逻辑。

以上为推导过程,干货才开始。。。。

### 面向对象的ReactNative组件\页面架构设计

 一个独立完整的组件\页面一般由以下元素构成:
 
1. root组件,1个, 
	1. 负责初始化state
	2. 负责提供对外props列表
	2. 负责组合子view组件形成页面效果
	3. 负责注册业务逻辑对象提供的业务逻辑方法
	4. 负责管理业务逻辑对象
1. view子组件,0-n个,
	1. 根据props进行视图的渲染
1. 业务逻辑对象,0-n个,
	2. 提供业务逻辑方法 

		
####root组件
root组件由以下元素组成:

1. props-公有属性
2. state-RN体系的状态,必须使用Immutable对象
3. 私有属性
4. 业务逻辑对象的引用-在componentWillMount中初始化
4. 私有方法-以下划线开头,内部使用or传递给子组件使用
5. 公有方法【不推荐】,子组件和外部组件都可以用,但不推荐用公有方法来对外发布功能,破坏了面向状态编程,尽可能的使用props来发布功能


![root](media/root.png)

	

####子view组件

子view组件中包含:

1. props-公有属性
2. 私有属性-强烈不建议有,除非你能理解以下几点,建议放在父组件or业务逻辑对象中
	3. 绝对不允许和父组件的属性or状态有冗余。无论是显性冗余还是计算结果冗余,除非你能确定结算是性能的瓶颈。
	4. 此属性只有自己会用,父组件和兄弟组件不会使用,如果你不确定这点,请把这个组件放到父组件上,方便组件间通信
3. 私有方法-仅作为渲染view的使用,不许有业务逻辑
4. 公有方法【不推荐,理由同root组件】 

![gsddfa](media/gsddfa.png)


	

	
####业务逻辑对象
业务逻辑对象由以下元素组成:

3. root组件对象引用-this.root
2. 构造器-初始化root对象,初始化私有属性
2. 私有属性
3. 公有方法-对外提供业务逻辑
3. 私有方法-以下划线开头,内部使用

	
![dafa](media/dafa.png)



	 
#### ps1:通用型组件只要求尽量满足上述架构设计

通用型组件一般为不包含任何业务的纯技术组件,具有高复用价值、高定制性、通常不能直接使用需要代码定制等特点。

可以说是一个系统的各个基础零件,比如一个蒙板效果,或者一个模态弹出框。

架构的最终目的是保证系统整体结构良好,代码质量良好,易于维护。一般编写通用型组件的人也是经验较为丰富的工程师,代码质量会有保证。而且,作为零件的通用组件的使用场景和生命周期都和普通组件\页面不同,所以,仅要求通用组件编写尽量满足架构设计即可。



####ps2:view子组件复用问题
	
抛出一个问题,设计的过程中,子组件是否需要复用?子组件是否需要复用会影响到组件设计。
	
6. 需复用,只暴露props,可以内部自行管理state【尽量避免除非业务需要】
7. 不需复用,只暴露props,内部无state【因为不会单独使用,不需要setState来触发渲染】
 
其实, 一般按照不需复用的情况设计,除非复用很明确,但这时候应该抽出去,变成独立的组件存在就可以了,所以这个问题是不存在的。
	
	
	
##适用场景分析

###flux系列框架

flux系列框架的适用场景我觉得应具有以下特点:

**一个页面中组件较多,组件之间较为独立,但是重叠使用模型,模型的变化会影响很多组件的展现和行为。**

比如,开发一个类似qq的聊天页面,左侧是联系人列表,右侧是与某人的消息对话框,当收到一个消息之后,1要刷新左侧联系人列表的最近联系人,2要右侧的消息对话框中显示这个消息,3要页面title要提示新消息。这就是典型的一个新消息到来事件【消息模型发生了变化】触发三个无关联的组件都有行为和展现的变化。如果用事件系统来开发就做到了解耦的极致,未来如果还要加入第4种处理也不用修改原来的逻辑,就直接注册一下就可以了,满足了开闭原则。

**需要对app运行过程进行监控,数据采样等**

flux系列框架是一个典型的门面模式,业务动作都要通过统一的门面dispatch进行,天生具有良好的监控解决方案。


###面向对象的RN组件架构

面向对象的RN组件架构的使用场景特点我没有总结出来,我觉得所有场景都可以用,只要你业务逻辑对象设计的好,都不是问题。

还拿上面聊天界面举例子,面向对象的RN组件架构其实也可以解耦的写出写上述场景,你完全可以将业务逻辑对象之间的交互设计成一个小的事件系统,只是架构没有直接约束这种解耦,flux系列架构直接在架构中就强制编码人员做到了解耦,但是如果我不需要解耦的时候就相当于增加了复杂度,得不偿失了。

所以面向对象的RN组件架构要更灵活,也更简单更容易让人理解,更容易预测代码的执行流向,但同时因为灵活对业务逻辑对象设计者的要求也较高,针对较为复杂or重要页面建议进行详细设计并leader检查来保证质量。


##如何做监控

因为面向对象的RN架构中去掉了统一的业务逻辑调用facade入口dispatch,那我们如何来做监控呢。

###方案1:在需要监控的地方人为加入监控点。
这个方案对业务代码和监控代码的耦合确实有点大,是最差的解决方案了。不推荐。
###方案2:在基类BaseLogicObj的构造器中对对象的所有方法进行代理-todo待验证
这个方案对业务代码透明,但是还只是个想法,未进行代码测试和验证。
###方案3.....还没有想出别的方案,有没有同学给点思路?


##架构之美

最后在分享demo代码之前,摘抄了天猫前端架构师团队对架构的认识,个人觉得十分认同。

简单:
简单的东西才能长久,HTML、CSS和JavaScript之所以能够活到现在,而其他类似的很牛的方案都死掉了,原因之一是简单,才有那么多人用它,所以我们需要把技术和产品方案朝着简单的思路发展,简单才是本质,复杂一定是临时的会过时的。天猫的前端技术架构为什么都基于Kissy,为什么是两层架构,就是朝着简单的方式去思考。看起来简单,用起来简单。

高效:
简单是高效的前提,复杂的高效都是临时的会过时的,技术架构一定要提高团队的工作效率,否则一定会被抛弃,因此把简单的规则自动化,把精确的重复的事情让机器去做,前端这么多年为什么开发环境不够成熟,就是自动化的工具太少,前端又很少能力驾驭编写工具的语言,而Nodejs的出现是一个前所未有的机会。

灵活:
高效往往和灵活是对立的,就像移动上Native和Web的关系,而我们就需要思考如何做到两者兼顾,既高效又灵活,所以要不断把事情做简单,思考本质、看到本质,基于本质去实现。比如Apple为什么敢于把鼠标和键盘去掉,是因为确信人直接和界面打交道比借助一个中间硬件更能够表达人机交互的本质。

新鲜:
面向未来,前端需要不停地更新自己,无论是思想还是技术。比如整个天猫基于Kissy,那么就使用最新的Kissy版本,基础设施能够升级是一种能力,如果有一天基础设施升不了啦,那么这套技术架构就老去了。比如发现Gulp比Grunt更能够代表未来,那么我们毫不犹豫地整个团队开始进行升级。

##完整demo代码

此demo仿照redux提供的todolist demo编写。

redux demo 地址:http://camsong.github.io/redux-in-chinese/docs/basics/ExampleTodoList.html

demo截图:

![](media/14503398097842.jpg)

 

todolist页面:

```


'use strict'


let React=require('react-native');
let Immutable = require('immutable');
var BbtRN=require('../../../bbt-react-native');


var {
    BaseLogicObj,
    }=BbtRN;


let {
    AppRegistry,
    Component,
    StyleSheet,
    Text,
    View,
    Navigator,
    TouchableHighlight,
    TouchableOpacity,
    Platform,
    ListView,
    TextInput,
    ScrollView,
    }=React;

//root组件开始-----------------

let  Root =React.createClass({

    //初始化模拟数据,
    data:[{
        name:'aaaaa',
        completed:true,
    },{
        name:'bbbbb',
        completed:false,
    },{
        name:'ccccc',
        completed:false,
    }
    ,{
        name:'ddddd',
        completed:true,
    }],


    componentWillMount(){

        //初始化业务逻辑对象
        this.addTodoObj=new AddTodoObj(this);
        this.todoListObj=new TodoListObj(this);
        this.filterObj=new FilterObj(this);

        //下面可以继续做一些组件初始化动作,比如请求数据等.
        //当然了这些动作最好是业务逻辑对象提供的,这样root组件将非常干净.
        //例如这样:this.todoListObj.queryData();
    },


    //状态初始化
    getInitialState(){
      return {
          data:Immutable.fromJS(this.data),//模拟的初始化数据
          todoName:'',//新任务的text
          curFilter:'all',//过滤条件 all no ok
      }
    },



    //这里组合子view组件 并 注册业务逻辑对象提供的方法到各个子view组件上
    render(){

        return (
            <View style={{marginTop:40,flex:1}}>

                <AddTodo todoName={this.state.todoName}
                        changeText={this.addTodoObj.change.bind(this.addTodoObj)}
                         pressAdd={this.addTodoObj.press.bind(this.addTodoObj)} />

                <TodoList todos={this.state.data}
                          onTodoPress={this.todoListObj.pressTodo.bind(this.todoListObj)} />

                <Footer curFilter={this.state.curFilter}
                    onFilterPress={this.filterObj.filter.bind(this.filterObj)} />

            </View>
        );
    },



});






//业务逻辑对象开始-------------------------可以使用OO的设计方式设计成多个对象

//业务逻辑对象要符合命名规范:以Obj结尾
//BaseLogicObj是架构提供的基类,里面封装了构造器和一些常用取值函数
class AddTodoObj extends BaseLogicObj{

    press(){
        if(!this.getState().todoName)return;
        let list=this.getState().data;
        let todo=Immutable.fromJS({name:this.getState().todoName,completed:false,});
        this.setState({data:list.push(todo),todoName:''});
    }

    change(e){
        this.setState({todoName:e.nativeEvent.text});
    }

}


class TodoListObj extends BaseLogicObj {




    pressTodo(todo){

        let data=this.getState().data;

        let i=data.indexOf(todo);

        let todo2=todo.set('completed',!todo.get('completed'));

        this.setState({data:data.set(i,todo2)});
    }
}


class FilterObj extends BaseLogicObj {


    filter(type){

        let data=this.getState().data.toJS();
        if(type=='all'){
            data.map((todo)=>{
                todo.show=true;
            });
        }else if(type=='no'){
            data.map((todo)=>{
                if(todo.completed)todo.show=false;
                else todo.show=true;
             });
        }else if(type=='ok'){
            data.map((todo)=>{
                if(todo.completed)todo.show=true;
                else todo.show=false;
            });
        }


        this.setState({curFilter:type,data:Immutable.fromJS(data)});
    }



}


//view子组件开始---------------------------


//子view对象中仅仅关注:从this.props转化成view
let Footer=React.createClass({

    render(){

        return (


            <View style={{flexDirection:'row', justifyContent:'flex-end',marginBottom:10,}}>

                <FooterBtn {...this.props} title='全部' name='all'  cur={this.props.curFilter=='all'?true:false} />
                <FooterBtn {...this.props} title='未完成' name='no' cur={this.props.curFilter=='no'?true:false} />
                <FooterBtn {...this.props} title='已完成' name='ok' cur={this.props.curFilter=='ok'?true:false} />

            </View>



        );
    },


});


let FooterBtn=React.createClass({

    render(){

        return (

            <TouchableOpacity onPress={()=>this.props.onFilterPress(this.props.name)}
                              style={[{padding:10,marginRight:10},this.props.cur?{backgroundColor:'green'}:null]} >
                <Text style={[this.props.cur?{color:'fff'}:null]}>
                    {this.props.title}
                </Text>
            </TouchableOpacity>

        );
    },


});


let AddTodo=React.createClass({

    render(){

        return (


            <View style={{flexDirection:'row', alignItems:'center'}}>


                <TextInput value={this.props.todoName}
                    onChange={this.props.changeText}
                    style={{width:200,height:40,borderWidth:1,borderColor:'e5e5e5',margin:10,}}></TextInput>


                <TouchableOpacity onPress={this.props.pressAdd}
                    style={{backgroundColor:'green',padding:10}} >
                    <Text style={{color:'fff'}} >
                        添加任务
                    </Text>
                </TouchableOpacity>

            </View>



        );
    },


});



let Todo=React.createClass({

    render(){
        let todo=this.props.todo;
        return (
            todo.get("show")!=false?
            <TouchableOpacity  onPress={()=>this.props.onTodoPress(todo)}
                style={{padding:10,borderBottomWidth:1,borderBottomColor:'#e5e5e5'}}>
                <Text style={[todo.get('completed')==true?{textDecorationLine:'line-through',color:'#999'}:null]} >
                    {todo.get('completed')==true?'已完成   ':'未完成   '} {todo.get('name')}
                </Text>
            </TouchableOpacity>
             :null
        );
    },


});


let TodoList=React.createClass({
    render(){
        return (
            <ScrollView style={{flex:1}}>
                {this.props.todos.reverse().map((todo, index) => <Todo {...this.props} todo={todo} key={index}  />)}
            </ScrollView>
        );
    },
});




module.exports=Root;


```

业务逻辑对象基类BaseLogicObj:

```


'use strict'

class BaseLogicObj{


    constructor(root){
        if(!root){
            console.error('实例化BaseLogicObj必须传入root组件对象.');
        }
        this.root=root;
    }

    getState(){
        return this.root.state;
    }

    setState(s){
        this.root.setState(s);
    }

    getRefs(){
        return this.root.refs;
    }

    getProps(){
        return this.root.props;
    }

}

module.exports=BaseLogicObj;

```




================================================
FILE: ReactNative开发指导/ReactNative组件状态设计思考.md
================================================
# ReactNative组件状态设计思考


这篇文章写的较早,是刚接触RN的时候进行的思考总结,是一个分析的过程,您还可以参考思想更成熟一点的这篇:RN组件架构设计:http://segmentfault.com/a/1190000004161358

设计React组件与设计一个jquery组件或者一个原生js组件最大的区别就是状态的设计。

##术语定义
1. 属性 
	2. 泛指用户在初始化组件时候可以传给组件的
	3. 有些框架也叫options
	4. 是public的
	5. 在RN体系中,叫props,其中还包含了事件
2. 事件
	3. 是public的
	4. 是function类型的
	5. 在RN体系中使用props来引用
3. 接口
	4. 是public的
	5. 是function类型的
	6. 通过组件实例化之后的对象,可以进行调用
4. 内部属性
	5. 是private的
	6. 传统设计方案中一般用于存储组件的状态,数据等
	6. RN体系中没有对其进行明确,可以自由设计 
5. 状态
	6. RN体系中明确提出的概念 
	7. 传统设计方案中一般使用内部属性来表示


##传统设计思路

按照原来设计组件的方法论,一个UI组件对外应该具有属性、事件、接口,对内具有内部属性,内部接口。

1. 属性就像一份配置文件,描述了组件应该具有的功能、外观或者初始状态。
2. 事件是组件在工作工程中,当满足某种条件的时候触发的回调函数
3. 接口是组件对象的方法,可以让组件去执行某个任务

在原来的设计理念中,并没有提出组件状态的概念,但是其也是一直存在的,通常是使用组件私有属性来存储。

比如,你设计一个按钮,那么他可能有正常状态,禁用状态,那么我们会设计一个属性disable={true|false}来通知组件初始化的具有的状态,设计2个接口disable、enable来赋予js有动态改变其状态的能力,设计2个事件onEnable、onDisable来通知回调函数组件状态发生了变化。伪代码如下:

```
//组件定义
class button{

	constructor(disable,pid){//构造函数
	
		this.disable=disable,//属性:组件初始化使用这个作为状态
		this.pid=pid;//属性:父容器的id
		
		this._disable=null,//状态:私有属性
		this._el=null,//对html节点的引用,私有属性

		if(this.disable==true){//根据属性来决定初始化状态
			this.disable();
		}else{
			this.enable();
		}
		this.render();//渲染组件
	}
		
	
	enable(){
		this._disable=false;
		if(this._el)this._el.set('disable',false);
		this.fireEvent('onEnable');//触发事件
	}
	
	disable(){
		this._disable=true;
		if(this._el)this._el.set('disable',true);
		this.fireEvent('onDisable');//触发事件
	}
	
	
	render(){
		//渲染组件,状态直接影响了组件的表现和功能
		$(this.pid).innerHTML='<button disable='+this._disable+' />';
		
		//初始化对dom节点的引用
		this._el=$(this.pid).getChild();
	}
	
}

//父容器
<div id='a'></div>

//实例化组件并使用
var btn = new button(false,'a');

//调用btn提供的方法,此时会触发onEnable事件
btn.enable();
```

##RN设计思路

上面的示例中,表示了一个传统UI组件的设计思路,_disable就是这个button组件的关键状态,它直接影响了组件的表现和行为。

而react架构直接把组件状态提升到了一个新的高度,主要有以下几点:

1. 使用固定的接口来声明组件状态和状态默认值
2. 使用固定的接口来获得和改变组件状态的值
2. 状态的改变一定会改变组件的表现,会导致组件的重新渲染

前两项都不是问题,因为我们原来也得有这些东西,只不过写法发生了变化,关键是最后一项。`这里说的不是问题,指的是思路上比较容易接受。这种固定写法,问题也很明显,因为要想把一个状态从RN状态体系拿进拿出,会产生一定的工作成本,很是不爽。`

我一直在思索,组件状态的变化一定要导致view的变化吗?

答案肯定是no,因为有些状态仅仅影响组件的行为,并不影响表现。`比如说,我赋予按钮一个新功能,它可以提交某个表单的数据,也就是需要一个新的状态formName,他就不影响表现,只影响行为。`

考虑到性能的极致,我们就只能把这种状态放到RN的状态体系之外,作为对象的私有属性存在。

RN号称diff算法性能很高,但也不是0损耗,如果对RN的渲染理解很透彻,你当然也可以不这样设计,但是我这里还是倾向于保守一些,否则后期的调整也是有工作量的,因为定义、初始化、取值、改值这些操作代码都不一样。`写到这里我突然想到,如果可以,我们可以通过某种方法方便的修改某个状态是否影响表现,不用改其它代码的话,那么我们设计状态的时候就不用区分了,就能让我们更关注设计本身。`


##结论

说道这里,基本可以理清思路了。

组件按照传统方式设计,该怎么设计就怎么设计,在设计原来组件内部属性的时候,多考虑一步,哪些内部属性的改变是影响表现的,哪些内部属性是不影响表现的。将影响表现的放入到RN状态体系中,将不影响表现的,放入内部属性中。即可。

##tips
1. 耦合性很强的父子组件,建议将状态统一放到父组件中,子组件中不要放状态了,无论是状态的跨组件共享,还是对view渲染的触发都很方便。除非你很确定某个状态只子组件内部使用,通常这种情况后边可能也会发生变化。
2. 以下问题可以帮助识别是否是state,摘自官网
	3. 是否是从父级通过 props 传入的?如果是,可能不是 state 。
	1. 是否会随着时间改变?如果不是,可能不是 state 。
	1. 能根据组件中其它 state 数据或者 props 计算出来吗?如果是,就不是 state 。
2. 根据state的特点进行识别,加入到上一条
	3. 属性的改变会影响到view的变化就可能是state
2. 参考地址
	3. https://facebook.github.io/react/docs/thinking-in-react.html
	4. http://wiki.jikexueyuan.com/project/react/thinking-in-react.html












================================================
FILE: ReactNative开发指导/ReactNative调试菜单.md
================================================
# ReactNative调试菜单


加上这2个就有rn调试菜单了

![](media/14773029386169.jpg)




================================================
FILE: ReactNative开发指导/React的render优化框架.md
================================================
# React的render优化通用解决方案

# 前言

在使用react框架(无论是单独使用react还是reactnative)的过程中,性能都是我们不得不考虑的因素,虽然react使用虚拟dom比对的方式来避免了频繁且冗余的真实dom操作,但是,虚拟dom的生成和比对并不是0损耗,仍然会耗费性能,当生成dom的逻辑过于复杂,当数据量非常大,当dom的节点非常多,都会放大这个损耗,都会使应用的帧数不足导致卡顿。

如何来降低这个损耗呢,让我们先来看一看官方提供的解决办法。

# 官方建议方案--shouldComponentUpdate

在说shouldComponentUpdate之前,先说一下setState的过程。

## setState的过程

setState是react的关键函数,对state的修改,会触发组件及其所有子组件的重绘动作。整个过程大致如下:

1. 组件A的state被改变了
1. 执行组件A的render方法。
2. 在组件A的render方法执行过程中,组件A的所有子组件也会执行render方法,子组件的子自己也会执行,以此类推,这是一个递归动作。
3. 当所有子组件、孙子组件等所有的后代组件都执行完render方法,react引擎就获得了组件A的虚拟dom。
4. react引擎使用组件A的虚拟dom和组件A的真实dom做diff
5. react引擎根据diff的结果去增量更新真实dom,这样一次setState的动作就完成了。

## shouldComponentUpdate

官方提供了shouldComponentUpdate生命周期事件来使业务代码获得控制组件是否需要执行render方法,整个setState过程变成如下:

1. 组件A的state被改变了
1. 执行组件的shouldComponentUpdate方法,如果返回false,就终止后续所有操作
1. 执行组件A的render方法。
2. 在组件A的render方法执行过程中,组件A的所有子组件也会执行render方法,子组件的子自己也会执行,以此类推,这是一个递归动作。
3. 当所有子组件、孙子组件等所有的后代组件都执行完render方法,react引擎就获得了组件A的虚拟dom。
4. react引擎使用组件A的虚拟dom和组件A的真实dom做diff
5. react引擎根据diff的结果去增量更新真实dom,这样一次setState的动作就完成了。


# 官方方案带来的问题

shouldComponentUpdate方法将react频繁的render动作转变成频繁的state和props的比对动作,但是因为shouldComponentUpdate方法会被频繁的调用,如果实现的不佳,性能也会出现问题。

那么如何优化shouldComponentUpdate方法,就成为了我们的关键路径问题.

# shouldComponentUpdate优化方案1----不可变数据类型

这是官方提供的推荐方案,确实比对的性能非常高,但是也有2个缺点,1是会创建更多的对象,占用了更多的内存,但是也还好,属于可接受范围内,2是改变了我们使用对象的原有方式和思路,习惯性的使用原有的操作对象的方法,就会产生bug,而且很难排查。

# shouldComponentUpdate优化方案2----浅比对+forceUpdate

首先设计state和props对象要尽量使用简单数据结构,也就是一层的对象结构。

然后在组件基类对象中实现默认的shouldComponentUpdate实现,并使用浅比对的方式比对state和props。

所有的组建都继承这个组件基类。

当不得不使用了复杂对象结构的时候,使用forceUpdate或者自行实现shouldComponentUpdate方法来解决。

这个方案的好处是,使用了折中的方式来解决这个问题,大部分情况使用浅比对,小部分情况使用forceUpdate;浅比对的性能虽然没有不可变数据类型好,但也不是很差,完全可以接受,而且没有引入颠倒开发思维的不可变数据类型,让出bug的几率降低,在取舍中达到一个比较令人满意的点。



[评论直达连接](https://github.com/cnsnake11/blog/issues/23)








================================================
FILE: ReactNative开发指导/已有工程集成ReactNaitve-IOS.md
================================================
# 已有工程集成ReactNative-IOS

以下步骤为手动添加的方式,使用rnpm的方式请参考官方文档。

本文是对官方文档的一个补充,大部分内容来源于官网文档。

官方参考地址: http://facebook.github.io/react-native/docs/linking-libraries-ios.html#content

中文参考地址:http://reactnative.cn/docs/linking-libraries-ios.html#content

#第一步:添加.xcodeproj文件
把需要的.xcodeproj文件,拖到你的XCode工程下(通常拖到XCode的Libraries分组里)


![](media/14519905288921.jpg)


react-native需要集成的.xcodeproj文件清单如下:

```
node_modules/react-native/React/React.xcodeproj
node_modules/react-native/Libraries/Image/RCTImage.xcodeproj
node_modules/react-native/Libraries/Network/RCTNetwork.xcodeproj
node_modules/react-native/Libraries/Text/RCTText.xcodeproj
node_modules/react-native/Libraries/Vibration/RCTVibration.xcodeproj
node_modules/react-native/Libraries/WebSocket/RCTWebSocket.xcodeproj
node_modules/react-native/Libraries/LinkingIOS/RCTLinking.xcodeproj
node_modules/react-native/Libraries/Settings/RCTSettings.xcodeproj

```

#第二步添加.a文件

点击你的主工程文件,选择Build Phases,然后把刚才所添加进去的.xcodeproj下的Products文件夹中的静态库文件(.a文件),拖到Link Binary With Libraries组内。


![](media/14519905532406.jpg)


#第三步注册头文件路径-不是所有依赖都需要,注册React.xcodeproj即可

需要在原生代码中使用这个库,还是只需要通过JavaScript访问?
如果你只需要通过JavaScript访问这个库,你就可以跳过这步了。


打开你的工程文件,选择Build Settings,然后搜索Header Search Paths,然后添加库所在的目录(如果它还有像React这样的子目录需要包含,注意要选中recursive选项)

![](media/14519906182589.jpg)


注意:React.xcodeproj是需要注册的。下面的目录要改成自己的目录。

$(SRCROOT)/RN/node_modules/react-native/React  

recursive


#报错: App Transport Security has blocked a cleartext HTTP (http://) resource load since it is insecure

报错原因是需要开启内网http的访问权限。

1. 在Info.plist中添加 NSAppTransportSecurity 类型 Dictionary ;
1. 在 NSAppTransportSecurity 下添加 NSAllowsArbitraryLoads 类型Boolean ,值设为 YES;

参考地址:

http://www.cnblogs.com/chglog/p/4746683.html


#报错:unrecognized selector sent to instance

解决方案:

Build Settings -> other linker flags -> -ObjC


参考地址1:https://github.com/facebook/react-native/issues/2396

参考地址2:http://stackoverflow.com/questions/32775481/rctbatchedbridge-perfstats-unrecognized-selector-sent-to-instance


#报错:RCTStatusBarManager module requires that the UIViewControllerBasedStatusBarAppearance key in the Info.plist is set to NO

错误信息说的很清楚了。

在Info.plist中添加View controller-based status bar appearance为NO。


#关闭自动启动调试服务器

在React.xcodeproj的Build Phases中的第一个(有8081那个)Run Script。用    <<!   代码代码代码  !  注释掉即可。

![123213123](media/123213123.png)




================================================
FILE: ReactNative开发指导/淘宝d2分享-ReactNative变革无线前端.md
================================================
#ReactNative变革无线前端-淘宝d2分享

![淘宝-ReactNative变革无线前端 49-1](media/%E6%B7%98%E5%AE%9D-ReactNative%E5%8F%98%E9%9D%A9%E6%97%A0%E7%BA%BF%E5%89%8D%E7%AB%AF%2049-1.jpeg)
![淘宝-ReactNative变革无线前端 50-2](media/%E6%B7%98%E5%AE%9D-ReactNative%E5%8F%98%E9%9D%A9%E6%97%A0%E7%BA%BF%E5%89%8D%E7%AB%AF%2050-2.jpeg)
![淘宝-ReactNative变革无线前端 51-3](media/%E6%B7%98%E5%AE%9D-ReactNative%E5%8F%98%E9%9D%A9%E6%97%A0%E7%BA%BF%E5%89%8D%E7%AB%AF%2051-3.jpeg)
![淘宝-ReactNative变革无线前端 52-4](media/%E6%B7%98%E5%AE%9D-ReactNative%E5%8F%98%E9%9D%A9%E6%97%A0%E7%BA%BF%E5%89%8D%E7%AB%AF%2052-4.jpeg)
![淘宝-ReactNative变革无线前端 53-5](media/%E6%B7%98%E5%AE%9D-ReactNative%E5%8F%98%E9%9D%A9%E6%97%A0%E7%BA%BF%E5%89%8D%E7%AB%AF%2053-5.jpeg)
![淘宝-ReactNative变革无线前端 54-6](media/%E6%B7%98%E5%AE%9D-ReactNative%E5%8F%98%E9%9D%A9%E6%97%A0%E7%BA%BF%E5%89%8D%E7%AB%AF%2054-6.jpeg)
![淘宝-ReactNative变革无线前端 55-7](media/%E6%B7%98%E5%AE%9D-ReactNative%E5%8F%98%E9%9D%A9%E6%97%A0%E7%BA%BF%E5%89%8D%E7%AB%AF%2055-7.jpeg)
![淘宝-ReactNative变革无线前端 56-8](media/%E6%B7%98%E5%AE%9D-ReactNative%E5%8F%98%E9%9D%A9%E6%97%A0%E7%BA%BF%E5%89%8D%E7%AB%AF%2056-8.jpeg)
![淘宝-ReactNative变革无线前端 57-9](media/%E6%B7%98%E5%AE%9D-ReactNative%E5%8F%98%E9%9D%A9%E6%97%A0%E7%BA%BF%E5%89%8D%E7%AB%AF%2057-9.jpeg)
![淘宝-ReactNative变革无线前端 58-10](media/%E6%B7%98%E5%AE%9D-ReactNative%E5%8F%98%E9%9D%A9%E6%97%A0%E7%BA%BF%E5%89%8D%E7%AB%AF%2058-10.jpeg)
![淘宝-ReactNative变革无线前端 59-11](media/%E6%B7%98%E5%AE%9D-ReactNative%E5%8F%98%E9%9D%A9%E6%97%A0%E7%BA%BF%E5%89%8D%E7%AB%AF%2059-11.jpeg)
![淘宝-ReactNative变革无线前端 60-12](media/%E6%B7%98%E5%AE%9D-ReactNative%E5%8F%98%E9%9D%A9%E6%97%A0%E7%BA%BF%E5%89%8D%E7%AB%AF%2060-12.jpeg)
![淘宝-ReactNative变革无线前端 61-13](media/%E6%B7%98%E5%AE%9D-ReactNative%E5%8F%98%E9%9D%A9%E6%97%A0%E7%BA%BF%E5%89%8D%E7%AB%AF%2061-13.jpeg)
![淘宝-ReactNative变革无线前端 62-14](media/%E6%B7%98%E5%AE%9D-ReactNative%E5%8F%98%E9%9D%A9%E6%97%A0%E7%BA%BF%E5%89%8D%E7%AB%AF%2062-14.jpeg)
![淘宝-ReactNative变革无线前端 63-15](media/%E6%B7%98%E5%AE%9D-ReactNative%E5%8F%98%E9%9D%A9%E6%97%A0%E7%BA%BF%E5%89%8D%E7%AB%AF%2063-15.jpeg)
![淘宝-ReactNative变革无线前端 64-16](media/%E6%B7%98%E5%AE%9D-ReactNative%E5%8F%98%E9%9D%A9%E6%97%A0%E7%BA%BF%E5%89%8D%E7%AB%AF%2064-16.jpeg)
![淘宝-ReactNative变革无线前端 65-17](media/%E6%B7%98%E5%AE%9D-ReactNative%E5%8F%98%E9%9D%A9%E6%97%A0%E7%BA%BF%E5%89%8D%E7%AB%AF%2065-17.jpeg)
![淘宝-ReactNative变革无线前端 66-18](media/%E6%B7%98%E5%AE%9D-ReactNative%E5%8F%98%E9%9D%A9%E6%97%A0%E7%BA%BF%E5%89%8D%E7%AB%AF%2066-18.jpeg)
![淘宝-ReactNative变革无线前端 67-19](media/%E6%B7%98%E5%AE%9D-ReactNative%E5%8F%98%E9%9D%A9%E6%97%A0%E7%BA%BF%E5%89%8D%E7%AB%AF%2067-19.jpeg)
![淘宝-ReactNative变革无线前端 68-20](media/%E6%B7%98%E5%AE%9D-ReactNative%E5%8F%98%E9%9D%A9%E6%97%A0%E7%BA%BF%E5%89%8D%E7%AB%AF%2068-20.jpeg)
![淘宝-ReactNative变革无线前端 69-21](media/%E6%B7%98%E5%AE%9D-ReactNative%E5%8F%98%E9%9D%A9%E6%97%A0%E7%BA%BF%E5%89%8D%E7%AB%AF%2069-21.jpeg)
![淘宝-ReactNative变革无线前端 70-22](media/%E6%B7%98%E5%AE%9D-ReactNative%E5%8F%98%E9%9D%A9%E6%97%A0%E7%BA%BF%E5%89%8D%E7%AB%AF%2070-22.jpeg)
![淘宝-ReactNative变革无线前端 71-23](media/%E6%B7%98%E5%AE%9D-ReactNative%E5%8F%98%E9%9D%A9%E6%97%A0%E7%BA%BF%E5%89%8D%E7%AB%AF%2071-23.jpeg)
![淘宝-ReactNative变革无线前端 72-24](media/%E6%B7%98%E5%AE%9D-ReactNative%E5%8F%98%E9%9D%A9%E6%97%A0%E7%BA%BF%E5%89%8D%E7%AB%AF%2072-24.jpeg)
![淘宝-ReactNative变革无线前端 73-25](media/%E6%B7%98%E5%AE%9D-ReactNative%E5%8F%98%E9%9D%A9%E6%97%A0%E7%BA%BF%E5%89%8D%E7%AB%AF%2073-25.jpeg)
![淘宝-ReactNative变革无线前端 74-26](media/%E6%B7%98%E5%AE%9D-ReactNative%E5%8F%98%E9%9D%A9%E6%97%A0%E7%BA%BF%E5%89%8D%E7%AB%AF%2074-26.jpeg)
![淘宝-ReactNative变革无线前端 75-27](media/%E6%B7%98%E5%AE%9D-ReactNative%E5%8F%98%E9%9D%A9%E6%97%A0%E7%BA%BF%E5%89%8D%E7%AB%AF%2075-27.jpeg)
![淘宝-ReactNative变革无线前端 76-28](media/%E6%B7%98%E5%AE%9D-ReactNative%E5%8F%98%E9%9D%A9%E6%97%A0%E7%BA%BF%E5%89%8D%E7%AB%AF%2076-28.jpeg)
![淘宝-ReactNative变革无线前端 77-29](media/%E6%B7%98%E5%AE%9D-ReactNative%E5%8F%98%E9%9D%A9%E6%97%A0%E7%BA%BF%E5%89%8D%E7%AB%AF%2077-29.jpeg)
![淘宝-ReactNative变革无线前端 78-30](media/%E6%B7%98%E5%AE%9D-ReactNative%E5%8F%98%E9%9D%A9%E6%97%A0%E7%BA%BF%E5%89%8D%E7%AB%AF%2078-30.jpeg)
![淘宝-ReactNative变革无线前端 79-31](media/%E6%B7%98%E5%AE%9D-ReactNative%E5%8F%98%E9%9D%A9%E6%97%A0%E7%BA%BF%E5%89%8D%E7%AB%AF%2079-31.jpeg)
![淘宝-ReactNative变革无线前端 80-32](media/%E6%B7%98%E5%AE%9D-ReactNative%E5%8F%98%E9%9D%A9%E6%97%A0%E7%BA%BF%E5%89%8D%E7%AB%AF%2080-32.jpeg)
![淘宝-ReactNative变革无线前端 81-33](media/%E6%B7%98%E5%AE%9D-ReactNative%E5%8F%98%E9%9D%A9%E6%97%A0%E7%BA%BF%E5%89%8D%E7%AB%AF%2081-33.jpeg)
![淘宝-ReactNative变革无线前端 82-34](media/%E6%B7%98%E5%AE%9D-ReactNative%E5%8F%98%E9%9D%A9%E6%97%A0%E7%BA%BF%E5%89%8D%E7%AB%AF%2082-34.jpeg)
![淘宝-ReactNative变革无线前端 83-35](media/%E6%B7%98%E5%AE%9D-ReactNative%E5%8F%98%E9%9D%A9%E6%97%A0%E7%BA%BF%E5%89%8D%E7%AB%AF%2083-35.jpeg)
![淘宝-ReactNative变革无线前端 84-36](media/%E6%B7%98%E5%AE%9D-ReactNative%E5%8F%98%E9%9D%A9%E6%97%A0%E7%BA%BF%E5%89%8D%E7%AB%AF%2084-36.jpeg)
![淘宝-ReactNative变革无线前端 85-37](media/%E6%B7%98%E5%AE%9D-ReactNative%E5%8F%98%E9%9D%A9%E6%97%A0%E7%BA%BF%E5%89%8D%E7%AB%AF%2085-37.jpeg)
![淘宝-ReactNative变革无线前端 86-38](media/%E6%B7%98%E5%AE%9D-ReactNative%E5%8F%98%E9%9D%A9%E6%97%A0%E7%BA%BF%E5%89%8D%E7%AB%AF%2086-38.jpeg)
![淘宝-ReactNative变革无线前端 87-39](media/%E6%B7%98%E5%AE%9D-ReactNative%E5%8F%98%E9%9D%A9%E6%97%A0%E7%BA%BF%E5%89%8D%E7%AB%AF%2087-39.jpeg)
![淘宝-ReactNative变革无线前端 88-40](media/%E6%B7%98%E5%AE%9D-ReactNative%E5%8F%98%E9%9D%A9%E6%97%A0%E7%BA%BF%E5%89%8D%E7%AB%AF%2088-40.jpeg)
![淘宝-ReactNative变革无线前端 89-41](media/%E6%B7%98%E5%AE%9D-ReactNative%E5%8F%98%E9%9D%A9%E6%97%A0%E7%BA%BF%E5%89%8D%E7%AB%AF%2089-41.jpeg)
![淘宝-ReactNative变革无线前端 90-42](media/%E6%B7%98%E5%AE%9D-ReactNative%E5%8F%98%E9%9D%A9%E6%97%A0%E7%BA%BF%E5%89%8D%E7%AB%AF%2090-42.jpeg)
![淘宝-ReactNative变革无线前端 91-43](media/%E6%B7%98%E5%AE%9D-ReactNative%E5%8F%98%E9%9D%A9%E6%97%A0%E7%BA%BF%E5%89%8D%E7%AB%AF%2091-43.jpeg)
![淘宝-ReactNative变革无线前端 92-44](media/%E6%B7%98%E5%AE%9D-ReactNative%E5%8F%98%E9%9D%A9%E6%97%A0%E7%BA%BF%E5%89%8D%E7%AB%AF%2092-44.jpeg)
![淘宝-ReactNative变革无线前端 93-45](media/%E6%B7%98%E5%AE%9D-ReactNative%E5%8F%98%E9%9D%A9%E6%97%A0%E7%BA%BF%E5%89%8D%E7%AB%AF%2093-45.jpeg)
![淘宝-ReactNative变革无线前端 94-46](media/%E6%B7%98%E5%AE%9D-ReactNative%E5%8F%98%E9%9D%A9%E6%97%A0%E7%BA%BF%E5%89%8D%E7%AB%AF%2094-46.jpeg)
![淘宝-ReactNative变革无线前端 95-47](media/%E6%B7%98%E5%AE%9D-ReactNative%E5%8F%98%E9%9D%A9%E6%97%A0%E7%BA%BF%E5%89%8D%E7%AB%AF%2095-47.jpeg)

![淘宝-ReactNative变革无线前端 96-48](media/%E6%B7%98%E5%AE%9D-ReactNative%E5%8F%98%E9%9D%A9%E6%97%A0%E7%BA%BF%E5%89%8D%E7%AB%AF%2096-48.jpeg)



================================================
FILE: ReactNative开发规范/目录与命名规范.md
================================================
#ReactNative目录与命名规范 

##RN项目结构规划如下:
![2015-12-22 11.47.01](media/2015-12-2211.47.01.png)


##业务模块目录与命名规范

###业务模块目录规范
![015-12-22 14.22.04](media/015-12-2214.22.04.png)



###业务模块文件规范


![2015-12-22 14.25.19](media/2015-12-2214.25.19.png)



##基础框架目录与命名规范

![2015-12-22 14.28.32](media/2015-12-2214.28.32.png)


##总结

1. 扩展名统一为.js
1. 样式文件要如下格式:组件名称.css.js
1. 紧挨着文件的文件夹名,直接使用组件/页面名称命名
1. 组件or页面的首字母要大写,驼峰命名
2. 如果同一个文件夹下有同名而不同作用的js文件,则通过中缀(小写)进一步区分,例如:HomeView.component.js,HomeView.css.js,HomeView.action.js等
1. img文件夹可选








================================================
FILE: ReactNative开发规范/组件、页面结构规范.md
================================================
#ReactNative组件/页面结构规范

## 业务页面/组件结构规范

 一个独立完整的组件\页面一般由以下元素构成:
 
1. root组件,1个, 
	1. 负责初始化state
	2. 负责提供对外props列表
	2. 负责组合子view组件形成页面效果
	3. 负责注册业务逻辑对象提供的业务逻辑方法
	4. 负责管理业务逻辑对象
1. view子组件,0-n个,
	1. 根据props进行视图的渲染
1. 业务逻辑对象,0-n个,
	2. 提供业务逻辑方法 

		
##root组件结构
root组件由以下元素组成:

1. props-公有属性
2. state-RN体系的状态,必须使用Immutable对象
3. 私有属性
4. 业务逻辑对象的引用-在componentWillMount中初始化
4. 私有方法-以下划线开头,内部使用or传递给子组件使用
5. 公有方法【不推荐】,子组件和外部组件都可以用,但不推荐用公有方法来对外发布功能,破坏了面向状态编程,尽可能的使用props来发布功能


![afasdfsa](media/afasdfsa.png)


##子view组件结构

子view组件中包含:

1. props-公有属性
2. 私有属性-强烈不建议有,除非你能理解以下几点,建议放在父组件or业务逻辑对象中
	3. 绝对不允许和父组件的属性or状态有冗余。无论是显性冗余还是计算结果冗余,除非你能确定结算是性能的瓶颈。
	4. 此属性只有自己会用,父组件和兄弟组件不会使用,如果你不确定这点,请把这个组件放到父组件上,方便组件间通信
3. 私有方法-仅作为渲染view的使用,不许有业务逻辑
4. 公有方法【不推荐,理由同root组件】 

![](media/14507661283304.jpg)

	

	
##业务逻辑对象结构
业务逻辑对象由以下元素组成:

3. root组件对象引用-this.root
2. 构造器-初始化root对象,初始化私有属性
2. 私有属性
3. 公有方法-对外提供业务逻辑
3. 私有方法-以下划线开头,内部使用

	
![](media/14507661365142.jpg)

####注意:定义root组件的state的时候,如果使用es6的方式,要把state的初始化放到componentWillMount中,如果在构造器中this.props为空。
	
	
##通用组件结构
	
参考业务组件结构,尽量遵守,灵活调整。
	
PropTypes ,必须要有且必须要写注释。

公用方法不推荐有,理由同业务开发规范,如果有,要求写注释。




## 组件方法声明的顺序

  - 原则上按如下顺序排列React组件的各个方法(生命周期):
  
  1. constructor
  1. 静态方法(static methods)
  1. 生命周期事件
  1. render

## 按如下方式定义propTypes, defaultProps, contextTypes等  

  ```javascript
  import React, { Component, PropTypes } from 'react';
  
  const propTypes = {
    id: PropTypes.number.isRequired,
    url: PropTypes.string.isRequired,
    text: PropTypes.string,
  };
  
  const defaultProps = {
    text: 'Hello World',
  };
  
  class Link extends Component {
    static methodsAreOk() {
      return true;
    }
  
    render() {
      return <a href={this.props.url} data-id={this.props.id}>{this.props.text}</a>
    }
  }
  
  Link.propTypes = propTypes;
  Link.defaultProps = defaultProps;
  
  export default Link;
  ```





##相关参考地址

https://github.com/cnsnake11/blog/blob/master/ReactNative开发指导/ReactNative的架构设计.md

https://github.com/cnsnake11/blog/blob/master/ReactNative开发指导/ReactNative组件状态设计思考.md



================================================
FILE: ReactNative开发规范/编码规范.md
================================================
#ReactNative编码规范


##组件引入

使用import

尽量用解构赋值React和BbtReact

*.css.js文件的引入,直接用css命名

```javascript
// bad
import Footer from './Component/Footer/FooterView'

// good
import Footer from './Component/Footer/Footer'

//good
import HomeView from './HomeView';

//good
import css from './HomeView.css';

//good
import * as HomeViewAction from './HomeView.action';

//good
import React,{ListView,Text,View}  from 'react-native';


```

## 组件声明
 使用class与extends关键字。不使用React.createClass方法。需要导出的组件直接在class关键字前使用export default。

注意export default当前版本RN(0.17.0)还不支持,需要等下一版本修复。

    ```javascript
    // bad
    export default React.createClass({
    });

    // good
    export default class HomeView extends React.Component {
    }
    ```

##业务逻辑类创建
使用 class AaaObj extends BaseLogicObj 的方式创建

首字母大写,以Obj结尾

## 方法
   下划线开头为私有方法,否则为public方法

 **todo es6 规范 babel flow**
 
##样式

一般情况建议使用行内样式

用style={[]}来定义样式,方便后期添加新样式

如果有复用,抽取为样式类,一般使用css来命名,例如var css=StyleSheet.create()

如果复用的样式较多,请将样式抽取到单独文件:组件名.css.js

**todo 使用var style代替var css 语义更准确;组件名.style.js**

##页面初始化

使用交互管理器保证转场动画流畅,页面直接显示loading和少量的不变组件比如header等,其余的渲染动作放到转场动画结束后执行。

如果页面有初始化数据,请立即执行请求,不要等转场动画结束执行。

##与服务器交互
统一使用fetch方法

##图片
静态图直接打包入app,使用相对路径的方式引入,source={require('相对路径')}

注意:服务器上的图注意必须要有高宽才能显示出来

##盒子模型属性

一定要尽可能的在view组件上写盒子模型属性,虽然有可能会造成标签冗余,但是不会出各种诡异问题。

text元素就不要写盒子模型属性,支持的很诡异


##touch*组件

onpress事件只能加在touch*组件上

一般不使用TouchHighlight,优先使用TouchOpacity

touch*一般包在view外面,如要加padding在view上,加margin加在touch*上


##jsx

不能写if else,可以用条件表达式代替

经常用array.map方式来渲染数组
	
参考地址:http://segmentfault.com/a/1190000003748270

##定时任务
不允许使用window.setTimeout和window.setInterval

要求使用TimerMixin

参考地址:https://github.com/cnsnake11/blog/blob/master/ReactNative翻译/react-native的定时器.md




## 对齐
   按下面的案例对齐:

    ```javascript
    // bad
    <Foo superLongParam="bar"
         anotherSuperLongParam="baz" />

    // good
    <Foo
      superLongParam="bar"
      anotherSuperLongParam="baz"
    />

    // 如果一行能摆下props,那就摆在一行
    <Foo bar="bar" />

    // 子组件照常缩进
    <Foo
      superLongParam="bar"
      anotherSuperLongParam="baz"
    >
      <Spazz />
    </Foo>
    ```

## state/props
  - 对于多个单词组成的props,使用驼峰命名法。不使用下划线或连接线。
    ```javascript
    // bad
    <Foo
      UserName="hello"
      phone_number={12345678}
    />

    // good
    <Foo
      userName="hello"
      phoneNumber={12345678}
    />
    ```
  - 读取state和props时,使用const与解构,必要时可使用let。不使用var。
    ```javascript
    // bad
    var userName = this.props.userName;
    let checked = this.state.checked;

    // good
    const { userName, age, sex } = this.props;
    const { checked } = this.state;
    ```  
    
## 括号
  - 当JSX标签超过一行时,使用括号包裹。
    ```javascript
    /// bad
    render() {
      return <MyComponent className="long body" foo="bar">
               <MyChild />
             </MyComponent>;
    }

    // good
    render() {
      return (
        <MyComponent className="long body" foo="bar">
          <MyChild />
        </MyComponent>
      );
    }

    // good, when single line
    render() {
      const body = <div>hello</div>;
      return <MyComponent>{body}</MyComponent>;
    }
    ```

## 标签
  - 对于没有子组件的JSX标签,始终自闭合。
    ```javascript
    // bad
    <Foo className="stuff"></Foo>

    // good
    <Foo className="stuff" />
    ```

  - 如果组件有多行属性,则另起一行进行自闭合。
    ```javascript
    // bad
    <Foo
      bar="bar"
      baz="baz" />

    // good
    <Foo
      bar="bar"
      baz="baz"
    />
    ```



================================================
FILE: ReactNative翻译/React Advanced Performance.md
================================================
# React Advanced Performance 性能进阶

英文原文地址:https://facebook.github.io/react/docs/advanced-performance.html

One of the first questions people ask when considering React for a project is whether their application will be as fast and responsive as an equivalent non-React version. The idea of re-rendering an entire subtree of components in response to every state change makes people wonder whether this process negatively impacts performance. React uses several clever techniques to minimize the number of costly DOM operations required to update the UI.

是否选择使用react,最常考虑的一点就是react的性能。每一次state的改变都会触发整个组件树的渲染,这种机制对性能的影响一定存在。react提供了几种办法来最小化这种影响。

#Use the production build 使用生产模式

If you're benchmarking or experiencing performance problems in your React apps, make sure you're testing with the minified production build. The development build includes extra warnings that are helpful when building your apps, but it is slower due to the extra bookkeeping it does.

如果你遇到了性能瓶颈,首先确保你使用了压缩过的生产模式版本。开发模式版本提供了更多的警告和提示信息,这会耗费一定的性能。

#Avoiding reconciling the DOM 避免dom重绘

React makes use of a virtual DOM, which is a descriptor of a DOM subtree rendered in the browser. This parallel representation allows React to avoid creating DOM nodes and accessing existing ones, which is slower than operations on JavaScript objects. When a component's props or state change, React decides whether an actual DOM update is necessary by constructing a new virtual DOM and comparing it to the old one. Only in the case they are not equal, will React reconcile the DOM, applying as few mutations as possible.

react使用了虚拟dom,它就是浏览器中dom树的一个镜像。所以,react可以避免直接操作真实dom,提升了速度。当组件的props或state发生了变化,react会去比对虚拟dom和真实dom的差异。当他们不一致,react才会去修改真实dom,并且只针对不一致的地方进行增量修改。【译者注:虚拟dom比较和真实dom的修改都属于react重绘的过程】

On top of this, React provides a component lifecycle function, shouldComponentUpdate, which is triggered before the re-rendering process starts (virtual DOM comparison and possible eventual DOM reconciliation), giving the developer the ability to short circuit this process. The default implementation of this function returns true, leaving React to perform the update:

基于上述原理,react提供了一个组件生命周期事件,shouldComponentUpdate,当重绘开始之前会触发(包括虚拟dom比较和真实dom修改之前),使得开发者可以精确的控制是否需要执行重绘。此事件的默认实现返回true,所以,默认情况下,react每次都会执行重绘的算法。

```
shouldComponentUpdate: function(nextProps, nextState) { // 默认实现
  return true;
}
```

Keep in mind that React will invoke this function pretty often, so the implementation has to be fast.

注意,react会非常频繁的执行这个事件,所以要保证你的实现性能极佳。

Say you have a messaging application with several chat threads. Suppose only one of the threads has changed. If we implement shouldComponentUpdate on the ChatThread component, React can skip the rendering step for the other threads:

假如你开发了一个聊天程序,里面会有很多的对话线程。当其中一个对话线程发生了变化。如果对话线程实现了shouldComponentUpdate,react可以取消掉其余没有改变的对话线程的重绘。

```
shouldComponentUpdate: function(nextProps, nextState) {
  // TODO: return whether or not current chat thread is
  // different to former one.
  
  // todo: 当前对话线程如果发生了改变返回true,否则返回false
}
```

So, in summary, React avoids carrying out expensive DOM operations required to reconcile subtrees of the DOM by allowing the user to short circuit the process using shouldComponentUpdate, and, for those which should update, by comparing virtual DOMs.

总结,react利用开发者实现的shouldComponentUpdate事件来避免不必要的重绘过程,当需要真实dom变化的时候,通过与虚拟dom的比对,对真实dom进行增量修改。

#shouldComponentUpdate in action 如何使用shouldComponentUpdate

Here's a subtree of components. For each one is indicated what shouldComponentUpdate returned and whether or not the virtual DOMs were equivalent. Finally, the circle's color indicates whether the component had to be reconciled or not.

下图是一个组件树。每一个组件都标识出了shouldComponentUpdate的返回值、虚拟dom是否相等2个状态。节点的颜色表明了是否需要修改真实dom。

![](media/14720341503791.jpg)

绿色scu - shouldComponentUpdate返回true

红色scu - shouldComponentUpdate返回false

绿色vDOMEq - 虚拟dom和真实dom一致

红色vDOMEq - 虚拟dom和真实dom不一致

绿色节点 - 无需修改真实dom

红色节点 - 需修改真实dom

In the example above, since shouldComponentUpdate returned false for the subtree rooted at C2, React had no need to generate the new virtual DOM, and therefore, it neither needed to reconcile the DOM. Note that React didn't even have to invoke shouldComponentUpdate on C4 and C5.

上面的例子中,如果shouldComponentUpdate返回false就像c2,react连c2及其子节点的虚拟dom都不会生成,当然,他们的真实dom节点也不会被修改。同时,c2的子节点c4和c5的shouldComponentUpdate都不会被触发。

For C1 and C3 shouldComponentUpdate returned true, so React had to go down to the leaves and check them. For C6 it returned true; since the virtual DOMs weren't equivalent it had to reconcile the DOM. The last interesting case is C8. For this node React had to compute the virtual DOM, but since it was equal to the old one, it didn't have to reconcile it's DOM.

当shouldComponentUpdate返回true就像c1和c3,react会继续询问他们的子组件的shouldComponentUpdate。c6返回了true,同时c6的虚拟dom和真实dom不一致,所以c6执行了真实dom增量修改操作。c8比较有趣,它的真实dom和虚拟dom节点是相等的,所以他不会执行真实dom增量修改动作。

Note that React only had to do DOM mutations for C6, which was inevitable. For C8, it bailed out by comparing the virtual DOMs, and for C2's subtree and C7, it didn't even have to compute the virtual DOM as we bailed out on shouldComponentUpdate.

上述例子中,真正执行了真实dom修改动作的只有c6;c8执行了真实dom和虚拟dom比较的动作;c2和c7因为他们shouldComponentUpdate返回了false,他们甚至都没有进行虚拟dom的计算。

So, how should we implement shouldComponentUpdate? Say that you have a component that just renders a string value:

综上,该如何实现shouldComponentUpdate方法呢?假如写一个显示一个字符串的组件。

```
React.createClass({
  propTypes: {
    value: React.PropTypes.string.isRequired
  },

  render: function() {
    return <div>{this.props.value}</div>;
  }
});
```

We could easily implement shouldComponentUpdate as follows:
shouldComponentUpdate如下:

```
shouldComponentUpdate: function(nextProps, nextState) {
  return this.props.value !== nextProps.value;
}
```

So far so good, dealing with such simple props/state structures is easy. We could even generalize an implementation based on shallow equality and mix it into components. In fact, React already provides such implementation: PureRenderMixin.

针对简单数据结构的props/state很容易。我们可以实现一个通用的方法来针对简单数据类型进行比对工作。并且react已经实现好了:PureRenderMixin。

But what if your components' props or state are mutable data structures? Say the prop the component receives, instead of being a string like 'bar', is a JavaScript object that contains a string such as, { foo: 'bar' }:

当props和state是复杂数据类型该如何处理呢?假如上个组件要显示的字符串使用了一个js对象中的一个属性,例如{ foo: 'bar' }。

```
React.createClass({
  propTypes: {
    value: React.PropTypes.object.isRequired
  },

  render: function() {
    return <div>{this.props.value.foo}</div>;
  }
});
```

The implementation of shouldComponentUpdate we had before wouldn't always work as expected:

我们之前实现的shouldComponentUpdate将不会发生作用。

```
// assume this.props.value is { foo: 'bar' }
// assume nextProps.value is { foo: 'bar' },
// but this reference is different to this.props.value 因为引用不同,所以不相等
this.props.value !== nextProps.value; // true
```

The problem is shouldComponentUpdate will return true when the prop actually didn't change. To fix this, we could come up with this alternative implementation:

上面例子里props没有改变shouldComponentUpdate也返回了true,我们换一种实现方式如下:

```
shouldComponentUpdate: function(nextProps, nextState) {
  return this.props.value.foo !== nextProps.value.foo;
}
```

Basically, we ended up doing a deep comparison to make sure we properly track changes. In terms of performance, this approach is pretty expensive. It doesn't scale as we would have to write different deep equality code for each model. On top of that, it might not even work if we don't carefully manage object references. Say this component is used by a parent:

原则上来讲,为了保证判断的准确性,必须要进行深比对。从性能的角度考虑,这种方式的损耗较大。而且可能会根据不同的模型写不同的深比对代码,具体的损耗不太好估量。更重要的是,如果对象引用关系处理的不好,会产生bug。比如下面这个父子组件通信的例子:

```
React.createClass({
  getInitialState: function() {
    return { value: { foo: 'bar' } };
  },

  onClick: function() {
    var value = this.state.value;
    value.foo += 'bar'; // ANTI-PATTERN! 反模式!
    this.setState({ value: value });
  },

  render: function() {
    return (
      <div>
        <InnerComponent value={this.state.value} />
        <a onClick={this.onClick}>Click me</a>
      </div>
    );
  }
});
```

The first time the inner component gets rendered, it will have { foo: 'bar' } as the value prop. If the user clicks on the anchor, the parent component's state will get updated to { value: { foo: 'barbar' } }, triggering the re-rendering process of the inner component, which will receive { foo: 'barbar' } as the new value for the prop.

子组件第一次渲染的时候,属性value的值是{ foo: 'bar'}。如果用户点击了锚点,父组件的state会变成{ value: { foo: 'barbar' } },同时会触发子组件的渲染过程,子组件会的属性value也会同时变成{ foo: 'barbar' }。

The problem is that since the parent and inner components share a reference to the same object, when the object gets mutated on line 2 of the onClick function, the prop the inner component had will change. So, when the re-rendering process starts, and shouldComponentUpdate gets invoked, this.props.value.foo will be equal to nextProps.value.foo, because in fact, this.props.value references the same object as nextProps.value.

现在的问题是,因为父组件和子组件都依赖了同一个对象引用,当这个对象在click方法中的第二行被改变了的时候,此时还没有setState,子组件依赖的对象也就立刻发生了变化,因为是同一个对象引用。所以,当渲染过程开始的时候,shouldComponentUpdate先被触发,this.props.value.foo和nextProps.value.foo是相等的,因为,实际上this.props.value和nextProps.value都引用了同一个对象。

Consequently, since we'll miss the change on the prop and short circuit the re-rendering process, the UI won't get updated from 'bar' to 'barbar'.

所以,我们就错过了属性值的改变和重新渲染的过程,页面也就不会从bar变成barbar。

#Immutable-js to the rescue 不可变数据类型的解决方案

Immutable-js is a JavaScript collections library written by Lee Byron, which Facebook recently open-sourced. It provides immutable persistent collections via structural sharing. Let's see what these properties mean:

Immutable-js是一个开源的js的集合库,作者是facebook的Lee Byron。他提供了可以通过结构共享的不可变、持久化集合类型。具体描述如下:

1. Immutable: once created, a collection cannot be altered at another point in time.
2. Persistent: new collections can be created from a previous collection and a mutation such as set. The original collection is still valid after the new collection is created.
3. Structural Sharing: new collections are created using as much of the same structure as the original collection as possible, reducing copying to a minimum to achieve space efficiency and acceptable performance. If the new collection is equal to the original, the original is often returned.

1. 不可变:集合类型一旦创建,就不会改变。
2. 持久化:新的集合可以通过老的集合或者通过老的集合的set方法来创建。此时老的集合仍然是可用的。
3. 结构共享:新创建的集合的结构和原始集合的保持一致,在创建过程中会尽可能的提升性能和降低内存损耗。如果新集合和原始集合是一模一样的,就不会创建新集合,而是直接返回原始集合。

Immutability makes tracking changes cheap; a change will always result in a new object so we only need to check if the reference to the object has changed. For example, in this regular JavaScript code:

不可变的特性可以使判断对象是否发生了变化变得很简单;因为发生了改变就会使用新的对象,所以只要判断对象的引用是否发生了改变就可以了。看下面这个例子,首先是正常的js代码:

```
var x = { foo: "bar" };
var y = x;
y.foo = "baz";
x === y; // true
```

Although y was edited, since it's a reference to the same object as x, this comparison returns true. However, this code could be written using immutable-js as follows:

尽管y被修改了,但是对象x的引用和y的引用还是同一个对象,并没有发生变化,所以y===x仍会返回true。下面是用immutable-js实现的代码示例:

```
var SomeRecord = Immutable.Record({ foo: null });
var x = new SomeRecord({ foo: 'bar'  });
var y = x.set('foo', 'baz');
x === y; // false
```

In this case, since a new reference is returned when mutating x, we can safely assume that x has changed.

在此示例中,当x被调用了set方法同时确实发生了变化,就会返回一个新的对象,所以x和y不是同一个对象的引用了,x===y是false,我们就可以方便的通过x和y是否相等来判断x是否发生了变化。

Another possible way to track changes could be doing dirty checking by having a flag set by setters. A problem with this approach is that it forces you to use setters and, either write a lot of additional code, or somehow instrument your classes. Alternatively, you could deep copy the object just before the mutations and deep compare to determine whether there was a change or not. A problem with this approach is both deepCopy and deepCompare are expensive operations.

侦测对象变化还有另外的办法,比如在对象的setter方法中加一个标识。这个方法的问题是你必须使用setter方法,并且还要添加很多额外的代码和使用说明。或者,你可以在对象变化的时候使用深拷贝,也或者,在判断对象变化的时候直接使用深比对。这2种方法的问题都是性能损耗过大。

So, Immutable data structures provides you a cheap and less verbose way to track changes on objects, which is all we need to implement shouldComponentUpdate. Therefore, if we model props and state attributes using the abstractions provided by immutable-js we'll be able to use PureRenderMixin and get a nice boost in perf.

所以,使用不可变数据类型的方案来侦测对象改变是性能最好效率最高的方式,我们只需要直接实现shouldComponentUpdate方法就好了。并且,如果model的props和state都是不可变数据类型,我们只需直接引入PureRenderMixin就可以得到性能的提升。

#Immutable-js and Flux 不可变数据类型和flux

If you're using Flux, you should start writing your stores using immutable-js. Take a look at the full API.

如果使用flux的话,可以使用immutable-js来编写store。

Let's see one possible way to model the thread example using Immutable data structures. First, we need to define a Record for each of the entities we're trying to model. Records are just immutable containers that hold values for a specific set of fields:

我们来看一看用不可变数据结构对the thread 例子的建模。首先,我们定义一个记录对象。记录对象是不可变数据容器,一般会有下面这些字段:

```
var User = Immutable.Record({
  id: undefined,
  name: undefined,
  email: undefined
});

var Message = Immutable.Record({
  timestamp: new Date(),
  sender: undefined,
  text: ''
});
```

The Record function receives an object that defines the fields the object has and its default values.

Record方法的输入参数是定义字段和字段默认值的对象。

The messages store could keep track of the users and messages using two lists:

消息store由users和messages组成:

```
this.users = Immutable.List();
this.messages = Immutable.List();
```

It should be pretty straightforward to implement functions to process each payload type. For instance, when the store sees a payload representing a new message, we can just create a new record and append it to the messages list:

处理这个数据结构很简单。例如,当收到一个新消息,我只需要新创建一个record并将其放入message list中:

```
this.messages = this.messages.push(new Message({
  timestamp: payload.timestamp,
  sender: payload.sender,
  text: payload.text
});
```

Note that since the data structures are immutable, we need to assign the result of the push function to this.messages.

注意,因为数据类型是不可变类型,我们需要将push的返回值从新赋给this.messages。

On the React side, if we also use immutable-js data structures to hold the components' state, we could mix PureRenderMixin into all our components and short circuit the re-rendering process.

在和react结合使用的时候,如果使用不可变数据类型作为组件的state,直接将PureRenderMixin应用到组件中,就能在渲染的过程中享用到极高的性能。





================================================
FILE: ReactNative翻译/React PureRenderMixin.md
================================================
# React PureRenderMixin

英文原文地址:https://facebook.github.io/react/docs/pure-render-mixin.html

If your React component's render function is "pure" (in other words, it renders the same result given the same props and state), you can use this mixin for a performance boost in some cases.

如果你的react组件是纯粹的(换句话说,如果传入相同的props和state,每次都将渲染相同的结果),在某些情况下,你就可以使用PureRenderMixin来提升性能。

Example:

```
var PureRenderMixin = require('react-addons-pure-render-mixin');
React.createClass({
  mixins: [PureRenderMixin],

  render: function() {
    return <div className={this.props.className}>foo</div>;
  }
});
```

Example using ES6 class syntax:

```
import PureRenderMixin from 'react-addons-pure-render-mixin';
class FooComponent extends React.Component {
  constructor(props) {
    super(props);
    this.shouldComponentUpdate = PureRenderMixin.shouldComponentUpdate.bind(this);
  }

  render() {
    return <div className={this.props.className}>foo</div>;
  }
}
```

Under the hood, the mixin implements shouldComponentUpdate, in which it compares the current props and state with the next ones and returns false if the equalities pass.

深入来讲,这个mixin实现了shouldComponentUpdate方法,它对当前props、state和即将要使用的props、state进行了比较,如果一致就返回false,有不相等项就返回true。

Note:
This only shallowly compares the objects. If these contain complex data structures, it may produce false-negatives for deeper differences. Only mix into components which have simple props and state, or use forceUpdate() when you know deep data structures have changed. Or, consider using immutable objects to facilitate fast comparisons of nested data.
Furthermore, shouldComponentUpdate skips updates for the whole component subtree. Make sure all the children components are also "pure".

注意:
这个方案仅仅对object进行了浅比对。如果是复杂数据类型,可能会出现错误。请将此mixin应用到使用了简单数据类型props和state的组件,或者当复杂数据类型发生变化时调用forceUpdate()方法。还有一个更好更快的方案,使用不可变数据类型。
shouldComponentUpdate会忽略掉整个组件树的更新操作,确保所有的子组件都是纯粹的。




================================================
FILE: ReactNative翻译/React Shallow Compare.md
================================================
# React Shallow Compare

英文原文地址:https://facebook.github.io/react/docs/shallow-compare.html

shallowCompare is a helper function to achieve the same functionality as PureRenderMixin while using ES6 classes with React.

shallowCompare是用es6方式来实现与PureRenderMixin一样的功能的函数。

If your React component's render function is "pure" (in other words, it renders the same result given the same props and state), you can use this helper function for a performance boost in some cases.

如果你的react组件是纯粹的(换句话说,如果传入相同的props和state,每次都将渲染相同的结果),在某些情况下,你就可以使用shallowCompare来提升性能。

Example:

```
var shallowCompare = require('react-addons-shallow-compare');
export class SampleComponent extends React.Component {
  shouldComponentUpdate(nextProps, nextState) {
    return shallowCompare(this, nextProps, nextState);
  }

  render() {
    return <div className={this.props.className}>foo</div>;
  }
}
```

shallowCompare performs a shallow equality check on the current props and nextProps objects as well as the current state and nextState objects.
It does this by iterating on the keys of the objects being compared and returning true when the values of a key in each object are not strictly equal.

shallowCompare在当前props和未来props(当前state和未来state)进行了浅比对。过程是遍历object的所有属性值并进行===的判断,当有不相等项的时候就返回true。

shallowCompare returns true if the shallow comparison for props or state fails and therefore the component should update.
shallowCompare returns false if the shallow comparison for props and state both pass and therefore the component does not need to update.

shallowCompare返回true当props或state有不相等项,此时组件将会更新。
shallowCompare返回true当props和state的所有项目都相等,此时组件不需要更新。




================================================
FILE: ReactNative翻译/ReactNative : A warning from Apple.md
================================================
# ReactNative : A warning from Apple

2017-03-08这一天,突然听到ios的同事说,收到了苹果的警告email,说rn有可能触犯了苹果的审核规则,有可能被拒。所以,去rn的官方看,发现已经有对应的issue被提出,rn官方也在积极的回应这件事,此处翻译一下issue的关键内容。

需要看结论的同学直接看最后一段即可。

原文地址:https://github.com/facebook/react-native/issues/12778

# 问题

I received a warning from Apple this morning , how to solve it :

今天早上我收到了苹果的警告邮件,该如何处理呢:

Dear Developer,

Your app, extension, and/or linked framework appears to contain code designed explicitly with the capability to change your app’s behavior or functionality after App Review approval, which is not in compliance with section 3.3.2 of the Apple Developer Program License Agreement and App Store Review Guideline 2.5.2. This code, combined with a remote resource, can facilitate significant changes to your app’s behavior compared to when it was initially reviewed for the App Store. While you may not be using this functionality currently, it has the potential to load private frameworks, private methods, and enable future feature changes.

您的app或者您app中使用的框架,被发现含有在苹果审核之后能修改app功能和行为的代码,这不符合Apple Developer Program License Agreement中的3.3.2章节,也不符合App Store Review Guideline的2.5.2章节。这些代码可以对app进行完全的修改,使其和审核时候的初始版本有很大的差异。也许你现在并没有使用这个功能,但是仍具有调用私有框架,私有方法,改变产品特性的潜在可能。

This includes any code which passes arbitrary parameters to dynamic methods such as dlopen(), dlsym(), respondsToSelector:, performSelector:, method_exchangeImplementations(), and running remote scripts in order to change app behavior or call SPI, based on the contents of the downloaded script. Even if the remote resource is not intentionally malicious, it could easily be hijacked via a Man In The Middle (MiTM) attack, which can pose a serious security vulnerability to users of your app.

像这种动态调用函数的代码,比如dlopen(), dlsym(), respondsToSelector:, performSelector:, method_exchangeImplementations(),还有为了改变app行为的执行远程脚本的行为,也叫SPI。尽管远程资源并不是有害的,但却很容易通过中间人攻击被劫持,这是一个很严重的安全漏洞。

Please perform an in-depth review of your app and remove any code, frameworks, or SDKs that fall in line with the functionality described above before submitting the next update for your app for review.

请仔细检查你的代码,并删除符合上述描述的代码,然后重新提交审核。

Best regards,

# grabbou解释了相关的苹果审核规则

3.3.2 of Apple Developer Program License:

苹果开发者协议的3.3.2章节:

An Application may not download or install executable code. Interpreted
code may only be used in an Application if all scripts, code and interpreters are
packaged in the Application and not downloaded. The only exception to the
foregoing is scripts and code downloaded and run by Apple's built-in WebKit
framework or JavascriptCore, provided that such scripts and code do not change
the primary purpose of the Application by providing features or functionality that are inconsistent with the intended and advertised purpose of the Application as
submitted to the App Store.

app不允许下载安装可执行代码。解释型的代码只允许打包到app中才可以被执行,下载的解释型代码不允许被执行。有一种情况是例外的,通过WebKit或者JavascriptCore执行的远程代码,并且这些远程代码并没有违反app提交审核时候的描述和声明。

explicitly mentions that: An Application may not download or install executable code

规则中明确的指出了:app不能下载安装可以执行代码。

React Native does none of these. And so, using React Native doesn't expose you to the aforementioned issue.

React Native并没有违反这一条。所以,使用React Native也并没有违反这一条。

As @ide mentioned, there are reports this message is addressed to those using Rollout.io. My assumption is that it uses aforementioned methods to patch executable code.

就像@ide提到的,使用Rollout的都被发警告邮件了。我的猜测是,Rollout使用了上述的方法来给可执行代码打补丁了。

With React Native, you can do so called OTA update, but this is updating Javascript, not native code. Whenever native code changes, you have to make a new release. That OTA update of Javascript code is explicitly allowed in the 3.3.2:The only exception to the foregoing is scripts and code downloaded and run by Apple's built-in WebKit framework or JavascriptCore。

使用React Native可以进行OTA在线更新,但是这是更新Javascript的代码,并不是更新原生代码。当有原生代码改变,你必须要重新发布版本提交审核。在开发者协议的3.3.2章节中,OTA更新Javascript代码是明确指出被允许的:有一种情况是例外的,通过WebKit或者JavascriptCore执行的远程代码,并且这些远程代码并没有违反app提交审核时候的描述和声明。

I believe everyone should follow up on this issue with Apple and sort out what's exactly causing the warning.

我建议大家还是仔细检查一下代码或者和apple沟通,看究竟是什么问题触发的警告。

# 官方最后给的结论

From reading the message from Apple and the data points we've observed, this warning is not about React Native.

根据苹果的信息和我们目前获得的情况,这个警告和React Native无关。

### On the technical concern of dynamically executing Objective-C described in Apple's email:苹果邮件中关于动态执行oc代码的分析

Apple's message reads to me that they're concerned about libraries like Rollout and JSPatch, which expose uncontrolled and direct access to native APIs (including private APIs) or enable dynamic loading of native code. Rollout and JSPatch are the only two libraries I've heard to be correlated with the warning.

苹果的描述在我看来,他们关系的是Rollout和JSPatch这类的库,这类的库可以在运行时直接进行无控制的并且直接的对原生代码的调用,甚至包括私有api。Rollout和JSPatch是我唯一知道和这个警告有关的库。

React Native is different from those libraries because it doesn't expose uncontrolled access to native APIs at runtime. Instead, the developer writes native modules that define some functions the app can call from JavaScript, like setting a timer or playing a sound. This is the same strategy that "hybrid" apps that use a UIWebView/WKWebView have been using for many years. From a technical perspective, React Native is basically a hybrid app except that it calls into more UI APIs.

而React Native和他们是不同的,RN在运行时候并没有暴露原生API的能力。相反,开发者必须按照RN的规范进行原生方法的定义,这样js才能调用得到,比如设置一个定时器,或者播放一段音频等。这种策略,hybrid应用已经使用了很长时间了。从技术的角度上说,React Native也是一个hybrid应用,只不过RN使用的是原生UI。

Technically it is possible for a WebView app or a React Native app also to contain code that exposes uncontrolled access to native APIs. This could happen unintentionally; someone using React Native might also use Rollout. But this isn't something specific to or systemic about React Native nor WebViews anyway

其实无论是WebView应用还是RN应用都可以做到运行时动态执行任何原生API。但这不是有意识的设计;比如你用RN也可以同时使用Rollout。但这不是RN或者Webview设计的初衷。

### On the strategy of calling native code from JavaScript:js调用原生代码的分析

Apple has been fine with WebViews in apps since the beginning of the App Store, including WebViews that make calls to native code, like in the Quip app. WKWebView even has APIs for native and web code to communicate. It's OK for a WebView to call out to your native code that saves data to disk, registers for push notifications, plays a sound, and so on.

在最开始,Apple就允许app中含有WebViews,并且允许WebViews中的js可以调用原生代码,就像Quip应用。WKWebView还发布了原生和web通信的接口。webview中的js可以通过调用原生api进行保存数据到存储,注册接收通知,播放音频,等等。

React Native is very much like a WebView except it calls out to one more native API (UIKit) for views and animations instead of using HTML.

React Native的机制其实和webview非常类似,只不过RN使用了更多的原生api来渲染页面和动画,而不是用html。

What neither WebViews nor React Native do is expose the ability to dynamically call any native method at runtime. You write regular Objective-C methods that are statically analyzed by Xcode and Apple and it's no easier to call unauthorized, private APIs.

webview和RN都没有暴露运行时动态执行原生代码的功能。你必须仍按照xcode和apple的规范编写oc的方法,并且使用静态编译的方式来执行,很难执行那些未授权的或者私有的api。

### Data points

The developers who received this email were using Rollout or JSPatch in their apps. People who are using only React Native or libraries/frameworks like CodePush and Expo are not affected and are continuing to have their apps accepted by the App Store review.

收到苹果警告的开发者一般是使用了Rollout或者jsPatch。如果仅仅是使用了RN,或者codepush等,并不会受到影响。

### Recommendations 建议

If you're writing a React Native or WebView app, be sure not to expose dynamic, uncontrolled access to native APIs and you should be OK. There was one third-party RN module that did this and the maintainers have taken it down. And in accordance with the iOS developer terms, make sure your updates don't change the primary purpose of your app and that the changes are consistent with the intended and advertised purpose of your app.

如果你正在进行RN或者webview应用的开发,请确保不要使用动态执行原生代码的功能,这样就不会有问题。有一个第三方的RN模块使用了类似的功能,他的开发者已经将其去掉了。并且,就像ios开发团队那样,保证你的在线升级不要违反app在提交审核时候声明的原则。



================================================
FILE: ReactNative翻译/Reconciliation.md
================================================
# 【翻译】Reconciliation React比对算法

原文地址:https://facebook.github.io/react/docs/reconciliation.html

React provides a declarative API so that you don't have to worry about exactly what changes on every update. This makes writing applications a lot easier, but it might not be obvious how this is implemented within React. This article explains the choices we made in React's "diffing" algorithm so that component updates are predictable while being fast enough for high-performance apps.

使用react你就不用去关注每次更新UI的时候真正更新了哪些节点。这样的话开发业务代码会非常简单,但并不能理解react的实现原理。本文会解释react的比对算法,理解了这个算法,会让你更容易构建高性能的应用。

# Motivation 动机

When you use React, at a single point in time you can think of the render() function as creating a tree of React elements. On the next state or props update, that render() function will return a different tree of React elements. React then needs to figure out how to efficiently update the UI to match the most recent tree.

在某一时刻,react的render方法会返回一组树形节点。当state发生变化,render方法会返回一组不同的树形节点。react需要分析出如何更新UI是最高效、损耗最小的。

There are some generic solutions to this algorithmic problem of generating the minimum number of operations to transform one tree into another. However, the state of the art algorithms have a complexity in the order of O(n3) where n is the number of elements in the tree.

会有几种算法来保证最小化的更新操作。然而,这些算法都还是有O(n3)的复杂度,n是节点的数量,n3是n的3次方。

If we used this in React, displaying 1000 elements would require in the order of one billion comparisons. This is far too expensive. Instead, React implements a heuristic O(n) algorithm based on two assumptions:

1. Two elements of different types will produce different trees.
2. The developer can hint at which child elements may be stable across different renders with a key prop.

In practice, these assumptions are valid for almost all practical use cases.

也就是说,如果有1000个节点,那就要比对1000000000次。这损耗太高了。所以,react实现了新的O(n)算法,但是需要满足如下2个假设:

1. 2个不同类型的节点,会产生不同的UI树
2. 开发者可以提供一个叫key的属性,来指出是否为同一个节点

在实际应用中,这2个假设都是普遍成立的。

# The Diffing Algorithm 比对算法

When diffing two trees, React first compares the two root elements. The behavior is different depending on the types of the root elements.

react比对2棵树的时候,会首先比对根节点。会根据根节点的类型来比对。

### Elements Of Different Types 不同类型的节点

Whenever the root elements have different types, React will tear down the old tree and build the new tree from scratch. Going from a to img, or from Article to Comment, or from Button to div - any of those will lead to a full rebuild.

当根节点是不同类型的时候,react将会移除整棵老树,完全新建一棵树替代。比如,a to img或者from Article to Comment, 或者 from Button to div,所有这些改变都会触发一次完整的重新构建动作。

When tearing down a tree, old DOM nodes are destroyed. Component instances receive componentWillUnmount(). When building up a new tree, new DOM nodes are inserted into the DOM. Component instances receive componentWillMount() and then componentDidMount(). Any state associated with the old tree is lost.

在移除老树的过程中,所有的dom节点都会被销毁。根组件实例会触发componentWillUnmount事件。当新建一棵新树,新的dom节点会别插入到dom中。根组件实例会触发componentWillMount及componentDidMount。所有老树的state也会被销毁。

Any components below the root will also get unmounted and have their state destroyed. For example, when diffing:

老树的所有孩子节点也会被完全的销毁,同时他们的state也会被销毁。比如下面的例子:

```
<div>
  <Counter />
</div>

<span>
  <Counter />
</span>
```

This will destroy the old Counter and remount a new one.

老的Counter会被销毁,会新建一个Counter替代。

### DOM Elements Of The Same Type 相同类型的dom节点

When comparing two React DOM elements of the same type, React looks at the attributes of both, keeps the same underlying DOM node, and only updates the changed attributes. For example:

在比较相同类型的节点的时候,react会比较两个节点的属性,保持dom节点对象不变,然后会更新值发生改变的属性。例如:

```
<div className="before" title="stuff" />

<div className="after" title="stuff" />
```

By comparing these two elements, React knows to only modify the className on the underlying DOM node.

react比对这2个节点后,只会更新className。

When updating style, React also knows to update only the properties that changed. For example:

当更新样式的时候,react也只更新改变的属性。例如:

```
<div style={{color: 'red', fontWeight: 'bold'}} />

<div style={{color: 'green', fontWeight: 'bold'}} />

```

When converting between these two elements, React knows to only modify the color style, not the fontWeight.


针对这2个节点,react会只更新color,而不会更新fontWeight。

After handling the DOM node, React then recurses on the children.

当比对完一个节点后,react会继续递归这个节点的孩子节点。

### Component Elements Of The Same Type 相同类型的component组件节点

When a component updates, the instance stays the same, so that state is maintained across renders. React updates the props of the underlying component instance to match the new element, and calls componentWillReceiveProps() and componentWillUpdate() on the underlying instance.

当组件节点更新,会保持同一个对象实例,state会保持不变。react会更新那些改变过组件节点的属性,并且触发他们的componentWillReceiveProps和componentWillUpdate。

Next, the render() method is called and the diff algorithm recurses on the previous result and the new result.

下一次改变发生时,整个流程会再次执行。

### Recursing On Children 递归孩子节点

By default, when recursing on the children of a DOM node, React just iterates over both lists of children at the same time and generates a mutation whenever there's a difference.

默认情况下,在递归孩子节点的时候,react会同时遍历新老树的孩子节点,并标记处出改变的地方。

For example, when adding an element at the end of the children, converting between these two trees works well:

举个栗子,在某个节点的末尾插入一个新节点,比对算法会高效的执行:

```
<ul>
  <li>first</li>
  <li>second</li>
</ul>

<ul>
  <li>first</li>
  <li>second</li>
  <li>third</li>
</ul>
```

React will match the two li first trees, match the two li second trees, and then insert the li third tree.

react会认为2个li first是相同的,2个li second是相同的,并找出了新增的li third。

If you implement it naively, inserting an element at the beginning has worse performance. For example, converting between these two trees works poorly:

但是,如果在某个几点的开头插入一个节点,比对算法会执行的很低效,例如:

```
<ul>
  <li>Duke</li>
  <li>Villanova</li>
</ul>

<ul>
  <li>Connecticut</li>
  <li>Duke</li>
  <li>Villanova</li>
</ul>
```

React will mutate every child instead of realizing it can keep the li Duke and li Villanova subtrees intact. This inefficiency can be a problem.

react会认为每一个孩子节点都发生了变化,而不是保持li Duke和li Villanova不变。这种低效的执行很成问题。


### Keys

In order to solve this issue, React supports a key attribute. When children have keys, React uses the key to match children in the original tree with children in the subsequent tree. For example, adding a key to our inefficient example above can make the tree conversion efficient:

为了解决这个问题,react使用了key属性。当孩子节点有key属性的时候,react会使用key属性的值去匹配2棵树的孩子节点。例如,在我们上面低效的例子中,为孩子节点添加key属性如下:

```
<ul>
  <li key="2015">Duke</li>
  <li key="2016">Villanova</li>
</ul>

<ul>
  <li key="2014">Connecticut</li>
  <li key="2015">Duke</li>
  <li key="2016">Villanova</li>
</ul>
```

Now React knows that the element with key '2014' is the new one, and the elements with the keys '2015' and '2016' have just moved.

这样的话,react就知道key是2014的是新增的,而2015和2016仅仅是移动了。

In practice, finding a key is usually not hard. The element you are going to display may already have a unique ID, so the key can just come from your data:

在实践中,使用key属性并不难。要显示的元素通常都有一个唯一的id,所以,使用这个id就可以了:

```
<li key={item.id}>{item.name}</li>
```

When that's not the case, you can add a new ID property to your model or hash some parts of the content to generate a key. The key only has to be unique among its siblings, not globally unique.

当没有合适的值作为key的时候,你最好在模型中加一个id属性,或者hash某个值作为key。这个key只需要在兄弟节点中唯一,并不需要全局唯一。

As a last resort, you can pass item's index in the array as a key. This can work well if the items are never reordered, but reorders will be slow.

还有一个办法,你可以使用数组的序号作为key。如果你的元素没有改变顺序的需求的话,就没有问题,但是如果有改变顺序的功能就会非常慢。

# Tradeoffs 设计的折中

It is important to remember that the reconciliation algorithm is an implementation detail. React could rerender the whole app on every action; the end result would be the same. We are regularly refining the heuristics in order to make common use cases faster.

目前,比对算法仍在改进中。react有可能会在每个动作之后都重新渲染整个app;并且渲染的结果可能都是相同的。我们正在不停的改进算法保证大部分的场景都是最高效的。

In the current implementation, you can express the fact that a subtree has been moved amongst its siblings, but you cannot tell that it has moved somewhere else. The algorithm will rerender that full subtree.

在目前的实现中,如果在兄弟节点中移动一个节点,是没有问题的,如果将这个节点移动到其它的地方去,会导致重新构建这个节点。

Because React relies on heuristics, if the assumptions behind them are not met, performance will suffer.

1. The algorithm will not try to match subtrees of different component types. If you see yourself alternating between two component types with very similar output, you may want to make it the same type. In practice, we haven't found this to be an issue.
2. Keys should be stable, predictable, and unique. Unstable keys (like those produced by Math.random()) will cause many component instances and DOM nodes to be unnecessarily recreated, which can cause performance degradation and lost state in child components.

如果上面提到的2个条件不能被满足,性能会比较差。

1. 目前的算法不会去比对类型不同节点的孩子节点。如果你的两个节点有着很类似的输出,最好保证其有相同的类型。在实际的应用中,这一般都不是一个问题。 

2. keys应该是稳定不变的,可预见的,并且唯一的。不稳定的key(比如用Math.random()产生的)将会导致大量的重复构建,这将会导致性能下降,也会导致孩子节点的state状态丢失。



================================================
FILE: ReactNative翻译/react-native的定时器.md
================================================
# 定时器 Timers 

英文原文地址:http://facebook.github.io/react-native/docs/timers.html

定时器是应用程序的重要组件,ReactNative实现了浏览器的定时器。

###定时器
1. setTimeout, clearTimeout
1. setInterval, clearInterval
1. setImmediate, clearImmediate
1. requestAnimationFrame, cancelAnimationFrame

requestAnimationFrame(fn) 与setTimeout(fn,0)并不一样,前面的是会等待当前的所有帧结束之后才触发,后面的是会尽快的被触发(over 1000x per second on a iPhone 5S 这句不会翻)。

setImmediate会在当前js执行块的最后立刻被执行,在与native通信之前。如果你使用这个方法,它会被立刻执行,不会被任何代码所有阻断包括native代码。

Promise的实现就是基于setImmediate作为基础的。

###InteractionManager交互管理器
原生app流畅的一大原因就是利用多线程在交互和动画的线程中避免同时执行大量计 算。在ReactNative中,会受到js只有一个执行线程的限制,但是你可以使用交互管
理器来保证耗时复杂工作在交互动画完成之后才开始执行。

示例代码:

```
InteractionManager.runAfterInteractions(() => {
   // ...long-running synchronous task...
});
```

几个定时器的比较:

1. requestAnimationFrame(): 在一个动画效果完成之后执行代码。
1. setImmediate/setTimeout/setInterval():稍后执行代码,这些方法可能会拖慢动画效果。
1. runAfterInteractions():稍后执行代码,不会拖慢当前的动画效果。

触摸系统会把一组触摸事件作为一次交互,runAfterInteractions()注册的回调函数会在当前的所有交互结束后触发。

你也可以使用交互管理器在自己的应用程序中,在动画的开始创建一个handle,在动画结束的时候清除掉它。

```
var handle = InteractionManager.createInteractionHandle();

//执行动画。。。。runAfterInteractions注册的函数会在稍后动画结束后触发。

InteractionManager.clearInteractionHandle(handle)

//所有的handle都clear之后就会触发注册的事件了

```

###TimerMixin 

用RN构建的app,发生系统崩溃通常都是因为定时任务在组件已经被卸载之后触发造成的。解决这个问题最好的办法就是使用TimerMixin。如果你引入了TimerMixin,你就可以使用this.setTimeout代替setTimeout,这个方法可以保证当组件被卸载时所有的定时任务都被正确的清除了。

RN中并没有带这个库,你可以在你的工程里用命令npm i react-timer-mixin --save来安装。

示例代码:

```
var TimerMixin = require('react-timer-mixin');

var Component = React.createClass({
  mixins: [TimerMixin],
  componentDidMount: function() {
    this.setTimeout(
      () => { console.log('I do not leak!'); },
      500
    );
  }
});

```

我们特别不建议使用原生的全局方法setTimeOut,强烈建议使用react-timer-mixin提供的this。setTimeout。这会消除很多隐性的bug,比如说在组件卸载后执行定时任务引起的app崩溃。







================================================
FILE: ReactNative翻译/react-native的性能.md
================================================
# react-native的性能

英文原文地址: http://facebook.github.io/react-native/docs/performance.html

使用react native 代替webview技术来构建app最大的理由就是60FPS流畅的体验。我们尽可能的让开发者可以专注于app开发而不是性能优化,但是目前RN还不能完全的达到此目标,并不能自动选择最优的方式,所以,还需要开发者关注并进行调整。

本篇文章介绍了性能调优的基本技巧,同时讨论一些常见问题及其解决方案。
## 帧数
动画效果其实就是静态图片的连续播放,每秒图片播放的越多,动画就越平滑流畅。60FPS的意思就是1秒有60张图片进行了播放,一张图叫一帧,如果想达到60FPS,需要16.67ms就要播放一帧,所以就要求程序在16.67ms就要生成一帧,如果超过这个时间,就会掉帧,就会觉得程序不流畅。

打开开发者菜单,点击 show fps monitor 会有2个帧数显示在屏幕上。
### Javascript frame rate【js帧数】
大多数情况下,你的业务逻辑会运行在js线程下。这个线程处理了api调用,触摸事件,等等...对原生view的更新是批量提交的,也是尽力保持在每帧之前提交。如果js线程在下一帧来到之前不能进行提交,就会掉帧。举个例子,如果你在一个复杂的组件的根节点调用`this.setState`方法,就会导致一次复杂的diff计算,如果这次计算耗时200ms就相当于掉了12帧。在这过程中,所有js控制的动画都会卡住。事实上只要超过100ms用户就会感觉到。

卡顿经常会发生在页面转场动画上:当进行页面转场的时候,js线程要计算新页面中所有的组件,以便通知原生去展现view。如果动画是js控制的,就通常会消耗几帧。所以,组件在`componentDidMount`中进行的工作会导致转场动画的掉帧。

另一个例子是触摸事件的反馈:如果你的js线程正在忙碌着,点击TouchableOpacity会有延迟。这是因为js不能及时的处理触摸事件,导致原生view 不能及时的做出反应。
### Main thread(UI thread) frame rate【UI线程帧数】
你可能会注意到`NavigatorIOS`的性能要比`Navigator`好,这是因为`Navigator`的转场动画是由主线程控制的,js的掉帧并不能影响它。参考阅读来帮助你选择导航器http://facebook.github.io/react-native/docs/navigator-comparison.html

同样的,ScrollView的滚动永远不会受到js的影响,这是因为ScrollView完全是基于原生的主线程的。尽管会有滚动事件分发到js,但这并不影响滚动的动作。


##常见问题和解决方案
###开发模式 dev=true
在开发模式下js的性能会受到严重的影响。这是不可避免的:要提供详细的提示和错误检查js就要有大量的工作要做。

###转场动画不流畅
如上所述,`Navigator`的转场动画是js控制的。就比如说从右推进来的这个动画效果:每一帧新页面都会从右像左移动一点,其实就是改变新页面的x轴坐标。在这过程中的每一帧,js都要告诉主线程新的x坐标是多少。如果js被别的任务锁定了,那这一帧就不能及时的更新x坐标了,你就会觉得动画卡顿了。

这个问题的最有效的解决办法就是把js控制的动画效果让主线程自己来控制。如果套用上面的场景可以这样重构,在动画的开始,js就计算好这次动画的所有x坐标值的数组,传递给主线程。这样的话,动画开始后,就不受js性能的影响了,就算动画刚开始有一些卡顿,你可能也注意不到。

但是,目前`Navigator`还不是这样实现的,所以,我们提供了`InteractionManager`来帮助你在转场动画的过程中,新页面只渲染必要的少量的内容。

`InteractionManager.runAfterInteractions`只有一个函数类型的参数,当转场动画结束,这个回调函数就会被触发(所有基于`Animated`API的动画都会触发InteractionManager.runAfterInteractions)。

示例代码如下:

```
class ExpensiveScene extends React.Component {
  constructor(props, context) {
    super(props, context);
    this.state = {renderPlaceholderOnly: true};
  }

  componentDidMount() {
    InteractionManager.runAfterInteractions(() => {
      this.setState({renderPlaceholderOnly: false});
    });
  }

  render() {
    if (this.state.renderPlaceholderOnly) {
      return this._renderPlaceholderView();
    }

    return (
      <View>
        <Text>Your full view goes here</Text>
      </View>
    );
  }


  _renderPlaceholderView() {
    return (
      <View>
        <Text>Loading...</Text>
      </View>
    );
  }
};
```
你不仅可以渲染一个loading指示器,也可以渲染你新页面内容的一小部分。比如说,当你打开Facebook你会看到将要放入文本的灰色的矩形。如果你要在新页面要放入一个地图,你可以放一个灰色的占位符或者一个loading直到动画结束,否则地图的初始化一定会导致转场动画的掉帧。

### 大数据量的ListView初始化慢或者滚动卡顿
我们提供了一些方法来调优,但是尚没有万能的办法,你可以尝试以下选项。
####initialListSize 初始帧渲染行数
这个属性定义了第一帧渲染list的行数。如果我们希望某些内容非常快的展现在页面上,可以设置`initialListSize`等于1,其余的行会在后边的帧里来渲染。每一帧渲染的行数是由`pageSize`决定的。
####pageSize 每一帧渲染行数
初始化使用`initialListSize`,`pageSzie`决定了每一帧渲染的行数。默认值是1,如果你的view很小而且渲染很简单,你可以加大这个数量。你可以通过测试来找到你满足你需求的值。
####scrollRenderAheadDistance 触发渲染的距离
在距离显示区域多远就开始渲染。

如果你的列表有2000行,那么一次渲染所有会耗费大量内存和计算资源。`scrollRenderAheadDistance`可以让你定义距离显示区域多远之内的rows可以被渲染。

####removeClippedSubviews删除屏幕外子视图
此值为true表示屏幕外的字视图(行容器是overflow=hidden的)会被从原生视图中移除。他可以提升列表滚动的性能。这个属性默认值就是ture。
这个属性对大数据列表非常重要。在安卓端overflow的默认值就是hidden,但是在ios端需要手动设置overflow的值为hidden在行容器上。

###不需要立即展现的组件渲染很慢
这通常是由listvew引起的,你先想办法调整一下listview。上面我们也提供了很多手段来分步渲染视图。Listview也可以横向展现,好好利用这一点。

###重新渲染那些很少改变的视图很慢
Listview可以使用`rowHasChanged`方法来降低diff判断的计算损耗。如果你使用了不可变数据类型,使用`=`就可以简单的判断是否是同一对象了。

同样的,`shouldComponentUpdate`可以精确的描述出需要重新渲染的状态。如果你正在写纯组件(render方法的返回完全由props和state来决定),使用`PureRenderMixin`可以帮助你提升性能。同样的,不可变数据类型也同样会提升性能和降低代码复杂度,特别是在大数据量的对象深比对上。

###js线程在同一时间做太多的事就会掉帧
过场动画卡顿就是因为这个原因,在某些场景下也会出现这个问题。使用InteractionManager是比较好的办法,但当你由于某些原因不能延迟执行任务时,你可以试试LayoutAnimation。

AnimatedApi的动画效果依赖于js,而LaoutAnimation使用了CoreAnimation 完全不受js线程和主线程掉帧的影响。

你可以查看相关文档来学习如何使用。

注意,只支持iOS。而且,只支持静态动画。如果需要动画过程有交互,还要使用Animated。
###在屏幕上移动view (scrolling, translating, rotating) ,UI线程会掉帧
这经常发生在一个背景透明的text在一个图片上,或者需要alpha合成并重新渲染view的时候。你可以使用shouldRasterizeIOS或者renderToHardwareTextureAndroid来改变这种情况。

但是这会极大的耗费内存。最好使用以上属性的时候监控一下内存,看能否接受。如果,不移动view的话,就一定要关了这2个属性。
### 改变图片大小的动画会使UI线程掉帧
在ios中,调整图片的高宽会导致从原始图片的重新剪裁。这很耗费资源,特别是大图。

最好用transform: [{scale}]来实现改变图片大小的动画。

一个场景是点击一个图并全屏展现的时候。
###Touch系列组件响应很慢
有时候点击一个touch组件,onPress事件会触发setSate,导致js线程立刻进行大量的计算工作,最终给用户的效果就是高亮或者透明的效果有延迟。

解决办法是使用requestAnimationFrame

```
handleOnPress() {
  // Always use TimerMixin with requestAnimationFrame, setTimeout and
  // setInterval
  this.requestAnimationFrame(() => {
    this.doExpensiveAction();
  });
}
```
###分析工具
用一些工具来获取js线程和UI主线程的细节信息。

在ios中使用an invaluable tool,安卓使用systrace。

For iOS, Instruments are an invaluable tool, and on Android you should learn to use systrace.


















================================================
FILE: ReactNative翻译/导航器比较.md
================================================
# Navigator Comparison 


英文原文地址:http://facebook.github.io/react-native/docs/navigator-comparison.html

###这篇看完发现没啥可翻的,记住结论就可以了:使用Navigator,不要用NavigatorIOS。

The differences between Navigator and NavigatorIOS are a common source of confusion for newcomers.

Both Navigator and NavigatorIOS are components that allow you to manage the navigation in your app between various "scenes" (another word for screens). They manage a route stack and allow you to pop, push, and replace states. In this way, they are similar to the html5 history API. The primary distinction between the two is that NavigatorIOS leverages the iOS UINavigationController class, and Navigator re-implements that functionality entirely in JavaScript as a React component. A corollary of this is that Navigator will be compatible with Android and iOS, whereas NavigatorIOS will only work on the one platform. Below is an itemized list of differences between the two.

###Navigator 
1. Extensive API makes it completely customizable from JavaScript.
1. Under active development from the React Native team.
1. Written in JavaScript.
1. Works on iOS and Android.
1. Includes a simple navigation bar component similar to the default NavigatorIOS bar: Navigator.NavigationBar, and another with breadcrumbs called Navigator.BreadcrumbNavigationBar. See the UIExplorer demo to try them out and see how to use them.
	1. Currently animations are good and improving, but they are still less refined than Apple's, which you get from NavigatorIOS.
1. You can provide your own navigation bar by passing it through the navigationBar prop.


###NavigatorIOS 

 

1. Small, limited API makes it much less customizable than Navigator in its current form.
1. Development belongs to open-source community - not used by the React Native team on their apps.
	1. A result of this is that there is currently a backlog of unresolved bugs, nobody who uses this has stepped up to take ownership for it yet.
1. Wraps UIKit, so it works exactly the same as it would on another native app. Lives in Objective-C and JavaScript.
	1. Consequently, you get the animations and behaviour that Apple has developed.
1. iOS only.
1. Includes a navigation bar by default; this navigation bar is not a React Native view component and the style can only be slightly modified.

For most non-trivial apps, you will want to use Navigator - it won't be long before you run into issues when trying to do anything complex with NavigatorIOS.



================================================
FILE: ReactNative问题汇总/Immutable.js的问题.md
================================================
#Immutable.js的问题


##容易与原生对象混淆

参考地址:http://zhuanlan.zhihu.com/purerender/20295971

这点是我们使用 Immutable.js 过程中遇到最大的问题。写代码要做思维上的转变。

虽然 Immutable.js 尽量尝试把 API 设计的原生对象类似,有的时候还是很难区别到底是 Immutable 对象还是原生对象,容易混淆操作。

Immutable 中的 Map 和 List 虽对应原生 Object 和 Array,但操作非常不同,比如你要用 `map.get('key')` 而不是 `map.key`,`array.get(0)` 而不是 `array[0]`。另外 Immutable 每次修改都会返回新对象,也很容易忘记赋值。

当使用外部库的时候,一般需要使用原生对象,也很容易忘记转换。

下面给出一些办法来避免类似问题发生:

1. 使用 Flow 或 TypeScript 这类有静态类型检查的工具约定变量命名规则:
1. 如所有 Immutable 类型对象以 `$$` 开头。
2. 使用 `Immutable.fromJS` 而不是 `Immutable.Map` 或 `Immutable.List` 来创建对象,这样可以避免 Immutable 和原生对象间的混用。


##tips 有时候还原回普通对象进行批量操作更方便



================================================
FILE: ReactNative问题汇总/ReactNative-0.14.2.md
================================================
# ReactNative-0.14.2

[toc]

##如果引入一个模块,但是这个模块没有写【module.exports】,报的错误描述不对
![](media/14486188240052.jpg)
##定义组件不能使用class name extends Component的形式,有state取不到的bug.

改成React.createClass后就好了

##TextInput的borederColor,color在安卓下不好使用

##如果listview有父节点但不满足以下条件,就会出现onEndReached不停触发的bug

####所有的祖宗节点都必须定义flex=1。
其实是因为没定义flex,高度就是无限高,就不停触发了,所以只要给固定高就行了

####所有的祖宗节点不能有ScrollVIew,只能是View。
解决方案:用listview的renderHeader和renderFooter方法来创建头尾,而不要嵌套用scrollview

感觉耦合略强.本不是列表组件的部分,也得和列表产生依赖。

##ListView的Android版本不支持sticky-header特性
https://github.com/facebook/react-native/issues/2700

##ListView的数据源切换导致sectionHeader重新渲染状态重置的bug
如果切换的数据源的dataSource.cloneWithRows传入的数组中没有元素,会导致已有的section都重新渲染。section相关的状态都会重置,相当于重新创建。【在RN0.15.0下,状态不会重置了,但是还会重新渲染,sectionHeader部分会空白一阵】

解决方案:可以让第二个listview加载任何一个数据就可以了,模拟的空数据也可以,比如这样的[{}].
##android不支持textDecoration系列

##安卓图片contain不管用,显示不对
https://github.com/facebook/react-native/issues/4031

##	安卓边框圆角单独设置不管用
https://github.com/facebook/react-native/issues/3040

设置全部borderRadius是管用的

##text不支持样式text-overflow
可以用属性 numberOfLines 替代

##	listview如果来回切换数据源,有时候会导致onEndReached事件不能触发
在RN0.15.0版本下,没有再复现过,当做已经修复了吧。




================================================
FILE: ReactNative问题汇总/ReactNative-0.15.0.md
================================================
# ReactNative-0.15.0

[toc]


##当图片位置发生调整,还加载原来位置
必须关了调试服务器,重新启动调试服务器,否则还加载原来的位置,并报错。

场景是把一个图剪切到新的位置。


## 安卓,textinput,当高度较小的时候文字显示不全
https://github.com/facebook/react-native/issues/3182

https://github.com/facebook/react-native/pull/2730

解决方案:设置padding=0,同时保证高度大于等于20就正常了


##Textinput不支持直接获得value
http://stackoverflow.com/questions/32913338/react-native-get-textinput-value

查遍了资料,翻看了源码,确实没有直接获得value的办法,放弃了。

官方给的方案是通过onchange不停的记录value,真不知道为啥要这样设计,太反人类了。

##安卓textinput不支持圆角
理论上可以利用外层view来进行圆角工作,未测试

##在【render中】获得不到同级组件的ref,因为组件还没渲染完,所以没有生成refs.
http://stackoverflow.com/questions/32680725/show-drawerlayoutandroid-via-toolbarandroid-oniconclicked

首先这不是一个bug。

这个问题的实质是,因为在render中,就想依赖同级组件,但是同级组件不能保证已经渲染完成,所以RN就干脆让你都取不到。

如果不是在render中,就没有这个问题了

this.refs['DRAWER_REF'] will only be accessible from the component that renders the drawer. If you want to access it from some component down the view hierarchy you need to either: pass ref down the view hierarchy as a property OR pass a callback method down the view hierarchy that will be defined on drawer parent component level


####解决方案1。
最后不得不把所有状态放到父组件中,然后通过props传递给子组件,达到了同级组件之间通信。

这样会导致设计组件状态时候要考虑组件间通信的问题,有时候子组件状态不得不升级到父组件中,影响设计逻辑

####解决方案2 
让子组件初始化的时候把this传递给父组件,这样父组件就有所有子组件的引用了,所有子组件通过父组件来来获得同级组件对象

这样做,如果组件渲染顺序不是预期的,仍然会拿不到。

####此问题还需要思考更好的解决方案

##经过各种测试,终于找到了一个隐藏组件的好办法


```
/**
* 隐藏
*/
hidden:{
  position:'absolute',
  left:-9999,
  height:10, //加高是为了解决listview不停触发底部滚动事件的
  width:10,  //加宽是为了解决viewpager隐藏时候,ios会崩溃的问题
},
        
```



##text组件的opacity从他的父亲view继承,且不能修改
https://github.com/facebook/react-native/issues/1314

解决方案:父组件使用rgba来写透明度,而不是opacity。请参考:https://github.com/facebook/react-native/commit/3c04bfcf53ced10aa3afc378b2b35afbfebc9678

##绝对定位是基于父组件的,这与css很不同。
要想基于页面进行定位,必须要放到根节点下面,不知道还有没有别的解决方案。参考地址:https://github.com/facebook/react-native/issues/3210

这是一个解决方案,是用原生来做的,只支持ios。地址:https://github.com/brentvatne/react-native-overlay

## 不支持zIndex
参考地址:https://github.com/facebook/react-native/issues/1076

##安卓和ios绝对定位对overflow的反应不同
```
<View style={css.parent}>
	<View style={css.child}>
	</View>
</View>
        
parent:{
   width:200,
   height:200,
   backgroundColor:'green',
   overflow:'visible',
},

child:{
   position:'absolute',
   top: 10,
   bottom: 0,
   left: 10,
   right: 0,

   width:400,
   height:500,
   backgroundColor:'red',

},             
```
1. parent上overflow=hidden,安卓ios表现一致,parent会挡住绝对定位的child
2. parent上overflow=visible,安卓parent仍然会挡住child,ios不会挡住。

注意:overflow在安卓下默认是hidden,在ios下默认是visible

##overflow在安卓下默认是hidden,在ios下默认是visible

overflow在安卓下默认是hidden,在ios下默认是visible
##TouchableOpacity和TouchableHighlight,第一次点击不触发press

场景:
 
1. 当touch组件在listview or scrollView的时候
2. 焦点在某个输入框中

解决方案:ListView or ScrollView上加入属性keyboardShouldPersistTaps={true}

 
####scrollview的keyboardShouldPersistTaps bool 
When false, tapping outside of the focused text input when the keyboard is up dismisses the keyboard. When true, the scroll view will not catch taps, and the keyboard will not dismiss automatically. The default value is false.

false的时候scrollview会catch事件,然后消失键盘,事件不会传递到touch。

true的时候相反。

经过测试这个属性ListView组件也可以用。

参考地址:https://github.com/facebook/react-native/issues/4087


##安卓不支持textDecorationLine的所有值
参考地址:https://github.com/facebook/react-native/pull/3816

##遇到了一个require有循环引用的情况,然后会报错

报错如下:

Invariant Violation: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object. Check the render method of `Result`.

解决方案:当时是header依赖search,search依赖result,result依赖header。然后我把header对search的依赖去掉,移动到更上一级中,就好了。

这个问题未来可能是个大坑。

##对自定义组件写style,不会自动传递给此组件的render根节点

比如自定组件A的render方法如下

	render(){
		return <View></View>
	}

使用A的时候如下

	<A style={{backgroundColor:'red'}}/>
	
背景色不会有任何的改变。

解决方案:可以这样定义A的render

	render(){
		return <View style={this.props.style}></View>
	}
	
	
	
##SwitchAndroid组件不能用,引入就报错

这个问题开始时真没想到会是个大坑,弄了差不多快一天的时间。。。。。。

一开始,发现官方其实还发布了平台通用的Switch组件,不过文档中没有,so翻看源码看怎么用,里面注释都很清楚。

在一个新的工程里能正常使用,但是在我的工程里就是死也显示不出来。

我就开始各种测试,各种升级,各种删了重装。。。。

最后终于发现是我工程里的android打包环境可能太旧了或者被我改过了啥【我印象中是没改过的】,把这个环境删了,然后用`react-native android`命令重新生成,然后重新打包,就一切都ok了。

##安卓中switch左侧显示不全
尝试用paddingLeft width等值让其显示全,没有用。

坐等官网修复。


## 安卓中image不支持defaultSource

## RN中的服务器地址的image,必须要给一个高宽
动态高宽的图片,如何支持还需要找解决方案

**如果父容器是flexDirection=column的,宽度貌似可以不写,因为宽默认就是100%了,待测试**

##安卓中dimensions获得window的高不准,差了20左右,
华为p8

https://github.com/facebook/react-native/issues/4934














================================================
FILE: ReactNative问题汇总/ReactNative-0.16.0.md
================================================
# ReactNative-0.16.0


## 升级后,测试服务器Whole Program Optimisations,非常慢
在17版本里dev=true的时候不会执行了,dev=false的时候还是很慢

## 升级后,ios和android必须一个是dev=true一个是false,否则报错

## 每个page的根节点都要声明背景色,否则页面转场的时候会是透明的。



================================================
FILE: ReactNative问题汇总/ReactNative-0.17.0.md
================================================
# ReactNative-0.17.0


#不支持export default 的写法

https://github.com/facebook/react-native/issues/4798

we should get updating to the latest Babel on the release schedule for .17 stable if possible.会在0.17.0的stable版本升级babel并修复。



================================================
FILE: ReactNative问题汇总/总体说明.md
================================================
# 总体说明

本文档描述了在实际使用ReactNative的过程中所遇到的问题和可能的解决方案。

了解这些,能帮助你在写代码之前就知道如何避开一些坑。

问题按照使用的ReactNative的版本进行的分类,不保证问题已经在新版本修复了,仅供参考。



================================================
FILE: data.json
================================================
[
    {
        "title": "ReactNative增量升级方案",
        "url": "https://raw.githubusercontent.com/cnsnake11/blog/master/ReactNative%E5%BC%80%E5%8F%91%E6%8C%87%E5%AF%BC/ReactNative%E5%A2%9E%E9%87%8F%E5%8D%87%E7%BA%A7%E6%96%B9%E6%A1%88.md",
        "content": "facebook的react-native给我们带来了用js写出原生应用的同时,也使得使用RN编写的代码的在线升级变得可能,终于可以不通过应用市场来进行升级,极大的提升了app修bug和赋予新功能的能力。----使用h5的方式也可以做到,但是rn的用户体验可要远远超过h5啊。一般使用RN编写的app的线上使用方式,是将react-native bundle命令打出bundle文件和assets文件夹,直接内置到app中,app在viewcontroller或者activity中直接加载app内部的bundle文件,比如下图。当修改了代码或者图片的时候,只要app使用新的bundle文件和assets文件夹,就完成了一次在线升级。",
        "imgUrl": "http://p0.so.qhimg.com/bdr/_240_/t0130ce82fe2c9e1b9a.jpg"
    },

    {
        "title": "ReactNative的组件架构设计",
        "url": "https://raw.githubusercontent.com/cnsnake11/blog/master/ReactNative%E5%BC%80%E5%8F%91%E6%8C%87%E5%AF%BC/ReactNative%E7%9A%84%E6%9E%B6%E6%9E%84%E8%AE%BE%E8%AE%A1.md",
        "content": "请注意,本篇写的是react native的架构设计,如果你用react来开发web程序,本篇文章只能仅供参考,问题都没有在web上去考虑过。本篇较长,前面是目前flux开源框架的一些分析,后面是架构设计过程。您可以直奔主题。用RN最大的难题是设计思想的转变,以前的设计方法论已经不太适用了。而RN仅仅提供了view的框架,构建完整app的架构并没有直接提供。考虑目前遇到的如下问题,希望架构给出解决方案。",
        "imgUrl": "http://p3.so.qhimg.com/bdr/_240_/t0147ebd93e5aec3513.jpg"
    },

    {
        "title": "ReactNative组件状态设计思考",
        "url": "https://raw.githubusercontent.com/cnsnake11/blog/master/ReactNative%E5%BC%80%E5%8F%91%E6%8C%87%E5%AF%BC/ReactNative%E7%BB%84%E4%BB%B6%E7%8A%B6%E6%80%81%E8%AE%BE%E8%AE%A1%E6%80%9D%E8%80%83.md",
        "content": "设计React组件与设计一个jquery组件或者一个原生js组件最大的区别就是状态的设计。按照原来设计组件的方法论,一个UI组件对外应该具有属性、事件、接口,对内具有内部属性,内部接口。1. 属性就像一份配置文件,描述了组件应该具有的功能、外观或者初始状态。2. 事件是组件在工作工程中,当满足某种条件的时候触发的回调函数3. 接口是组件对象的方法,可以让组件去执行某个任务",
        "imgUrl": "http://p3.so.qhimg.com/bdr/_240_/t013b826be69e97f2d8.jpg"
    },

    {
        "title": "ReactNative安卓首屏白屏优化",
        "url": "https://raw.githubusercontent.com/cnsnake11/blog/master/ReactNative%E5%BC%80%E5%8F%91%E6%8C%87%E5%AF%BC/ReactNative%E5%AE%89%E5%8D%93%E9%A6%96%E5%B1%8F%E7%99%BD%E5%B1%8F%E4%BC%98%E5%8C%96.md",
        "content": "公司现有app中部分模块使用reactnative开发,在实施的过程中,rn良好的兼容性,极佳的加载、动画性能,提升了我们的开发、测试效率,提升了用户体验。但是,在android中,当点击某个rn模块的入口按钮,弹出rn的activity到rn的页面展现出来的过程中,会有很明显的白屏现象,不同的机型不同(cpu好的白屏时间短),大概1s到2s的时间。注意,只有在真机上才会有此现象,在模拟器上没有此现象完全是秒开。ios上也是秒开,测试的最低版本是ios7,iphone4s。",
        "imgUrl": "http://p3.so.qhimg.com/bdr/_240_/t01d369ccc394843f33.jpg"
    },

    {
        "title": "ReactNative导航设计与实现",
        "url": "https://raw.githubusercontent.com/cnsnake11/blog/master/ReactNative%E5%BC%80%E5%8F%91%E6%8C%87%E5%AF%BC/ReactNative%E5%AF%BC%E8%88%AA%E8%AE%BE%E8%AE%A1%E4%B8%8E%E5%AE%9E%E7%8E%B0.md",
        "content": "关于reactnaitve的导航,官方提供了2个组件,NavigatorIOS和Navigator,其中官方并不推荐使用NavigatorIOS,它不是官方维护的,不能保证及时的更新和维护。所以本文中是以Navigator组件为基础,进行导航的设计和实现。Navigator的劣势:Navigator组件是纯js的实现,所以在页面进行转场动画的过程中,如果js不能保证在16ms内完成其它操作的话,转场动画会有卡顿现象,后面会介绍优化的方案。官方的Navigator组件使用方式较为灵活,本文的目的是选取一种最佳用法,并提取出通用功能应对常用场景,规范和设计项目中导航的使用。",
        "imgUrl": "http://p2.so.qhimg.com/bdr/_240_/t018c3358b3c28ed25c.jpg"
    }
]

================================================
FILE: xmind/RN阶段总结-里程碑2.xmind
================================================
[File too large to display: 12.4 MB]

================================================
FILE: xmind/增量升级.xmind
================================================
[File too large to display: 10.2 MB]

================================================
FILE: 其它/2
================================================
# 弱特征广告方案

# 目标

一般浏览器拦截页面内广告会使用css选择器,比如qq浏览器的规则:

```
hide=###app_mask,##.load-app,##div[class^="bbt-pregnant-timeline bbt-pregnant-timeline-"],##div[class^="bottom-layer-"],##div[class="bbt-header-dingtong"],##div[class*="-header-pregnancy"],##div[class*="-footer-pregnancy"],##section[class$="-brand"],##section[class$="-tool"],##div[class$="-footer-expand"]
filter=/base.js?v*&method=$third-party /www/default/base.js$third-party
```
从规则可以看出,弱特征化就是将class弱特征化。

# 方案1 纯前端方案

方案描述:
1. 广告模板包括css,html和js,页面直接输出此模板
2. 广告引擎js会读取模板,并将css中的class名称替换成随机,同时替换html和js的class名称
3. 最后将替换后的模板嵌入到页面中

优势:
1. 每次算法都是随机,通过classname来定位广告基本不可能

劣势:
1. 插入html的位置不好确定,位置可能会成为新的特征
2. 广告模板是特征很强的元素,不能加密,直接输出到html中,线索被暴露了
3. 广告模板转换为真正的广告html是一个关键路径方法,理论上,可以通过上述线索较为容易的找到,找到后,浏览器引擎可以在方法执行前,将此方法置空
4. 纯前端渲染,页面会有一定时间的阻塞

# 方案2 前后端结合方案

方案描述:


优势:
1.

劣势:
1. css文件增大,浪费了流量
2. js编码复杂一些,不过广告功能一般比较简单,可以接受
3. 如果广告拦截使用枚举的方式和你死磕,好像没有什么好的办法,因为换一组盐,就要重新生成css文件,流量较为浪费。
4. 盐如果发生了变化,







================================================
FILE: 其它/Building the DOM faster: speculative parsing, async, defer and preload(part 1).md
================================================
# 【翻译】Building the DOM faster: speculative parsing, async, defer and preload (part 1)

# 更快的dom渲染:预解析,异步,延迟和提前加载 ~ 第一部分

原文地址:https://hacks.mozilla.org/2017/09/building-the-dom-faster-speculative-parsing-async-defer-and-preload/

In 2017, the toolbox for making sure your web page loads fast includes everything from minification and asset optimization to caching, CDNs, code splitting and tree shaking. However, you can get big performance boosts with just a few keywords and mindful code structuring, even if you’re not yet familiar with the concepts above and you’re not sure how to get started.

优化网页打开速度的办法有很多,比如,压缩静态资源文件,使用缓存,使用cdn,代码拆分等。然而,尽管你可能不了解上述的办法,你也可以通过一些少量的代码和特定的代码结构来大幅提升网页的性能。

The fresh web standard ``` <link rel="preload"> ```, that allows you to load critical resources faster, is coming to Firefox later this month. You can already try it out in Firefox Nightly or Developer Edition, and in the meantime, this is a great chance to review some fundamentals and dive deeper into performance associated with parsing the DOM.

最新的web标准提供了``` <link rel="preload"> ```的写法,可以更快的加载特定的资源,这个特性在FIrefox中即将支持。现在,可以在firefox的nightly版本或者开发者版本中试用,同时在试用的时候,我们可以深入研究一下浏览器解析dom的细节。

Understanding what goes on inside a browser is the most powerful tool for every web developer. We’ll look at how browsers interpret your code and how they help you load pages faster with speculative parsing. We’ll break down how defer and async work and how you can leverage the new keyword preload.

其实,对浏览器渲染原理的深入理解才是web开发者最强大的武器。在这篇文章中,将会介绍浏览器是如何解析代码,并且是如何使用预解析来提升页面的加载速度的。还会对defer和async的工作原理进行说明,并且会介绍最新的属性preload。

# Building blocks

HTML describes the structure of a web page. To make any sense of the HTML, browsers first have to convert it into a format they understand – the Document Object Model, or DOM. Browser engines have a special piece of code called a parser that’s used to convert data from one format to another. An HTML parser converts data from HTML into the DOM.

HTML语言描述了网页的结构。为了解析html,浏览器首先会将其转换为文档对象模型(Document Object Model),简称DOM。浏览器引擎有一个专门的模块来处理这种转换,这个模块称为html解析器。

In HTML, nesting defines the parent-child relationships between different tags. In the DOM, objects are linked in a tree data structure capturing those relationships. Each HTML tag is represented by a node of the tree (a DOM node).

html语言可以描述出不同标签之间的父子关系。在dom中,使用树形结构来描述这种父子关系。每一个html标签都会被映射到dom树中的一个节点上。

The browser builds up the DOM bit by bit. As soon as the first chunks of code come in, it starts parsing the HTML, adding nodes to the tree structure.

浏览器会一点一点的增量构建dom。只要html的代码一抵达浏览器,就会立刻开始一点一点的构建dom树,而无需等待html代码全部下载完。

![](media/15118651219648.gif)

The DOM has two roles: it is the object representation of the HTML document, and it acts as an interface connecting the page to the outside world, like JavaScript. When you call document.getElementById(), the element that is returned is a DOM node. Each DOM node has many functions you can use to access and change it, and what the user sees changes accordingly.

DOM树有2个主要的职责:他是html文档的对象结构,并且,他是页面与外界交互的桥梁。当你使用document.getELementById()方法,返回的就是一个dom节点。每一个dom节点都有很多操作接口,可以对其进行更改。

![](media/2.gif)

CSS styles found on a web page are mapped onto the CSSOM – the CSS Object Model. It is much like the DOM, but for the CSS rather than the HTML. Unlike the DOM, it cannot be built incrementally. Because CSS rules can override each other, the browser engine has to do complex calculations to figure out how the CSS code applies to the DOM.

css样式表会被映射为CSSOM---css对象模型(CSS Object Model)。他与DOM类似,但是,cssom不能被一点点的增量构建。因为,css规则存在互相覆盖的可能性,所以,浏览器引擎会进行复杂的计算来分析出最后生效的css代码。

![](media/15120386476962.jpg)

# The history of the ```<script>``` tag. ```<script>```标签的历史

As the browser is constructing the DOM, if it comes across a ```<script>```...```</script>``` tag in the HTML, it must execute it right away. If the script is external, it has to download the script first.

当浏览器构建dom的过程中,如果遇到了```<script>```...```</script>```标签段,必须要将其中的js代码先执行完。如果是引用的方式的js,还必须要将其先下载下来。

Back in the old days, in order to execute a script, parsing had to be paused. It would only start up again after the JavaScript engine had executed code from a script.

为了执行script代码,html解析dom的工作必须要暂停,当js的代码执行完之后才会继续解析dom。

![](media/15120386940727.jpg)

Why did the parsing have to stop? Well, scripts can change both the HTML and its product―the DOM. Scripts can change the DOM structure by adding nodes with document.createElement(). To change the HTML, scripts can add content with the notorious document.write() function. It’s notorious because it can change the HTML in ways that can affect further parsing. For example, the function could insert an opening comment tag making the rest of the HTML invalid.

这里解释一下执行js的时候为啥要停止dom的解析。因为js是可以改变html同时也是可以改变dom的。比如,js可以通过添加节点来更改dom树结构的改变。比如,js可以通过document.write()方法来改变html,虽然这个方法是不建议使用的。不建议使用的原因是,这个方法有可能会影响未来的dom解析。比如,使用document.write()插入一个html注释符的左半边来让后面的html都失效。

![](media/3.gif)

Scripts can also query something about the DOM, and if that happens while the DOM is still being constructed, it could return unexpected results.

js脚本也可以对dom节点进行查询,如果在查询的过程中进行dom构建,很可能会返回异常的结果。

![](media/15120388518927.jpg)


document.write() is a legacy function that can break your page in unexpected ways and you shouldn’t use it, even though browsers still support it. For these reasons, browsers have developed sophisticated techniques to get around the performance issues caused by script blocking that I will explain shortly.

document.write()已经是很老旧的方法了,同时这个方法会对页面带来不好的影响,是不推荐使用的,尽管目前的浏览器还支持这个方法。因而,浏览器规范的制定者们也在探索更佳的解决方案来解决这种由于js脚本带来的对dom渲染的阻塞,后边就会介绍这些方案。




================================================
FILE: 其它/Building the DOM faster: speculative parsing, async, defer and preload(part 2).md
================================================
# 【翻译】Building the DOM faster: speculative parsing, async, defer and preload (part 2)

# 更快的dom构建:预解析,异步,延迟和提前加载 ~ 第二部分

原文地址:https://hacks.mozilla.org/2017/09/building-the-dom-faster-speculative-parsing-async-defer-and-preload/

# What about CSS? css的情况如何呢?

JavaScript blocks parsing because it can modify the document. CSS can’t modify the document, so it seems like there is no reason for it to block parsing, right?

js会阻断页面的dom构建是因为js可以修改html和dom。那么,css不能修改html和dom,所以理论上css应该不会阻断页面dom的构建,对吗?

However, what if a script asks for style information that hasn’t been parsed yet? The browser doesn’t know what the script is about to execute—it may ask for something like the DOM node’s background-color which depends on the style sheet, or it may expect to access the CSSOM directly.

然而,当js需要css的信息但是css还未解析完怎么办呢?浏览器并不知道js在执行的过程中是否需要访问到类似节点背景色这种依赖css的信息。

![](media/15120388873174.jpg)

Because of this, CSS may block parsing depending on the order of external style sheets and scripts in the document. If there are external style sheets placed before scripts in the document, the construction of DOM and CSSOM objects can interfere with each other. When the parser gets to a script tag, DOM construction cannot proceed until the JavaScript finishes executing, and the JavaScript cannot be executed until the CSS is downloaded, parsed, and the CSSOM is available.

所以,css是否会阻塞dom的构建要看引入css和js的顺序。如果,css是在js之前被引入的,dom的构建和cssom的构建互不影响。当解析到script标签,dom构建就会停下来直到js下载并执行完毕,同时,如果cssom还没有解析完成,js的执行也会被阻塞。下图很清楚的说明了这种关系:

![](media/15120389027978.jpg)

Another thing to keep in mind is that even if the CSS doesn’t block DOM construction, it blocks rendering. The browser won’t display anything until it has both the DOM and the CSSOM. This is because pages without CSS are often unusable. If a browser showed you a messy page without CSS, then a few moments later snapped into a styled page, the shifting content and sudden visual changes would make a turbulent user experience.

另外一个需要注意的点是尽管css不会阻断DOM的构建,但是却会阻断页面的渲染。直到dom和cssom都准备完毕了,页面才会显示出来。这是因为,未加载完css的页面是不稳定的。如果浏览器一开始加载了一个没有css的页面,然后很快样式又加载了,这个页面样子转换的过程给用户的体验很不好。

That poor user experience has a name – Flash of Unstyled Content or FOUC

这种不佳的用户体验有一个名字 --- 无样式闪屏 或者 FOUC

To get around these issues, you should aim to deliver the CSS as soon as possible. Recall the popular “styles at the top, scripts at the bottom” best practice? Now you know why it was there!

所以,为了让页面更快的展现出来,需要尽快的让css加载完成。还记得网页优化军规中的“将css放在页面上面,script放在页面下面”吗?以上就是这样做的原因。

# Back to the future – speculative parsing 更先进的算法--预解析

Pausing the parser whenever a script is encountered means that every script you load delays the discovery of the rest of the resources that were linked in the HTML.

遇到script标签就停止解析html的算法会延迟页面其它资源文件的下载。

If you have a few scripts and images to load, for example–

如果有如下的代码:

```
<script src="slider.js"></script>
<script src="animate.js"></script>
<script src="cookie.js"></script>
<img src="slide1.png">
<img src="slide2.png">
```

–the process used to go like this:

会有如下的过程:

![](media/15120389720745.jpg)

That changed around 2008 when IE introduced something they called “the lookahead downloader”. It was a way to keep downloading the files that were needed while the synchronous script was being executed. Firefox, Chrome and Safari soon followed, and today most browsers use this technique under different names. Chrome and Safari have “the preload scanner” and Firefox – the speculative parser.

在2008年的时候,ie首先提出了一个预先下载的算法。在解析到srcipt的标签的时候仍然继续下载页面的其它资源。firefox和chrome还有safari很快也使用了这个算法。不同的浏览器给他们起了不同的名字,chrome和safari称其为the preload scanner【提前加载扫描器】,firefox称其为speculative parser【预解析】。

The idea is: even though it’s not safe to build the DOM while executing a script, you can still parse the HTML to see what other resources need to be retrieved. Discovered files are added to a list and start downloading in the background on parallel connections. By the time the script finishes executing, the files may have already been downloaded.

这个思路很简单:虽然在执行js的过程中构建dom不安全,但是,可以继续解析html来下载其它的资源。这些资源会在后台并行的进行下载,当js执行完后,这些资源的下载可能已经完成。

The waterfall chart for the example above now looks more like this:

这个算法的图如下:

![](media/15120389914931.jpg)

The download requests triggered this way are called “speculative” because it is still possible that the script could change the HTML structure (remember document.write ?), resulting in wasted guesswork. While this is possible, it is not common, and that’s why speculative parsing still gives big performance improvements.

这个算法被称为预解析的原因是,因为js可能会改变html的结构(比如使用document.write),所以被下载的资源有可能是浪费的。虽然可能会存在浪费,但是这种情况并不常见,所以这个预解析的算法可以极大的提升页面加载性能。

While other browsers only preload linked resources this way, in Firefox the HTML parser also runs the DOM tree construction algorithm speculatively. The upside is that when a speculation succeeds, there’s no need to re-parse a part of the file to actually compose the DOM. The downside is that there’s more work lost if and when the speculation fails.

在这个算法中,其它的浏览器都仅仅是执行下载,而firefox同时也会继续执行dom的构建。这样做的优势很明显,当预解析成功,dom的构建会更快的完成。但是,劣势也存在,当预解析失败,浏览器执行了很多无效的工作。




================================================
FILE: 其它/Building the DOM faster: speculative parsing, async, defer and preload(part 3).md
================================================
# 【翻译】Building the DOM faster: speculative parsing, async, defer and preload (part 3)

# 更快的dom构建:预解析,异步,延迟和提前加载 ~ 第三部分

原文地址:https://hacks.mozilla.org/2017/09/building-the-dom-faster-speculative-parsing-async-defer-and-preload/

# (Pre)loading stuff 预解析的内容

This manner of resource loading delivers a significant performance boost, and you don’t need to do anything special to take advantage of it. However, as a web developer, knowing how speculative parsing works can help you get the most out of it.

预解析算法提升了浏览器加载页面的性能,并且,无需开发者做什么特殊的工作就可以享用到这个算法带来的性能提升。但是,作为web开发者来说,能深刻理解预解析算法的原理和工作过程才能更好的利用这个算法。

The set of things that can be preloaded varies between browsers. All major browsers preload:

1. scripts
1. external CSS
1. and images from the ```<img>``` tag

不同的浏览器会预解析不同的内容。所有主流浏览器都预解析如下内容:

1. scripts
1. 外部CSS
1. 使用```<img>``` 标签定义的图片


Firefox also preloads the poster attribute of video elements, while Chrome and Safari preload @import rules from inlined styles.

firefox也会预解析vidoe标签上定义的poster,而chrome和safari会预解析通过@import引入的css。

There are limits to how many files a browser can download in parallel. The limits vary between browsers and depend on many factors, like whether you’re downloading all files from one or from several different servers and whether you are using HTTP/1.1 or HTTP/2 protocol. To render the page as quickly as possible, browsers optimize downloads by assigning priority to each file. To figure out these priorities, they follow complex schemes based on resource type, position in the markup, and progress of the page rendering.

预解析内容的同时并行下载数量是有限制的。这个限制不同浏览器不同,在不同的情况下也会不同,比如说,下载的资源是同一个域名还是多个域名,或者使用的是HTTP/1.1还是HTTP/2的协议。浏览器会对预加载内容的下载顺序进行优化来保证更快的页面加载速度。为了计算内容的下载优先级顺序,浏览器会通过资源的类型位置和当前页面的状态来进行计算。

While doing speculative parsing, the browser does not execute inline JavaScript blocks. This means that it won’t discover any script-injected resources, and those will likely be last in line in the fetching queue.

当执行预加载算法的时候,浏览器将不会执行页面上的行内js。这意味着如果在页面的行内js中有js注入的下载资源,他们将会在执行完预加载后才会执行加载。比如下面的这种代码:

```
var script = document.createElement('script');
script.src = "//somehost.com/widget.js";
document.getElementsByTagName('head')[0].appendChild(script);
```

You should make it easy for the browser to access important resources as soon as possible. You can either put them in HTML tags or include the loading script inline and early in the document. However, sometimes you want some resources to load later because they are less important. In that case, you can hide them from the speculative parser by loading them with JavaScript late in the document.

如果需要让浏览器立即下载某些主要的资源,你可以将其放在页面的最顶部。如果某些资源并不重要,并不影响页面的展现,你可以将其通过行内js来加载,并将这段行内js放到页面的最底部。

# defer and async

Still, synchronous scripts blocking the parser remains an issue. And not all scripts are equally important for the user experience, such as those for tracking and analytics. Solution? Make it possible to load these less important scripts asynchronously.

通过预解析js对文件下载的阻断已经解决了,但是js阻断dom构建还仍然是个问题。其实,并不是所有的js都在页面加载过程是必须的,比如说一些记录日志的js。我们可以让其不阻断页面dom的构建。

The defer and async attributes were introduced to give developers a way to tell the browser which scripts to handle asynchronously.

defer和async属性可以设置script标签进行异步的加载,而不影响页面dom的构建。

Both of these attributes tell the browser that it may go on parsing the HTML while loading the script “in background”, and then execute the script after it loads. This way, script downloads don’t block DOM construction and page rendering. Result: the user can see the page before all scripts have finished loading.

这2个属性都会使浏览器在遇到script标签后不停止对dom的构建和对页面的渲染。所以,用户看到页面的时候,设置了这2个属性的js可能还没有执行完成。

The difference between defer and async is which moment they start executing the scripts.

这2个属性的区别是js执行的时机。

defer was introduced before async. Its execution starts after parsing is completely finished, but before the DOMContentLoaded event. It guarantees scripts will be executed in the order they appear in the HTML and will not block the parser.

一般更推荐使用defer属性,而不是async属性。defer属性的js会在页面完全的解析渲染完成的时候执行,并且是在DOMContentLoaded事件之前执行。同时,defer属性会保证按照在页面中定义的顺序执行,而且也保证绝对不会阻断页面的渲染。如图:

![](media/15120391161617.jpg)

async scripts execute at the first opportunity after they finish downloading and before the window’s load event. This means it’s possible (and likely) that async scripts are not executed in the order in which they appear in the HTML. It also means they can interrupt DOM building.

async属性的js仅仅是下载不阻断dom构建,执行仍会阻断dom构建,它执行的时机是当js一下载完成就立即执行,这时会阻断dom的构建,而且也不保证会按照js在页面中定义的顺序执行。

Wherever they are specified, async scripts load at a low priority. They often load after all other scripts, without blocking DOM building. However, if an async script finishes downloading sooner, its execution can block DOM building and all synchronous scripts that finish downloading afterwards.

定义了async属性的script标签的加载优先级很低,无论他们定义在页面的什么位置。他们经常会在所有其他不阻断dom构建的js加载完后才被加载。然而,一旦一个async的js下载完,他的执行仍然会阻断dom的构建,也会阻断页面上之后其他同步js的下载。

![](media/15120391311853.jpg)

Note: Attributes async and defer work only for external scripts. They are ignored if there’s no src.

注意:async和defer属性都只对外部js生效,如果script标签上没定义src,将会忽略这2个属性。

# preload

async and defer are great if you want to put off handling some scripts, but what about stuff on your web page that’s critical for user experience? Speculative parsers are handy, but they preload only a handful of resource types and follow their own logic. The general goal is to deliver CSS first because it blocks rendering. Synchronous scripts will always have higher priority than asynchronous. Images visible within the viewport should be downloaded before those below the fold. And there are also fonts, videos, SVGs… In short – it’s complicated.

async和defer可以处理掉那些页面初始化过程中不重要的scripts,那么那些重要的资源还有更好的处理办法吗?浏览器的预解析引擎虽然用起来简单,但是他只能解析小部分的资源类型,而且算法也较为固定。我们的目标是让css尽早下载解析完成,同步的脚本的优先级高于异步脚本,在视区内的图片应该尽早下载,而且还有像字体文件,视频,svg等等资源需要考虑,总之,情况很复杂。

As an author, you know which resources are the most important for rendering your page. Some of them are often buried in CSS or scripts and it can take the browser quite a while before it even discovers them. For those important resources you can now use ```<link rel="preload">``` to communicate to the browser that you want to load them as soon as possible.

只有开发者才能知道哪些资源对页面初始化过程是最重要的。这些资源很可能是通过css或者js来引入的,浏览器对他们的下载时机是很晚的。那么现在,你可以使用```<link rel="preload">```来加载这类资源,浏览器会在第一时间加载这些资源。

All you need to write is:

你可以这样写:

```
<link rel="preload" href="very_important.js" as="script">
```

You can link pretty much anything and the as attribute tells the browser what it will be downloading. Some of the possible values are:

这中preload的写法支持很多种资源类型,比如:

1. script
1. style
1. image
1. font
1. audio
1. video

You can check out the rest of the content types on MDN.

你可以查看MDN的官方文档:https://developer.mozilla.org/en-US/docs/Web/HTML/Preloading_content#What_types_of_content_can_be_preloaded

Fonts are probably the most important thing that gets hidden in the CSS. They are critical for rendering the text on the page, but they don’t get loaded until browser is sure that they are going to be used. That check happens only after CSS has been parsed, and applied, and the browser has matched CSS rules to the DOM nodes. This happens fairly late in the page loading process and it often results in an unnecessary delay in text rendering. You can avoid it by using the preload attribute when you link fonts.

字体文件就是被隐藏在css文件中并且页面初始化过程很重要的资源。但是,加载字体文件的时机一般都比较晚,因为需要等css先加载完成,并且应用到dom节点上之后,字体文件才会被加载。所以,文本的渲染可能会有延迟的感觉。现在,可以通过使用preload来尽早加载字体文件了。

One thing to pay attention to when preloading fonts is that you also have to set the crossorigin attribute even if the font is on the same domain:

加载字体文件的时候,通常要加一个crossorigin的属性,这是固定写法。

```
<link rel="preload" href="font.woff" as="font" crossorigin>
```

The preload feature has limited support at the moment as the browsers are still rolling it out, but you can check the progress here.

目前preload属性只有少部分的浏览器支持,可以通过 https://caniuse.com/#search=preload 查看。

# Conclusion 总结

Browsers are complex beasts that have been evolving since the 90s. We’ve covered some of the quirks from that legacy and some of the newest standards in web development. Writing your code with these guidelines will help you pick the best strategies for delivering a smooth browsing experience.

浏览器重90年代发展到现在已经越来越复杂了。很多遗留的特性和未来的标准混杂在一起。通过这篇文章,你可以理解如何让页面的渲染更快速的原理。




================================================
FILE: 其它/Designing Websites for iPhone X.md
================================================
# 【翻译】Designing Websites for iPhone X 

# 让网站适配 iphone X 

原文地址: https://webkit.org/blog/7929/designing-websites-for-iphone-x/

The section below about safe area insets was updated on Oct 31, 2017 to reflect changes in the iOS 11.2 beta.

以下关于safe area insets的内容已经在20171031的时候进行了修改,会在ios 11.2beta中表现出来。

Out of the box, Safari displays your existing websites beautifully on the edge-to-edge display of the new iPhone X. Content is automatically inset within the display’s safe area so it is not obscured by the rounded corners, or the device’s sensor housing.

无需任何修改,在ihponeX中safari可以将网页显示的很美观。网页的内容,会在safe area中显示出来,所以,网页的内容不会被圆角和设备的传感器条挡住。

The inset area is filled with the page’s background-color (as specified on the <body>or <html> elements) to blend in with the rest of the page. For many websites, this is enough. If your page has only text and images above a solid background color, the default insets will look great.

安全区域以外的地方(也就是屏幕上下奇形怪状的地方),会自动被填充背景色(在body或者html元素上定义的背景色)。在大多数情况下,这样进行兼容就足够了。只要你的页面是固定背景色的,这种默认的填充方式就足够用了。

Other pages — especially those designed with full-width horizontal navigation bars, like the page below — can optionally go a little further to take full advantage of the features of the new display. The iPhone X Human Interface Guidelines detail a few of the general design principles to keep in mind, and the UIKit documentation discusses specific mechanisms native apps can adopt to ensure that they look good. Your website can make use of a few similar new pieces of WebKit API introduced in iOS 11 to take full advantage of the edge-to-edge nature of the display.

另外的一些页面,特别是那种有导航条的-可以有选择的进行更深层次的优化来利用新的显示特性。在ios11中,你的网站可以使用新的webkit api来适配显示。

While reading this post you can tap on any of the images to visit a corresponding live demo page and take a peek at the source code.

本篇文章的图片都可以点击到对应的demo页面。【注:请点击原文中的图片】


![](media/15099614906501.png)
图:safari默认的兼容行为。


# Using the Whole Screen 使用全部的屏幕


The first new feature is an extension to the existing viewport meta tag called viewport-fit, which provides control over the insetting behavior. viewport-fit is available in iOS 11.

viewport标签有一个新属性viewport-fit,这个属性可以控制视图的显示行为。viewport-fit在ios11上可以使用。

The default value of viewport-fit is auto, which results in the automatic insetting behavior seen above. In order to disable that behavior and cause the page to lay out to the full size of the screen, you can set viewport-fit to cover. After doing so, ourviewport meta tag now looks like this:

viewport-fit的默认值是auto,这个值的行为就像上面的截图那些,页面不会撑到屏幕边缘。设置这个值为cover就会让页面覆盖整个页面,包括屏幕边缘。示例代码:

```
<meta name='viewport' content='initial-scale=1, viewport-fit=cover’>
```

After reloading, the navigation bar looks much better, running from edge to edge. However, it is immediately clear why it is important to respect the system’s safe area insets: some of the page’s content is obscured by the device’s sensor housing, and the bottom navigation bar is very hard to use.

页面刷新之后,导航条已经可以撑满屏幕边缘了。同时,问题也很明显:内容被传感器条挡住了,并且,底部的导航条和虚拟按键也重叠了。

![](media/15099634742457.png)
图:Use `viewport-fit=cover` to fill the whole screen.使用viewport-fit=cover来铺满整个屏幕。

# Respecting the Safe Areas 安全区域

The next step towards making our page usable again after adopting viewport-fit=cover is to selectively apply padding to elements that contain important content, in order to ensure that they are not obscured by the shape of the screen. This will result in a page that takes full advantage of the increased screen real estate on iPhone X while adjusting dynamically to avoid the corners, sensor housing, and indicator for accessing the Home screen.

在使用了viewport-fit=cover之后,需要在一些地方加padding来避免被遮挡。如果你能动态的适配iPhone X屏幕的圆角,顶部传感器条,底部虚拟按键,那么就可以完全的享用到iPhone X的大屏幕。

![](media/15099656914598.png)
图:The safe and unsafe areas on iPhone X in the landscape orientation, with insets indicated.iPhone X的横屏安全区域,及几个固定变量的示意图。

To achieve this, WebKit in iOS 11 includes a new CSS function, env(), and a set of four pre-defined environment variables, safe-area-inset-left, safe-area-inset-right, safe-area-inset-top, and safe-area-inset-bottom. When combined, these allow style declarations to reference the current size of the safe area insets on each side.

为了达成动态自适应的目的,ios 11 的webkit提供了一个新的css方法:env(),和有四个预先定义的环境变量,safe-area-inset-left, safe-area-inset-right, safe-area-inset-top, and safe-area-inset-bottom。使用这些变量,就可以获得屏幕的安全区域距离屏幕边缘的距离。

The env() function shipped in iOS 11 with the name constant(). Beginning with Safari Technology Preview 41 and the iOS 11.2 beta, constant() has been removed and replaced with env(). You can use the CSS fallback mechanism to support both versions, if necessary, but should prefer env() going forward.

env()方法是在ios11中被支持的,一开始他被命名为constant()。在Safari Technology Preview 41 and the iOS 11.2 beta的版本中,constant()已经被重命名为env()。你可以使用css的权重机制来适配所有的版本,如果不是必须的话,使用env()来适配最新的版本即可。

env() works anywhere var() does — for example, inside the padding properties:

env()使用的方式和var()基本一致,例如,在定义padding的时候:

```
.post {
    padding: 12px;
    padding-left: env(safe-area-inset-left);
    padding-right: env(safe-area-inset-right);
}

```

For browsers that do not support env(), the style rule that includes it will be ignored; for this reason, it is important to continue to separately specify fallback rules for any declarations using env().

当浏览器不支持env()的时候,这条样式会失效;所以,要将这种使用env()的样式,独自定义。

![](media/15100240680308.png)
图:Respect safe area insets so that important content is visible.使用了环境变量的适配效果。

# Bringing It All Together, With min() and max() 使用min()和max()

This section covers features that are available starting in Safari Technology Preview 41 and the iOS 11.2 beta.

本节讲的内容在 Safari Technology Preview 41 and the iOS 11.2 beta中开始支持。

If you adopt safe area insets in your website design, you might notice that it is somewhat difficult to specify that you want a minimum padding in addition to the safe area inset. In the page above, where we replaced our 12px left padding with env(safe-area-inset-left), when we rotate back to portrait, the left safe area inset becomes 0px, and the text sits immediately adjacent to the screen edge.

当使用了安全区域变量,并不能解决所有的问题。比如,上面的页面,当横屏的时候, env(safe-area-inset-left)是有值的,当竖屏的时候,env(safe-area-inset-left)=0px,此时,文本就会挤到屏幕的边缘了。

![](media/15100270621233.png)
图:Safe area insets are not a replacement for margins.使用Safe area insets带来的问题。

To solve this, we want to specify that our padding should be the default padding or the safe area inset, whichever is greater. This can be achieved with the brand-new CSS functions min() and max() which will be available in a future Safari Technology Preview release. Both functions take an arbitrary number of arguments and return the minimum or maximum. They can be used inside of calc(), or nested inside each other, and both functions allow calc()-like math inside of them.

解决这个问题,其实是需要给padding设置一个默认值,当safe-area-inset-left有值的时候,设置成safe-area-inset-left,没值的时候使用默认值。我们可以使用一组新的css函数min() and max()来解决这个问题。这2个函数可以接受任意个数的参数,并返回最大或者最小的那个。他们也可以用到calc()中,也可以相互嵌套使用。

For this case, we want to use max():

解决上述问题的示例:

```
@supports(padding: max(0px)) {
    .post {
        padding-left: max(12px, env(safe-area-inset-left));
        padding-right: max(12px, env(safe-area-inset-right));
    }
}
```

It is important to use @supports to feature-detect min and max, because they are not supported everywhere, and due to CSS’s treatment of invalid variables, to not specify a variable inside your @supports query.

注意:@supports语句可以检查是否支持max,但不要在其中使用变量,例如:@supports(padding: max(env(safe-area-inset-left))),因为css对待无效的变量是返回默认值,也就是这个例子中的padding的初始值。【此处具体的细节可以参考:https://drafts.csswg.org/css-variables/#invalid-variables,本文最后也翻译了一下这块。】

In our example page, in portrait orientation, env(safe-area-inset-left) resolves to 0px, so the max() function resolves to 12px. In landscape, when env(safe-area-inset-left) is larger due to the sensor housing, the max() function will resolve to that size instead, ensuring that the important content within is always visible.

在上述的示例中,当竖屏时, env(safe-area-inset-left)是0,所以max函数返回了12px。当横屏时,env(safe-area-inset-left)的值会大于12,所以,max函数会返回env(safe-area-inset-left)的值。这就保证了页面的动态适应性。

![](media/15100271200055.png)
图:Use max() to combine safe area insets with traditional margins.使用max函数来保证竖屏的兼容。

Experienced web developers might have previously encountered the “CSS locks” mechanism, commonly used to clamp CSS properties to a particular range of values. Using min() and max() together makes this much easier, and will be very helpful in implementing effective responsive designs in the future.

min() and max()函数可以使用到更多的场景中,他们可以帮助开发者更容易的创建兼容性更好的页面。

# 参考:无效变量的说明

原文地址:https://drafts.csswg.org/css-variables/#invalid-variables

直接翻译了3.1节中的例子,比较直观

For example, in the following code:

例如,如下的代码:

```
:root { --not-a-color: 20px; }
p { background-color: red; }
p { background-color: var(--not-a-color); }

```

the <p> elements will have transparent backgrounds (the initial value for background-color), rather than red backgrounds. The same would happen if the custom property itself was unset, or contained an invalid var() function.

p元素的背景将是transparent(也就是background-color的初始值),而不是红色。这种变量值无效的情况和没写background-color的表现是一致的。

Note the difference between this and what happens if the author had just written background-color: 20px directly in their stylesheet - that would be a normal syntax error, which would cause the rule to be discarded, so the background-color: red rule would be used instead.

注意这种情况和直接写错background-color: 20px的区别,如果直接写错成ackground-color: 20px,会导致错误的这条样式失效,background-color: red仍会生效。

Note: The invalid at computed-value time concept exists because variables can’t "fail early" like other syntax errors can, so by the time the user agent realizes a property value is invalid, it’s already thrown away the other cascaded values.

说明:不合法的变量值问题是因为变量的出错时机是比较晚的,所以,当浏览器识别到变量值无效的时候,已经将其它的有效的之前定义的值抛弃了。


补充说明:最后这里说的是【变量】值不合法才会导致整条样式失效。如果是直接不支持env或者不支持env里写的属性名称(这些都不是变量的情况),就不会导致之前的有效定义被抛弃(在chrome里做过测试)。





================================================
FILE: 其它/FlatList.md
================================================
高性能的简单列表组件,支持下面这些常用的功能:

完全跨平台。
支持水平布局模式。
行组件显示或隐藏时可配置回调事件。
支持单独的头部组件。
支持单独的尾部组件。
支持自定义行间分隔线。
支持下拉刷新。
支持上拉加载。
支持跳转到指定行(ScrollToIndex)。


本组件实质是基于<VirtualizedList>组件的封装,因此也有下面这些需要注意的事项:

1. 当某行滑出渲染区域之外后,其内部状态将不会保留。请确保你在行组件以外的地方保留了数据。
1. 为了优化内存占用同时保持滑动的流畅,列表内容会在屏幕外异步绘制。这意味着如果用户滑动的速度超过渲染的速度,则会先看到空白的内容。这是为了优化不得不作出的妥协,而我们也在设法持续改进。
1. 本组件继承自PureComponent而非通常的Component,这意味着如果其props在浅比较中是相等的,则不会重新渲染。所以请先检查你的renderItem函数所依赖的props数据(包括data属性以及可能用到的父组件的state),如果是一个引用类型(Object或者数组都是引用类型),则需要先修改其引用地址(比如先复制到一个新的Object或者数组中),然后再修改其值,否则界面很可能不会刷新。(译注:这一段不了解的朋友建议先学习下js中的基本类型和引用类型。)
1. 默认情况下每行都需要提供一个不重复的key属性。你也可以提供一个keyExtractor函数来生成key。


# 常用属性

#### data: ?Array<ItemT> 

为了简化起见,data属性目前只支持普通数组。如果需要使用其他特殊数据结构,例如immutable数组,请直接使用更底层的VirtualizedList组件。


#### getItemLayout?: (data: ?Array<ItemT>, index: number) =>
  {length: number, offset: number, index: number} 

getItemLayout是一个可选的优化,用于避免动态测量内容尺寸的开销,不过前提是你可以提前知道内容的高度。如果你的行高是固定的,getItemLayout用起来就既高效又简单,类似下面这样:

getItemLayout={(data, index) => ( {length: 行高, offset: 行高 * index, index} )}
注意如果你指定了SeparatorComponent,请把分隔线的尺寸也考虑到offset的计算之中。


#### initialNumToRender: number 

指定一开始渲染的元素数量,最好刚刚够填满一个屏幕,这样保证了用最短的时间给用户呈现可见的内容。注意这第一批次渲染的元素不会在滑动过程中被卸载,这样是为了保证用户执行返回顶部的操作时,不需要重新渲染首批元素。


#### initialScrollIndex?: ?number 

开始时屏幕顶端的元素是列表中的第 initialScrollIndex 个元素, 而不是第一个元素。设置这个属性会关闭对“滚动到顶端”这个动作的优化(参见VirtualizedList 的 initialNumToRender 属性)。位于 initialScrollIndex 位置的元素总是会被立刻渲染。需要先设置 getItemLayout 属性。

#### keyExtractor: (item: ItemT, index: number) => string 

此函数用于为给定的item生成一个不重复的key。Key的作用是使React能够区分同类元素的不同个体,以便在刷新时能够确定其变化的位置,减少重新渲染的开销。若不指定此函数,则默认抽取item.key作为key值。若item.key也不存在,则使用数组下标。


#### onEndReached?: ?(info: {distanceFromEnd: number}) => void 

当列表被滚动到距离内容最底部不足onEndReachedThreshold的距离时调用。

#### onEndReachedThreshold?: ?number 

决定当距离内容最底部还有多远时触发onEndReached回调。注意此参数是一个比值而非像素单位。比如,0.5表示距离内容最底部的距离为当前列表可见长度的一半时触发。

# 常用方法

#### scrollToEnd(params?: object) 

滚动到底部。如果不设置getItemLayout属性的话,可能会比较卡。

#### scrollToIndex(params: object) 

将位于指定位置的元素滚动到可视区的指定位置,当 viewPosition 为 0 时将它滚动到屏幕顶部,为 1 时将它滚动到屏幕底部,为 0.5 时将它滚动到屏幕中央。

如果不设置getItemLayout属性的话,无法跳转到当前可视区域以外的位置。

#### scrollToItem(params: object) 

这个方法会顺序遍历元素。尽可能使用 scrollToIndex 。 如果不设置getItemLayout属性的话,可能会比较卡。

#### scrollToOffset(params: object) 

滚动列表到指定的偏移(以像素为单位),等同于 ScrollView 的 scrollTo 方法。


================================================
FILE: 其它/How TensorFlow Lite Brings Machine Learning to Mobile Devices.md
================================================
# 【翻译】How TensorFlow Lite Brings Machine Learning to Mobile Devices

# TensorFlow Lite --- 赋予移动设备机器学习的能力

原文地址: http://www.tomsitpro.com/articles/tensorflow-light-machine-learning-mobile,1-3670.html

Android developers will appreciate TensorFlow Lite, which promises to give them machine learning tools for mobile apps.

安卓的开发者将会使用到TensorFlow Lite用于移动设备机器学习的开发。

![](media/15090124219258.jpg)

Machine learning requires incredibly complex computing power and resources. While research and artificial intelligence breakthroughs gain most of the attention, the most dramatic difference in daily computing happens on mobile devices. It's smartphones where the user is typically interacting with information that is personal, and would benefit from a computer that anticipates one's needs.

机器学习需要大量的计算资源。伴随着人工智能领域研究的突破,移动设备的计算方式也在发生着巨大的变化。我们通过智能手机获取信息的方式,可以从计算机的智能预测需求中获益。

Businesses are counting on machine learning to enhance productivity and do things that were previously impossible. Google recently offered some insights into how the company wants to affect change with its own mobile operating system.

商业可以利用机器学习提高生产力,并且做到之前做不到的事情。谷歌最近提出了一些观点:公司如何改善自己的移动操作软件。

Android developers should keep an eye on TensorFlow Lite, which is promised to give them machine learning tools for building such smarts into their own mobile applications. It's an optimized version of TensorFlow, which is Google's popular open-source library that enables researchers and developers to apply machine learning to their applications.

安卓开发者应该时刻关注TensorFlow Lite,它会为应用带来机器学习的能力。TensorFlow Lite是TensorFlow的优化版,TensorFlow是谷歌的开源机器学习框架。

The news about TensorFlow Lite was first announced at Google I/O, where the company illustrated the potentials for machine learning on mobile devices by showing off how Google Lens will be able to recognize objects and infuse artificial intelligence in other ways into image recognition. At I/O and in other announcements, Google has made a point of casting itself as an "AI-first" company.

TensorFlow Lite是在谷歌IO大会行公布的,大会上演示了Google Lens的图片识别及人工智能技术。google已经宣称自己是AI-first公司。

# Arrival of new APIs 新的api

While developers await the arrival of TensorFlow Lite, they can look to some new APIs rolling out to the standard version of TensorFlow for inspiration. While it's not a direct indication of what the Lite model will look like, they exhibit further insight into what TensorFlow and its machine learning capabilities make possible.

在开发者等待TensorFlow Lite正式发布的过程中,可以先调研一下基于TensorFlow衍生出来的心api,这会带来新的灵感。这虽然不能看出TensorFlow Lite的模型是什么样的,但却能看出未来机器学习的潜力都是什么。

Google recently also release a new Object Detection API to assist those working with computer vision models. As outlined in a Google Research blog post, the new set of APIs enables researchers to create more complex object detection. An example of TensorFlow at work illustrates how machine learning enables recognition of kites and people from the following scene.

google最近发布了对象检测api,他可以为视觉分析提供帮助。Google Research blog概括了一下,新的api可以让开发者对复杂的对象进行识别。下边的场景会说明TensorFlow是怎样应用到机器学习中进行图形识别的。

"This codebase is an open-source framework built on top of TensorFlow that makes it easy to construct, train and deploy object detection models. Our goals in designing this system was to support state-of-the-art models while allowing for rapid exploration and research," wrote research scientist Jonathan Huang and software engineer Vivek Rathod on the Google Research blog.

“这个代码库是基于TensorFlow开发的开源框架,它可以很简单进行构造,训练,部署对象检测模型。我们设计这个系统的目标是去支持顶尖的模型,来进行快速的研究工作”,开发者们说。

Google, of course, isn't the only one offering machine learning resources to developers. Facebook, Apple and Microsoft have been building their own resources. Facebook's Caffe2Go framework has its own models that can run on smartphones. Apple's Core ML is built for running machine learning on iOS. Microsoft Azure also offers machine learning as a service.

Google并不是唯一一家提供机器学习开发资源的公司。facebook,apple,微软,都在建设他们自己的资源。facebook的Caffe2Go框架也已经可以运行在智能手机上了。苹果的Core ML是ios上运行机器学习的解决方案。Microsoft Azure也提供了机器学习作为一个服务。

The capabilities are growing quickly, as illustrated by the current release of the TensorFlow APIs. The ongoing challenge of performing machine learning on device is the resource constraints inherent to mobile computing. While doing such computing on the device itself enhances privacy and in some cases may be more efficient, much of the work must still be performed in the cloud.

目前版本的TensorFlow的功能增长非常快。在移动设备上运行机器学习的最大挑战是硬件资源。有时候需要设备有非常快的运算速度,所以部分工作可能还是需要在云端处理。

Also at I/O, Google also promised that Android O would include a framework for more accelerated neural computation. Google, Apple and other companies that make devices will also have to think about machine learning as they design their hardware and software. SSD models are lightweight enough, for example, to run in real-time on mobile devices. But as phones become always-aware, intelligent assistants, the role of machine learning in everything from at the system level to third-party applications will become larger.

在IO大会上,谷歌也表示在android O上,会内置性能很高的神经网络计算框架。谷歌,苹果等公司已经开始去考虑如何设计软件硬件来支持机器学习。SSD模型就是一个轻量级的即时运算的机器学习模型,可以运行在移动设备上。随着手机越来越智能,机器学习将会在系统级别和第三方应用中大展宏图。




================================================
FILE: 其它/PanResponder.md
================================================
# PanResponder

移动设备上的手势识别要比在web上复杂得多。用户的一次触摸操作的真实意图是什么,App要经过好几个阶段才能判断。比如App需要判断用户的触摸到底是在滚动页面,还是滑动一个widget,或者只是一个单纯的点击。甚至随着持续时间的不同,这些操作还会转化。此外,还有多点同时触控的情况。

PanResponder是reactnative中实现手势系统的类。

PanResponder类可以将多点触摸操作协调成一个手势。它使得一个单点触摸可以接受更多的触摸操作,也可以用于识别简单的多点触摸手势。

它提供了一个对触摸响应系统响应器的可预测的包装。对于每一个处理函数,它在原生事件之外提供了一个新的gestureState对象。

onPanResponderMove: (event, gestureState) => {}

gestureState对象有如下的字段:

	•	stateID - 触摸状态的ID。在屏幕上有至少一个触摸点的情况下,这个ID会一直有效。
	•	moveX - 最近一次移动时的屏幕横坐标
	•	moveY - 最近一次移动时的屏幕纵坐标
	•	x0 - 当响应器产生时的屏幕坐标
	•	y0 - 当响应器产生时的屏幕坐标
	•	dx - 从触摸操作开始时的累计横向路程
	•	dy - 从触摸操作开始时的累计纵向路程
	•	vx - 当前的横向移动速度
	•	vy - 当前的纵向移动速度
	•	numberActiveTouches - 当前在屏幕上的有效触摸点的数量


示例代码:

```
componentWillMount: function() {
    this._panResponder = PanResponder.create({
      // 要求成为响应者:
      onStartShouldSetPanResponder: (evt, gestureState) => true,
      onStartShouldSetPanResponderCapture: (evt, gestureState) => true,
      onMoveShouldSetPanResponder: (evt, gestureState) => true,
      onMoveShouldSetPanResponderCapture: (evt, gestureState) => true,

      onPanResponderGrant: (evt, gestureState) => {
        // 开始手势操作。给用户一些视觉反馈,让他们知道发生了什么事情!

        // gestureState.{x,y} 现在会被设置为0
      },
      onPanResponderMove: (evt, gestureState) => {
        // 最近一次的移动距离为gestureState.move{X,Y}

        // 从成为响应者开始时的累计手势移动距离为gestureState.d{x,y}
      },
      onPanResponderTerminationRequest: (evt, gestureState) => true,
      onPanResponderRelease: (evt, gestureState) => {
        // 用户放开了所有的触摸点,且此时视图已经成为了响应者。
        // 一般来说这意味着一个手势操作已经成功完成。
      },
      onPanResponderTerminate: (evt, gestureState) => {
        // 另一个组件已经成为了新的响应者,所以当前手势将被取消。
      },
      onShouldBlockNativeResponder: (evt, gestureState) => {
        // 返回一个布尔值,决定当前组件是否应该阻止原生组件成为JS响应者
        // 默认返回true。目前暂时只支持android。
        return true;
      },
    });
  },

  render: function() {
    return (
      <View {...this._panResponder.panHandlers} />
    );
  },


```



================================================
FILE: 其它/RN分享提纲.md
================================================
# RN分享提纲

# 目标

最终目标:能够在孕育app中进行rn开发。

本期目标:了解孕育中开发rn的一般过程。

# 实施项目

孕育中专家答和记录tab。

# 环境搭建

#### ios

xcode+app的ios代码+js编辑器+rn开发服务器+真机or模拟器

#### android(不推荐,建议直接真机)

jdk+androidSdk+androidStudio+app的android代码+js编辑器+rn开发服务器+真机or模拟器

#### 安装react-native cli

#### 安装xcode

#### git库下载代码


# 开发过程

1. 启动rn开发服务器
2. 启动模拟器,点开app,设置自动reload
3. 启动js代码编辑器,coding---save---看效果
4. tips:可以直接让首页显示你要开发的页面,可以快速查看效果

```
// tips用到的代码,替换index页面的最后一行
AppRegistry.registerComponent('Ask', () => require('../../../demo/demo1/animate/drag2'));
```

# 调试过程

1. console.log
2. 断点调试


# 发版过程

### 全量发布

全量发布是将rn相关资源打包进app中,是无需网络下载的。

一般过程:

1. coding结束
2. 使用全量打包命令,打出android和ios全量包
3. 将包发给android和ios的工程师即可

### 增量发布

[增量升级方案](https://github.com/cnsnake11/blog/blob/master/ReactNative%E5%BC%80%E5%8F%91%E6%8C%87%E5%AF%BC/ReactNative%E5%A2%9E%E9%87%8F%E5%8D%87%E7%BA%A7%E6%96%B9%E6%A1%88.md)

一般过程:

1. coding结束
2. 使用全量打包命令,打出android和ios全量包
3. 使用增量打包命令,打出android和ios增量包
4. 将增量包上传到后台管理系统,上线即可

### 增量包测试过程

1. 打出增量包
2. 将增量包上传到升级后台,上线标识为false
3. 手机开启测试模式(isDev=true)
4. 手动更新增量包

# 课后希望

搭建开发环境,把上面的内容都操作一下。



****************************  和下期分享的分割线  *********************************

# 开发规范

# 状态管理

# 常用组件和接口

### 导航、列表等

### 与app的交互

### 埋点

# 自定义原生组件

# 性能tips




================================================
FILE: 其它/Range.md
================================================
# Range

在做富文本编辑器的开发过程中,Selection和Range对象是用来操作选中区域的办法,本篇主要介绍一下Range对象的常用接口和属性。

# 介绍

Range可以用 Document 对象的 createRange方法创建,也可以用Selection对象的getRangeAt方法取得。另外,可以通过构造函数 Range() 来获得一个 Range 。


# 属性

#### Range.collapsed 只读
返回一个用于判断 Range 起始位置和终止位置是否相同的布尔值。
#### Range.commonAncestorContainer 只读
返回包含 startContainer 和 endContainer 的最深的节点。
#### Range.endContainer 只读
返回包含 Range 终点的节点。
#### Range.endOffset 只读
返回 endContainer 中表示Range终点位置的数字。
#### Range.startContainer 只读
返回包含 Range 开始的节点。
#### Range.startOffset 只读
返回 startContainer 中表示 Range 起始位置的数字。

# 方法

#### Range.setStart()
设置 Range 的起点。
#### Range.setEnd()
设置 Range 的终点。
#### Range.setStartBefore()
以其它节点 ( Node)为基准,设置 Range 的起点。
#### Range.setStartAfter()
以其它节点为基准,设置 Range 的始点。
#### Range.setEndBefore()
以其它节点为基准,设置 Range 的终点。
#### Range.setEndAfter()
以其它节点为基准,设置 Range 的终点。
#### Range.selectNode()
设定一个包含节点和节点内容的 Range 。
#### Range.selectNodeContents()
设定一个包含某个节点内容的 Range 。
#### Range.collapse()
向指定端点折叠该 Range 。


#### Range.cloneContents()
返回 Range 当中节点的文档片段(DocumentFragment)。
#### Range.deleteContents()
从文档(Document)中移除 Range 中的内容。
#### Range.extractContents()
把 Range 的内容从文档树移动到文档片段中。
#### Range.insertNode()
在 Range 的起点处插入节点。
#### Range.surroundContents()
将 Range 的内容移动到一个新的节点中。


#### Range.compareBoundaryPoints()
比较两个 Range 的端点。
#### Range.cloneRange()
返回拥有和原 Range 相同端点的克隆 Range 对象。
#### Range.detach()
从使用状态释放 Range,此方法用于改善性能。
#### Range.toString()
把Range内容作为字符串返回。





================================================
FILE: 其它/ReactNative分享议题.md
================================================
# ReactNative分享议题

# 所属专题

前端,混合开发,App开发,React,React Native

# 演讲主题

React Native项目实战之最后一公里——增量升级解决方案(未分享过)

# 主题摘要

宝宝树在最新上线的专家答模块中,完整的应用了React Native技术体系,除了享受到React Native带来的组件化、跨平台、原生体验等红利外,还自主研发了React Native增量升级系统,达成了不发版字节级的升级模式,目前已经运行在线上环境中。
本次演讲介绍了React Native技术体系在宝宝树核心产品中的集成和使用方式;重点介绍宝宝树React Native增量升级方案,包括React Native打包工具,增量包算法,app升级策略,服务端升级api算法,升级后台,升级流程等内容。

# 听众受益

1. React Native在核心产品中的应用
2. React Native在已有app中的集成方式和发版方式
3. 宝宝树的React Native的增量更新机制和关键算法





rn简单介绍
获得到的好处和坏处
app集成方式、app瘦身、安卓首屏白屏优化等。
基础框架,性能优化办法。
增量升级
发版模式





================================================
FILE: 其它/ReactNative分享议题PPT大纲.md
================================================
# ReactNative分享议题PPT大纲

# React Native项目实战之最后一公里——增量升级解决方案

# 主题摘要

宝宝树在最新上线的专家答模块中,完整的应用了React Native技术体系,除了享受到React Native带来的组件化、跨平台、原生体验等红利外,还自主研发了React Native增量升级系统,达成了不发版字节级的升级模式,目前已经运行在线上环境中。
本次演讲介绍了React Native技术体系在宝宝树核心产品中的集成和使用方式;重点介绍宝宝树React Native增量升级方案,包括React Native打包工具,增量包算法,app升级策略,服务端升级api算法,升级后台,升级流程等内容。

现状介绍-包含目前的一些问题,为使用rn做铺垫
rn简单介绍
获得到的好处和坏处
app集成方式、app瘦身、安卓首屏白屏优化等。
基础框架,性能优化办法。
增量升级
发版模式

背景 方案 实现 成果 未来


# APP开发现状

## 原生开发现状

不能跨平台,一个逻辑两套代码,开发、测试成本都比较高;
开发效率一般,coding-》编译—》打包-》调试-》coding;
版本发布不灵活,;

总结:开发体验差,用户体验好

## H5开发现状

用户体验不如原生,优化成本较高;

总结:开发体验好,用户体验差

# 怎么办呢?【配图】

## ReactNative技术【配图】

H5的开发体验,原生的用户体验;

## 我们宝宝树怎么用的

# 







================================================
FILE: 其它/Scrollview.md
================================================

一个包装了平台的ScrollView(滚动视图)的组件,同时还集成了触摸锁定的“响应者”系统。

ScrollView和ListView/FlatList应该如何选择?ScrollView会简单粗暴地把所有子元素一次性全部渲染出来。其原理浅显易懂,使用上
Download .txt
gitextract_zekn0oua/

├── HybirdAPI/
│   ├── AudioPlayer.md
│   ├── AudioRecorder.md
│   └── index.md
├── README.md
├── ReactNative开发指导/
│   ├── CodePush.md
│   ├── ReactNative入门知识.md
│   ├── ReactNative分享.md
│   ├── ReactNative增量升级方案.md
│   ├── ReactNative安卓首屏白屏优化.md
│   ├── ReactNative导航设计与实现.md
│   ├── ReactNative开发技巧总结.md
│   ├── ReactNative打离线包-android篇.md
│   ├── ReactNative打离线包-ios篇.md
│   ├── ReactNative的ios崩溃整理分析.md
│   ├── ReactNative的架构设计.md
│   ├── ReactNative组件状态设计思考.md
│   ├── ReactNative调试菜单.md
│   ├── React的render优化框架.md
│   ├── 已有工程集成ReactNaitve-IOS.md
│   └── 淘宝d2分享-ReactNative变革无线前端.md
├── ReactNative开发规范/
│   ├── 目录与命名规范.md
│   ├── 组件、页面结构规范.md
│   └── 编码规范.md
├── ReactNative翻译/
│   ├── React Advanced Performance.md
│   ├── React PureRenderMixin.md
│   ├── React Shallow Compare.md
│   ├── ReactNative : A warning from Apple.md
│   ├── Reconciliation.md
│   ├── react-native的定时器.md
│   ├── react-native的性能.md
│   └── 导航器比较.md
├── ReactNative问题汇总/
│   ├── Immutable.js的问题.md
│   ├── ReactNative-0.14.2.md
│   ├── ReactNative-0.15.0.md
│   ├── ReactNative-0.16.0.md
│   ├── ReactNative-0.17.0.md
│   └── 总体说明.md
├── data.json
├── xmind/
│   ├── 20160125RN增量升级讨论会.xmind
│   ├── 201602Todo.xmind
│   ├── 2016规划.xmind
│   ├── RN分享议题PPT大纲.xmind
│   ├── RN安卓启动优化.xmind
│   ├── RN阶段总结-里程碑2.xmind
│   ├── react环境搭建.xmind
│   ├── web性能监控方案.xmind
│   ├── web资源缓存.xmind
│   ├── 增量升级.xmind
│   ├── 增量升级新方案.xmind
│   ├── 孕育集成能不能吃-IOS.xmind
│   ├── 已有App集成RN.xmind
│   ├── 文档编写大纲.xmind
│   └── 腾讯x5集成.xmind
├── 其它/
│   ├── 2
│   ├── Building the DOM faster: speculative parsing, async, defer and preload(part 1).md
│   ├── Building the DOM faster: speculative parsing, async, defer and preload(part 2).md
│   ├── Building the DOM faster: speculative parsing, async, defer and preload(part 3).md
│   ├── Designing Websites for iPhone X.md
│   ├── FlatList.md
│   ├── How TensorFlow Lite Brings Machine Learning to Mobile Devices.md
│   ├── PanResponder.md
│   ├── RN分享提纲.md
│   ├── Range.md
│   ├── ReactNative分享议题.md
│   ├── ReactNative分享议题PPT大纲.md
│   ├── Scrollview.md
│   ├── Selection.md
│   ├── Understanding the WebView Viewport in iOS 11 ~ 1.md
│   ├── Understanding the WebView Viewport in iOS 11 ~ 2.md
│   ├── WebAssembly(1) A cartoon intro to WebAssembly.md
│   ├── WebAssembly(2-1)A crash course in just-in-time (JIT) compilers.md
│   ├── WebAssembly(2-2)A crash course in just-in-time (JIT) compilers.md
│   ├── WebAssembly(3)A crash course in assembly.md
│   ├── WebAssembly(4-1)Creating and working with WebAssembly modules.md
│   ├── WebAssembly(4-2)Creating and working with WebAssembly modules.md
│   ├── WebAssembly(5-1)What makes WebAssembly fast?.md
│   ├── WebAssembly(5-2)What makes WebAssembly fast?.md
│   ├── WebAssembly(6-1)Where is WebAssembly now and what’s next?.md
│   ├── WebAssembly(6-2)Where is WebAssembly now and what’s next?.md
│   ├── ios11和iPhone X中Webview的适配.md
│   ├── node与shell的交互与通讯.md
│   ├── node中文件操作的简单介绍.md
│   ├── package.json中版本号的含义.md
│   ├── performance.timing.md
│   ├── rn分享5.md
│   ├── 一个类似微信群聊程序的技术方案设计过程.md
│   ├── 了解一个新概念---区块链.md
│   ├── 前端和开闭原则.md
│   ├── 前端应该掌握的一些app开发知识-android篇(1).md
│   ├── 前端应该掌握的一些app开发知识-android篇(2).md
│   ├── 前端应该掌握的一些app开发知识-ios篇(1).md
│   ├── 前端应该掌握的一些app开发知识-ios篇(2).md
│   ├── 前端监控平台.md
│   ├── 前端资源打包设计.md
│   ├── 富文本编辑器1~html转结构化数据.md
│   ├── 富文本编辑器2~复制粘贴的处理.md
│   ├── 富文本编辑器3~自定义元素.md
│   ├── 富文本编辑器4~站外图片的粘贴.md
│   ├── 富文本编辑器的命令执行.md
│   ├── 开坑机器学习?.md
│   ├── 弱特征广告方案.md
│   ├── 微信二次分享.md
│   ├── 数据结构--树型数据的处理(1).md
│   ├── 数据结构--树形数据的处理2.md
│   ├── 机器学习-入门篇(1).md
│   ├── 机器学习-入门篇(2).md
│   ├── 机器学习-入门篇(3).md
│   ├── 机器学习-入门篇(4).md
│   ├── 架构/
│   │   └── 通用组件规范.md
│   └── 模式/
│       ├── 代理模式.md
│       ├── 单例模式(1).md
│       ├── 单例模式(2).md
│       ├── 原型模式.md
│       ├── 多个工厂方法模式.md
│       ├── 建造者模式.md
│       ├── 抽象工厂模式.md
│       ├── 普通工厂模式.md
│       ├── 桥接模式.md
│       ├── 装饰器模式.md
│       ├── 门面模式.md
│       └── 静态工厂方法模式.md
└── 日常记录与计划/
    ├── 2015总结与2016畅想.md
    ├── 2016-09-13.md
    ├── todo list.md
    ├── week2015-11-23.md
    ├── week2015-11-30.md
    ├── week2015-12-07.md
    ├── week2015-12-14.md
    ├── week2016-01-04.md
    ├── 总体计划1.md
    └── 总体计划2.md
Condensed preview — 131 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (578K chars).
[
  {
    "path": "HybirdAPI/AudioPlayer.md",
    "chars": 319,
    "preview": "# AudioPlayer\n\n# 概述\n\n音频播放对象,播放本地音频。\n\n注:网络音频请使用h5的audio标签。\n\n# 常量\n\n### TYPE_SPEAKER\n### TYPE_EARPIECE\n\n# 方法\n\n### play\n### "
  },
  {
    "path": "HybirdAPI/AudioRecorder.md",
    "chars": 181,
    "preview": "# AudioRecorder\n\n# 概述\n\n调用麦克风进行录音操作\n\n# 方法\n\n### record\n\nfilePath\nsamplerate\nformat\n\n### stop\n### getFilePath\n### clear\n\n# "
  },
  {
    "path": "HybirdAPI/index.md",
    "chars": 101,
    "preview": "# HybirdAPI\n\n# 概述\n\n此系列文档是为了描述app中如何提供一套统一的原生接口,供js调用。\n\napp中webview中的js可以调用。\n\napp中reactnative模块可以调用。\n\n"
  },
  {
    "path": "README.md",
    "chars": 6262,
    "preview": "# 文章目录\n\n大家有问题欢迎留言issues讨论。\n\n### [【翻译】理解ios11中的webview viewport(第一部分)](https://github.com/cnsnake11/blog/blob/master/%E5%"
  },
  {
    "path": "ReactNative开发指导/CodePush.md",
    "chars": 1366,
    "preview": "#CodePush\n\nhttps://github.com/Microsoft/react-native-code-push\n\n#重要说明\n\n<http://microsoft.github.io/code-push/faq/index.h"
  },
  {
    "path": "ReactNative开发指导/ReactNative入门知识.md",
    "chars": 732,
    "preview": "# ReactNative入门知识\n\n本文也可以作为RN的入门知识范围,为入门RN提供了一个知识大纲。掌握这些知识帮助你快速入门RN,少走弯路。\n\n#es6\n\nlet和const\n\n箭头函数\n\n类定义\n\n解构赋值Destructuring\n"
  },
  {
    "path": "ReactNative开发指导/ReactNative分享.md",
    "chars": 3441,
    "preview": "\n# ReactNative分享提纲\n\n# 分享的目的\n\n1. 了解rn是什么,特点和使用场景\n2. 本次重点是学习架构(思想)而不是学习框架(用法)\n3. 学习组件化的思想及其好处,目标是能运用到工作中\n4. 希望随时打断进行交流讨论\n\n"
  },
  {
    "path": "ReactNative开发指导/ReactNative增量升级方案.md",
    "chars": 5924,
    "preview": "# ReactNative增量升级方案\n\n# 前言\nfacebook的react-native给我们带来了用js写出原生应用的同时,也使得使用RN编写的代码的在线升级变得可能,终于可以不通过应用市场来进行升级,极大的提升了app修bug和赋"
  },
  {
    "path": "ReactNative开发指导/ReactNative安卓首屏白屏优化.md",
    "chars": 9166,
    "preview": "# ReactNative安卓首屏白屏优化\n\n#问题描述\n公司现有app中部分模块使用reactnative开发,在实施的过程中,rn良好的兼容性,极佳的加载、动画性能,提升了我们的开发、测试效率,提升了用户体验。\n\n但是,在android"
  },
  {
    "path": "ReactNative开发指导/ReactNative导航设计与实现.md",
    "chars": 10118,
    "preview": "# ReactNative导航设计与实现\n\n# 前言\n\n关于reactnaitve的导航,官方提供了2个组件,NavigatorIOS和Navigator,其中官方并不推荐使用NavigatorIOS,它不是官方维护的,不能保证及时的更新和"
  },
  {
    "path": "ReactNative开发指导/ReactNative开发技巧总结.md",
    "chars": 684,
    "preview": "# ReactNative开发技巧总结\n\n#样式\n不支持选择器\n\n无复用就尽量用行内,避免命名难题\n\n不支持position=fixed,利用flexbox可以搞定。<https://medium.com/@Nayflix/building"
  },
  {
    "path": "ReactNative开发指导/ReactNative打离线包-android篇.md",
    "chars": 3069,
    "preview": "# ReactNative打离线包-android篇\n\n\n官方文档:<http://facebook.github.io/react-native/docs/running-on-device-android.html#content>\n\n"
  },
  {
    "path": "ReactNative开发指导/ReactNative打离线包-ios篇.md",
    "chars": 3264,
    "preview": "# ReactNative打离线包-ios篇\n\n官方文档,内容很旧:<http://facebook.github.io/react-native/docs/running-on-device-ios.html#content>\n\n相关链接"
  },
  {
    "path": "ReactNative开发指导/ReactNative的ios崩溃整理分析.md",
    "chars": 16657,
    "preview": "# ReactNative的ios崩溃整理分析\n\n共12种异常,如下:\n\n```\nwanghonglu  18:14\n>---------------------- Row   1 -----------------------<\n=> S"
  },
  {
    "path": "ReactNative开发指导/ReactNative的架构设计.md",
    "chars": 14132,
    "preview": "# ReactNative的组件架构设计\n\n还有一篇较早的文章,也是分析的过程,可以对本篇文章进行一个补全:RN组件状态设计思考:http://segmentfault.com/a/1190000004180955 \n\n请注意,本篇写的是r"
  },
  {
    "path": "ReactNative开发指导/ReactNative组件状态设计思考.md",
    "chars": 3002,
    "preview": "# ReactNative组件状态设计思考\n\n\n这篇文章写的较早,是刚接触RN的时候进行的思考总结,是一个分析的过程,您还可以参考思想更成熟一点的这篇:RN组件架构设计:http://segmentfault.com/a/119000000"
  },
  {
    "path": "ReactNative开发指导/ReactNative调试菜单.md",
    "chars": 68,
    "preview": "# ReactNative调试菜单\n\n\n加上这2个就有rn调试菜单了\n\n![](media/14773029386169.jpg)\n\n\n"
  },
  {
    "path": "ReactNative开发指导/React的render优化框架.md",
    "chars": 1834,
    "preview": "# React的render优化通用解决方案\n\n# 前言\n\n在使用react框架(无论是单独使用react还是reactnative)的过程中,性能都是我们不得不考虑的因素,虽然react使用虚拟dom比对的方式来避免了频繁且冗余的真实do"
  },
  {
    "path": "ReactNative开发指导/已有工程集成ReactNaitve-IOS.md",
    "chars": 2333,
    "preview": "# 已有工程集成ReactNative-IOS\n\n以下步骤为手动添加的方式,使用rnpm的方式请参考官方文档。\n\n本文是对官方文档的一个补充,大部分内容来源于官网文档。\n\n官方参考地址: http://facebook.github.io/"
  },
  {
    "path": "ReactNative开发指导/淘宝d2分享-ReactNative变革无线前端.md",
    "chars": 6491,
    "preview": "#ReactNative变革无线前端-淘宝d2分享\n\n![淘宝-ReactNative变革无线前端 49-1](media/%E6%B7%98%E5%AE%9D-ReactNative%E5%8F%98%E9%9D%A9%E6%97%A0%"
  },
  {
    "path": "ReactNative开发规范/目录与命名规范.md",
    "chars": 526,
    "preview": "#ReactNative目录与命名规范 \n\n##RN项目结构规划如下:\n![2015-12-22 11.47.01](media/2015-12-2211.47.01.png)\n\n\n##业务模块目录与命名规范\n\n###业务模块目录规范\n!["
  },
  {
    "path": "ReactNative开发规范/组件、页面结构规范.md",
    "chars": 2045,
    "preview": "#ReactNative组件/页面结构规范\n\n## 业务页面/组件结构规范\n\n 一个独立完整的组件\\页面一般由以下元素构成:\n \n1. root组件,1个, \n\t1. 负责初始化state\n\t2. 负责提供对外props列表\n\t2. 负责组"
  },
  {
    "path": "ReactNative开发规范/编码规范.md",
    "chars": 3436,
    "preview": "#ReactNative编码规范\n\n\n##组件引入\n\n使用import\n\n尽量用解构赋值React和BbtReact\n\n*.css.js文件的引入,直接用css命名\n\n```javascript\n// bad\nimport Footer f"
  },
  {
    "path": "ReactNative翻译/React Advanced Performance.md",
    "chars": 14517,
    "preview": "# React Advanced Performance 性能进阶\n\n英文原文地址:https://facebook.github.io/react/docs/advanced-performance.html\n\nOne of the fi"
  },
  {
    "path": "ReactNative翻译/React PureRenderMixin.md",
    "chars": 1916,
    "preview": "# React PureRenderMixin\n\n英文原文地址:https://facebook.github.io/react/docs/pure-render-mixin.html\n\nIf your React component's "
  },
  {
    "path": "ReactNative翻译/React Shallow Compare.md",
    "chars": 1641,
    "preview": "# React Shallow Compare\n\n英文原文地址:https://facebook.github.io/react/docs/shallow-compare.html\n\nshallowCompare is a helper f"
  },
  {
    "path": "ReactNative翻译/ReactNative : A warning from Apple.md",
    "chars": 7970,
    "preview": "# ReactNative : A warning from Apple\n\n2017-03-08这一天,突然听到ios的同事说,收到了苹果的警告email,说rn有可能触犯了苹果的审核规则,有可能被拒。所以,去rn的官方看,发现已经有对应的"
  },
  {
    "path": "ReactNative翻译/Reconciliation.md",
    "chars": 9089,
    "preview": "# 【翻译】Reconciliation React比对算法\n\n原文地址:https://facebook.github.io/react/docs/reconciliation.html\n\nReact provides a declara"
  },
  {
    "path": "ReactNative翻译/react-native的定时器.md",
    "chars": 1832,
    "preview": "# 定时器 Timers \n\n英文原文地址:http://facebook.github.io/react-native/docs/timers.html\n\n定时器是应用程序的重要组件,ReactNative实现了浏览器的定时器。\n\n###"
  },
  {
    "path": "ReactNative翻译/react-native的性能.md",
    "chars": 4710,
    "preview": "# react-native的性能\n\n英文原文地址: http://facebook.github.io/react-native/docs/performance.html\n\n使用react native 代替webview技术来构建ap"
  },
  {
    "path": "ReactNative翻译/导航器比较.md",
    "chars": 2463,
    "preview": "# Navigator Comparison \n\n\n英文原文地址:http://facebook.github.io/react-native/docs/navigator-comparison.html\n\n###这篇看完发现没啥可翻的,记"
  },
  {
    "path": "ReactNative问题汇总/Immutable.js的问题.md",
    "chars": 622,
    "preview": "#Immutable.js的问题\n\n\n##容易与原生对象混淆\n\n参考地址:http://zhuanlan.zhihu.com/purerender/20295971\n\n这点是我们使用 Immutable.js 过程中遇到最大的问题。写代码要"
  },
  {
    "path": "ReactNative问题汇总/ReactNative-0.14.2.md",
    "chars": 1130,
    "preview": "# ReactNative-0.14.2\n\n[toc]\n\n##如果引入一个模块,但是这个模块没有写【module.exports】,报的错误描述不对\n![](media/14486188240052.jpg)\n##定义组件不能使用class"
  },
  {
    "path": "ReactNative问题汇总/ReactNative-0.15.0.md",
    "chars": 4459,
    "preview": "# ReactNative-0.15.0\n\n[toc]\n\n\n##当图片位置发生调整,还加载原来位置\n必须关了调试服务器,重新启动调试服务器,否则还加载原来的位置,并报错。\n\n场景是把一个图剪切到新的位置。\n\n\n## 安卓,textinput"
  },
  {
    "path": "ReactNative问题汇总/ReactNative-0.16.0.md",
    "chars": 192,
    "preview": "# ReactNative-0.16.0\n\n\n## 升级后,测试服务器Whole Program Optimisations,非常慢\n在17版本里dev=true的时候不会执行了,dev=false的时候还是很慢\n\n## 升级后,ios和a"
  },
  {
    "path": "ReactNative问题汇总/ReactNative-0.17.0.md",
    "chars": 225,
    "preview": "# ReactNative-0.17.0\n\n\n#不支持export default 的写法\n\nhttps://github.com/facebook/react-native/issues/4798\n\nwe should get updat"
  },
  {
    "path": "ReactNative问题汇总/总体说明.md",
    "chars": 128,
    "preview": "# 总体说明\n\n本文档描述了在实际使用ReactNative的过程中所遇到的问题和可能的解决方案。\n\n了解这些,能帮助你在写代码之前就知道如何避开一些坑。\n\n问题按照使用的ReactNative的版本进行的分类,不保证问题已经在新版本修复了"
  },
  {
    "path": "data.json",
    "chars": 2993,
    "preview": "[\n    {\n        \"title\": \"ReactNative增量升级方案\",\n        \"url\": \"https://raw.githubusercontent.com/cnsnake11/blog/master/Re"
  },
  {
    "path": "其它/2",
    "chars": 957,
    "preview": "# 弱特征广告方案\n\n# 目标\n\n一般浏览器拦截页面内广告会使用css选择器,比如qq浏览器的规则:\n\n```\nhide=###app_mask,##.load-app,##div[class^=\"bbt-pregnant-timeline"
  },
  {
    "path": "其它/Building the DOM faster: speculative parsing, async, defer and preload(part 1).md",
    "chars": 5603,
    "preview": "# 【翻译】Building the DOM faster: speculative parsing, async, defer and preload (part 1)\n\n# 更快的dom渲染:预解析,异步,延迟和提前加载 ~ 第一部分\n"
  },
  {
    "path": "其它/Building the DOM faster: speculative parsing, async, defer and preload(part 2).md",
    "chars": 5100,
    "preview": "# 【翻译】Building the DOM faster: speculative parsing, async, defer and preload (part 2)\n\n# 更快的dom构建:预解析,异步,延迟和提前加载 ~ 第二部分\n"
  },
  {
    "path": "其它/Building the DOM faster: speculative parsing, async, defer and preload(part 3).md",
    "chars": 8360,
    "preview": "# 【翻译】Building the DOM faster: speculative parsing, async, defer and preload (part 3)\n\n# 更快的dom构建:预解析,异步,延迟和提前加载 ~ 第三部分\n"
  },
  {
    "path": "其它/Designing Websites for iPhone X.md",
    "chars": 10003,
    "preview": "# 【翻译】Designing Websites for iPhone X \n\n# 让网站适配 iphone X \n\n原文地址: https://webkit.org/blog/7929/designing-websites-for-iph"
  },
  {
    "path": "其它/FlatList.md",
    "chars": 2309,
    "preview": "高性能的简单列表组件,支持下面这些常用的功能:\n\n完全跨平台。\n支持水平布局模式。\n行组件显示或隐藏时可配置回调事件。\n支持单独的头部组件。\n支持单独的尾部组件。\n支持自定义行间分隔线。\n支持下拉刷新。\n支持上拉加载。\n支持跳转到指定行(S"
  },
  {
    "path": "其它/How TensorFlow Lite Brings Machine Learning to Mobile Devices.md",
    "chars": 5165,
    "preview": "# 【翻译】How TensorFlow Lite Brings Machine Learning to Mobile Devices\n\n# TensorFlow Lite --- 赋予移动设备机器学习的能力\n\n原文地址: http://w"
  },
  {
    "path": "其它/PanResponder.md",
    "chars": 1947,
    "preview": "# PanResponder\n\n移动设备上的手势识别要比在web上复杂得多。用户的一次触摸操作的真实意图是什么,App要经过好几个阶段才能判断。比如App需要判断用户的触摸到底是在滚动页面,还是滑动一个widget,或者只是一个单纯的点击。"
  },
  {
    "path": "其它/RN分享提纲.md",
    "chars": 1243,
    "preview": "# RN分享提纲\n\n# 目标\n\n最终目标:能够在孕育app中进行rn开发。\n\n本期目标:了解孕育中开发rn的一般过程。\n\n# 实施项目\n\n孕育中专家答和记录tab。\n\n# 环境搭建\n\n#### ios\n\nxcode+app的ios代码+js"
  },
  {
    "path": "其它/Range.md",
    "chars": 1439,
    "preview": "# Range\n\n在做富文本编辑器的开发过程中,Selection和Range对象是用来操作选中区域的办法,本篇主要介绍一下Range对象的常用接口和属性。\n\n# 介绍\n\nRange可以用 Document 对象的 createRange方"
  },
  {
    "path": "其它/ReactNative分享议题.md",
    "chars": 544,
    "preview": "# ReactNative分享议题\n\n# 所属专题\n\n前端,混合开发,App开发,React,React Native\n\n# 演讲主题\n\nReact Native项目实战之最后一公里——增量升级解决方案(未分享过)\n\n# 主题摘要\n\n宝宝树"
  },
  {
    "path": "其它/ReactNative分享议题PPT大纲.md",
    "chars": 663,
    "preview": "# ReactNative分享议题PPT大纲\n\n# React Native项目实战之最后一公里——增量升级解决方案\n\n# 主题摘要\n\n宝宝树在最新上线的专家答模块中,完整的应用了React Native技术体系,除了享受到React Na"
  },
  {
    "path": "其它/Scrollview.md",
    "chars": 1233,
    "preview": "\n一个包装了平台的ScrollView(滚动视图)的组件,同时还集成了触摸锁定的“响应者”系统。\n\nScrollView和ListView/FlatList应该如何选择?ScrollView会简单粗暴地把所有子元素一次性全部渲染出来。其原理"
  },
  {
    "path": "其它/Selection.md",
    "chars": 1248,
    "preview": "# Selection\n\n在做富文本编辑器的开发过程中,Selection和Range对象是用来操作选中区域的办法,本篇主要介绍一下Selection对象的常用接口和属性。\n\n# 介绍\n\nwindow.getSelection()可以获得S"
  },
  {
    "path": "其它/Understanding the WebView Viewport in iOS 11 ~ 1.md",
    "chars": 4558,
    "preview": "# 【翻译】Understanding the WebView Viewport in iOS 11(part 1)\n\n# 理解ios11中的webview viewport(第一部分)\n\n原文地址:http://ayogo.com/blo"
  },
  {
    "path": "其它/Understanding the WebView Viewport in iOS 11 ~ 2.md",
    "chars": 5352,
    "preview": "# 【翻译】Understanding the WebView Viewport in iOS 11(part 2)\n\n# 理解ios11中的webview viewport(第二部分)\n\n原文地址:http://ayogo.com/blo"
  },
  {
    "path": "其它/WebAssembly(1) A cartoon intro to WebAssembly.md",
    "chars": 2581,
    "preview": "# [翻译] WebAssembly(1) A cartoon intro to WebAssembly 看卡通,入门WebAssembly\n\n原文地址: https://hacks.mozilla.org/2017/02/a-cartoo"
  },
  {
    "path": "其它/WebAssembly(2-1)A crash course in just-in-time (JIT) compilers.md",
    "chars": 8559,
    "preview": "# [翻译] WebAssembly(2-1) A crash course in just-in-time (JIT) compilers JIT编译原理速成\n\n原文地址:https://hacks.mozilla.org/2017/02"
  },
  {
    "path": "其它/WebAssembly(2-2)A crash course in just-in-time (JIT) compilers.md",
    "chars": 4774,
    "preview": "# [翻译] WebAssembly(2-2) A crash course in just-in-time (JIT) compilers JIT编译原理速成\n\n原文地址:https://hacks.mozilla.org/2017/02"
  },
  {
    "path": "其它/WebAssembly(3)A crash course in assembly.md",
    "chars": 5280,
    "preview": "# [翻译] WebAssembly(3) A crash course in assembly 汇编原理速成\n\n原文地址:https://hacks.mozilla.org/2017/02/a-crash-course-in-assemb"
  },
  {
    "path": "其它/WebAssembly(4-1)Creating and working with WebAssembly modules.md",
    "chars": 5791,
    "preview": "# [翻译] WebAssembly(4-1) Creating and working with WebAssembly modules\n\n原文地址:https://hacks.mozilla.org/2017/02/creating-a"
  },
  {
    "path": "其它/WebAssembly(4-2)Creating and working with WebAssembly modules.md",
    "chars": 8282,
    "preview": "# [翻译] WebAssembly(4-2) Creating and working with WebAssembly modules\n\n原文地址:https://hacks.mozilla.org/2017/02/creating-a"
  },
  {
    "path": "其它/WebAssembly(5-1)What makes WebAssembly fast?.md",
    "chars": 5910,
    "preview": "# [翻译]WebAssembly(5-1) What makes WebAssembly fast? WebAssembly运行快速的原理\n\nIn the last article, I explained that programmin"
  },
  {
    "path": "其它/WebAssembly(5-2)What makes WebAssembly fast?.md",
    "chars": 7248,
    "preview": "# [翻译]WebAssembly(5-2) What makes WebAssembly fast? WebAssembly运行快速的原理\n\n# Compiling + optimizing 编译+优化\n\nAs I explained i"
  },
  {
    "path": "其它/WebAssembly(6-1)Where is WebAssembly now and what’s next?.md",
    "chars": 4081,
    "preview": "# [翻译]WebAssembly(6-1) Where is WebAssembly now and what’s next? WebAssembly的现在和未来\n\nOn February 28, the four major brows"
  },
  {
    "path": "其它/WebAssembly(6-2)Where is WebAssembly now and what’s next?.md",
    "chars": 5693,
    "preview": "# [翻译]WebAssembly(6-2) Where is WebAssembly now and what’s next? WebAssembly的现在和未来\n\n\n# Adding post-MVP features to the s"
  },
  {
    "path": "其它/ios11和iPhone X中Webview的适配.md",
    "chars": 284,
    "preview": "# ios11和iPhone X中Webview的适配.md\n\n原理和原因请参考:\n\nios11的webview的默认渲染页面的方式发生了变化,不再和ios7~ios10一致:\n\nios7~ios10:会将页面铺满整个屏幕,也就相当于是vi"
  },
  {
    "path": "其它/node与shell的交互与通讯.md",
    "chars": 1269,
    "preview": "#  node与shell的交互与通讯\n\nnode提供了调用shell的能力,主要是通过子进程模块来实现。\n\n示例代码:\n\n```\nconst { spawn } = require('child_process');\nconst ls ="
  },
  {
    "path": "其它/node中文件操作的简单介绍.md",
    "chars": 1658,
    "preview": "# node中文件操作的简单介绍\n\n通过 require('fs') 使用文件系统模块。 所有的方法都有异步和同步的形式。\n\n异步方法的最后一个参数都是一个回调函数。 传给回调函数的参数取决于具体方法,但回调函数的第一个参数都会保留给异常。"
  },
  {
    "path": "其它/package.json中版本号的含义.md",
    "chars": 742,
    "preview": "# package.json中版本号的含义\n\n\n参考地址:https://docs.npmjs.com/files/package.json#dependencies\n\n\n```\nversion Must match version exa"
  },
  {
    "path": "其它/performance.timing.md",
    "chars": 3030,
    "preview": "# performance.timing\n\n#### PerformanceTiming.navigationStart 只读\n是一个无符号long long 型的毫秒数,表征了从同一个浏览器上下文的上一个文档卸载(unload)结束时的U"
  },
  {
    "path": "其它/rn分享5.md",
    "chars": 5088,
    "preview": "# RN分享5\n\n# 目录结构\n\n![](media/15064850344896.jpg)\n\nbbt-react-native:基础技术框架。存放业务无关的可复用的组件、接口等。\n\nbbt-rn-bundle-repository:包仓库"
  },
  {
    "path": "其它/一个类似微信群聊程序的技术方案设计过程.md",
    "chars": 1795,
    "preview": "# 一个类似微信群聊程序的技术方案设计过程\n\n本次项目的技术方案抉择很有趣也很具有典型性,印证了没有最好的技术,只有最适合的技术,所以在此进行记录。\n\n# 项目背景\n\n公司新立的一个项目,项目还处于保密阶段,他的具体背景在这不太方便说,简单"
  },
  {
    "path": "其它/了解一个新概念---区块链.md",
    "chars": 1606,
    "preview": "# 了解一个新概念---区块链\n\n### 前言\n\n大家都知道,比特币在2017年底疯涨,最高突破过2w美金,目前也在1w3美金。\n\n区块链就是比特币的底层技术。\n\n但区块链可以应用到更多的领域中去,不仅仅是在虚拟货币的领域中,有很多人也把区"
  },
  {
    "path": "其它/前端和开闭原则.md",
    "chars": 4413,
    "preview": "# 前端和开闭原则\n\n# 前言\n\n在前端工作日趋复杂的今天,需要有良好的设计思想来指导我们进行程序设计,使我们开发出的系统结构优美,更稳定,更易维护,更易扩展,让我们有更多喝喝茶看看书陪陪家人的时间。\n\n# 什么是开闭原则\n\n## 开闭原则"
  },
  {
    "path": "其它/前端应该掌握的一些app开发知识-android篇(1).md",
    "chars": 1847,
    "preview": "# 前端应该掌握的一些app开发知识-android篇(1).md\n\n移动端混合开发是各大公司非常常见的开发模式,作为前端能了解一些原生开发的基础知识,对程序设计,问题分析都会有很大的益处。\n\n此系列文章对android原生app开发的一些"
  },
  {
    "path": "其它/前端应该掌握的一些app开发知识-android篇(2).md",
    "chars": 2409,
    "preview": "# 前端应该掌握的一些app开发知识-android篇(2).md\n\n接前篇,本次主要整理一下前端应了解的android的一些重要的概念。\n\n# ide\n\n目前几个主流java的ide都支持android的开发,但是目前最主流的,也是官方推"
  },
  {
    "path": "其它/前端应该掌握的一些app开发知识-ios篇(1).md",
    "chars": 2106,
    "preview": "# 前端应该掌握的一些app开发知识-ios篇(1)\n\n移动端混合开发是各大公司非常常见的开发模式,作为前端能了解一些原生开发的基础知识,对程序设计,问题分析都会有很大的益处。\n\n此系列文章对ios原生app开发的一些基础知识做出了归纳和总"
  },
  {
    "path": "其它/前端应该掌握的一些app开发知识-ios篇(2).md",
    "chars": 1754,
    "preview": "# 前端应该掌握的一些app开发知识-ios篇(2)\n\n移动端混合开发是各大公司非常常见的开发模式,作为前端能了解一些原生开发的基础知识,对程序设计,问题分析都会有很大的益处。\n\n此系列文章对ios原生app开发的一些基础知识做出了归纳和总"
  },
  {
    "path": "其它/前端监控平台.md",
    "chars": 74,
    "preview": "# 前端监控平台\n\n# 背景-为什么需要它\n\n# 目标-要实现什么功能,达到什么要求\n\n# 实现思路-根据具体目标,逐个描述\n\n# 架构设计\n\n\n\n"
  },
  {
    "path": "其它/前端资源打包设计.md",
    "chars": 425,
    "preview": "# 前端资源打包设计\n\n# 前言\n\n一般我们现在开发web应用都会做模块化开发,上线一个web应用前,都会把前端资源进行打包,也就是合并压缩编译等工作,那么打包的输出结构是如何进行设计的,为什么要这么设计。\n\n最近的面试工作中和很多的面试者"
  },
  {
    "path": "其它/富文本编辑器1~html转结构化数据.md",
    "chars": 6584,
    "preview": "# 富文本编辑器1~html转结构化数据\n\n# 行业背景\n\n在目前的互联网环境下,能源源不断产生优质的内容的平台,一定会受到用户的喜爱。\n\n那么如何能让作者们快速产生优质的内容是内容平台一个不可或缺的功能。\n\n一般来说,会使用一个叫富文本编"
  },
  {
    "path": "其它/富文本编辑器2~复制粘贴的处理.md",
    "chars": 2395,
    "preview": "# 富文本编辑器2~复制粘贴的处理\n\n# 业务场景分析\n\n在编辑文章的过程中,复制粘贴是一个很常见的场景,一般会有2种情况。\n\n#### 1 站外复制\n\n用户的文章已经写好,并保存在第三方平台,比如微信公众平台、头条编辑平台、word中等。"
  },
  {
    "path": "其它/富文本编辑器3~自定义元素.md",
    "chars": 3474,
    "preview": "# 富文本编辑器3~自定义元素\n\n# 业务场景\n\n编写文章的过程中需要插入一些特殊的元素。\n\n比如,商品:\n\n![](media/15078008076304.jpg)\n\n比如,音频:\n\n![](media/15078008240143.j"
  },
  {
    "path": "其它/富文本编辑器4~站外图片的粘贴.md",
    "chars": 3537,
    "preview": "# 富文本编辑器4~站外图片的粘贴\n\n# 业务场景分析\n\n在第二篇文章中,介绍过如何进行站外内容的复制粘贴,当时将html元素都转换为带段落的文字,并且将图片等其它标签直接去掉了。\n\n这样做,对用户的使用并不友好,用户想把站外的文章连文字一"
  },
  {
    "path": "其它/富文本编辑器的命令执行.md",
    "chars": 1097,
    "preview": "# 富文本编辑器的命令执行\n\n当一个HTML文档切换到设计模式(designMode)时,文档对象暴露 execCommand方法,该方法允许运行命令来操纵可编辑区域的内容。大多数命令影响文档的选择(粗体,斜体等),而其他命令插入新元素(添"
  },
  {
    "path": "其它/开坑机器学习?.md",
    "chars": 459,
    "preview": "# 开坑机器学习?\n\n# 来由\n\n如果你关注了前一阵的柯杰大战阿尔法狗,你就会知道,人工智能阿尔法狗3比0完胜了人类最强柯杰,并且阿尔法狗被各围棋八段九段誉为神一样的对手。\n\n在围棋领域,人工智能的水平已经远远超出人类的最高水平。\n\n最近几"
  },
  {
    "path": "其它/弱特征广告方案.md",
    "chars": 2465,
    "preview": "# 弱特征广告方案\n\n# 前言\n\n本文参考了以下两篇文章,如有雷同,也是必然。\n\nhttp://testudy.cc/tech/2016/11/29/ad.html\n\nhttp://testudy.cc/tech/2016/12/01/ad"
  },
  {
    "path": "其它/微信二次分享.md",
    "chars": 1450,
    "preview": "# 微信二次分享遇到的一些坑\n\n# 什么是微信二次分享\n\n微信二次分享指的是,当从app中调用微信sdk分享一篇文章之后,这个分享会在微信中按照固定的格式进行显示,比如下面这样:\n\n![](media/15084912795540.jpg)"
  },
  {
    "path": "其它/数据结构--树型数据的处理(1).md",
    "chars": 2175,
    "preview": "# 数据结构--树形数据的处理(1)\n\n# 定义\n\n以下定义摘自互联网。\n\n在计算机科学中,树是非常有用的抽象概念。我们形象的去描述一棵树,一个家族的老祖可能有两个儿子,这两个儿子一个有一个儿子,一个有三个儿子,像这样发展下去的一个族谱,就"
  },
  {
    "path": "其它/数据结构--树形数据的处理2.md",
    "chars": 4311,
    "preview": "# 数据结构--树形数据的处理(2)\n\n# 前文提要\n\n假如有这样一组树形数据:\n\n```\n{\n    treeData: [\n        {id: 1, parentId: 0, title: 地球},\n        {id: 2,"
  },
  {
    "path": "其它/机器学习-入门篇(1).md",
    "chars": 1795,
    "preview": "# 机器学习-入门篇(1)\n\n# 我们的世界正在发生着巨大的改变\n\n我们的世界正在发生着巨大的改变,伴随着海量数据的积累和计算机计算能力的不断增强,人工智能领域发展迅速,正在逐渐的改变着我们的生活,原来科幻小说和机器猫里的桥段已经和正在变为"
  },
  {
    "path": "其它/机器学习-入门篇(2).md",
    "chars": 1255,
    "preview": "# 机器学习-入门篇(2)\n\n在我们更深入之前要先了解一些机器学习的基本概念。\n\n机器学习算法分为两大类:监督学习和无监督学习。\n\n# 监督学习\n\n延续我们第一篇文章中估计房价的例子,假设你是一名房产中介,生意越做越大,因此你雇了一批实习生"
  },
  {
    "path": "其它/机器学习-入门篇(3).md",
    "chars": 1606,
    "preview": "# 机器学习-入门篇(3)\n\n\n让我们继续第一篇文章里房价评估的例子。\n\n#### 先按正常方式写个程序\n\n如果按照我们正常的逻辑可能会这么写我们的房价评估程序:\n\n```\nfunction 房价评估程序(卧室数量, 面积, 位置, 楼层)"
  },
  {
    "path": "其它/机器学习-入门篇(4).md",
    "chars": 1395,
    "preview": "# 机器学习-入门篇(4)\n\n书接上回,如何能快速的找到一组优秀的权重值呢。\n\n首先,写出一个简单的等式表示前述步骤2:\n\n这是你的代价函数:\n\n![](media/14981234076616.jpg)\n\n接着,让我们将这同一个等式用机器"
  },
  {
    "path": "其它/架构/通用组件规范.md",
    "chars": 3900,
    "preview": "\n# 目标\n\n本文档主要描述出,封装通用组件的全过程和一些建议和原则。\n\n# 定义\n\n1. 通用组件:不依赖任何第三方库的组件。本文档中的组件,都指的是通用组件。\n2. 通用view组件:不依赖任何第三方库的且含有视图(html和css)的"
  },
  {
    "path": "其它/模式/代理模式.md",
    "chars": 1470,
    "preview": "# 代理模式\n\n代理模式就是多一个代理类出来,替原对象进行一些操作,比如我们在租房子的时候回去找中介,为什么呢?因为你对该地区房屋的信息掌握的不够全面,希望找一个更熟悉的人去帮你做,此处的代理就是这个意思。再如我们有的时候打官司,我们需要请"
  },
  {
    "path": "其它/模式/单例模式(1).md",
    "chars": 1685,
    "preview": "# 单例模式(1)\n\n单例对象(Singleton)是一种常用的设计模式。在Java应用中,单例对象能保证在一个JVM中,该对象只有一个实例存在。这样的模式有几个好处:\n\n1. 某些类创建比较频繁,对于一些大型的对象,这是一笔很大的系统开销"
  },
  {
    "path": "其它/模式/单例模式(2).md",
    "chars": 2647,
    "preview": "# 单例模式(2)\n\n上一篇文章中最后的写法似乎解决了之前提到的问题,将synchronized关键字加在了内部,也就是说当调用的时候是不需要加锁的,只有在instance为null,并创建对象的时候才需要加锁,性能有一定的提升。但是,这样"
  },
  {
    "path": "其它/模式/原型模式.md",
    "chars": 2286,
    "preview": "# 原型模式\n\n原型模式虽然是创建型的模式,但是与工程模式没有关系,从名字即可看出,该模式的思想就是将一个对象作为原型,对其进行复制、克隆,产生一个和原对象类似的新对象。在Java中,复制对象是通过clone()实现的,先创建一个原型类:\n"
  },
  {
    "path": "其它/模式/多个工厂方法模式.md",
    "chars": 663,
    "preview": "# 多个工厂方法模式\n\n多个工厂方法模式,是对普通工厂方法模式的改进,在普通工厂方法模式中,如果传递的字符串出错,则不能正确创建对象,而多个工厂方法模式是提供多个工厂方法,分别创建对象。关系图:\n\n![](media/15223782818"
  },
  {
    "path": "其它/模式/建造者模式.md",
    "chars": 986,
    "preview": "# 建造者模式\n\n\n工厂类模式提供的是创建单个类的模式,而建造者模式则是将各种产品集中起来进行管理,用来创建复合对象,所谓复合对象就是指某个类具有不同的属性,其实建造者模式就是前面抽象工厂模式和最后的Test结合起来得到的。我们看一下代码:"
  },
  {
    "path": "其它/模式/抽象工厂模式.md",
    "chars": 1482,
    "preview": "# 抽象工厂模式\n\n工厂方法模式有一个问题就是,类的创建依赖工厂类,也就是说,如果想要拓展程序,必须对工厂类进行修改,这违背了闭包原则,所以,从设计角度考虑,有一定的问题,如何解决?就用到抽象工厂模式,创建多个工厂类,这样一旦需要增加新的功"
  },
  {
    "path": "其它/模式/普通工厂模式.md",
    "chars": 2261,
    "preview": "# 普通工厂模式\n\n普通工厂模式是最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。\n\n在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。\n\n意图:"
  },
  {
    "path": "其它/模式/桥接模式.md",
    "chars": 1988,
    "preview": "# 桥接模式\n\n桥接模式就是把事物和其具体实现分开,使他们可以各自独立的变化。桥接的用意是:将抽象化与实现化解耦,使得二者可以独立变化,像我们常用的JDBC桥DriverManager一样,JDBC进行连接数据库的时候,在各个数据库之间进行"
  },
  {
    "path": "其它/模式/装饰器模式.md",
    "chars": 1288,
    "preview": "# 装饰器模式\n\n顾名思义,装饰模式就是给一个对象增加一些新的功能,而且是动态的,要求装饰对象和被装饰对象实现同一个接口,装饰对象持有被装饰对象的实例,关系图如下:\n\n![](media/15272464307619.jpg)\n\n\nSour"
  },
  {
    "path": "其它/模式/门面模式.md",
    "chars": 2372,
    "preview": "# 门面模式\n\n门面模式是为了解决类与类之家的依赖关系的,像spring一样,可以将类和类之间的关系配置到配置文件中,而门面模式就是将他们的关系放在一个Facade类中,降低了类类之间的耦合度,该模式中没有涉及到接口,看下类图:(我们以一个"
  },
  {
    "path": "其它/模式/静态工厂方法模式.md",
    "chars": 690,
    "preview": "# 静态工厂方法模式\n\n将上面的多个工厂方法模式里的方法置为静态的,不需要创建实例,直接调用即可。\n\n```\n\n\t1.\tpublic class SendFactory {  \n\t2.\t      \n\t3.\t    public stati"
  },
  {
    "path": "日常记录与计划/2015总结与2016畅想.md",
    "chars": 2963,
    "preview": "# 2015总结与2016畅想\n\n#2015总结\n\n我是11月9号加入宝宝树FE团队的,在这2个月的时间里认识了很多新朋友,也逐渐的适应了新的环境。目前主要负责跟进react-native在宝宝树产品中的实施和推广工作,使用了react-n"
  },
  {
    "path": "日常记录与计划/2016-09-13.md",
    "chars": 353,
    "preview": "# 混合开发技术体系支撑计划\n\n# 愿景目标(现状问题)\n\n当前孕育app的dau已经是500W+,目前公司的期望是dau再突破一个新的数量级。\n\t\n# 解决思路\n\n主要从2个方面来解决,1是留存,2是新增。\n\n## 留存\n\n留存,是最重要"
  },
  {
    "path": "日常记录与计划/todo list.md",
    "chars": 1458,
    "preview": "# todo list\n1. 相对路径的图片,是否是从服务器下载的,如何做到下载一次就就不用下载了,脱离服务器 ok\n\t2. 应该是相对这个生成的js的某个文件夹会存,和js一起打包到app中即可,待验证\n2. 高宽未知的图片的应用方案。 "
  },
  {
    "path": "日常记录与计划/week2015-11-23.md",
    "chars": 1211,
    "preview": "# week 2015-12-23\n##本周的工作思路是用开发实际应用继续加深理解RN。\n\n###20151125周三\n1. 将代码提交到了github上\n2. 首页中今日特卖和即将上线的功能开发\n\t1.\t对同一个listview,动态切换"
  },
  {
    "path": "日常记录与计划/week2015-11-30.md",
    "chars": 1722,
    "preview": "# week 2015-11-30\n\n##本周的工作主题\n### 通用组件的封装,包括但不限于\n1. 后台分页listview\n2. 通用导航组件\n3. 基础样式组,比如隐藏等\n4. tab页组件\n5. 提示框组件\n6. loading组件"
  },
  {
    "path": "日常记录与计划/week2015-12-07.md",
    "chars": 1438,
    "preview": "#### week 2015-12-07\n\n##本周的工作主题\n### 继续 通用组件的封装,这周应完成组件的第一轮开发工作,至少列出的要开发完,包括但不限于:\n1. 后台分页listview -ok\n2. 通用导航组件\n3. 基础样式组,"
  },
  {
    "path": "日常记录与计划/week2015-12-14.md",
    "chars": 182,
    "preview": "#### week 2015-12-14\n\n##本周的工作主题\n### 整理重构一切成果,包括文档编写,代码重构。原则上不启动新的开发工作。\n### 本周要发布出BbtRN的1.0版本。重点是标准和规范。\n### 遗留的难点问题和todol"
  },
  {
    "path": "日常记录与计划/week2016-01-04.md",
    "chars": 170,
    "preview": "# 2016-01-04\n\n本周基本计划,从以下任务中按顺序尽量执行。\n\n1. 集成RN到app中-ios版本\n\t2. 集成方案验证\n\t3. 与native交互接口验证\n2. 集成RN到app中-安卓版本\n\t2. gradle深入学习\n2."
  },
  {
    "path": "日常记录与计划/总体计划1.md",
    "chars": 1301,
    "preview": "# RN总体计划\n\t1. 相关地址\n\t\ta. 文档发布地址:https://github.com/cnsnake11/blog\n\t\tb. 工程地址:https://github.com/cnsnake11/AwesomeProject\n\t\t"
  },
  {
    "path": "日常记录与计划/总体计划2.md",
    "chars": 392,
    "preview": "#总体计划2\n\n1. 里程碑3\n\t2. 内容\n\t\t1. 工程化 \n\t\t\t2. 能不能吃集成到现有app \n\t\t\t3. 打包-离线模式\n\t\t\t4. 自动化打包\n\t\t\t4. 增量升级\n\t\t1. 基于native开发自定义组件、API层\n\t\t1."
  }
]

// ... and 15 more files (download for full content)

About this extraction

This page contains the full source code of the cnsnake11/blog GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 131 files (23.0 MB), approximately 144.2k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!