Apr18

百度前端的七巧板 - infoQ百度技术沙龙第13期

上周六做为infoQ百度技术沙龙讲师,给大家分享了《百度前端的七巧板——Tangram JavaScript库》,讲的是在设计Tangram的时候,我们有过什么样的考虑,采用了怎样的解决方案,契合这次沙龙的主题:“JavaScript库的设计与应用”的前半部份。但是由于这个slide是第一次讲,准备不够充分,比预计时间提前十分钟就结束了。其实还有很多重要的细节和有意思的东西没有介绍到。 不过,来参加沙龙的朋友中,很少有在企业和团队中做通用技术的研发工作的人。后面QA时间,我收到了20多张提问纸条,大多是问一些技术细节和功能实现方面的问题。而事实上,做为一个开源项目,所有的细节都可以在 http://tangram.baidu.com里面找到。 大家可以去SlideShare上看到我的slide。 如果大家还有什么问题或看法,欢迎在下面留言讨论。

trackback Tags: 评论 (1)

Dec30

Tangram base的设计

上周,Tangram开源了,有不少人阅读代码后提出了自己的意见、对Tangram的期望,很感谢这些热心的朋友的支持。与此同时,也看到了一些对Tangram设计的疑问,因此想在周末写一篇小文来介绍一下,但由于恰逢年底,小组内一堆杂务要处理,加上咳嗽很严重,一直延到今天。 这篇文章主要是介绍在设计Tangram base时的一些考虑,以及它适合做什么事情。 细粒度拆分 只要看过Tangram文档或源码的人,一定会发现它拆分粒度够细。将每一个方法独立写成一个文件,用户可以通过codeSearch功能,获得定制好的Tangram,然后基于其开发业务组件和逻辑。 在百度来说,前端工程师一直都很关注流量和加载性能,按需定制可以最大程度的节省带宽、加快页面的加载和渲染速度。 同时,Tangram面向的产品跨度广,从搜索产品到社区产品到商业产品,而工程师动手能力都很强,他们能很轻松的基于Tangram提供的方法集,封装一套适合自身的产品底层库。不同的产品间,封装差异会比较大,但是由于底层库相同,交流沟通并不会产生多少障碍。 静态方法,无污染 除了拆分粒度细之外,Tangram库名字空间整洁,所有的方法都是静态的,对环境的污染很小。 一些老产品中总会有一些匪夷所思的代码,而且很多产品中会有第三方代码,为了最大程度的避免冲突,Tangram仅仅暴露一个变量到window中,而且用户完全可以把Tangram放在闭包中使用,这样即使页面上出现两套Tangram,他们之间也不会有任何冲突。 复杂的RIA产品需要一个开发框架时,采用Tangram做为底层库也很有优势,因为Tangram是静态的,封装和覆写都特别方便,如果发现在自身环境下对某些函数有特别的要求(如性能要求极高),可以自己编写新函数覆盖。函数是独立而且简单的,开发人员也可以很方便的对其进行研究,了解原理进而更好的使用。 上面的内容大多是Tangram针对产品团队的设计考虑。而对于一些通用组件开发者,基于Tangram开发时,他可以把Tangram当成一个函数库,仅仅选取他需要的部分,保证组件的体积精简。同时不必遵从Tangram的封装方式,可以按照需求,封装出自己想要的风格然后release。事实上,百度内已经有数个以这种形式存在的通用组件。 改进 Tangram一直都在不断升级,简单说说我们接下来要做的几件事情: 修改库中方法调用的baidu前缀,这件事情会在下一个版本发布前完成,做为一个开源项目,它应该保持自己的独立性。 Codesearch整理后,也会被随项目放出,这样大家就能很方便的在本地选取任何一个版本的Tangram代码了。 我们会不断整理Tangram的设计细节,开发规范,工具,并且在社区和blog中发布,即使你不使用Tangram,也完全可以参考和借鉴我们的思路。 不断完善文档,良好的中文文档也是Tangram相对其他库的一个优势。 开发团队 在百度FE,我所在的小组叫通用组,负责包括Tangram的所有前端通用技术的研发与维护,同时所有工程师都可以贡献代码到Tangram。开源后,Tangram将接受更多来自百度外部的意见,保持Tangram的不断成长和进步。欢迎前往github的network(base,component)围观我们每天的代码提交,更欢迎各位fork,为Tangram提供想法和代码。 小结 这篇文章介绍了Tangram base的设计特点、面向场景等,做为一个基础函数库,Tangram base很容易被封装和扩展,你也可以很放心的使用它来进行二次开发。 Tangram的文档地址是:http://tangram.baidu.com,你也可以前往github查看最新的源码(dev分支) 我们基于Tangram base,开发了Tangram component,这是一个组件库,它的设计考虑和实现方式就更复杂了,这部分留到下次再谈,如果你关注Tangram,欢迎订阅我的blog。

