iOS 8.1/8.2 第三方输入法无法响应 keyup 事件

这是前两天遇到的一个坑。场景是一个包含一个输入框和一个“提交”按钮(默认 disabled)的 H5 页面,当在输入框中输入合法数据后,“提交”按钮会变得可用,然后用户可以点击提交数据。

之前的实现是监听输入框的keyup事件,当输入合法数据后,修改按钮样式变为可用。

但部分用户反馈无论输入什么样内容,按钮始终不可点击,所以猜测可能是keyup事件没有响应。通过整理出问题的 OS,发现主要是 iOS 8.1/8.2两个版本。测试后发现的确是这两个版本的 WebView 下第三方输入法对keyup事件无响应。

最终的解决方案是修改为监听input事件,问题解决。先写这么多,留坑总结下两个事件的不同。

注:转载注明出处并联系作者,本文链接:https://nodefe.com/keyup-dont-work-under-ios8_1-and-ios8_2/


阅读全文 »

stringify 实现及 JSON 数据类型思考

背景

记之前遇见的一道面试题,让现场写出 JavaScript 中stringify函数的实现。首先写一下自己最开始的思路,然后针对里面的一些问题进行逐步修改,并且引出对 JSON 这种轻量级数据传输格式所拥有数据类型的学习与思考。

一、最初实现

首先给定题目

将一个 JSON 格式对象转换为字符串,转换后的结果可以通过JSON.parse()方法将该字符串重新转换为一个 JSON 对象。

先简化问题,将数据类型简单划分(并不正确,下文会给描述)为:对象(Object)、数组(Array)和字符串(String)这三种类型。对于 String,只需要简单的对它进行toString()调用,并包裹在"中处理,对于前两者则需要采取不同操作。考虑到他们的子元素也是 JSON 对象,定义具有递归性,所以代码也采用递归来实现。最初代码如下:

代码的思路就是传入一个对象,然后判断它的类型:1. 如果非数组和对象类型,就直接返回它的字符串形式;2. 如果是对象类型,则遍历每个键值对,判断每个键对应值的类型,如果是


阅读全文 »

HTTP 缓存机制学习实践

1. 背景

这两天研究了下 HTTP 的缓存机制,其中版本是HTTP 1.0/1.1。现在将几个和 HTTP cache 有关的 Header 的用法做一个总结。

2. 缓存机制

2.1 Header 取值

服务器在返回的 response 中主要使用两个 Header 来控制浏览器的缓存行为:

  1. Expires:在HTTP 1.0版本中定义,为了兼容老版本 UA 常常也会加上该 Header,后面跟一个绝对时间字符串,表示过期时间。
  2. Cache-Control:在HTTP 1.1版本中定义,除了提供了同Expires相同并更精确的缓存功能,还提供了验证机制,它可以取以下这些值:
    • max-age:功能和Expires类似,但是后面跟一个以“秒”为单位的相对时间,来供浏览器计算过期时间。
    • no-cache:提供了过期验证机制,下文会再着重介绍。
    • no-store:表示当前请求资源禁用缓存。
    • private:指示只有用户客户端可以缓存,而 CDN 等不可。
    • public:指示用户客户端和 CDN 都可以缓存当前资源。
2.2 直接缓存


阅读全文 »

React Native 下拉菜单容器实现

背景

本周算是把一个 react native 版的商家管理工具(iOS 版花花内嵌商家后台)完成,所以现在花一点时间来把其中一些值得记录下的东西整理一下写出来。 根据 UI 设计,很多页面都采下图的展示方式:

截图

可以看到,两个页面的结构相似:顶部都是若干个PickerIOS组件的集合(红色框部分),然后下面是不同的组件(蓝色框组件)。例如左图有3个PickerIOS而右图有4个PickerIOS,并且分别代表不同的筛选条件。左图中的内容组件包括一个图表以及一个列表,而右图只有一个列表。所以考虑把公共部分提取出一个公共组件,该组件可以实现:

  1. 红色框内的PickerIOS数量以及内容可以定制。
  2. 蓝色框内的内容组件可以作为一个属性传递给该组件,用来展示信息。
  3. 切换筛选条件,能够向后端请求数据,并更新内容组件。

