react reactnative 绝对定位怎么定位警告

6355人阅读
Android开发(148)
Android高手进阶(68)
iOS开发之旅(30)
React Native(32)
本文出自系列文章。
在做React Native开发时,少不了的需要对React Native程序进行调试。调试程序是每一位开发者的基本功,高效的调试不仅能提高开发效率,也能降低Bug率。本文将向大家分享React Native程序调试的一些技巧和心得。
Developer Menu
Developer Menu是React Native给开发者定制的一个开发者菜单,来帮助开发者调试React Native应用。
提示:生产环境release (production) 下Developer Menu是不可用的。
如何开启Developer Menu
在模拟器上开启Developer Menu
Android模拟器:
可以通过Command? + M快捷键来快速打开Developer Menu。也可以通过模拟器上的菜单键来打开。
心得:高版本的模拟器通常没有菜单键的,不过Nexus S上是有菜单键的,如果想使用菜单键,可以创建一个Nexus S的模拟器。
iOS模拟器:
可以通过Command? + D快捷键来快速打开Developer Menu。
在真机上开启Developer Menu:
在真机上你可以通过摇动手机来开启Developer Menu。
Reloading JavaScript
在只是修改了js代码的情况下,如果要预览修改结果,你不需要重新编译你的应用。在这种情况下,你只需要告诉React Native重新加载js即可。
提示:如果你修改了native 代码或修改了Images.xcassets、res/drawable中的文件,重新加载js是不行的,这时你需要重新编译你的项目了。
Reload js即将你项目中js代码部分重新生成bundle,然后传输给模拟器或手机。
在Developer Menu中有Reload选项,单击Reload让React Native重新加载js。对于iOS模拟器你也可以通过Command? + R快捷键来加载js,对于Android模拟器可以通过双击r键来加载js。
提示:如果Command? + R无法使你的iOS模拟器加载js,则可以通过选中Hardware menu中Keyboard选项下的 “Connect Hardware Keyboard” 。
小技巧:Automatic reloading
Enable Live Reload
React Native旨在为开发者带来一个更好的开发体验。如果你觉得上文的加载js代码方式太low了或者不够方便,那么有没有一种更简便加载js代码的方式呢?
答案是肯定的。
在 Developer Menu中你会看到”Enable Live Reload” 选项,该选项提供了React Native动态加载的功能。当你的js代码发生变化后,React Native会自动生成bundle然后传输到模拟器或手机上,是不是觉得很方便。
Hot Reloading
另外,Developer Menu中还有一项需要特别介绍的,就是”Hot Reloading”热加载,如果说Enable Live Reload解放了你的双手的话,那么Hot Reloading不但解放了你的双手而且还解放了你的时间。
当你每次保存代码时Hot Reloading功能便会生成此次修改代码的增量包,然后传输到手机或模拟器上以实现热加载。相比 Enable Live Reload需要每次都返回到启动页面,Enable Live Reload则会在保持你的程序状态的情况下,就可以将最新的代码部署到设备上,听起来是不是很疯狂呢。
提示:当你做布局的时候启动Enable Live Reload功能你就可以实时的预览布局效果了,这可以和用AndroidStudio或AutoLayout做布局的实时预览相媲美。
Errors and Warnings
在development模式下,js部分的Errors 和 Warnings会直接打印在手机或模拟器屏幕上,以红屏和黄屏展示。
React Native程序运行时出现的Errors会被直接显示在屏幕上,以红色的背景显示,并会打印出错误信息。
你也可以通过console.error()来手动触发Errors。
React Native程序运行时出现的Warnings也会被直接显示在屏幕上,以黄色的背景显示,并会打印出警告信息。
你也可以通过console.warn()来手动触发Warnings。
你也可以通过console.disableYellowBox = true来手动禁用Warnings的显示,或者通过console.ignoredYellowBox = ['Warning: ...'];来忽略相应的Warning。
提示:在生产环境release (production)下Errors和Warnings功能是不可用的。
Chrome Developer Tools
Chrome 开发工具
谷歌 Chrome 开发工具,是基于谷歌浏览器内含的一套网页制作和调试工具。开发者工具允许网页开发者深入浏览器和网页应用程序的内部。该工具可以有效地追踪布局问题,设置 JavaScript 断点并可深入理解代码的最优化策略。
Chrome 开发工具一共提供了8大组工具:
Element 面板: 用于查看和编辑当前页面中的 HTML 和 CSS 元素。
Network 面板:用于查看 HTTP 请求的详细信息,如请求头、响应头及返回内容等。
Source 面板:用于查看和调试当前页面所加载的脚本的源文件。
TimeLine 面板: 用于查看脚本的执行时间、页面元素渲染时间等信息。
Profiles 面板:用于查看 CPU 执行时间与内存占用等信息。
Resource 面板:用于查看当前页面所请求的资源文件,如 HTML,CSS 样式文件等。
Audits 面板:用于优化前端页面,加速网页加载速度等。
Console 面板:用于显示脚本中所输出的调试信息,或运行测试脚本等。
提示:对于调试React Native应用来说,Sources和Console是使用频率很高的两个工具。
你可以像调试JavaScript代码一样来调试你的React Native程序。
如何通过 Chrome调试React Native程序
你可以通过以下步骤来调试你的React Native程序:
第一步:启动远程调试
在Developer Menu下单击”Debug JS Remotely” 启动JS远程调试功能。此时Chrome会被打开,同时会创建一个“.” Tab页。
第二步:打开Chrome开发者工具
在该“.”Tab页下打开开发者工具。打开Chrome菜单-&选择更多工具-&选择开发者工具。你也可以通过快捷键(Command? + Option? + I on Mac, Ctrl + Shift + I on Windows)打开开发者工具。
打开Chrome开发着工具之后你会看到如下界面:
打开”RCTWebSocketExecutor.m “文件,将“localhost”改为你的电脑的ip,然后在Developer Menu下单击”Debug JS Remotely” 启动JS远程调试功能。
在Android上
在Android5.0以上设备上,将手机通过usb连接到你的电脑,然后通过adb命令行工具运行如下命令来设置端口转发。
adb reverse tcp:8081 tcp:8081
你也可以通过在“Developer Menu”下的“Dev Settings”中设置你的电脑ip来进行调试。
心得:在使用真机调试时,你需要确保你的手机和电脑处在同一个网段内,即它们实在同一个路由器下。
巧用Sources面板
Sources 面板提供了调试 JavaScript 代码的功能。它提供了图形化的V8 调试器。
Sources 面板可以让你看到你所要检查的页面的所有脚本代码,并在面板选择栏下方提供了一组标准控件,提供了暂停,恢复,步进等功能。在窗口的最下方的按钮可以在遇到异常(exception)时强制暂停。源码显示在单独的标签页,通过点击
打开文件导航面板,导航栏中会显示所有已打开的脚本文件。
心得:Chrome开发着工具中的Sources面板几乎是我最常用的功能面板。通常只要是开发遇到了js报错或者其他代码问题,在审视一遍自己的代码而一无所获之后,我首先就会打开Sources进行js断点调试。
执行控工具
从上图可以看到“执行控工具”按钮在侧板顶部,让你可以按步执行代码,当你进行调试的时候这几个按钮非常有用:
继续(Continue): 继续执行代码直到遇到下一个断点。
单步执行(Step over): 步进代码以查看每一行代码对变量作出的操作,当代码调用另一个函数时不会进入这个函数,使你可以专注于当前的函数。
跳入(Step into): 与 Step over 类似,但是当代码调用函数时,调试器会进去这个函数并跳转到函数的第一行。
跳出(Step out): 当你进入一个函数后,你可以点击 Step out 执行函数余下的代码并跳出该函数。
断点切换(Toggle breakpoints): 控制断点的开启和关闭,同时保持断点完好。
查看js文件
如果你想在开发者工具上预览你的js文件,可以在打开Sources tab下的debuggerWorker.js选项卡,该选项卡下会显示当前调试项目的所有js文件。
断点其实很简单
断点(Breakpoint) 是在脚本中设置好的暂停处。在DevTools中使用断点可以调试JavaScript代码,DOM更新和 network calls。
心得:你可以像使用Xcode/AndroidStudio调试Native应用一样,来使用Chrome开发者工具通过断点对程序进行调试。
添加和移除断点
在 Sources 面板的文件导航面板中打开一个JavaScript文件来调试,点击边栏(line gutter) 为当前行设置一个断点,已经设置的断点处会有一个蓝色的标签,单击蓝色标签,断点即被移除。
心得:右键点击蓝色标签会打开一个菜单,菜单包含以下选项:执行到此(Continue to Here),黑盒脚本(Blackbox scripts),移除断点(Remove Breakpoint), 编辑断点(Edit Breakpoint),和 禁用断点(Disable Breakpoint)。在这里你可以对断点进行更高级的定制化的操作。
上文讲到右键点击蓝色标签会打开一个菜单,下面就介绍一下该菜单下的高级操作。
执行到此(Continue to Here):
如果你想让程序立即跳到某一行时,这个功能会帮到你。如果在该行之前还有别的断点,程序会依次经过前面的断点。另外需要提出的是这个功能在任意一行代码的边栏(gutter line)前单击右键都会看到。
黑盒脚本(Blackbox scripts):
黑盒脚本会从你的调用堆栈中隐藏第三方代码。
编辑断点(Edit Breakpoint):
通过该功能你可以创建一个条件断点,你也可以在边栏(gutter line) 右键并选择添加条件断点(Add Conditional Breakpoint) 。在输入框中,输入一个可解析为真或假的表达式。仅当条件为真时,执行会在此暂停。
心得:如果你想让程序在某处从来都不要暂停,可以编辑一个条件永远为false的条件断点。另外,你也可以在该行代码的边栏(gutter line)前单击右键选择“Never pause here”即可,你会发现“Never pause here”其实就是在该行代码上设了一个永远为false的条件断点。
管理你的断点
你可以通过Chrome开发者工具的右边面板来统一管理你的断点。
心得:你可以通过断点前的复选框来启用和禁用断点,也可以单击右键来进行更多的操作(如:移除断点,移除所有断点,启用禁用断点等)。
有一种断点叫全局断点
全局断点的作用是,当程序出现异常时,会在异常的地方暂停,这对快速定位异的常位置很方便。
做iOS开发的同学都知道在Xcode中可以设置全局断点,其实在Chrome 开发者工具中也同样有与之对应的功能,叫“Pause On Caught Exceptions”。如果勾选上此功能,则即使所发生运行时异常的代码在 try/catch 范围内,Chrome 开发者工具也能够在错误代码处停住。
不要忽略控制台
DevTools 控制台(Console) 可以让你在目前已暂停的状态下进行试验。按 Esc 键打开/关闭控制台。
心得:你可以在控制台(Console)上打印变量,执行脚本等操作。在开发调试中非常有用。
本文出自系列文章。
了解更多,可以
[Reac Native布局详细指南]( Native布局/React Native布局详细指南/React Native布局详细指南.md)
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:821962次
积分:10900
积分:10900
排名:第1551名
原创:177篇
评论:205条
文章:33篇
阅读:103591
文章:12篇
阅读:63892
文章:25篇
阅读:124587
文章:25篇
阅读:202069
(3)(1)(1)(1)(2)(1)(4)(1)(5)(11)(7)(5)(1)(3)(2)(1)(2)(2)(3)(2)(1)(1)(4)(7)(6)(2)(5)(16)(17)(33)(27)(1)(1)(4)深入浅出 React Native:使用 JavaScript 构建原生应用 - 知乎专栏
{"debug":false,"apiRoot":"","paySDK":"/api/js","wechatConfigAPI":"/api/wechat/jssdkconfig","name":"production","instance":"column","tokens":{"X-XSRF-TOKEN":null,"X-UDID":null,"Authorization":"oauth c3cef7c66aa9e6a1e3160e20"}}
{"database":{"Post":{"":{"contributes":[{"sourceColumn":{"lastUpdated":,"description":"关注前端前沿技术,探寻业界深邃思想。https://qianduan.group 欢迎微信/微博搜索『前端外刊评论』,关注我们。欢迎给本专栏投稿,原作译作不限,要求:质量高!如果愿意尝试从事前端技术相关的书籍的编写或翻译工作,请私信外刊君。","permission":"COLUMN_PUBLIC","memberId":3313,"contributePermission":"COLUMN_PUBLIC","translatedCommentPermission":"all","canManage":true,"intro":"关注前端技术,探寻深邃思想,https://qianduan.group","urlToken":"FrontendMagazine","id":699,"imagePath":"bd21f286e6aa5e210b60e2e257ce890b.jpeg","slug":"FrontendMagazine","applyReason":"","name":"前端外刊评论","title":"前端外刊评论","url":"/FrontendMagazine","commentPermission":"COLUMN_ALL_CAN_COMMENT","canPost":true,"created":,"state":"COLUMN_NORMAL","followers":40934,"avatar":{"id":"bd21f286e6aa5e210b60e2e257ce890b","template":"/{id}_{size}.jpeg"},"activateAuthorRequested":false,"following":false,"imageUrl":"/bd21f286e6aa5e210b60e2e257ce890b_l.jpeg","articlesCount":176},"state":"accepted","targetPost":{"titleImage":"/c5a1ff5b78ec226ce5edd_r.jpg","lastUpdated":,"imagePath":"c5a1ff5b78ec226ce5edd","permission":"ARTICLE_PUBLIC","topics":[],"summary":"本篇为联合翻译,译者:,,,,感谢帮忙校对的 数月前,,这个框架允许你使用 JavaScript 开发原生的 iOS 应用——就在今天,释出了!基于
使用 Java…","copyPermission":"ARTICLE_COPYABLE","translatedCommentPermission":"all","likes":0,"origAuthorId":65549,"publishedTime":"T19:23:29+08:00","sourceUrl":"","urlToken":,"id":179524,"withContent":false,"slug":,"bigTitleImage":false,"title":"深入浅出 React Native:使用 JavaScript 构建原生应用","url":"/p/","commentPermission":"ARTICLE_ALL_CAN_COMMENT","snapshotUrl":"","created":,"comments":0,"columnId":699,"content":"","parentId":0,"state":"ARTICLE_PUBLISHED","imageUrl":"/c5a1ff5b78ec226ce5edd_r.jpg","author":{"bio":"常常感谢很少赞同","isFollowing":false,"hash":"dfafc151f61985dab7f885c","uid":96,"isOrg":false,"slug":"kmokidd","isFollowed":false,"description":"头像是挚爱的画手 | 依然尚无才华 | CSS/LESS 的问题还是可以稍微解答一下 JS 渣渣哦","name":"kmokidd","profileUrl":"/people/kmokidd","avatar":{"id":"6f3d8cb2d2baf8be1f84e8cdf53a7050","template":"/{id}_{size}.png"},"isOrgWhiteList":false},"memberId":65549,"excerptTitle":"","voteType":"ARTICLE_VOTE_CLEAR"},"id":266438}],"title":"深入浅出 React Native:使用 JavaScript 构建原生应用","author":"kmokidd","content":"本篇为联合翻译,译者:,,,,感谢帮忙校对的数月前,,这个框架允许你使用 JavaScript 开发原生的 iOS 应用——就在今天,释出了!基于
使用 JavaScript 和 HTML5 开发 iOS 应用已经有好几年了,那 React Native 有什么牛的?React Native 真的很牛,让大家兴奋异常的主要原因有两点:可以基于 React Native使用 JavaScript 编写应用逻辑,UI 则可以保持全是原生的。这样的话就没有必要就 HTML5 的 UI 做出常见的妥协;React 引入了一种与众不同的、略显激进但具备高可用性的方案来构建用户界面。长话短说,应用的 UI 简单通过一个基于应用目前状态的函数来表达。React Native 的关键就是,以把
编程模式的能力带到移动开发来作为主要目标。它的目标不是跨平台一次编写到处执行,而是一次学习跨平台开发。这个是一个非常大的区别。这篇教程只介绍 iOS 平台,不过你一旦掌握了相关的概念,就可以应用到 Android 平台,快速构建 Android 应用。如果之前只用过 Objective-C 或者 Swift 写应用的话,你很可能不会对使用 JavaScript 来编写应用的愿景感到兴奋。尽管如此,作为一个 Swift 开发者来说,上面提到的第二点应该可以激起你的兴趣!你通过 Swift,毫无疑问学习到了新的更多有效的编码方法和技巧,鼓励转换和不变性。然而,构建 UI 的方式还是和使用 Objective-C 的方式一致。仍然以 UIKit 为基础,独断专横。通过像 virtual DOM 和 reconciliation 这些有趣的概念,React 将函数式编程直接带到了 UI 层。这篇教程将带着你一路构建一个 UK 房产搜索应用:如果你之前一点 JavaScript 都没写过,别担心。这篇教程带着你进行一步一步进行编码。React 使用 CSS 属性来定义样式,一般比较容易读也比较容易理解。但是如果你想了解更多的话,可以去看看 ,很不错的。想要学习更多,继续往下读!准备工作React Native 框架。你可以通过两种方式获取到它:使用 git 克隆仓库,或者下载一个 zip 压缩包文件。如果你的机器上已经安装了 React Native,在着手编码前还有其他几个因素需要考虑。React Native 借助 ,即 JavaScript 运行时来创建 JavaScript 代码。如果你已经安装了 Node.js,那就可以上手了。首先,使用 Homebrew 官网提供的指引,然后在终端执行以下命令:brew install node\n接下来,使用 homebrew 安装 ,一个来自Facebook 的观察程序:brew install watchman\n通过配置 watchman,React 实现了在代码发生变化时,完成相关的重建的功能。就像在使用 Xcode 时,每次保存文件都会进行一次创建。 接下来使用 `npm` 安装 React Native CLI 工具:npm install -g react-native-cli\n 这使用 Node 包管理器抓取 CLI 工具,并且全局安装;`npm` 在功能上与 CocoaPods 或者 Carthage 类似。\n浏览到你想要创建 React Native 应用的文件夹下,使用 CLI 工具构建项目:react-native init PropertyFinder\n 现在,已经创建了一个初始项目,包含了创建和运行一个 React Native 应用所需的一切。 如果仔细观察了创建的文件夹和文件,你会发现一个 node_modules 文件夹,包含了 React Native 框架。你也会发现一个 index.ios.js 文件,这是 CLI 工具创建的一个空壳应用。最后,会出现一个 Xcode 项目文件和一个 iOS 文件夹,包含了少量的代码用来引入 bootstrap 到你的项目中。 打开 Xcode 项目文件,然后创建并运行。模拟器将会启动并且展示下面的问候语:\n你可以能发现,有一个终端窗口弹出,输出了下面的信息:$ npm start\n\n& react-native@0.1.0 start /Users/colineberhardt/Projects/react-native\n& ./packager/packager.sh\n\n ===============================================================\n |
Running packager on port 8081.
Keep this packager running while developing on any JS
projects. Feel free to close this tab and run your own
packager instance if you prefer.
https:///facebook/react-native
\n ===============================================================\n\n\n
React packager ready.\n\n这就是 React Native 包,在 node 下运行。一会儿你就会知道它是用来干什么的。不要关闭终端窗口;就然它在后台运行。如果你不小心关了,只需要停下来使用 Xcode 重新运行项目。注意:在进入编码工作之前,还有最后一件事 —— 在这个教程中,你需要编写大量的 JavaScript 代码,Xcode 并非是最好的工具!我使用 ,一个价格合理且应用广泛的编辑器。不过,, 或者其他轻量的编辑器都能胜任这份工作。React Native 你好在开始“搜房App”之前,先来个简单的 Hello World App 热热身。在这一节里,你将会使用到一些组件。在你钟爱的编辑其中打开 index.ios.js,删除当前的内容,因为你要从头构建你自己的应用。然后在文件顶部增加下面这样一行::'use strict';\n这行代码是用于开启 Strict Mode,Strict mode的错误处理可以有所提高,JavaScript的一些语言缺陷也可以避免。简而言之就是,JavaScript在这种模式下工作地更好!注意:想要研究一下 Strict Mode 的朋友,我会推荐你阅读 然后,加上这一行:var React = require('react-native');\n这句代码是将 react-native 模块加载进来,并将它赋值给变量 React 的。React Native 使用同 Node.js 相同的模块加载方式:require,这个概念可以等同于 Swift 中的“链接库”或者“导入库”。注意:想要了解更多关于 JavaScript 模块的知识,我推荐阅读。在 require 语句的下面,加上这一段:var styles = React.StyleSheet.create({\n
color: 'black',\n
backgroundColor: 'white',\n
fontSize: 30,\n
margin: 80\n
}\n});\n以上代码定义了一段应用在 “Hello World” 文本上的样式。如果你曾接触过Web开发,那你很可能已经发现了:React Native 使用的是
来定义应用界面的样式。现在我们来关注应用本身吧!依然是在相同的文件下,将以下代码添加到样式代码的下面:class PropertyFinderApp extends React.Component {\n
render() {\n
return React.createElement(React.Text, {style: styles.text}, \"Hello World!\");\n
}\n}\n是的,奏是 JavaScript class!类 (class) 是在ES6中被引入的,纵然JavaScript一直在进步,但Web开发者受困于兼容浏览器的状况中,不能怎么使用JS的新特性。React Native运行在JavaScriptCore中是,也就是说,你可以使用JS的新特性啦,完全不用担心兼容什么的呢。注意:如果你是一名 Web 开发者,我百分百鼓励你要使用现代的JavaScript,然后使用像
这样的工具生成兼容性的 JavaScript,用于支持兼容性不好的老浏览器。PropertyFinderApp 继承了 ponent(React UI的基础模块)。组件包含着不可变的属性,可变的状态变量以及暴露给渲染用的方法。这会你做的应用比较简单,只用一个渲染方法就可以啦。React Native 组件并不是 UIKit 类,它们只能说是在某种程度上等同。框架只是将 React 组件树转化成为原生的UI。最后一步啦,将这一行加在文件末尾:React.AppRegistry.registerComponent('PropertyFinder', function() { return PropertyFinderApp });\nAppRegistry 定义了App的入口,并提供了根组件。保存 PropertyFinderApp.js,回到Xcode中。确保 PropertyFinder 规划(scheme)已经勾选了,并设置了相应的 iPhone 模拟器,然后生成并运行你的项目。几秒之后,你应该就可以看到 “Hello World” 应用正在运行了:这个JavaScript应用运行在模拟器上,使用的是原生UI,没有任何内嵌的浏览器哦!这个JavaScript应用运行在模拟器上,使用的是原生UI,没有任何内嵌的浏览器哦!还不相信这是真的?:] 那打开你的 Xcode,选择 Debug\\View Debugging\\Capture View Hierarchy,你看 native view hierarchy 中都没有 UIWebView,就只有一个原生的view!:]你一定很好奇其中的原理吧,那就在 Xcode 中打开 AppDelegate.m,接着找到 application:didFinishLaunchingWithOptions:这个方法构建了 RCTRootView 用于加载 JavaScript 应用以及渲染最后的视图的。当应用开始运行的时候,RCTRootView将会从以下的URL中加载应用:http://localhost:8081/index.ios.bundle\n重新调用了你在运行这个App时打开的终端窗口,它开启了一个 packager 和 server 来处理上面的请求。在 Safari 中打开那个 URL;你将会看到这个 App 的 JavaScript 代码。你也可以在 React Native 框架中找到你的 “Hello World” 代码。当你的App开始运行了以后,这段代码将会被加载进来,然后 JavaScriptCore 框架将会执行它。在 Hello World 的例子里,它将会加载 PropertyFinderApp 组件,然后构建出原生的 UIKit 视图。关于这部分的内容,后文里会再详细解释的。你好 JSX 的世界你当前的应用程序会使用 React.createElement 来构建应用 UI ,React会将其转换到原生环境中。在当前情况下,你的JavaScript代码是完全可读的,但一个更复杂的 UI 与嵌套的元素将迅速使代码变成一大坨。 确保应用程序仍在运行,然后回到你的文本编辑器中,编辑 PropertyFinderApp.js 。修改组件 render 方法的返回语句如下:return &React.Text style={styles.text}&Hello World (Again)&/React.Text&;\n这是 JSX ,或 JavaScript 语法扩展,它直接在你的 JavaScript 代码中混合了类似 HTML 的语法;如果你是一个 web 开发人员,应该对此不陌生。在本篇文章中你将一直使用 JSX 。把你的改动保存到 PropertyFinderApp.js 中,并返回到模拟器。按下 Cmd + R ,你将看到你的应用程序刷新,并显示更新的消息 “Hello World(again)”。重新运行一个 React Native 应用程序像刷新 web 浏览器一样简单!:]因为你会使用相同的一系列 JavaScript 文件,您可以让应用程序一直运行,只在更改和保存 PropertyFinderApp.js 后刷新即可注意:如果你感到好奇,可以看看你的“包”在浏览器中,JSX被转换成什么。这个 “Hello World” 已经够大家玩耍了,是时候构建实际的应用程序了!添加导航我们的房产查找应用使用标准的栈式导航,基于 UIKit 的 navigation controller。现在正是添加的时候。在 index.ios.js 文件中,把 PropertyFinderApp 重命名为HelloWorld:class HelloWorld extends React.Component {\n“Hello World” 这几个字你还需要让它显示一会儿,但它不再是应用的根组件了。接下来,在 HelloWorld 这个组件下面添加如下这个类:class PropertyFinderApp extends React.Component {\n
render() {\n
return (\n
&React.NavigatorIOS\n
style={styles.container}\n
initialRoute={{\n
title: 'Property Finder',\n
component: HelloWorld,\n
}\n}\n构造一个 navigation controller,应用一个样式,并把初始路由设为 Hello World 组件。在 Web 开发中,路由就是一种定义应用导航的一种技术,即定义页面——或者说是路由——与 URL 的对应关系。在同一个文件中,更新样式定义,包含如下 container 的样式:var styles = React.StyleSheet.create({\n
color: 'black',\n
backgroundColor: 'white',\n
fontSize: 30,\n
margin: 80\n
container: {\n
}\n});\n在随后的教程中会告诉你 flex: 1 是什么意思。回到模拟器,Cmd+R,看看新 UI 的样子:这就是包含了 root view 的 navigation controller,目前 root view 就是 “Hello World”。很棒——应用已经有了基础的导航结构,到添加这就是包含了 root view 的 navigation controller,目前 root view 就是 “Hello World”。很棒——应用已经有了基础的导航结构,到添加真实 UI 的时候了。创建搜索页在项目中添加一个新文件,命名为 SearchPage.js,然后将其放在PropertyFinderApp.js 所在目录下。在文件中添加下面代码:'use strict';\n\nvar React = require('react-native');\nvar {\n
StyleSheet,\n
TextInput,\n
TouchableHighlight,\n
ActivityIndicatorIOS,\n
Component\n} = React;\n你会注意到,位于引入 react-native 所在位置的前面有一个严格模式标识,紧接着的声明语句是新知识。这是一种解构赋值,准许你获取对象的多个属性并且使用一条语句将它们赋给多个变量。结果是,后面的代码中可以省略掉 React 前缀;比如,你可以直接引用 StyleSheet ,而不再需要 React.StyleSheet。解构同样适用于操作数组,。继续在 SearchPage.js 文件中添加下面的样式:var styles = StyleSheet.create({\n
description: {\n
marginBottom: 20,\n
fontSize: 18,\n
textAlign: 'center',\n
color: '#656565'\n
container: {\n
padding: 30,\n
marginTop: 65,\n
alignItems: 'center'\n
}\n});\n同样,以上都是标准的 CSS 属性。和 Interface Builder 相比,这样设置样式缺少了可视化,但是比起在 viewDidLoad() 中逐个设置视图属性的做法更友好!只需要把组件添加到样式声明的前面:class SearchPage extends Component {\n
render() {\n
return (\n
&View style={styles.container}&\n
&Text style={styles.description}&\n
Search for houses to buy!\n
&Text style={styles.description}&\n
Search by place-name, postcode or search near your location.\n
}\n}\nrender 很好地展示出 JSX 以及它表示的结构。通过这个样式,你可以轻易地描绘出组件 UI 的结构:一个容器,包含两个 text 标签。最后,将下面的代码添加到文件末尾:module.exports = SearchPage;\n这可以 export SearchPage 类,方便在其他文件中使用它。下一步是更新应用的路由,以初始化路由。打开 PropertyFinderApp.js,在文件顶部紧接着上一个 require 语句的位置添加下面代码:var SearchPage = require('./SearchPage');\n在 PropertyFinderApp 类的 render 函数内部,通过更新 initialRoute 来引用最新添加的页面,如下:component: SearchPage\n此时,如果你愿意则可以移除 HelloWorld 类以及与它相关联的样式。你不在需要那段代码了。切换到模拟器,按下 Cmd+R 查看新的 UI:使用 Flexbox 定义外观使用 Flexbox 定义外观现在,你已经看到了用基本的 CSS 属性来控制外间距(margin),内间距(padding)还有颜色(color)。不过,可能你还不太了解要如何使用伸缩盒(flexbox),flexbox 是最近新加入 CSS 规范,用它就能很便利地布局界面。React Native 用 (这是一个用 JavaScript 实现flexbox标准然后编译成 C(iOS平台)或者Java(Android平台)的库)。Facebook把这个项目单独出来实在太正确了,这样可以编译成多种语言,促进更多新颖的应用的发展,比如。在你的App中,容器(container)默认地是纵向布局,也就是说在它的子元素将会竖直地排列,像这样: 这被称为主轴 (main axis),它的方向可以是竖直的也可以是水平的。这被称为主轴 (main axis),它的方向可以是竖直的也可以是水平的。每一个子元素在竖直方向上的位置是由它的margin,height和padding共同决定的。容器的 alignItems 属性也要设置成 center,这个属性可以控制子元素在十字轴上的位置。在这里,它实现了居中对齐的文本。好啦,现在我们把输入框和按钮加上去吧。打开 SearchPage.js,将下面的代码插入第二个 Text 元素的后面:&View style={styles.flowRight}&\n
&TextInput\n
style={styles.searchInput}\n
placeholder='Search via name or postcode'/&\n
&TouchableHighlight style={styles.button}\n
underlayColor='#99d9f4'&\n
&Text style={styles.buttonText}&Go&/Text&\n
&/TouchableHighlight&\n&/View&\n&TouchableHighlight style={styles.button}\n
underlayColor='#99d9f4'&\n
&Text style={styles.buttonText}&Location&/Text&\n&/TouchableHighlight&\n现在你已经加上了两个最高等级的视图(top-level view),一个视图包含了文本输入框和一个按钮,还有一个视图内只有一个按钮。在后文中你会看到,它们的样式是什么样的。接着,添加上对应的样式:flowRight: {\n
flexDirection: 'row',\n
alignItems: 'center',\n
alignSelf: 'stretch'\n},\nbuttonText: {\n
fontSize: 18,\n
color: 'white',\n
alignSelf: 'center'\n},\nbutton: {\n
height: 36,\n
flex: 1,\n
flexDirection: 'row',\n
backgroundColor: '#48BBEC',\n
borderColor: '#48BBEC',\n
borderWidth: 1,\n
borderRadius: 8,\n
marginBottom: 10,\n
alignSelf: 'stretch',\n
justifyContent: 'center'\n},\nsearchInput: {\n
height: 36,\n
padding: 4,\n
marginRight: 5,\n
flex: 4,\n
fontSize: 18,\n
borderWidth: 1,\n
borderColor: '#48BBEC',\n
borderRadius: 8,\n
color: '#48BBEC'\n}\n要注意格式问题:每一个样式都是用逗号分隔开的,所以别忘了在container 选择器后面还要加上一个逗号。以上的样式将会应用在你刚刚加上的输入框和按钮上。现在返回到模拟器,然后按下 Cmd+R 刷新界面: 文本区域和 ’Go’ 按钮在同一行,不需要显式地定义两个组件的宽度,你只需要将它们放在同一个容器中,加上 flexDirection:'row' 样式,再定义好它们的 flex 值。文本区域是 flex:4,按钮则是 flex:1,这说明两者的宽度比是4:1。文本区域和 ’Go’ 按钮在同一行,不需要显式地定义两个组件的宽度,你只需要将它们放在同一个容器中,加上 flexDirection:'row' 样式,再定义好它们的 flex 值。文本区域是 flex:4,按钮则是 flex:1,这说明两者的宽度比是4:1。大概你也发现了,你的“按钮”其实并不是按钮!:] 使用了 UIKit 后,按钮更倾向于是可以轻碰(tap)的标签(label),所以 React Native 团队决定直接在 JavaScript 中构建按钮了。所以你在 App 中使用的按钮是 TouchableHighlight,这是一个 React Native 组件,当轻碰 TouchableHighlight 时,它会变得透明从而显示出衬底的颜色(也就是按钮下层的组件颜色)。搜索界面的最后一步就是加上一张图片.你可以从并解压。在Xcode中打开Images.xcassets文件,点击加号添加一个新的图片集。然后将图片素材拖进正确的“区间”: 你需要重启应用才能让图片生效。将以下代码添加到 TouchableHighlight 组件后面,它将用于“获取位置”按钮:&Image source={require('image!house')} style={styles.image}/&\n现在再样式表的最后加上图片对应的样式,别忘了给原样式中最后一个加上逗号哦:image: {\n
width: 217,\n
height: 138\n}\nrequire('image!house') 语句用于确定在你应用的asset目录下的图片资源,在 Xcode 中,如果你的打开了 Images.xcassets,你会看到一个“房屋”的图标,正是上面代码中引用到的。返回到模拟器,Cmd+R刷新UI: 注意:如果你这会没有看到“房屋”图片,取而代之的是一张“找不到资源”的图片,尝试重启packager(也就是在终端里输入 npm start 命令)。现在你的应用看起来挺不错的啦,不过它还少了点功能。接下来你的任务就是给它加上点状态,让它执行一些操作。添加组件状态每个 React 组件都带有一个key-value存储的状态对象,你必须在组件渲染之前设置其初始状态。在 SearchPage.js 中,我们对 SearchPage 类中,render方法前添加以下的代码。constructor(props) {\n
super(props);\n
this.state = {\n
searchString: 'london'\n
};\n}\n现在你的组件拥有一个状态变量:searchString ,且初始值被设置为 london 。这时候你需要利用起组件中的状态了。在render方法中,用以下的代码替换TextInput元素中的内容:&TextInput\n
style={styles.searchInput}\n
value={this.state.searchString}\n
placeholder='Search via name or postcode'/&\n这一步设置了 TextInput 组件 value 属性的值,这个值用于把状态变量 searchString 的当前值作为展示给用户的文字。我们已经考虑初始值的设定了,但如果用户编辑这里的文字会发生什么呢?第一步需要建立一个方法来处理事件。在 SearchPage 类中添加以下的代码:onSearchTextChanged(event) {\n
console.log('onSearchTextChanged');\n
this.setState({ searchString: event.nativeEvent.text });\n
console.log(this.state.searchString);\n}\n上面的代码从 events 中取出了 text 属性的值,并用于更新组件的状态。这里面也添加了一些有用的调试代码。当文字改变时,需要让这个方法被调用,调用后的文字会通过 render 函数返回到组件中。因此我们需要在标签上添加一个 onChange 属性,添加后的标签如下所示:&TextInput\n
style={styles.searchInput}\n
value={this.state.searchString}\n
onChange={this.onSearchTextChanged.bind(this)}\n
placeholder='Search via name or postcode'/&\n当用户更改文本时,会调用 onChange 上 的函数;在本例中,则是 onSearchTextChanged 。注意:你估计会对 bind(this) 语句有疑问。在 JavaScript 中,this 这个关键字有点不同于大多数其他语言;在 Swift 表示 “自身”。在这种情况中,bind 可以确保在 onSearchTextChanged 方法中, this 可以作为组件实例的引用。有关更多信息,请参见页面。在你再次刷新你的应用程序之前,还有一个步骤:在 return 前添加以下语句,打印一条日志来记录 render() 函数的调用: console.log('SearchPage.render');\n你会从这些日志语句中学到一些很有趣的东西!:]回到你的模拟器,然后按Cmd + R。您现在应该看到文本输入的初始值为 “london” ,编辑一下文本,从而在 Xcode 控制台中产生一些日志: 注意看上面的截图,日志打印的顺序看起来有些奇怪:第一次调用 render() 函数用于设置视图。当文本变化时, onSearchTextChanged 函数被调用。之后,通过更新组件的状态来反映输入了新的文本,这会触发另一次 render 。 onSearchTextChanged() 函数也会被调用,会将改变的字符串打印出来。每当应用程序更新任何 React 组件,将会触发整个UI层的重新绘制,这会调用你所有组件的 render 方法。这是一个好主意,因为这样做把组件的渲染逻辑,从状态变化影响UI这一过程中完全解耦出来。与其他大多数 UI 框架所不同的是,你既不需要在状态改变的时候去手动更新 UI ,或使用某种类型的绑定框架,来创建某种应用程序状态和它的 UI 表现的关联;例如,我的文章中讲的,。在 React 中,你不再需要担心 UI 的哪些部分可能受到状态变化的影响;你的整个应用程序的 UI,都可以简单地表示为一个函数的状态。此时,你可能已经发现了这一概念中一个根本性的缺陷。是的,非常准确——性能!你肯定不能在 UI 变化时,完全抛弃掉整个 UI 然后重新绘制吧 ?这就是 React 高明的地方了。每当 UI 渲染出来后,render 方法会返回一颗视图渲染树,并与当前的 UIKit 视图进行比较。这个称之为 reconciliation 的过程的输出是一个简单的更新列表, React 会将这个列表应用到当前视图。这意味着,只有实际改变了的部分才会重新绘制。这个令人拍案叫绝的崭新概念让ReactJS变得独特——virtual-DOM(文档对象模型,一个web文档的视图树)和 reconciliation 这些概念——被应用于iOS应用程序。稍后你可以整理下思路,之后,在刚才的应用中你仍然有一些工作要做。日志代码增加了代码的繁琐性,已经不需要了,所以删除掉日志代码。初始化搜索功能为了实现搜索功能,你需要处理 “Go” 按钮的点击事件,调用对应的 API,并提供一个视觉效果,告诉用户正在做查询。在 SearchPage.js 中,在构造函数中把初始状态更新成:this.state = {\n
searchString: 'london',\n
isLoading: false\n};\n新的 isLoading 属性将会记录是否有请求正在处理的状态。在 render 开始的添加如下逻辑:var spinner = this.state.isLoading ?\n
( &ActivityIndicatorIOS\n
hidden='true'\n
size='large'/& ) :\n
( &View/&);\n这是一个三元操作符,与 if 语句类似,即根据组件 isLoading 的状态,要么添加一个 indicator,要么添加一个空的 view。因为整个组件会不停地更新,所以你自由地混合 JSX 和 JavaSript 代码。回到用 JSX 定义搜索界面的地方,在图片的下面添加:{spinner}\n给渲染“Go”的 TouchableHighlight 标记添加如下的属性:onPress={this.onSearchPressed.bind(this)}\n接下来,添加下面这两个方法到 SearchPage 类中:_executeQuery(query) {\n
console.log(query);\n
this.setState({ isLoading: true });\n}\n\nonSearchPressed() {\n
var query = urlForQueryAndPage('place_name', this.state.searchString, 1);\n
this._executeQuery(query);\n}\n_executeQuery() 之后会进行真实的查询,现在的话就是简单输出一条信息到控制台,并且把 isLoading 设置为对应的值,这样 UI 就可以显示新的状态了。提示:JavaScript 的类并没有访问修饰符,因此没有 “私有” 的该奶奶。因此常常会发现开发者使用一个下划线作为方法的前缀,来说明这些方法是私有方法。当 “Go” 按钮被点击时,onSearchPressed() 将会被调用,开始查询。最后,添加下面这个工具函数在定义 SearchPage 类的上面:function urlForQueryAndPage(key, value, pageNumber) {\n
var data = {\n
country: 'uk',\n
pretty: '1',\n
encoding: 'json',\n
listing_type: 'buy',\n
action: 'search_listings',\n
page: pageNumber\n
data[key] = value;\n\n
var querystring = Object.keys(data)\n
.map(key =& key + '=' + encodeURIComponent(data[key]))\n
.join('&');\n\n
return 'http://api.nestoria.co.uk/api?' + querystring;\n};\n这个函数并不依赖 SearchPage,因此被定义成了一个独立的函数,而不是类方法。他首先通过 data 来定义查询字符串所需要的参数,接着将 data 转换成需要的字符串格式,name=value 对,使用 & 符号分割。语法 =& 是一个箭头函数,又一个,提供了这个便捷的语法来创建一个匿名函数。回到模拟器,Cmd+R,重新加载应用,点击 “Go” 按钮。你可以看到 activity indicator 显示出来,再看看 Xcode 的控制台:activity indicator 渲染了,并且作为请求的 URL 出现在输出中。把 URL 拷贝到浏览器中访问看看得到的结果。你会看到大量的 JSON 对象。别担心——你不需要理解它们,之后会使用代码来解析之。提示:应用使用了 。API 返回的 JSON 数据非常的直白。但是你也可以看看文档了解更多细节,请求什么 URL 地址,以及返回数据的格式。下一步就是从应用中发出请求。执行 API 请求还是 SearchPage.js 文件中,更新构造器中的初始 state 添加一个message 变量:this.state = {\n
searchString: 'london',\n
isLoading: false,\n
message: ''\n};\n在 render 内部,将下面的代码添加到 UI 的底部:&Text style={styles.description}&{this.state.message}&/Text&\n你需要使用这个为用户展示多种信息。在 SearchPage 类内部,将以下代码添加到 _executeQuery() 底部:fetch(query)\n
.then(response =& response.json())\n
.then(json =& this._handleResponse(json.response))\n
.catch(error =& \n
this.setState({\n
isLoading: false,\n
message: 'Something bad happened ' + error\n
}));\n这里使用了 fetch 函数,它是 。和 XMLHttpRequest 相比,它提供了更加先进的 API。异步响应会返回,成功的话会转化 JSON 并且为它提供了一个你将要添加的方法。最后一步是将下面的函数添加到 SearchPage:_handleResponse(response) {\n
this.setState({ isLoading: false , message: '' });\n
if (response.application_response_code.substr(0, 1) === '1') {\n
console.log('Properties found: ' + response.listings.length);\n
} else {\n
this.setState({ message: 'Loc please try again.'});\n
}\n}\n如果查询成功,这个方法会清除掉正在加载标识并且记录下查询到属性的个数。注意:Nestoria 有具备潜在的用途。比如,202 和 200 会返回最佳位置列表。当你创建完一个应用,为什么不处理一下这些,可以为用户呈现一个可选列表。保存项目,然后在模拟器中按下 Cmd+R,尝试搜索 ‘london’;你会在日志信息中看到 20 properties were found。然后随便尝试搜索一个不存在的位置,比如 ‘narnia’,你会得到下面的问候语。 是时候看一下这20个房屋所对应的真实的地方,比如伦敦!是时候看一下这20个房屋所对应的真实的地方,比如伦敦!结果显示创建一个新的文件,命名为 SearchResults.js,然后加上下面这段代码:'use strict';\n\nvar React = require('react-native');\nvar {\n
StyleSheet,\n
TouchableHighlight,\n
ListView,\n
Component\n} = React;\n你肯定注意到啦,这里用到了 require 语句将 react-native 模块引入其中,还有一个重构赋值语句。接着就是加入搜索结果的组件:class SearchResults extends Component {\n\n
constructor(props) {\n
super(props);\n
var dataSource = new ListView.DataSource(\n
{rowHasChanged: (r1, r2) =& r1.guid !== r2.guid});\n
this.state = {\n
dataSource: dataSource.cloneWithRows(this.props.listings)\n
renderRow(rowData, sectionID, rowID) {\n
return (\n
&TouchableHighlight\n
underlayColor='#dddddd'&\n
&Text&{rowData.title}&/Text&\n
&/TouchableHighlight&\n
render() {\n
return (\n
&ListView\n
dataSource={this.state.dataSource}\n
renderRow={this.renderRow.bind(this)}/&\n
}\n\n}\n上述的代码里用到了一个特定的组件 – ListView – 它能将数据一行行地呈现出来,并放置在一个可滚动的容器内,和 UITableView 很相似。通过 ListView.DataSource 将 ListView 的数据引入,还有一个函数来显示每一行UI。在构建数据源的同时,你还需要一个函数用来比较每两行之间是否重复。 为了确认列表数据的变化,在 reconciliation 过程中ListView 就会使用到这个函数。在这个实例中,由 Nestoria API 返回的房屋数据都有一个guid 属性,它就是用来测试数据变化的。现在将模块导出的代码添加至文件末尾:module.exports = SearchResults;\n将下面这段代码加到 SearchPage.js 较前的位置,不过要在 require 语句的后面哦:var SearchResults = require('./SearchResults');\n这样我们就能在 SearchPage 类中使用刚刚加上的 SearchResults 类。还要把 _handleResponse 方法中的 console.log 语句改成下面这样:this.props.navigator.push({\n
title: 'Results',\n
component: SearchResults,\n
passProps: {listings: response.listings}\n});\nSearchResults 组件通过上面的代码传入列表里。在这里用的是 push方法确保搜索结果全部推进导航栈中,这样你就可以通过 ‘Back’ 按钮返回到根页面。回到模拟器,按下 Cmd+R 刷新页面,然后试试看我们的搜索。估计你会得到类似下面这样的结果:耶!你的搜索实现了呢,不过这搜索结果页面的颜值也太低了,不要担心,接下来给它化化妆。可点击样式这些 React Native 的原生代码现在应该理解起来轻车熟路了,所以本教程将会加快速度。在 SearchResults.js 中,destructuring 声明后面添加以下语句来定义样式:var styles = StyleSheet.create({\n
thumb: {\n
width: 80,\n
height: 80,\n
marginRight: 10\n
textContainer: {\n
separator: {\n
height: 1,\n
backgroundColor: '#dddddd'\n
price: {\n
fontSize: 25,\n
fontWeight: 'bold',\n
color: '#48BBEC'\n
title: {\n
fontSize: 20,\n
color: '#656565'\n
rowContainer: {\n
flexDirection: 'row',\n
padding: 10\n
}\n});\n这些定义了每一行的样式。接下来修改 renderRow() 如下:renderRow(rowData, sectionID, rowID) {\n
var price = rowData.price_formatted.split(' ')[0];\n\n
return (\n
&TouchableHighlight onPress={() =& this.rowPressed(rowData.guid)}\n
underlayColor='#dddddd'&\n
&View style={styles.rowContainer}&\n
&Image style={styles.thumb} source={{ uri: rowData.img_url }} /&\n
style={styles.textContainer}&\n
&Text style={styles.price}&?{price}&/Text&\n
&Text style={styles.title} \n
numberOfLines={1}&{rowData.title}&/Text&\n
&View style={styles.separator}/&\n
&/TouchableHighlight&\n
);\n}\n这个操作修改了返回的价格,将已经格式了化的”300000 GBP”中的GBP后缀删除。然后它通过你已经很熟悉的技术来渲染每一行的 UI 。这一次,通过一个 URL 来提供缩略图的数据, React Native 负责在主线程之外解码这些数据。同时要注意 TouchableHighlight 组件中 onPress属性后使用的箭头函数;它用于捕获每一行的 guid。最后一步,给类添加一个方法来处理按下操作:rowPressed(propertyGuid) {\n
var property = this.props.listings.filter(prop =& prop.guid === propertyGuid)[0];\n}\n该方法通过用户触发的属性来定位。目前该方法没有做任何事,你可以稍后处理。现在,是时候欣赏你的大作了。回到模拟器,按下 Cmd + R 查看结果:看起来好多了——尽管你会怀疑是否任何人都能承受住在伦敦的代价!是时候向应用程序添加最后一个视图了。房产详情视图添加一个新的文件 PropertyView.js 到项目中,在文件的顶部添加如下代码:'use strict';\n\nvar React = require('react-native');\nvar {\n
StyleSheet,\n
Component\n} = React;\n信手拈来了吧!接着添加如下样式:var styles = StyleSheet.create({\n
container: {\n
marginTop: 65\n
heading: {\n
backgroundColor: '#F8F8F8',\n
separator: {\n
height: 1,\n
backgroundColor: '#DDDDDD'\n
image: {\n
width: 400,\n
height: 300\n
price: {\n
fontSize: 25,\n
fontWeight: 'bold',\n
margin: 5,\n
color: '#48BBEC'\n
title: {\n
fontSize: 20,\n
margin: 5,\n
color: '#656565'\n
description: {\n
fontSize: 18,\n
margin: 5,\n
color: '#656565'\n
}\n});\n然后加上组件本身:class PropertyView extends Component {\n\n
render() {\n
var property = this.props.property;\n
var stats = property.bedroom_number + ' bed ' + property.property_type;\n
if (property.bathroom_number) {\n
stats += ', ' + property.bathroom_number + ' ' + (property.bathroom_number & 1\n
? 'bathrooms' : 'bathroom');\n
var price = property.price_formatted.split(' ')[0];\n\n
return (\n
&View style={styles.container}&\n
&Image style={styles.image} \n
source={{uri: property.img_url}} /&\n
&View style={styles.heading}&\n
&Text style={styles.price}&?{price}&/Text&\n
&Text style={styles.title}&{property.title}&/Text&\n
&View style={styles.separator}/&\n
&Text style={styles.description}&{stats}&/Text&\n
&Text style={styles.description}&{property.summary}&/Text&\n
}\n}\nrender() 前面部分对数据进行了处理,与通常的情况一样,API 返回的数据良莠不齐,往往有些字段是缺失的。这段代码通过一些简单的逻辑,让数据更加地规整一些。render 剩余的部分就非常直接了。它就是一个简单的这个状态不可变状态的函数。最后在文件的末尾加上如下的 export:module.exports = PropertyV\n返回到 SearchResults.js 文件,在顶部,require React 的下面,添加一个新的 require 语句。var PropertyView = require('./PropertyView');\n接下来更新 rowPassed(),添加跳转到新加入的 PropertyView:rowPressed(propertyGuid) {\n
var property = this.props.listings.filter(prop =& prop.guid === propertyGuid)[0];\n\n
this.props.navigator.push({\n
title: \"Property\",\n
component: PropertyView,\n
passProps: {property: property}\n
});\n}\n你知道的:回到模拟器,Cmd + R,一路通过搜索点击一行到房产详情界面:物廉价美——看上去很不错哦!物廉价美——看上去很不错哦!应用即将完成,最后一步是允许用户搜索附近的房产。地理位置搜索在 Xcode 中,打开 Info.plist 添加一个新的 key,在编辑器内部单击鼠标右键并且选择 Add Row。使用NSLocationWhenInUseUsageDescription 作为 key 名并且使用下面的值:PropertyFinder would like to use your location to find nearby properties\n下面是当你添加了新的 key 后,所得到的属性列表:你将把这个关键的细节提示呈现给用户,方便他们请求访问当前位置。打开 SearchPage.js,找到用于渲染 Location 按钮的TouchableHighlight,然后为其添加下面的属性值:onPress={this.onLocationPressed.bind(this)}\n当你用手指轻点这个按钮,会调用 onLocationPressed —— 接下来会定义这个方法。将下面的代码添加到 SearchPage 类中:onLocationPressed() {\n
navigator.geolocation.getCurrentPosition(\n
location =& {\n
var search = location.coords.latitude + ',' + location.coords.longitude;\n
this.setState({ searchString: search });\n
var query = urlForQueryAndPage('centre_point', search, 1);\n
this._executeQuery(query);\n
error =& {\n
this.setState({\n
message: 'There was a problem with obtaining your location: ' + error\n
});\n}\n通过 navigator.geolocation 检索当前位置;这是一个 接口,所以对于每个在浏览器中使用 location 服务的用户来说这个接口都应该是一致的。React Native 框架借助原生的 iOS location 服务提供了自身的 API 实现。如果当前位置很容易获取到,你将调用第一个箭头函数;这会向Nestoria 发送一个 query。如果出现错误则会得到一个基本的出错信息。因为你已经改变了属性列表,你需要重新启动这个应用以看到更改。抱歉,这次不可以 Cmd+R。请中断 Xcode 中的应用,然后创建和运行项目。在使用基于位置的搜索前,你需要指定一个被 Nestoria 数据库覆盖的位置。在模拟器菜单中,选择 Debug\\Location\\Custom Location … 然后输入 55.02 维度和 -1.42 经度,这个坐标是英格兰北部的一个景色优美的海边小镇,我经常在那给家里打电话。警示:我们可以正常地使用位置搜索功能,不过可能有部分同学不能使用(在访问时返回 access denied 错误)—— 我们尚不确定其原因,可能是 React Native 的问题?如果谁遇到了同样的问题并且已经结果,烦请告诉我们。这里没有伦敦那样值得炫耀 —— 不过更加经济!:]下一步行动?完成了第一个 React Native 应用呢,恭喜你!你可以,亲自来试试看。如果已经接触过 Web 开发了,你会发现使用 JavaScript 和 React 来定义与原生 UI 相连接的接口和导航是多么地容易。而如果你曾经开发过原生 App,我相信在使用 React Native 的过程里你会感受到它种种好处:快速的应用迭代,JavaScript 的引入以及清晰地使用 CSS 定义样式。也许下次做 App 的时候,你可以试试这个框架?或者说,你依然坚持使用 Swift 或者 Objective-C?无论之后你的选择是怎么样的,我都希望读完这篇文章的你有所收获,还能把这些收获融入到你的项目当中是最好的啦。如果你对这篇教程有任何疑问,请在的讨论区留言!原文:外刊君推荐1. 关注微博:","updated":"T11:23:29.000Z","canComment":false,"commentPermission":"anyone","commentCount":117,"collapsedCount":0,"likeCount":423,"state":"published","isLiked":false,"slug":"","isTitleImageFullScreen":false,"rating":"none","titleImage":"/c5a1ff5b78ec226ce5edd_r.jpg","links":{"comments":"/api/posts//comments"},"reviewers":[],"topics":[],"adminClosedComment":false,"titleImageSize":{"width":1280,"height":854},"href":"/api/posts/","excerptTitle":"","column":{"slug":"FrontendMagazine","name":"前端外刊评论"},"tipjarState":"inactivated","annotationAction":[],"sourceUrl":"","pageCommentsCount":117,"hasPublishingDraft":false,"snapshotUrl":"","publishedTime":"T19:23:29+08:00","url":"/p/","lastestLikers":[{"bio":"","isFollowing":false,"hash":"c3163bcc13cea8475ae09e","uid":36,"isOrg":false,"slug":"he-xiaoxin","isFollowed":false,"description":"ihtswtsp#immt#iaasn","name":"何xiao鑫","profileUrl":"/people/he-xiaoxin","avatar":{"id":"87e04adb927c11f0b2c778ca0d3031ad","template":"/{id}_{size}.jpg"},"isOrgWhiteList":false},{"bio":"程序员/程序员/程序员","isFollowing":false,"hash":"2af595ac983d6b4f7036","uid":12,"isOrg":false,"slug":"shang-jin-78-69","isFollowed":false,"description":"","name":"风和时光","profileUrl":"/people/shang-jin-78-69","avatar":{"id":"da8e974dc","template":"/{id}_{size}.jpg"},"isOrgWhiteList":false},{"bio":"前端攻城狮","isFollowing":false,"hash":"2f60fdde1","uid":28,"isOrg":false,"slug":"po-wen-jie-16","isFollowed":false,"description":"生活不止眼前的苟且,还有诗和远方","name":"朴文杰","profileUrl":"/people/po-wen-jie-16","avatar":{"id":"v2-06d4da3cffaaffdac5d34f5b84bd7160","template":"/{id}_{size}.jpg"},"isOrgWhiteList":false},{"bio":"一直在睡,什么都不会。","isFollowing":false,"hash":"d456d227f1f03aeb2a2ce746c04ec830","uid":907100,"isOrg":false,"slug":"lin-bin-85-26","isFollowed":false,"description":"","name":"林斌","profileUrl":"/people/lin-bin-85-26","avatar":{"id":"da8e974dc","template":"/{id}_{size}.jpg"},"isOrgWhiteList":false},{"bio":"全干工程师ヽ(??▽?)ノ","isFollowing":false,"hash":"8c40f1c7dc","uid":28,"isOrg":false,"slug":"jiangkai-paranoid","isFollowed":false,"description":"http://jiangkai.site","name":"paranoidjk","profileUrl":"/people/jiangkai-paranoid","avatar":{"id":"ec3e5da22e406ffdec79f","template":"/{id}_{size}.jpg"},"isOrgWhiteList":false}],"summary":"本篇为联合翻译,译者:,,,,感谢帮忙校对的 数月前,,这个框架允许你使用 JavaScript 开发原生的 iOS 应用——就在今天,释出了!基于
使用 Java…","reviewingCommentsCount":0,"meta":{"previous":{"isTitleImageFullScreen":false,"rating":"none","titleImage":"/50/8d2feda9daac5e7e3686_xl.jpg","links":{"comments":"/api/posts//comments"},"topics":[],"adminClosedComment":false,"href":"/api/posts/","excerptTitle":"","author":{"bio":"常常感谢很少赞同","isFollowing":false,"hash":"dfafc151f61985dab7f885c","uid":96,"isOrg":false,"slug":"kmokidd","isFollowed":false,"description":"头像是挚爱的画手 | 依然尚无才华 | CSS/LESS 的问题还是可以稍微解答一下 JS 渣渣哦","name":"kmokidd","profileUrl":"/people/kmokidd","avatar":{"id":"6f3d8cb2d2baf8be1f84e8cdf53a7050","template":"/{id}_{size}.png"},"isOrgWhiteList":false},"column":{"slug":"FrontendMagazine","name":"前端外刊评论"},"content":"译者注:本篇为 Flexbox 设计指南系列第二篇,第一篇请戳一如之前说过的, 是一个很强大的 。它的优点之一就是,如果你想要将水平布局的 flexbox 改为垂直布局,一行 CSS 代码就能搞定,而且盒子中的元素排列顺序也能用 CSS 来更改。这个特性简直就是为了现在流行的而存在的,我们都知道为了兼顾用户体验,在小屏幕中页面元素会被重新布局。那么在这篇文章里,我们将会讨论到设计师可以如何利用 flexbox 这一特性。首先,先创建一个简单的布局:&figure id=\"flex\"&\n
&div id=\"triangle\"&&/div&\n
&div id=\"square-vert\"&&/div&\n
&div id=\"circle-vert\"&&/div&\n&/figure&\n再加上点样式:#flex { \n
display: flex; \n
padding: 2rem; \n}\n#triangle {\n
width: 0; height: 0;\n
border-bottom: 114px solid hsl(240, 30%, 50%);\n
border-left: 63px solid transparent;\n
border-right: 63px solid transparent;\n}\n#square-vert {\n
width: 126px; height: 126px;\n
background: hsl(300, 30%, 50%);\n}\n#circle-vert {\n
width: 126px; height: 126px;\n
border-radius: 50%;\n
background: hsl(340, 30%, 50%);\n}\n这么写完之后,这三个元素会水平显示。想要改变它们的显示方向,我们只需要加上一行 CSS 语句:#flex {\n
flex-direction: column;\n}\n注意!这三个元素现在是默认地从上向下排列,并且向左对齐。我在上一篇文章中所讨论到的属性,在这个例子里你都能看到:现在上下文是垂直的,而不是水平的。子元素重新排列后,只要容器的高度依然能够保证其正常显示,那么把子元素放到容器的尾部也很简单。同时让元素垂直对齐,接着倒转它们的顺序。#flex {\n
height: 500px;\n
justify-content: flex-end;\n
flex-direction: column-reverse;\n
align-items: center;\n}\n使用在水平和竖直方向上都对齐的 flexbox,Web 设计师就能实现完美的居中元素。唔,这个方法也是之一呢。移动端上的 Flexbox 基础篇使用 flexbox 布局,你能在大小屏幕之间来去自如。举个例子:&header&&/header&\n&div id=wrapper&\n
&nav&&/nav&\n
&main&&/main&\n&/div&\n&footer&&/footer&\n我们可以让 &nav& 和
元素并排布局(水平):div#wrapper { \n
display: flex; \n}\n到小屏幕上呈现上下布局:@media (max-width: 400px) {\n
div#wrapper { flex-direction: column }\n}\n到目前为止,你只看到了
的冰山一角,请期待后续的文章,我将展现出更多 flexbox 魔法。原文:关注微博:","state":"published","sourceUrl":"","pageCommentsCount":0,"canComment":false,"snapshotUrl":"","slug":,"publishedTime":"T19:28:57+08:00","url":"/p/","title":"Flexbox 设计指南2:垂直布局","summary":"译者注:本篇为 Flexbox 设计指南系列第二篇,第一篇请戳 一如之前说过的, 是一个很强大的 。它的优点之一就是,如果你想要将水平布局的 flexbox 改为垂直布局,一行 CSS 代码就能搞定,而且盒子中的元素排列顺序也能用 CSS 来更改…","reviewingCommentsCount":0,"meta":{"previous":null,"next":null},"commentPermission":"anyone","commentsCount":14,"likesCount":76},"next":{"isTitleImageFullScreen":false,"rating":"none","titleImage":"/50/7f4c5127cdf9ab6099488_xl.jpg","links":{"comments":"/api/posts//comments"},"topics":[],"adminClosedComment":false,"href":"/api/posts/","excerptTitle":"","author":{"bio":"周二去打球?好。","isFollowing":false,"hash":"1a797c28e9e44d7d56c01f","uid":68,"isOrg":false,"slug":"mrsunny","isFollowed":false,"description":"知乎创始人不是我,我是切图圣斗士","name":"周源","profileUrl":"/people/mrsunny","avatar":{"id":"2eba218b3","template":"/{id}_{size}.jpg"},"isOrgWhiteList":false},"column":{"slug":"FrontendMagazine","name":"前端外刊评论"},"content":"上次我写已经是三年前了,那是我写过最火的文章了。三年了,我仍然会在Twitter上收到关于这篇文章的消息。从2012年到现在,一篇文章都没发过让我觉得有点羞羞哒。三年是一段很长的时间,很多东西都发生了改变。2012年,我鼓励同学们去学习浏览器开发者工具和模块化;虽然有很多同学会觉得CSS预编译和客户端模板引擎并不靠谱,但我仍然想要说一说它们;还有JSHint,虽然有#getoffmylawn(滚出我的地盘)的警告,但依然无法阻止JSHint成为一个受欢迎的理念(准确的说,JSLint真的(只是)存在过)。已经是2015年了,我想写一篇新的,但是当我坐下来开始动笔的时候,想到了两个事情。一,这些东西被称作“必知必会”可能有人会觉得不太公平——如果你已经觉得如此,那本文也是一样的了。也许有同学会说,我们应该把 “足够应付业务需求的技能” 作为 “前端必须掌握的知识”,但考虑到前端行业里也有各种各样的工作可供选择,这么做也只能得到一个并不适合所有人的 “前端基础知识”。对于我来说,我需要的不是工作,我想要的是被邀请去做一份牛逼的工作。我想要的不只是去干活而已,而是想和一群牛逼的人一起做牛逼的事。我不想仅仅满足于用已有的知识来完成现在的工作,而是希望掌握更多的知识来解决未来将会面对的问题。第二,我现在已经完全把Javascript作为我的核心了:CSS知识只有在必须关注性能问题时才会用到,其他场景已经用的越来越少。我知道有很多牛逼的前端同学并不是这样的,但我也意识到,关注JS的同学和关注CSS的同学之间的距离也越来越远。这可能需要在另起一篇文章来讨论,不过我想说的是,这篇文章中不会有介绍CSS技能标准的内容,因为我还远远没有达到能那么做的水平。总之,就算这个技能列表并不适合你的前端工作,没关系,不要有压力,地球也不会爆炸。Javascript回想2009年,那时候当你知道 HTML5 在2014年才能用的时候,你是不是觉得这辈子基本上都用不到它了?如果是,那么你需要准备好接受进展缓慢但是已经趋于稳定的ES6了,它也是下一代的Javascript(现在叫
了,嗯,这名字至少表示今年就能用了)。就我而言,ES6,额,ES2015 无疑是我个人现在最关注的 Javascript 内容。在 ES6 中将会出现一些比较大的变化:类,真正的私有,经过改进更易用的函数和参数设定,可导入的模块,等等等等。那些掌握和理解新的语法的同学以后将会在 JS 社区牛逼闪闪。相关阅读:,Nicholas Zakas 正在写的书。BabelJS,一个可以把你写的 ES6 的代码编译成 ES5 并在现代浏览器中运行的工具。他们也有一个不错的。,里面有大量的文章探索 ES6 的特性,语义和缺陷。你也许会问:那我需要成为一个 ES6 专家么?也许现在不需要,但至少你得和你的同事懂的一样多吧?或者比他们稍微多一点?当然,如果能在你的下一个新项目中作为一个娱乐性的技术尝试也是不错的,做好准备肯定没错的,因为我们永远不知道下一刻会发生什么。先不说新的语言特性,使用回调和 promises 管理异步 Javascript 至少得背的滚瓜烂熟吧。浏览器端应用加载,以及应用间通信策略得形成一套自己的观点吧。而且你应该知道哪种框架最适合你,而不是现在还把时间花在理解各种框架的实现原理和该选择哪种框架上。模块化和构建工具毫无疑问,模块化是构建 Web 客户端应用的基石。回到2012年,关于使用哪种模块化(/)方案构建浏览器端应用还存在很多争论。而最近慢慢火起来的则在保证代码可复用的前提下尝试避免这样的问题。 其实也没什么好争得,毕竟这俩玩意儿之间也就差几个字符吧?我觉得类似这样的争论其实并不都需要有一个答案,这也是我觉得从2012年到现在我们发生的最大的转变,当然,也许只是我自己这么认为。因为我觉得与其说“我再也不用 AMD 了”之类的话,倒不如多去讨论 “在开发和打包过程中使用 CommonJS 和 npm 遇到的各种难题” 来的更有价值。虽然很感激曾经对模块化做出的贡献,不过现在我开始有点迷恋了。 webpack 的构建配置比 RequireJS 更加易于理解,也更具访问性。通过它的热插拔特性和内置的本地静态服务器可以让发布更加便捷。它并不强制要求使用 AMD 或者 CommonJS – 两个它都支持。它还实现了一大堆加载器,用来完成常见的繁琐工作。也值得去了解一下,不过我个人认为它比 Webpack 落后很多。一些靠谱的朋友告诉我说也是这个领域的竞争者,不过我还没有用过,而且它的文档烂的我连看都不想看。不过我觉得它的好基友(包管理器)比较有趣,jspm 可以让你从各种包管理服务器加载你需要的各种组件,(组件必须是符合 ES6, AMD, CommonJS and globals 规范的),包括 npm, github 等,但是我对于这两个玩意的合体还是有点不太理解。啊,还有,虽然我说了这么多关于模块化之外的内容,但我从来没想过放弃 AMD,我们边走边看吧。我觉得如果要停止对模块化和构建工具的争论,形成统一的模块化系统,并且在这个系统里面,任何项目的代码都可以共享,而且还不需要 UMD 这样额外的补丁工具,我们还有很长的路要走。理想状况下,的到来会解决这些问题,不过在这一天到来之前,类似 UMD 之类的转换器会填补这些空缺,不过貌似这样做我们又把事情变得复杂了,好像我们也总喜欢把事情弄得复杂。与此同时,前端开发人员也需要对构建工具,各种模块化系统有自己的见解和知识储备。不管是好是坏,根据 Javascript 现在的进度,你的模块化策略会对你的项目有比较大的影响。测试客户端的代码测试变得越来越普遍,最近也诞生了一些新的测试框架:,。我发现基于 promise 的 Intern 的异步测试方法相当优雅。不过可能是因为习惯,我大多数情况下还是用 Mocha 写测试用例。测试的主要障碍其实是前端开发者的代码编写方式。我在2012年发表过一个关于的演讲,紧接着几个月后又发表了一篇。测试的第二大障碍是工具。Webdriver 是一个艰难而巨大的工作。目前在各个浏览器端做持续集成的 UI 自动化测试基本上是不可能的,更不用说移动端了。我们仍然停留在局限于某一小部分浏览器和设备上做轻量级的自动化功能测试,尽我们所能去研究怎样快速,低成本的进行这种测试的阶段。如果你对如何改进代码的可测试性感兴趣的话,那么唯一一本最值得看的书是(。作者 Michael Feathers 定义了“遗留代码”的概念:任何未经测试的代码都是遗留代码。在测试领域,最基本的要素就是上面这句话,尽管你可能不这么认为。流程自动化你首先会想到,这也是理所当然的。而和的自动化构建方式也别具匠心。我没用过Broccoli,只玩过Gulp,我也开始意识到Grunt对于依赖其他服务的复杂任务的自动化工作存在局限性,尤其是当这种任务每天需要运行上千次的时候。是在我写完2012年的那篇文章仅仅45天之后发布的,我承认当时我并没有及时去尝试一下。不过最近我开始启动一些新项目,这些新项目有两个特点 a) 这些项目都是从零开始 b) 尝试用一些不同的技术方案,试图通过这种方式找到 Bazaarvoice(提供第三方点评服务)上第三方 JS 应用的规范化的开发方式。 Yeoman 在这两方面做的都很好。一个简单的 yo react-webpack 命令就可以为你初始化好你的项目,然后各种你想要的玩具也都应有尽有:生成测试用例,本地静态服务器,hello world 入门程序,等等等等。如果 React 和 webpack 不是你想要的,也许你会在 Yeoman 的 generators(项目生成器)里面找到一个你想要的,当然,自己自定义一个这样的构建包也是比较容易的。鉴于 Yeoman 只是一个在项目开始时才会用到的构建工具,并且鉴于我们并不是总是做新项目,所以大多情况下了解一下就够了。除非,你也想去规范整个项目开发过程,那么它可能会更有价值一点。Broccoli 已经得到了 ember-cli 的采纳,我觉得他们的配对可能会有一个新名字,这样在未来才比较方便和 Grunt /Yeoman 对抗。而 Grunt 和 Yeoman 的开发进度也放缓了,所以未来会发生什么,我们还是静观其变吧。代码质量如果你像我一样,一看见违反代码规范的代码时就开始抓狂,那么和 就是老天赐给你的礼物,而2012压根就没这些玩意。他们都提供了自定义代码规范的方式,并且可以在代码提交前对你的代码做自动化校验。这让我想起了…Git从2012年到现在,github 的使用流程并没有发生很大的变化,比如在 pull request 页面连个分支名都没有(只是恶搞一下)。你应该非常清楚和流畅地使用功能分支(feature branches), 使用 rebase 合并别人的代码干活,使用交互式 rebase 命令和 squash 合并提交记录,或者尽可能细颗粒度的划分项目内容,避免引起代码冲突。另一个可用的 Git 工具是钩子,具体而言,就是你可以在 push 前,commit 前,执行你的各种测试用例,检查代码质量。你可以自己写钩子,也可以使用,由于 ghooks 使钩子工作变得非常简单,所以你简直没有理由不用它。客户端模板这可能是我在2012年的那篇文章中写的最烂的内容了,某种意义上的“烂”。客户端模板还是很有价值的,而且它已经被内置到 ES2015 里面了,这不仅仅只是一件好事而已。这些年也有一些惨重的教训,不少团队把所有的渲染工作全部丢到浏览器端去做,结果产生了严重的性能问题,所以 “在浏览器端渲染生成所有 HTML” 的做法理所当然的被摒弃了。 而更为聪明的做法则是,把 HTML 生成放在服务器端,或者通过预编译的方式,先将模板做为静态资源储存起来,在需要时快速的编译成 HTML,需要更新时也可以直接在客户端更新模板。这里会有一些新的展望,不仅是对我自己,也是对所有人,当你在考虑性能问题时,也许没必要把自己完全限定在浏览器范围内。所以,这又让我想起了……Node听说你懂 Javascript,那么我觉得你也应该懂 Node,至少在遇到 Node 问题是能帮得上忙的,如果连忙都帮不上,那也至少深入研究一下吧:Node 的文件系统,流,服务器,完全不同于前端的一些开发模式等等。对后端敬而远之只会限制我们前端的发展潜力。即使你的真实生产环境中后端不用 Node,当你的工作被后端限制或阻碍的时候,Node 也是一个非常有用的工具。最起码,你也应该熟悉怎么去初始化一个 Node 项目,怎么用 Express 搭建服务器设置路由,怎么使用请求模块代理请求。最后感谢 Paul, Alex, Adam, Ralph 对本文的 Review,感谢他们毫不吝啬的指出我的不足之处,并给我提了很好的意见。就这样,祝你好运。也许,三年之后我们会再见。原文链接: 外刊君推荐阅读:关注微博:","state":"published","sourceUrl":"","pageCommentsCount":0,"canComment":false,"snapshotUrl":"","slug":,"publishedTime":"T13:52:15+08:00","url":"/p/","title":"2015 前端[JS]工程师必知必会","summary":"上次我写已经是三年前了,那是我写过最火的文章了。三年了,我仍然会在Twitter上收到关于这篇文章的消息。从2012年到现在,一篇文章都没发过让我觉得有点羞羞哒。三年是一段很长的时间,很多东西都发生了改变。2012年,我鼓励同学们…","reviewingCommentsCount":0,"meta":{"previous":null,"next":null},"commentPermission":"anyone","commentsCount":40,"likesCount":387}},"annotationDetail":null,"commentsCount":117,"likesCount":423,"FULLINFO":true}},"User":{"kmokidd":{"isFollowed":false,"name":"kmokidd","headline":"头像是挚爱的画手 | 依然尚无才华 | CSS/LESS 的问题还是可以稍微解答一下 JS 渣渣哦","avatarUrl":"/6f3d8cb2d2baf8be1f84e8cdf53a7050_s.png","isFollowing":false,"type":"people","slug":"kmokidd","bio":"常常感谢很少赞同","hash":"dfafc151f61985dab7f885c","uid":96,"isOrg":false,"description":"头像是挚爱的画手 | 依然尚无才华 | CSS/LESS 的问题还是可以稍微解答一下 JS 渣渣哦","profileUrl":"/people/kmokidd","avatar":{"id":"6f3d8cb2d2baf8be1f84e8cdf53a7050","template":"/{id}_{size}.png"},"isOrgWhiteList":false,"badge":{"identity":null,"bestAnswerer":null}}},"Comment":{},"favlists":{}},"me":{},"global":{"experimentFeatures":{"ge3":"ge3_9","ge2":"ge2_1","appStoreRateDialog":"close","nwebStickySidebar":"sticky","qrcodeLogin":"qrcode","favAct":"default","default":"None","mobileQaPageProxyHeifetz":"m_qa_page_nweb","newMore":"new","iOSNewestVersion":"4.2.0","newMobileColumnAppheader":"new_header","newBuyBar":"livenewbuy3","sendZaMonitor":"true","homeUi2":"default","answerRelatedReadings":"qa_recommend_by_algo_related_with_article","wechatShareModal":"wechat_share_modal_show","qaStickySidebar":"sticky_sidebar","androidProfilePanel":"panel_b","liveStore":"ls_a2_b2_c1_f2","zcmLighting":"zcm"}},"columns":{"next":{},"FrontendMagazine":{"following":false,"canManage":false,"href":"/api/columns/FrontendMagazine","name":"前端外刊评论","creator":{"slug":"stein.cun"},"url":"/FrontendMagazine","slug":"FrontendMagazine","avatar":{"id":"bd21f286e6aa5e210b60e2e257ce890b","template":"/{id}_{size}.jpeg"}}},"columnPosts":{},"columnSettings":{"colomnAuthor":[],"uploadAvatarDetails":"","contributeRequests":[],"contributeRequestsTotalCount":0,"inviteAuthor":""},"postComments":{},"postReviewComments":{"comments":[],"newComments":[],"hasMore":true},"favlistsByUser":{},"favlistRelations":{},"promotions":{},"switches":{"couldAddVideo":false},"draft":{"titleImage":"","titleImageSize":{},"isTitleImageFullScreen":false,"canTitleImageFullScreen":false,"title":"","titleImageUploading":false,"error":"","content":"","draftLoading":false,"globalLoading":false,"pendingVideo":{"resource":null,"error":null}},"drafts":{"draftsList":[],"next":{}},"config":{"userNotBindPhoneTipString":{}},"recommendPosts":{"articleRecommendations":[],"columnRecommendations":[]},"env":{"edition":{},"isAppView":false,"appViewConfig":{"content_padding_top":128,"content_padding_bottom":56,"content_padding_left":16,"content_padding_right":16,"title_font_size":22,"body_font_size":16,"is_dark_theme":false,"can_auto_load_image":true,"app_info":"OS=iOS"},"isApp":false},"sys":{},"message":{"newCount":0},"pushNotification":{"newCount":0}}}

我要回帖

更多关于 react native 定位 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信