trackback Tags: 评论 (4)

Dec22

Tangram Javascript库开源了!

2009年中旬,百度FE开始系统的整理、开发自己的前端Javascript库,从那时起,Tangram这个名字就诞生了。Tangram是”七巧板”的英译,选择Tangram(读音)这个词,是因为我们希望这个JS库,能够自由地组合到各个百度产品中,通过七巧板搭建出丰富多彩的产品。 经过一年多发展,Tangram已成为公司内部产品基础库的首选,近20个百度产品线已经使用Tangram做为其基础库。而现在,我们决定将这个库开放给整个互联网,希望有更多的团队和公司,通过Tangram搭建出自己的产品。 一方面我们希望能通过开源,促进国内前端开发者的交流,更重要的是促进自身的成长和进步。业界通行的开源工作方式的引入,来自社区的反馈和建议,都能让Tangram更加完善。 Tangram的目标是成为一个容易扩展和定制,集轻巧和高效于一体的团队开发类库。 我们的开源站点是:http://tangram.baidu.com,上面有详细的文档,DEMO和一些使用介绍。Tangram遵循BSD授权协议,你可以自由的使用他。你可以从github上获取源码,欢迎大家fork和pull。 Tangram分作两个部分,Base和Component。 Base部分是基础工具库,现包含200多个基础接口,已经发展到1.3版本,代码比较稳定; Component部分是组件库,现包含20余个UI组件和行为,19个动画特效,现在仍处于beta状态,我们还在不断的完善和改进。 除了现在已经开源的Base和Component部分,Tangram系还包括Tangram Editor(在线编辑器)和Tangram Mobile(移动设备库)。Tangram Editor已经使用在百度空间、百度百科、百度经验等产品线上,正在不断完善;Tangram Mobile集合了百度产品移动版的通用功能,仍在紧张开发中。这两部分我们也会择期开源,希望百度FE能不断地给中国前端带来惊喜。

trackback Tags: 评论 (3)

Oct30

百度前端技术交流会

敝公司前端技术交流会第一次对外开放,有幸被邀请成为嘉宾上台交流。 我分享的主题是:百度前端基础平台分享。提前放出Keynote下载 //update@10.31 根据 @catchen 的建议,把keynote放到了slideshare上。 另外,Q&A环节里面,有一个问题:你在开发这个基础平台时,最先要考虑的是什么? 我的答案:需求,公司产品线的需求。技术方案不是第一要考虑的,所有技术方案都应当基于产品线需求来设计。就像pm做决策一样,不是用户嚷嚷要什么,就应当要给什么,而是要深入分析产品线特点,站在通用的角度上去考虑,我应该提供什么。我的keynote的每一个部分都是从公司现状讲起,然后到设计,到解决方案。没有现状和需求谈设计和方案是没有什么意义的。看着Yahoo,google的方案,自己山寨一套,不考虑公司情况,也一定是不适用的。 基础平台,没有最好,只有最适合。

trackback Tags: 评论 (16)

Apr13

opera下的onload、onunload事件无法正确处理?

今天,QA在测试JS框架的时候发现了一个问题:opera下不能绑定onunload事件,最新的opera 10.51也不行。 网上的解释千奇百怪,有说opera不支持unload事件的,有说使用beforeunload事件代替unload事件,还有的人说把通过js修改opera的history.navigationMode为’compatible’后就能正常支持这个事件了。 而按照我的测试,不管是按照window.unload绑定还是用addEventListener绑定的事件都无法在刷新、前进、后退,页面关闭,浏览器关闭时被执行。beforeunload事件表现相同。正在我怀疑opera彻底不支持unload事件时,恰好找到了bytes.com上的这篇文章。上面说的很清楚: There is no solution because according to Opera developers and users this is not a bug. Opera maintains the runstate of scripts, so it’s as if we never left the page when we return back to it. According to Opera, onload should only fire when loading the page for the first […]

trackback Tags: 评论 (2)

Mar12

傲游、世界之窗下的getBoundingClientRect问题

