人性化的软件开发

只要有了优秀的编程工具、高级的编程语言、丰富的构件库和辅助程序建立系统,就能解决所有问题?并及时地在预算范围内交付良好的软件系统吗? 一个软件开发团队如果想要在项目中获得最大限度的成功,离不开人的因素。

软件开发团队中的意见

一个软件开发团队如果想要在项目中获得最大限度的成功,取决于团队中的成员能否形成技术性一致意见。但为什么这点如此重要呢?是不是团队成员只 要在诸如目录表格的布局上达成一致,或者建立一个很好的错误汇报机制就行了呢?技术性一致意见指的并不是与同事打成一片就可以了(当然,这也不是说在同事 之间建立良好的关系有什么错误)。技术性一致意见是指充分吸取团队中每个成员的技巧和经验,其目的是为了开发出更好的软件。

职业软件人员也许能够迅速理解一款好的软件,至少当他们看见一个好的软件时会宣称自己能够理解它,但是,在软件开发者中,很少有人能理解技术性 一致意见。可能许多软件开发者会说,我们以前使用过一致意见的方法来解决问题,但是效果非常差,他们还会举出许多例子,比如,一些很棒的构想就是在不断的 讨论中葬送了,最后为了所谓的整体性只得做出妥协;本来 6 个月可以完成的项目最后拖了 1 年:团队的能力也没有完全发挥出来。但如果仔细地听听他们的意见,你就会意识到他们所说的解决问题的方式根本就不是技术性一致意见,而是折衷。那么,二者 之间有什么差异呢?

折衷是没有前途的

折衷意味着所做出的选择是一种似是而非的东西。既不是甲,也不是乙,而是一个介于二者之间的东西。我们可以通过一个典型的例子来说明。如你的团 队正在开发一个图形用户界面的项目,一部分人强烈建议直接将控制按钮放在屏幕底部,而另一部分人建议在屏幕的左侧放置一个控制窗体。在这两种意见中,一种 是水平放置,一种是垂直放置,形成了两个极端。那么,一个最具有代表性的折衷方案就是,将控制按钮沿着对角线放置在屏幕的中央。

就像上面的例子所描述的,由折衷所产生的解决方案常常要比任何一个原有的方案都要差劲。但是技术性一致意见就恰恰相反,它所产生的解决方案要比 任何一个原有的方案都要好。如果不使用技术性一致意见,往往会由于顾忌到每种备选方案的优点,而采用优点均衡的方式,但实际上每种备选方案的优点也就丧失 了。真正的一致意见不是基于那种让每个个体都做出让步的折衷,而是基于综合的,新的综合体要比原有的任何一个个体都要好。最后的结局就是,开发出了更好的 软件。

一个综合体是一种具有新颖性的新个体,是集成了原有的每个建议和方案的本质特征的个体。在上面所说的界面设计例子中,可以明显地看出,一个具有 创造性的综合方案是给控制按钮窗体加上选项,由用户来决定是采用水平放置还是采用垂直放置。一致意见的方法不仅仅是将各种选择方案的优点集中起来,而且综 合方案还体现了新的特性和功能。通过集成水平放置和垂直放置这两种方案,我们可以实现终端用户定制。这样,最后的软件产品就集成了各种方案的好的方面,而 不是坏的方面。

形成真正的一致意见并不是一件容易的事情,那些政客和工人谈判代表们对此深有感触。达成一个技术性的一致意见与达成一个政策性的一致意见是有所不同的,但是有些本质特征是基本相似的:二者都需要制定一些约束条件以达成共识,参与者在讨论过程中都需要保持一种信念。

真正的信徒

团队成员必须坚信,从每个人的意见中提取出最好的方面并将其综合起来,就此形成一个技术性的综合体是完全可能的。只有坚信这点,成员们才有可能 坚定不移地寻找最好的解决方案,而不是轻易地折衷或者固执己见。每个成员发表自己对问题的看法,讲述方案的优缺点,通过坚持不懈地努力,成员们可以提高形 成具有创造性方案的可能性,而这种创造性的方案会比原有的任何方案都更好。