功能实现

顶部的Picker集合采用配置的方式实现,即单独创建一个配置文件模块DropdownViewConfig.js,文件内容大致如下:

每个 key(如 platform 和 date 等)对


阅读全文 »

动态侧边导航栏 JS 实现

背景

来美丽说后做的第一个大的页面改版就是商家后台整个发宝页改版,感觉其中一个比较有意思的地方就是侧边导航栏的实现。页面内容非常多,涉及到商品的不同属性信息以及其他一些功能模块,所以整个页面的 js 实现也分模块组织。这次要记录的侧边导航就是sideNav.js这个模块。

页面效果

最终的效果如下图(如果有美丽说商家账号也可以直接访问该 链接 来看):

侧边导航栏

页面根据商品的不同属性信息划分为:在店铺的分类、款式/属性、标题/副标题/简述、货号/美丽制造货号、SKU设置、价格/库存、运费、图片信息和其他信息共8个大模块。其中图片信息模块下又分为封面图、产品介绍、商品细节、商品实拍、尺码说明、资质认证和店铺介绍工7个固定模块,以及可以动态添加或删除的自定义模块。现在侧边导航要实现的功能为:

  1. 点击侧边导航栏的不同选项,页面滚动到对应的功能区域。
  2. 根据页面当前滚动位置,高亮所在区域对应的侧边导航项;如果该项不在视野内,则滚动导航栏使该项移动至视野内。
  3. 点击添加或删除自定义模块后,能自动在导航栏中对应添加或删除对应导航项。
  4. 点击保存宝贝后,会进行信息校验;如果有错误,会在侧边导航中添加


阅读全文 »

Nginx 配置 location 匹配规则总结

今天和同事讨论一个有关 nginx 中的location配置问题,就想查一下它的匹配规则。结果 Google 出的文章基本都是同一篇,而且各种莫名其妙的示例看得自己更云里雾里,索性上官网查文档,现对它的用法做个梳理。

语法

这是location的使用方法,这里暂不考虑@的用法。

分类

匹配规则其实可以分为两类:

  1. prefix string:即前缀字符串匹配,包括= uri^~ uriuri三种形式。
  2. regex:即正则匹配,包括~ uri(大小写敏感)和~* uri(大小写不敏感)两种形式。

匹配过程

nginx 对 location 的匹配流程为:

  1. 首先遍历 location 规则中所有的 prefix string 类型,如果有=规则并且=后的 uri 和请求的 uri 完全匹配,那么直接命中该条规则,然后立刻终止匹配;若无满足上述条件,则进行下一步。
  2. 上一步中没有匹配的=规则,nginx 会持续遍历完成所有的 prefix string 类型规则。遍历完成后,如果有单个匹配的^~规则,则


阅读全文 »

青岛骑记

楔子

距离十一骑行青岛已经两个多月,一直懒着没有写游记,今天给补上。十一本想和车队几个哥们儿一起找个地方玩,但乐乐结婚,小乐子去广西,老唐备考注会,所以就剩了我一光杆司令。时值乐乐跳槽有9月一个月假期,他一人从合肥骑车到杭州,看得好不快活。加上去年4月骑行川藏后,就没有再骑过中远途,所以十一前一个多星期临时决定找个地方独自骑个小远途。因为一直还想去海边,加上距离合适,就选择了青岛,买了帐篷睡袋,请了一天假,订好10月7日青岛回北京的高铁,就准备出发。因为一个人骑行,又打算路上可能会住帐篷,所以东西带的很多很全,但又尽量减少不必要的装备,以减轻负重。下面就是我的装备:

装备

行程