问题 今天,同事爆料suggeestion在傲游、世界之窗下,使用滚轮缩放后,suggestion的框和input不能对齐,会出现类似下面的效果(示意图): 页面是quirk模式,如果换用standard模式,就不会有问题。 追踪 追查发现,发现计算input位置一个库函数得到的结果不准确。对比yui和jquery的代码后,发现处理逻辑完全一致:如果是IE系列,直接使用getBoundingClientRect得到元素的top和left,之后再看是否为qurik模式,决定是否要减去两个像素。 问题就很明确了,是getBoundingClientRect()返回值与实际值不一致。此外,发现一个现象,如果放大屏幕,那结果偏小,缩小屏幕,结果偏大。于是尝试使用getBoundingClientRect()的返回值除以放大比率,果然这样就匹配了。 解决 首先,建议页面全部使用standard模式。 由于不知道如何使用傲游或者世界之窗的方法来直接获得缩放比率,同时担心在不同的IE外壳下会有兼容性问题,于是写了下面这个函数,很trick,实在不行的时候可以考虑用用: function getIEShellZoomRate (){ var div = document.createElement(“DIV”); div.style.position = “absolute”; div.style.top = “100px”; document.body.appendChild(div); var divBox = (div.getBoundingClientRect()).top; if(!browser.isStrict){ //fix 2px in IE while in quirksmode divBox -= 2; } document.body.removeChild(div); return parseFloat(divBox/100); } 其他 初步判断,原因应该是getBoundingClientRect()返回值是真实肉眼看到的像素值,而如果把这个像素值设置到元素的top和left属性后,实际值会随着缩放效果放大或缩小,造成两者不一致。 此外,在傲游中,页面加载完毕后,需要闪烁一下才能到缩放后的效果,傲游可能是在获得IE的渲染结果以后,再自行放大,如果使用了standard模式,重新绘制的区域是没有缩放效果的。 IE外壳的确方便了最终用户使用浏览器,但是也无形中让用户更依赖一个本来就很破旧的浏览器,不愿意升级到浏览器的更新版本。 珍爱生命,远离IE;拒绝毒品,抵抗浏览器外壳。

trackback Tags: 评论

Dec29

添加第一个功能按钮 – 在线编辑器(3)

在实现了在网页中插入一个可编辑区域以后,用户已经可以在这个区域中操作富文本内容。但是做为一个真正的编辑器是要有工具栏的,用户能通过工具栏上的按钮方便的对选中的文本进行操作。本文将介绍如何添加编辑器功能按钮。 加粗按钮 首先,我们在页面中添加工具条的HTML代码: <div id=”editor_toolbar”>     <input id=”editor_toolbar_bold” type=”button” value=”B” style=”font-weight:bold;” onclick=”editorInstance.bold()” /> </div> 工具条中包含一个按钮,在按钮被按下时,调用editorInstance的bold()方法。期望的结果是:在编辑框内,选中的区域将被加粗。 加粗操作 接下来需要实现加粗功能,在此之前,需要对execCommand()有一定了解 execCommand execCommand浏览器自带的一个接口,通过它,我们可以对document、selection、或者一个给定的range进行操作。如加粗、斜体等。 语法: bSuccess = object.execCommand(sCommand [, bUserInterface] [, vValue])   sCommand String,指定需要执行的命令,如Bold   bUserInterface Boolean,可选,决定是否显示用户界面,如弹出一个提示框让用户输入,默认为false。   vValue Variant,可选,一个字符串、数字、或者其他需要assign的值 一般来说,第二个参数会传入false,因为编辑器本身会接管用户界面,第三个参数按照实际需要传入。这样就可以实现对选区的加粗: document.execCommand("Bold", false, false); 代码实现 只需调用浏览器的execCommand方法,选区就被加粗了。 editor.Editor.prototype.bold = function(){ this.document.execCommand("Bold",false,false); }; 简单极了!但是总觉得少了什么?是的,没有状态反射。不论用户选中的是否一段加粗的文本,按钮只有一个状态,用户无法感知当前选中文本的状态。 状态反射 添加状态反射的思路是:在选区发生变化的时候,编辑器核心派发一个事件,在此事件发生时判断此时选区的状态,根据状态设置按钮样式。 为何不由编辑器核心直接设置按钮样式呢?这是因为通过事件通讯能最大程度的降低模块和核心之间的耦合,也是模块可插拔的基础。 监听选区变化 造成选区发生变化的根源是鼠标点击或者键盘击键。因此,通过监听onkeydown和onmouseup事件就可以较粗略的得知选区变化。其实,此处将成为编辑器复杂后的第一个性能瓶颈,具体优化办法今后将具体描述。 事件机制 […]

trackback Tags: 评论

Dec23

历史、现状和目标 – 在线编辑器(1)

关于本系列文章 计划暂时是这样,首先介绍一些历史、知识背景,然后详细分析现状和需求,开始设计一个可扩展,低耦合的编辑器,最后针对一些难点问题进行单个分析。 历史、现状 起初,世界上的浏览器本没有编辑器功能。到了IE4.0 (1997年),微软提供了document.selection,利用这个对象,前端开发人员可以让一个iframe进入编辑状态,里面可以输入富文本内容,并且能通过程序添加复杂的编辑操作。那个时候还没有W3C的相关规范,这个selection对象以及两种选区类型(textRange和controlRange)都是微软自己实现的。 三年后,有了W3C的相关规范(2000年),这个规范和IE的实现完全不同,firefox等一干浏览器陆续根据规范实现了自己的selection和Range对象。 前端工程师的悲剧就这样酿成了,有两套截然不同的方式来处理选区(selection),不仅仅如此,对execCommand()方法的支持也大相径庭,一个相同的命令在不同的浏览器下执行会出现不同的效果。最要命的,浏览器还经常会有一些诡异的问题,比如在某些时候对选区的不当操作会导致IE直接崩溃等。 但是在线编辑器的使用场景相当广泛:写blog、论坛发帖、淘宝卖东西、在线聊天等应用场景都需要使用编辑器,他们对编辑器的要求各不相同。编辑器已经成为了一个基础件,几乎所有的互联网公司都需要用到。 后来出现了一些开源编辑器,比较出名的有:ckeditor(原来叫fckeditor), tinymce,eWebEditor等,最近,淘宝也开源了他们的kissy编辑器(功能尚不完善)。但是开源编辑器都各有不足,ckeditor足够强大,重写了浏览器的所有操作。但是模块之间的耦合性很高(3.0有所改善,但仍然不够),体积过于庞大,其他的一些编辑器则要么bug太多,功能不全,要么不方便二次开发。另外,一些对编辑器要求很高的服务,像zoho、Google docs等等,都带有一个很强大的编辑器。 目标 一个优秀的编辑器,首先要尽量解决浏览器之间的差异,在不同的浏览器下表现一致。 另外,为了让编辑器在各种不同环境下适应不同的需求,尤其是二次开发的需求,这个编辑器还应该是“通用”、“可扩展”、“低耦合”的。 具体的设计思路在后面我会专门撰文说明,首先的这几篇文章,是让一些没有接触过编辑器开发的童鞋了解一些基础知识。 本文是在线编辑器系列文章的第一篇,在这个系列文章中,我会逐步深入和大家分享编辑器开发过程中的奥妙和各种奇怪的问题。下一篇文章将介绍如何拥有一个可编辑区域,如果你对我的文章感兴趣,欢迎从页面右边订阅我的博客及时收到更新。

trackback Tags: 评论 (1)

Dec5

在javascript编程中灵活使用try-catch

上周,在分享家的qq交流群里,经常有人向我反馈不能下载东西。于是直接联系了一个用户,发现他的浏览器报出pageTracker对象不存在错误。 问题很显然了,由于我在下载链接的onmousedown事件中添加了Event统计,如果用户的Google Analytics代码没有加载成功(显然是万恶的教育网造成的),那么就会报出这样错误。 请看原来的代码片段: function analytics(category, action, label, value){   pageTracker._trackEvent(category, action, label, value);   } 修改一下,加上try-catch屏蔽这个错误: function analytics(category, action, label, value){       try{           pageTracker._trackEvent(category, action, label, value);       }catch(e){}   } 用try-catch来屏蔽浏览器错误是一个Javascript编程中很常用的一个技巧,灵活使用可以给开发者减少很多麻烦,下面再举一例。 最近,我在开发一个通用的所见即所得编辑器。某些时候,程序需要记录住当前状态的节点,给后续程序处理。但麻烦来了,用户如果持续的在进行编辑动作,在程序后续处理时,节点可能已经不在DOM树中了。 在IE下,如果你调用一个不存在的文本节点(nodeType == 3)的任何属性或者方法,浏览器直接报错。根本找不到能判断这个节点是否存于DOM树中的方法。于是有了如下代码: try{     if(ele.ownerDocument != editor.document) return false; }catch(e){ […]

trackback Tags: 评论

Jun19

offsetwidth、clientWidth、scrollWidth的区别

最近在写一个拖拽模块,支持range,也就是说一个element只能在一个固定的范围内拖动。于是我需要知道当前被拖动的element的大小。 最初我使用scrollWidth,发现在ie6下,如果这个element有border,就会有偏差,后来经过erik的建议使用offsetWidth解决。 上网查了一下,得到如下答案: scrollWidth是对象的实际内容的宽,不包边线宽度,会随对象中内容的多少改变(内容多了可能会改变对象的实际宽度)。 clientWidth是对象可见的宽度,不包滚动条等边线,会随窗口的显示大小改变。 offsetWidth是对象的可见宽度,包滚动条等边线,会随窗口的显示大小改变。 这篇日志是每日一web-dev tip计划的一部分,如果你关注web开发或者linux,请订阅我的rss。

trackback Tags: 评论