当每个成员都相信开发一个好的软件要比在软件中使用自己所喜爱的方案更重要时,一致意见式的设计会发挥更大的作用。如果我们注重最终软件产品的质量,在团队讨论过程中会更容易发现每种意见的优点。

如果团队中的成员不是独自炫耀个人能力,而是认同联合协作的工作方式,那么对于软件开发会更有帮助。有些公司愿意奖励杰出的个人,而不是奖励团 队;或者晋升那些惯于单打独斗,特别是那些不会也不可能与他人共事,常常一个人解决问题的程序员,而不是表彰整个团队。这样的公司会做出如下论断:最好的 软件是他们的天才程序员开发出来的。这些公司意识不到,除了这种方法以外,其实还有其他的方法可以达到更好的效果。

在建立技术性一致意见时,一个必须遵循的原则就是:绝不能以货易货!对于政客们来说,采用以货易货的贸易方式是一种获得成功的经典策略,但对于 技术性一致意见而言,这是有害无益的。举例来说,在上面的界面设计例子中我们可以采用以货易货的方式,如果让我同意你的愚蠢方案,将控制按钮窗体放在屏幕 底部,那么你就要同意我聪明的设计思想,加上没有标签的图标。最终的结果就是,界面不是最好,而只是一个具有两个普通特性的界面。这种以货易货的策略其实 是另一种形式的折衷,而折衷之所以糟糕,是因为在不同方面所做的决策会相互影响。好的技术性一致意见必须将问题分别对待,对于不同的问题分别采用最好的解 决方案,而绝不能因为某个方面固执己见,致使另一个方面让步。

尊重事实

一般来说,大家都认为技术决策所依据的都是技术性因素,诸如事实、可测量的数值、应用中需要考虑的事项等。但实际情况是,诸如感觉、意见、直 觉、偏见等,都会对决策的制定或者问题的解决产生影响,这些都是人在做事情时所不可避免的因素。尽管有些人试图否认、控制、压制这些非理性的因素,但这些 都是绝不可能完全避免的。

对于那些希望采用技术性一致意见方式来解决问题的团队,有一个基本的技巧是必须掌握的:将事实和意见分开。对于一个协同工作的团队来说,如果期 望创造性地解决问题并获得最好的结论,他们必须知道他们已经掌握了哪些信息,并能够随时获得最好的信息。发表意见并不是错误,团队成员应该能够自由地表达 他们的意见。意见是有用的,特别是那些经过深思熟虑的意见,但是成员在表达意见时必须能够保证他们的意见不要和事实、数据、分析混在一起。就算是事实,也 是具有局限性的。例如,在美学或者行销领域中,事实所起的作用可能就会不太显著。遗憾的是,有些团队成员一旦形成自己的意见,他们往往就对事情的真实程度 视而不见了。

有时候,把某些东西称为事实并不意味着它就是真正的事实,因此,团队必须学会如何单刀直入地解决问题,而且大家还需达成一致——不玩文字游戏。 我的第一任妻子在我们共同生活的早期就学会了这一点,只要我说出以“事实很清楚地表明……”开头的一段话,她就会对我所讲的东西表示怀疑,因为这意味着随 后所讲的话极有可能只是我个人的看法,而不是基于任何数据或证据所得到的结论。除了这个尴尬的话题外,我有时还会掉入另一个语言陷阱中,那就是众所周知的 “95%的科学家都认为……”。有些人可能意识到了,在软件业中,有一句同样著名的话:“你知道的,绝大多数的职业软件工程师,至少 95%以上,都会采用这个方法。”当然,如果你还想继续使用这个小技巧,你必须改变百分数,例如:“将近 78%的 WordPerfect 用户都知道最好的方法是……”,“如果我们做个调查,2/3以上的C程序员都会同意……”。有时候,看上去好像真的有那么多的科学家、软件工程师、终端用 户站在你的背后支持你的意见。

但是,这仅仅是我的看法。

Facebook 宣布 10 亿美元收购 Instagram

【搜狐IT消息】4月10日消息,Facebook宣布将以10亿美元收购在线照片共享服务商Instagram。