北京到青岛700km+,计划每天160km+左右,这样5天应该可以骑到青岛,但最终由于路上种种原因,还是根据每天具体情况量力而行。9月30日出发,4号下午到青岛,7号上午返京。

  1. 9.30 回龙观 – 滩里镇(北京 – 河北)
  2. 10.1 滩里镇 – 无棣县(河北 – 山东)
  3. 10.2 无棣县 – 寿光市
  4. 10.3 寿光市 – 高密市
  5. 10.4 高密市 – 青岛
  6. 10


阅读全文 »

React Native 集成至已有 APP — 双向通信 II

今天看到 react-native 的官方 doc 上放出了最新的文档,正巧是介绍题目描述的问题,不过具体的方法还是参考这篇文档。所以可以直接去官网看文档。这里只是作为自己项目中的一个记录。

背景

承接上一篇介绍的 react-native 和已有 APP 之间的双向通信问题,本篇介绍另一个方向的通信,即:appCon -> appChild。

实现

思路是在 js 代码中订阅一个事件并绑定事件处理函数,然后在 native 代码中触发该事件。以下是在 native 中触发时间的代码

上面代码触发onOrderHelperClick事件,并且传递参数订单链接order_url。在 js 代码中相应添加对应事件订阅代码:

这样只要在 native 中执行上述代码,js 中就能捕获事件并获取参数,然后执行事件处理函数。

最后

大部分内容和思想在官方文档中都有提及,本文只是结合笔者自己项目简单记录实现思想。另,由于 react-native 的


阅读全文 »

React Native 集成至已有 APP — 双向通信 I

背景

因为之前用 react 开发了部门内部的技术分享网站,加之手上负责一个 WAP 业务模块。因为是 APP 内嵌的 h5 页面,也没有做过优化处理,所以考虑使用 react-native 重新实现一遍该模块改善体验。

经过1个月开发,产品作为独立 APP 开发完成,但经过与PM讨论,还是决定将它作为一个功能模块嵌入一个已有的 APP 中(下文简称 appCon,新的模块成为 appChild)。这就遇到几个需要考虑的点:

  • 如何将代码嵌入已有 appCon;
  • 如何实现 appCon 和 appChild 之间的双向通信。

其中双向通信有这样两个场景:

  1. appChild 中点击一个 button 会自动唤醒 appCon 中的聊天功能;
  2. appCon 中点击一个链接会自动跳转到 appChild 中的订单详情页。

本文先来实现上述第一点:appChild -> appCon 的通信。

实现

思路是在 appCon 中创建一个自定义模块,其中的方法理所当然可以调用 appCon 中其它部分的功能代码,比如唤醒聊天。然后通过 react-native 提供的方法将该模


阅读全文 »

Mac下编辑器选用

自打从ubuntu转战OS X,加上后端转前端,主力编辑器就从vi调整为Sublime,不知不觉已有半年之久。这些天需要重新在后端用PHP写接口,所以今天重新配置了vi,印象中还是vi撸后端更欢快一些。用了半天,感觉还是不如Sublime舒服。想了想就做了一下对比,列出继续使用Sublime作为主力编辑器的原因:

  1. 最主要的一点,MBP/MBA的触摸板彻底解决了鼠标和键盘之间切换的不便;使用vi的一大原因就是想要解放右手。。使用键盘操作光标移动,在两种模式下分别完成命令和编辑操作;但是Mac的触摸板使用太过方便,所以不再有该问题;
  2. Sublime下的丰富的插件,相比vi并不逊色;
  3. 与vi同样出色的快捷键配置方式;
  4. GUI更友好,右侧的代码位置窗口很实用,能很直观的了解到当前视野在文档中的位置;
  5. 快捷的文件打开和tag跳转方式(vi的nerdtree和taglist也能实现);
  6. 避免打开过多term,因为不喜欢使用term的tab,所以如果使用vi不可避免开启很多term,一个解决方案是使用多个桌面,然后在之间切换,但还是不如直接开两个程序方便。

综上,现在使用Sublime作为项


阅读全文 »