据华尔街日报消息,Facebook已经与Instagram达成协议,将以10亿美元现金和股票收购后者。这意味着在Facebook IPO之前,它正利用市场财富自我增长。

Facebook CEO扎克伯格在网站时间轴(TimeLine)上宣布此事。他发表消息11分钟后,已经有3.4万人“Like(相当于推荐)”。

Instagram于2010年10月正式登录App store,首批用户2.5万名。到12月,注册用户超100万。用户大约每人上传3张图片。

2011年2月,进行首轮融资,金额700万美元,用户达200万。3月,每周用户增13万,每周220万用户上传360万张照片。到2011 年5月,团队只有4人。2011年6月,用户量达500万,分享照片破1亿张,每月新增用户62.5万。2011年7月,用户量达700万。8月照片达 1.5亿张,日上传1.3万张。2011年12月,用户数达1200万。

Instagram的开发和发布只用了8周时间,但在这之前的准备工作几乎用了一年时间。

附Facebook CEO扎克伯格声明:

我非常高兴与大家分享一则消息,我们同意收购Instagram,它的人才团队会加盟Facebook。

数年来,我们专注于建立自己的最佳图片分享体验,让用户更好地与朋友、家人分享。现在,我们可以更密切地与Instagram团队合作,让用户与自己感兴趣的人分享移动照片,提供最好的体验。

我们相信二者间有可以互补的不同体验之处。为了做得更好,我们需要留心并巩固Instagram的优势和功能,而不能只是将它的一切与Facebook整合。

因此,我们承诺会保持Instagram独立,继续巩固并保持它的增长。全球数百万人喜爱Instagram应用,喜爱与此品牌相关的元素,我们的目标是帮助程序和品牌拓展,让更多人喜欢。

我们认同一个事实,即让Instagram与其它非Facebook服务相连是体验的重要部分。我们计划保留一些功能,比如让用户在其它社交网 发表内容,如果用户不想在Facebook上分享Instagram内容,也可以停用,用户还可以只在Facebook上成为别人的粉丝并让别人成为你的 粉丝。

我们知道,这些及其它功能是Instagram体验的重要部分。我们会从Instagram体验中学习,在Facebook其它产品中建立相似服务。同时,我们会帮助Instagram 继续增长,主要是通过使用Facebook优秀的工程团队、基础设施来协助。

对于Facebook来说,这是一个重要的里程碑,这是我们首次收购一家拥有众多用户的企业,收购一款拥有众多用户的产品。我们无意进行太多此 类收购,甚至不会再收购。不过,人们之所以爱Facebook,有一个重要的原因是为了照片分享体验,我们知道让两家企业合并是值得的。

我们会继续与Instagram团队合作,一起开发新的好体验。

附Instagram CEO凯文·西斯特罗姆(Kevin Systrom)声明:

大约2年前,麦克和我创立了Instagram,目的是改变、改进世界通信和分享的方式。我们度过了难忘的时光,看着Instagram发展成全球用户喜欢的、有活力的社区。今天,我们更高兴地宣布一件事,Instagram同意出售给Facebook。

在过去的每一天里,我们看到越来越多的体验通过Instagram方式分享,这些方式出乎意料。因为有了专注而富有才华的团队,我们才能走这么 远;有了Facebook的支持,及其创意、人才的支持,我们希望能为Instagram和Facebook开创一个更激动人心的未来。

有一点要澄清,Facebook并没有离开。我们会与Facebook合作推动Instagram发展,建设网络。我们会不断向产品增加新功能,寻找新方式创造更好的移动照片体验。

Instagram程序会和过去一样。大家所追随的人没有变,追随大家的粉丝也没有变。大家仍然可以在其它网络上分享。大家同样拥有其它一切功能,它们让程序更有趣,更独特。

为什么我们要学习Haskell这样的编程语言

最近的几个月,我一直在学习一种叫Haskell的编程语言。由于里面有太多的从未遇到的编程概念,整个过程就像是完全重新学习如何编程。在i.TV网站上,我写了很多JavaScript(node.js和前端代码)。虽然有不少的函数式/haskell式的编程模式不能引用进来,但仍有大量的技术思想让我在使用javascript编程语言时受益不少。

你会发现Haskell库里有能够处理各种事情的各种各样的函数。起初我以为这些只是一种技术上的积累,但随后我认识到,这些函数相比起其它语言里的函数,它们能应用到形式更广泛的问题中。这使得它们更有价值,因为我们都不太喜欢对一些常见的问题还不得不自己去写解决方案。

这些函数是可以相互组合的:它们能针对性的解决某些问题,而不对你的代码做任何依赖,所以,你可以拼装它们,组合成一个能够解决你的大问题的东西。

高阶函数(Higher Order Functions)

在Haskell语言中,最多的被反复使用的函数都是高阶函数(higher order functions)——能以函数作为参数、能返回函数的函数。这使得它们具有固有的灵活性。下面是一个不太灵活的函数:它计算一个数组里等于某个值的元素的个数。

// 不灵活function countMatching(array, value) {    var counted = 0    for (var i = 0; i < array.length; i++) {        if (array[i] == value)            counted++    }    return counted}// == 2countMatching([1,3,3,4,5], 3)

它不灵活,因为它只能用来计算一个数组中精确匹配某个值的元素的个数。

下面是一个灵活一些的版本,它能接受一个函数,而不是一个值,作为参数。我们可以用它来对任何数据、任何对象进行比较。

// more flexiblefunction count(array, matching) {    var counted = 0    for (var i = 0; i < array.length; i++) {        if (matching(array[i]))            counted++    }    return counted}// == 2, same as first examplecount([1,3,3,4,5], function(num) {    return (num == 3)})// == 2, now we can use our functions for ANY kind of items or match test!count([{name:"bob"}, {name:"henry"}, {name:"jon"}], function(obj) {    return (obj.name.length < 4)})

因为高阶函数更具灵活性,你就更少有机会去写它们,因为你一旦你写成一个,你可以它应用到各种不同的情况中。

可重复利用的比较函数

你可能注意到了,count函数的写法比countMatching更冗长。但是,虽然count函数可复用了,但比较函数2却不可复用。如果是一些简单的情况,这就足够了,但经常,我们会需要更复杂的比较方法的函数。这样的函数不仅仅可用于计数,它们可以用于任何事情上,一但你写成或找到了这样的函数,从长期的角度看,它们会节省你大量的时间和调试功夫。

让我们来定义一个可复用的比较函数,达到我们的目的。==不是一个函数。我们是否可以定义一个eq函数来帮我们完成类似的事情呢?

function eq(a, b) {    return (a == b)}count([1,3,3,4,5], function(num) {    return eq(3, num)})

我们向前迈进了一步:我们用了一个库函数来完成比较任务,而不是使用我们现写的代码。如果eq函数很复杂,我们可以测试它并可以在其它的地方复用它。

但这使代码变得冗长,因为count函数的参数是一个只需要一个参数——数组元素——的函数,而eq函数却需要两个参数。我还是要定义我们自己的匿名函数。让我们来简化一下这些代码。

function makeEq(a) {    // countMatchingWith wants a function that takes     // only 1 argument, just like the one we're returning    return function(b) {        return eq(a, b)    }}// now it's only on one line!count([1,3,3,4,5], makeEq(3))

我们写了一个兼容count函数的函数(一个参数——数组元素——返回true或false)。看起来就像是count函数调用的是eq(3, item)。这叫做偏函数用法(partial function application)。

偏函数用法(Partial Application)

偏函数用法(Partial Function Application)是指创建一个调用另外一个部分参数已经预置的函数的函数的用法。这样,它就能被别的地方,比如count函数,以更少的参数形式来调用。我们在makeEq函数里已经实现了这些,但是,我们并不想针对我们各种功能开发出各种版本的makeX(比如makeEqt,makeGt,makeLt等)函数。让我们来找一种方法能通用于各种形式的函数。

function applyFirst(f, a) {    return function(b) {        return f.call(null, a, b)    }}count([1,3,3,4,5], applyFirst(eq, 3))

现在我们不再需要一个makeEq函数了。任何2个参数的库函数,我们都可以按这种方式调用。通过偏函数用法,使得定义即使是诸如==这样简单功能的各种函数都变得十分有意义,我们可以在高阶函数中更容易的使用它们。

对那些超过2个参数的函数如何办呢?下面的这一版本3能让我们接受任意多的参数,高阶函数可以自己追加参数。

function apply(f) {    var args = Array.prototype.slice.call(arguments, 1)    return function(x) {        return f.apply(null, args.concat(x))    }}function propertyEquals(propertyName, value, obj) {    return (obj[propertyName] == value)}count([{name:"bob"},{name:"john"}], apply(propertyEquals, "name", "bob")) // == 1

我们预置了2个参数,“name” 和 “bob”,count函数补足了最后一个参数来完成整个调用。偏函数用法使我们能接受各样的函数为参数,例如eq,然后把它们用于各样的高阶函数,例如count,以此来解决我们特定的问题。

配合ES5的 Map 和 Filter 功能函数的偏函数用法

ES5里有很多非常好的高阶函数,underscore里的数量更多。让我们看看filter函数——一个接收比较函数、过滤数组内容的函数。

// this equals [1,3,3][1,3,3,4,5].filter(function(num) {    return (num < 4)})

让我们把它替换成一个可以复用的比较函数lt (less than)。

function lt(a, b) {    return (a < b)}[1,3,3,4,5].filter(apply(lt, 4))

看上去添加这个lt函数的做法有点傻,但是,我们可以使用偏函数用法来创造一个很简练的比较函数,当这个比较函数变的很复杂的时候,我们就能从对它的复用过程中获得好处。

map函数能让你把数组里的一个东西变成另外一个东西。

var usersById = {"u1":{name:"bob"}, "u2":{name:"john"}}var user = {name:"sean", friendIds: ["u1", "u2"]}// == ["bob", "john"]function friendsNames(usersById, user) {    return user.friendIds.map(function(id) {        return usersById[id].name    })}

我们写一个可以复用的map变换函数,就像之前我们的可复用比较函数一样。让我们写一个叫做lookup的函数。

function lookup(obj, key) {    return obj[key]}// == [{name:"bob"}, {name:"john"}]function friends(usersById, user) {    return user.friendIds.map(apply(lookup, usersById))}

很接近要求,但我们需要的是名称,而不是friend对象本身。如果我们再写一个参数颠倒过来的 lookup函数,通过第二次的map可以把它们的名称取出来。

function lookupFlipped(key, obj) {    return lookup(obj, key)}// == ["bob", "john"]function friendsNames(usersById, user) {    return friends(usersById, user)            .map(apply(lookupFlipped, "name"))}

但是我不想定义这个lookupFlipped函数,这样干有点傻。这样,我们来定义一个函数,它接收参数的顺序是从右到左,而不是从左到右,于是我们就能够复用lookup了。

function applyr(f) {    var args = Array.prototype.slice.call(arguments, 1)    return function(x) {        return f.apply(null, [x].concat(args))    }}// == ["bob", "john"]function friendsNames(usersById, user) {    return friends(usersById, user)            .map(applyr(lookup, "name")) // we can use normal lookup!}

applyr(lookup, "name")函数返回的函数只接受一个参数——那个对象——返回对象的名称。我们不再需要反转任何东西:我们可以按任何顺序接受参数。

偏函数用法需要对一些常见的功能定义各种不同的函数,就像lt函数,但这正是我们的目的。你可以以偏函数用法把lt函数既用于count函数,也可用于Array.filter函数。它们可以复用,可以组合使用。

函数组合

在之前的例子中,我们遍历了数组两次,一次用来获取users,一次为了获取names。如果能在一次map映射操作中同时做这两件事情,效率会高很多。

function friendsNames(usersById, user) {    return user.friendIds.map(function(id) {        var friend = lookup(usersById, id)        return lookup(friend, "name")    })}

我们得到首次lookup的结果,把它第二次传入lookup函数组合意思是串联多个函数,组成一个新的函数,每一次串联都是把前一个函数的输出当作下一个函数的输入。

让我们来写一个能这样运转的高阶函数,利用它把friendsNames函数重写成一个只需要单次map操作的函数。需要注意的是,函数串联的执行顺序是从右到左的,就跟你写出f(g(x))这样的代码的运行方式一样。

function compose(f, g) {    return function(x) {        return f(g(x))    }}function friendsNames(usersById, user) {    return user.friendIds.map(compose(applyr(lookup, "name"), apply(lookup, usersById)))}

对数组的遍历只进行了一次,只使用一次map操作,跟我们头一个例子一样。

我们不能使用我们写出的friends函数,因为它既包含了如何取出一个friend的业务逻辑,也包含了map操作。friends函数是不能复用的,它的职责太多了——它是针对特定事物的。如果你们再写一个friend函数,让它只map一个friend,写一个name函数,让它返回对象的名称呢?

var friend = lookup // lookup 恰巧能干我们想要的事情。var name = applyr(lookup, "name")function friendsNames(usersById, user) {    // this line is now more semantic.     return user.friends.map(compose(name, apply(friend, usersById)))}

相较于定义一个既包含转换操作,又包含遍历操作的friends函数,我们只定义了一个可做转换操作的friend函数,而我们已经有了map函数为我做变换操作。friend函数比friends函数更具复用性,因为它包含更少的特定业务逻辑,能在更多的情形中使用。

这里你能找到更多的关于JavaScript里函数组合的信息。

函数式和功能单一化让你的代码库更整洁

我发现我的很多的JavaScript代码都是从无到有自己写出来的。这不仅仅是说比起使用现成的程序包要效率低,它还会暗藏更多的bug,更难阅读和维护。使用高阶函数和偏函数用法,我们可以写出可复用的程序库,每个函数都精准的对应解决它们能解决的一部分问题。

随着时间的推移,项目会变得越来越复杂,各部分越来越耦合,如果我们拥有的是一个能够各自独立测试不依赖的程序库,我们的项目会从中受益,变得更健康,更稳定。

  1. 一种宽泛的组合。并不特指函数或对象组合,只是一种你用小东西组建大东西的思想。

  2. “Matching functions”被称作predicates,但我这里不想引入新的编程术语。

  3. 这里有更通用的apply实现。

[本文英文原文链接:Learn You a Haskell: For Great Good? ]

25+ 个 jQuery 网页拖放操作的插件

这篇文章为你介绍27个jQuery插件,使得你的Web前端具备拖放操作的能力。

Ajax Upload

提供文件拖放上传,并显示上传进度

drag-drop-upload

Drop n’ Save – Drag & Drop Uploader

另外一个文件拖放上传功能的实现。

drop-n-save

MORE INFO |DEMO by Codecanyon (premium plugin)

jqDnR

jqDnR作为jQuery是一个轻量级的,让你拖、放自如,并且调整其大小的元素插件。这个插件很简单,重量轻(972字节),非常容易实现。 能够让您的网站更方便用户使用。

resize-drag

jQuery Drag Expose | Draggable Image Gallery

使用一种不同的方式来显示照片,并可进行拖放操作

drag-expose

MORE INFO |DEMO by Codecanyon (premium plugin)

Sortable Lists

很酷的脚本用来对列表进行拖放操作

sortable-list

jQuery OneByOne Slider Plugin

OneByOne Slider 是一个轻量级的 jQuery 插件,可用来显示图片和文本,使用 CSS3 动画效果,支持触摸设备上的左右滑动,可使用鼠标拖放操作进行显示

onebyone-slider-plugin

MORE INFO |DEMO by Codecanyon (premium plugin)

Table Drag and Drop JQuery plugin

在表格内对行数据进行拖放

dragable-table

Dynamic Drag’n Drop With jQuery And PHP

Drag’n drop 是一个完全使用 jQuery & jQuery UI 实现的拖放功能。

jquery-drag-n-drop

Easy Scroll

可轻松实现拖放滚动效果的页面。

easy-scroll

MORE INFO |DEMO by Codecanyon (premium plugin)

Draggable

一个基于jQuery的拖放插件,易于使用,所有的操作均通过调用draggable进行。

draggable

Drag-and-Drop with jQuery: Your Essential Guide

学习如何使用 jQuery 和 jQuery UI 的拖放插件来创建具有拖放效果的 Web 应用,包含一个完整的扑克牌拖放操作演示。

drag-and-drop-guide

Zoomer jQuery Products Showcase

Zoomer! 是一个用来显示产品列表的工具,内置缩放和拖放功能。

jQuery-zoomer

MORE INFO |DEMO by Codecanyon (premium plugin)

animaDrag

AnimaDrag 允许拖拉的元素具有动画效果。

animadrag

Ultra small code to drag everything in HTML pages

这是一个很基本的快速实现拖放操作的教程,可重用以及个性化定制。

drag-everything

$.event.special.drag

这是 jQuery 的事件实现拖放事件模型,开发者无需了解太多拖放的细节。

special-drag

(mb)ConteinersPlus

很有用的插件用于实现皮肤化的容器,支持拖拉、大小更改以及最小化等操作。

drag and drop jquery plugins

resizable

可对元素使用拖放操作来更改大小

resizable

ppDrag

ppDragjQuery 的拖放插件,简化了 jQuery UI‘s Draggable.ppdrap

NestedSortable

nested-sortable

jQuery File Tree Aza’s revised version

drag and drop jquery plugins

Dragscrollable

用于在一个可视范围内滚动一个很大的嵌套层,类似地图。

dragscrollable

dragndrop

轻松实现拖放操作

dragndrop

Collidable Draggables

Adds collision detection to draggable objects. Add “collide: ‘block’” or “collide: ‘flag’” when you create a draggable: $(".box").draggable({collide: 'flag'}); or $(".box").draggable({collide: 'block'}); In ‘flag’ mode overlapping objects receive new classes – ‘ui-draggable-overlapping’ for the object being dragged and ‘ui-draggable-overlapped’ for the other object. In ‘block’ mode objects are blocked from overlapping other objects by being snapped to the edge of the object they collided with.

jQuery UI multiple draggable plugin

jQuery multiple draggable plugin 是 jQuery UI 的拖放插件扩展,可实现分组拖放draggable-plugin

jQuery List DragSort

一个轻量级的 jQuery 插件,提供拖放排序列表的功能

list-dragsort

Jquery iviewer

JQuery.iviewer 是一个用来在一个固定范围内查看图片的插件,可对图片进行缩放以及拖放移动显示

drag and drop jquery plugins

(mb)ImgNavigator

相册插件,用于显示很大的图片,通过拖放进行浏览

drag and drop jquery plugins

$().mapbox

实现类似 Google 地图的拖拉操作。

drag and drop jquery plugins

Drag n Drop Scattered Gallery

Drag and drop gallery script with various look and feel options.

scattered-gallery

MORE INFO |DEMO by Codecanyon (premium plugin)

英文原文OSCHINA原创翻译

腾讯定制Android系统“tita”上线不久被关闭

腾讯将推定制Android系统“tita” 主页被关闭

腾讯近日将推出基于Android操作系统的定制版ROM,内部已经将该系统定名为tita。

据腾讯内部人士介绍说,tita来自于音译踢踏,象徵着轻快、简洁。“tita是基于Android 4.0内核开发的,具备快速刷机功能。”上述人士介绍说,将手机连接到电脑后,只需按一个键就能完成刷机。

腾讯将推定制Android系统“tita” 主页被关闭

从腾讯内部泄露的截图显示,tita还具备“电量策略管理”“趣味短信”“高级文件管理”等功能。一位参与测试tita的用户表示,tita现在暂时只支持nexus S手机,尚不够ROM级别,“最多只能算桌面软件加上通讯录和QQ管家功能”。

此前,腾讯已经推出了中间件“QQ service”,内置一系列腾讯产品,并与HTC、华为等公司合作,推出了多款基于该平台的深度定制手机。马化腾曾多次在公开场合表示,腾讯不会自产硬件,也不会推出自有品牌手机,“腾讯会依靠与手机制造商的合作”。

RTdot:今日上午tita内测版页面(tita.qq.com)上线一段时间后,就被关闭,具体原因不详。MIUI是目前最流行的第三方ROM之一,盛大此前也推出乐众ROM,他们都是以提供本地化用户体验为卖点。tita已经有了,QPhone还会远吗?