初创团队如何提高工作效率?

http://jianshu.io/p/e61e458dbfe0

条件
初创团队:3-5人(或远程)。
工作效率:
问题1:和大公司不同,没有成熟的架构、流程,一个人往往要承担多人的工作。
问题2:时间窗问题,如果效率不高,短时间内做不到一定的质和量,就要被竞争对手搞死啦~
所以:工作效率对于早期初创团队至关重要。
本质:专注核心业务。以最短的资金和时间投入,完成非核心、但是必须要完成的事情。
要素
要素1:不要重新发明轮子。
要素2:以最低的成本(包含资金和学习成本),发现和使用最高效的工具。
个人时间管理
日历
Google:国内速度极慢,不间断被屏蔽。
Calendar(Apple):苹果设备间同步。
重点:个人时间管理。我没有用Any.do、WunderList等。暂时用不同颜色,来区分:1、公司项目,2、兴趣项目,3、个人安排。技巧:每周末需要花足够多的时间,安排下周的工作,确定重点。
硬件配置
多屏幕切换:扩展屏幕。浏览器、Evernote等放在大屏幕。聊天窗、邮件回复等放在小屏幕。
键盘、鼠标:对于每天和电脑打交道的人来说,一个机械键盘真的能提高打击的愉悦感和效率。
Mac/iPad/iPhone:Mac处理工作。iPad回复邮件。iPhone回复微信。
重点:很多人以为是装逼,其实真的是,也不全是。多屏幕解决的第1个问题是:同步处理多件小事情。举例:日历、微信、QQ、换歌同步处理。多屏幕解决的第2个问题是:平行的思考一件大事情的几个部分。举例:浏览器查资料、Evernote记录内容、回邮件。
思考内容沉淀
简书:把重要的内容沉淀下来,避免重新思考一样的事情,方便把问题的核心复制、传递~
翻墙
云梯:不解释…云梯的一个好处是,可以自由选择台湾、日本、美国、香港等不同线路,选择其中速度最快的一条。
公司内部管理
项目管理
Fengche:前一个月免费,后续收费。
TeamBition:对于互联网、设计、广告、传媒行业有流程优化。
Pivotal Tracker:程序员专用利器。
重点:任务的布置最好由Team Leader来做。这是一个思考项目整体的机会,以及静下来思考每个任务如何落地操作、难以程度、安排多少时间、几个人、任务顺序、优先级、性价比的最好的机会。即是Team Leader静下心来反思整体项目最好的机会。
文件共享工具
百度云盘:酷盘自从被收购之后,整个人都不好了…
Dropbox:对于小团队来说Dropbox基本够用了,功能也够全(或者Box)。
Google Drive:需翻墙,你懂得…
重点:合理地利用文件共享工具,能够避免很多邮件传来传去的时间。另外,高阶的文件协同编辑的功能也可以考虑~
实施会议
Fuze:远程团队沟通非常适用。
iPhone:如果只是通话,苹果自带的多人通话已经非常好用。
微信群
微信:多人工作交流不二之选。
重点:合理设置群名称、针对性挑选置顶群是一门学问。
Evernote
项目知识树链条:TeamBition、Evernote、简书。Evernote在整条知识树链条中处于中间环节。上游由TeamBition来梳理项目的整体和每个任务。下游由简书来沉淀思考、进行分享。Evernote在中游承担零星知识点的积累、梳理、归档的功能。Evernote同时也可以部分承担CRM管理、项目管理的职责。
重点:技巧1:合理地设置笔记本组、笔记本、笔记的三层关系。技巧2:充分适用Evernote提供的小功能,比如:演示、分享等。
企业邮箱
QQ企业邮箱:免费、设置方便、速度快、超大附件上传。
客户关系管理
MikeCRM:HighRise在国内的速度实在太慢。
重点:MikeCRM的几项功能:XLS导入联系人、联系人分组、邮件群发、在线问卷调查/回收。
其它
财务管理:挖财。
易耗品管理(InnoSpace广告贴):R2
项目运营
活动发布平台(做活动)
活动行:针对国内。
EventBrite:针对国外。
视频制作(做视频)
Powtoon:傻瓜式视频制作工具,整个视频制作过程和PPT制作类似。长于1分钟的视频,收费15美金/月。
重点:对于质量要求比高的视频,字幕和背景音乐是个难点。
海报(做海报)
简图:iOS APP,简洁的排版、文字少、速度快。微信转发适用~
Phoster:iOS APP,模板多。
海报工场:iOS APP,模板多(美图秀秀出品)。
Canvas:适合对设计要求较高的人群。
核心:学会”Say No”
提高工作效率的目的是:争取更多的时间段,在状态最好的时间窗内,集中处理最重要的事情~
最核心的技巧是:学会”Say No”。不要让不重要的人和事打断你。如果不确定,要有能力在最短的时间内做出判断,然后坚定地”Say No”。
“一个好销售的核心能力,是能在最短的时间内精确判断这个人是不是值得花时间去争取的客户。”

初创团队工作流与开发模式探讨

2012年版本

http://saturn.yoozi.org/iTalk/#title-slide

初创团队工作流与开发模式探讨胡杨刚(a.k.a. Saturn)
Slides and Source on Github Me 2012/11/18 ku6.com, Beijing Video
主题 Walkthrough

初创团队协作工具选型及各自角色
高效协作开发三剑客:Basecamp、Github、QQ 企业邮箱

基于 Git-Flow 的 Web 开发模型
简单介绍 Git 及 Git-Flow 开发模型

使用 Git 对 CI 应用进行自动化部署
Case Study: 利用 Github Service WebHook 调用脚本执行自动化部署

协作/开发工具选型标准 Considerations

体验:是否简单易用?
降低因引入新的工作软件/模式所带来的学习成本。

协作:是否方便多人远程协作?
完全线上协作,集中资源闹革命;不必再为无法找到合适的本地人才而烦恼。

信息整合:是否支持丰富的 API 功能?
API 方便将团队所有工具信息流进行整合、归档,形成团队专属知识库/Bug集中营。

成本:是否需要花费精力维护?是否便宜?
选用在业界具有知名度的 SaaS 型工具,降低软件维护成本和财务成本。

推荐方案 Recommendation

适合 10~50 人之间的开发团队,每月固定财务花费约 200 USD(~ 1400 CNY)。

Basecamp:产品设计与规划执行
用例:产品功能讨论(Messages)、文档协同撰写(Writeboards)、待办事项(To-Dos)、团队日历(Calendar)和时间管理(Time Tracking)

Github:源代码管理与缺陷跟踪
用例:代码托管(Git)、产品功能路线图(Milestone)、代码审查(Code Review)、Bug 跟踪(Issues)

QQ 企业邮箱:信息中心与消息推送
用例:通过绑定 QQ 或微信,将开发相关任务即时、准确的传达到每位订阅成员。

工作信息流 A Workflow for startup

Basecamp:制定产品规划与开发分工
QQ企业邮箱:成员参与讨论与制定规划
微信/QQ:推送订阅信息到指定成员
Github:开发所需功能、缺陷跟踪
生产环境服务器:自动部署上线

Why Git?

Git – the stupid content tracker
Git Manual
相较集中式版本控制工具 CVS / SVN 等,Git 的特点主要包括:

分支(Branching)成本较低。
合并(Merging)操作简单直观。
分布式离线操作。
Why Git?

Photo credit to nvie.com.

Git-Flow:一个 Git 分支模型

Photo credit to nvie.com.

简单部署模型:架构

Photo credit to https://github.com/logsol/Github-Auto-Deploy.

开发人员将代码 push 到 Github 远程服务器(Remotes/Origin)时:

触发 Git Post-Receive Hook(Git Origin 接收并处理完当前 Push 请求后均执行此钩子)。
Github 将当前 push 信息以 HTTP POST 方式调用给事先定义好的 WebHook Url(s)。
WebHook Url(s) 对应一个或多个专门用于处理产品部署逻辑的 HTTP 服务。
HTTP 服务接收 POST 数据、执行部署逻辑(如压缩合并文件和重置缓存等)、完成部署。
简单部署模型:HTTP 服务配置

HTTP 部署服务需以 Daemon 形式长期驻留系统,推荐使用 Python/Node.js 编写。

{
“port”: 8001,
“repositories”:
[{
“url”: “https://github.com/cnsaturn/iTalk”,
“path”: “/your/local/path/on/target/server/here”,
“deploy”: “make deploy” // 自定义 makefile
}]
}
简单部署模型:HTTP 服务

采用 Python 编写、用于解析 Post-Receive Hook POST 请求的 HTTP 示例服务核心逻辑:

def pull(self, path):
if(not self.quiet):
print “\nPost push request received”
print ‘Updating ‘ + path
call([‘cd “‘ + path + ‘” && git pull’], shell=True)

def deploy(self, path):
config = self.getConfig()
for repository in config[‘repositories’]:
if(repository[‘path’] == path):
if ‘deploy’ in repository:
if(not self.quiet):
print ‘Executing deploy command’
call([‘cd “‘ + path + ‘” && ‘ + repository[‘deploy’]], shell=True)
break
简单部署模型:部署逻辑(1)

程序部署除代码直接更新外,通常我们还需要处理如下问题:

前端代码优化
如压缩合并 JavaScript/CSS 文件、压缩和优化图片、CDN 文件同步。

更新程序运行环境变量
如 CI 入口文件 index.php 中的 ENVIRONMENT 常量。

数据库结构变更
重置/预加载系统缓存等其他部署逻辑。
简单部署模型:部署逻辑(2)

为了解决此问题,通常会使用 Make / Ant / Maven 等 Build 工具来实现自动化操作:

前端文件的处理使用比如 uglifyjs(npm包)、jshint(npm包)、yuicompressor(jar包)来实现。
环境变量的替换可以事先制作成模板,然后按需替换。
数据库结构变更在 CI 中可使用 DB Migration 库轻松实现。

一个想法变成靠谱的创业项目

大部分的创业想法一开始都是十分不靠谱的,都是满怀对理想中的未来充满憧憬,觉得所有人未来应该是这样,客户对这个需求庞大甚至超出预估值,自己找到了新蓝海,自己在改变世界,那么理想与现实差距到底有多大呢?这次我把朋友的一个创业想法的演变过程展现给大家看看,这样可以让大家看到更多细节,可以更清晰地了解一个不靠谱的创业项目想法如何变成一个靠谱的创业项目。
从一个想法,变成一个靠谱的想法
文浩是在一次偶然的机会下看到刘子骏创办的小猫家网站后认识的,他加了我在网站上留下的QQ号与我交流他的创业计划。文浩之前是在四大会计事务所之一的机构工作,是项目组的经理,虽然待遇还可以,但他每天的工作就是要对着一大堆渺无生趣的数字,然而他觉得这不是他想要的生活,所以他开始计划起自己的创业项目,当他看到小猫家的网站后觉得这很符合他创业的风格,所以主动与我交流,并约我出来面谈。
我有一个想法
在他朋友的酒吧里,文浩拿出iphone手机给我展示了一些国外知名的创意家具品牌,还有一些做创意家居概念设计师做的作品,他说他有一个想法,想创办一家专为年轻人打造的创意家居公司,并且联系了一些国外的设计师可以帮忙做家具的设计,希望可以打造出国内知名的家具品牌出来,然后问我觉得怎么样。其实我做小猫家也是因为对创意家具产品有浓厚的兴趣才创办的,文浩的想法跟我的兴趣点很合拍,所以我很赞赏他的创业项目。不过这次见面我们也只是闲聊了一些家居网站和家居款式,没有聊到具体如何开展如何经营等问题。
然后接下来的几次我们都是约在这家酒吧里聊,但是聊了好几次之后我发现每次跟文浩聊的很多都是行业趋势,行业动态和概念性的东西,没有聊到具体应该如何把想法实现的层面上。所以有一晚我就跟文浩说,这样聊下去是不会有结果的,我们应该聊的是如何把想法落实到行动上,这样我们的交流才有意义,否则我们的思路一直在场外跑,这不会有任何进展的。当时我们是在聊的很开心的情况下,突然被我杀出这句话,文浩立刻被震惊到了。其实在当时聊天的过程中,我大概知道文浩一直有一些顾虑,家具不像快消品,买了一次可能要很久很久才会买第二次,所以用户黏性和用户的边际价值不会很大,这样是很难形成规模式的增长。而且生产能力也是一个很大的问题,所以综合各种原因让文浩开始犹豫不决。
第一次转变
在相隔几个月之后,文浩再次联系我,这次他说已经找到很好的方向了,这次依然是做家居产品,但是不再做大型的家具,只做小型的家居用品,例如泰国进口的手工皂,还有一些小型的收纳柜子等等。并且还屯了不少货,看上去比之前更有信心了。毕竟这次选的都是小件物品,而且都是家居型的快消品,这些产品不再有之前的众多顾虑了。不过他进的这些产品在网上同类太多了,加上价格没有太多优势,而且他的业务市场就是在互联网,所以最后也只能先放放。
第二次转变
就在前两个月文浩再次联系我,不过这次转变很大,可以说是直接转型了,确实让我很惊讶。这次不是做家居产品,而是直接转成做蛋糕了。他觉得生活只需多一点情趣,多一点惊喜,多一点味道就能让生活品质变得更美好,所以他的品牌叫”一点”,英文名Little&CO。选择蛋糕是因为蛋糕是最好的媒介,蛋糕给人的感觉就是快乐和喜悦,所以他要从这一点开始为顾客的生活带来惊喜。他借鉴了很多蛋糕店和蛋糕培训机构,他觉得去蛋糕店完全直接购买一个现成的,太没有心思了。但是如果完完全全靠自己去学习去制作,这要花费太多的精力和时间了,而且自己去采购所有的原材料确实挺麻烦的,所以他这次采用的是提供一整套完整的原材料和工具,并且把部分材料优先处理好,这样顾客就不需要电子秤,量杯,量勺等工具了,让原本需要1个多小时完成的蛋糕,现在只需20分钟即可做完所有功夫。这样对于客户来说既减少了原材料采购的时间和麻烦,也加快了制作蛋糕的速度,而且这块还没有任何蛋糕企业在做,所以他对这块蓝海充满信心。
考虑到目标消费群体都是年轻一族,所以他选择了冻酸奶蛋糕作为主打产品,蛋糕的主要材料就是冻酸奶,饼底采用消化饼+黄油,这样感觉会更香脆。选择这款蛋糕也是考虑到很多家庭都没有烤箱,而这款蛋糕只需要有冰箱就可以制作了,这确实能让顾客可以更简便地操作和降低了顾客的成本。这款蛋糕吃起来不会像传统用奶油制作的蛋糕那么腻,而且夏天吃会有种吃雪糕的感觉口感特好,确实挺适合夏季推出。很快文浩就买齐所有的工具和设备,然后邀请我过去体验了一下制作蛋糕的过程,这个过程确实很快,对于一个没有制作蛋糕经验的我来说确实能在20分钟左右就可以完成蛋糕的制作,当然这是有文浩的帮忙才这么顺利。当时就只差设计师出外包装和LOGO,项目就可以完全启动了。
第一个顾客发现的硬伤
我把我第一个亲手做的蛋糕带回公司与同事们分享,同事们品尝后都觉得味道不错,总共15人,14人给了好评,1人觉得还可以,成绩不错。最后大家都给了不少建议,觉得饼底可以再做厚一些,口味可以再多一些等等。我把信息反馈给文浩,他也很高兴,毕竟他的产品获得了大家的认可。
隔了一个多星期之后,同事小强走进了我的办公室,说他女朋友下个星期二生日,他品尝过我做的蛋糕,觉得很不错,所以自己也想做一个送给他的女朋友,给她一个惊喜。我立刻把这个好消息告诉文浩,他也非常高兴,这是第一个真正付费的顾客,然后文浩就立刻去安排材料等事情了。我也很高兴的去跟小强说一切都没有问题,但是突然我想到了一个问题,我问小强你家有没有打蛋器,因为做蛋糕手打是不行的,不单止效率慢,而且能把蛋糕做好的几率几乎为零。当小强回复” 木有”的时候,我的大脑跳了一下,这怎么办呢?小强也不会为了做个蛋糕专门去买一个可能一年才用一次的打蛋器。如果借打蛋器给小强用,这是可以的,毕竟是同事,但是其他顾客呢?不可能每次都连打蛋器一起卖吧,当然这也可以,但是如果我们的目标顾客群体是针对每天早九晚六的年轻上班族,他们有多少愿意这样来配套购买呢?首先在我面前的小强一定不会,很多顾客也不会,因为他们要的是蛋糕,而不是打蛋器。
这个周末我约了文浩出来给他说我想到的东西,我把小强的情况跟他讲了一遍,确实有很多年轻人家里都没有打蛋器等工具,所以如果这样看来这项目的经营模式对于顾客端来说太重了不够轻,顾客除了购买我们的产品,而且还需要购买其他配套的东西,这是很难推广项目的便利性的,所以说这是这个项目的一大硬伤。
还有顾客购买的是半加工后的原材料,虽然减少了部分工作量,但是针对的用户群会非常模糊,喜欢做蛋糕或会做蛋糕的专业人群一定不会给你指定的原材料绑死,他们会自己采购喜欢的原材料来制作蛋糕,普通消费群体对做蛋糕一窍不通,单纯给原材料和教程他们一定只会做出一个失败的作品,就像我没有了文浩这样有制作蛋糕经验的人带着做,我做的蛋糕也会失败。而且这还没有完,当顾客购买你的东西制作失败后,他们会觉得你品牌的产品真烂,心里各种负面情绪都会展现出来,在这个自媒体时代,负面信息传播速度是最快的,后果可想而知。
最后我给文浩建议把模式改成直接做好整个蛋糕基底卖给顾客,然后让顾客在上面自己DIY放水果放自己喜爱的食物,这样不但可以大大减少了顾客很多不必要的劳动,而且增加了客户参与感和乐趣。毕竟做蛋糕基底又繁琐又无趣,而且又凸显不了顾客的自我价值,但是如果顾客可以在一个现成的蛋糕基底上发挥自己的想象力和创意,我觉得这才是顾客想要的,而且这对于顾客来说非常轻便,只需要去买点水果什么的就可以自己设计了。这种模式最最大的好处是带给顾客更轻便的体验,而且又不丢失顾客的参与感。
这模式还能延伸很多周边消费,例如我们可以提供蛋糕花样的制作教程,我们可以把材料和制作教程一起卖,还有如果顾客需要制作特殊的花纹图案,我们也可以销售花纹磨具给顾客,而且我们还可以定制包装盒,让收到蛋糕的对象获得更多惊喜。
其实我们公司之前同事生日的时候,我们就尝试问过很多蛋糕店,蛋糕店基本都不干,他们就是靠蛋糕上面的花纹样式设计来赚钱,单单卖个蛋糕基底给顾客看上去就不那么值钱了,而且这样也卖不出多少钱,所以蛋糕店一定不会这样干。而蛋糕培训中心呢,他们主要是培训做蛋糕的整个流程,如果只是教教他们在蛋糕基底上设计样式,可能就收取不了几千块甚至上万块的培训费了。所以这样的模式才有突围的可能,项目的运营和推广工作才会更容易开展。
以上就是一个创业项目想法的整个演变过程,我们注意到一开始大家都是很理想化地思考项目的前景而忽视了项目要面对的诸多问题,所以不要被你理想化的思路忽悠到,大量现实的问题都隐藏在理想化的下面。就像我提醒文浩要把思路回归到执行上面后,他就发现原来项目要实现起来会有这么多阻力,考虑到阻力太大并且无法解决的时候,适当作出改变是很好的解决方式。有很多创业者盲目地信奉坚持就是胜利,最后越做越困难越做越不好做,最终导致失败。所以当你准备执行你的创业项目时,发现原来有很多顾虑都没有很好的方式来解决的时候,这就表明你的地利不足,可以适当考虑调整业务模式或转型,甚至停止,没必要去硬碰南墙。
没有完美的想法和计划,只有执行时不断的补丁
其实当所有产品和想法都没有触碰到真正消费者的时候,这个项目都只是个人的猜想或个人的需求而已,并不代表市场。你看做这个蛋糕项目大家都觉得想法不错,大家品尝蛋糕的时候都给予了相当好的评价。但是当遇到第一个真正顾客小强的时候,项目的硬伤立刻就凸显出来了。注意,这个消费者并不是你请朋友品尝,请朋友评价就能获取到真正需要的信息,必须是消费对象有这样的需求,并且愿意付费的情况下,这样才能发现真正的问题。
还有现在的创业模式必须够轻才能快速走起,这个轻不单指企业的经营模式,消费者那边的使用也要够轻才行。像刚刚蛋糕的项目,企业要花时间来把原材料加工,消费者也需要购买工具,有了工具还未必能把蛋糕做好,所以这种模式对于企业和消费者来说太重太麻烦了。经过改良后,企业直接批量制作蛋糕底盘就可以,而消费者买了蛋糕底盘只需要买些水果等材料就可以轻松实现DIY蛋糕的梦想了,两边都轻松,而且够简便。
可能最初的那个想法是你一直想做,但是鉴于现在的能力和资源不能实现,那可以先放放,找一个能符合你现状的项目启动它,当你有钱、有人脉、有资源的时候回头过来再做也不迟。或许到那个时候你会发现现在做的项目原来是可以跟最初的想法完美结合成一个新产品或新模式。就像上面的例子,文浩一开始想做的是家居产品,后来改做蛋糕,说不定以后家居产品和蛋糕可以结合成新的商业模式呢。
所以说创业是没有完美的想法和计划,只有执行时不断的补丁!

SCSS 与 Sass 的不同

SCSS 是 Sass 3 引入新的语法,其语法完全兼容 CSS3,并且继承了 Sass 的强大功能。也就是说,任何标准的 CSS3 样式表都是具有相同语义的有效的 SCSS 文件。另外,SCSS 还能识别大部分 CSS hacks(一些 CSS 小技巧)和特定于浏览器的语法,例如:古老的 IE filter 语法

由于 SCSS 是 CSS 的扩展,因此,所有在 CSS 中正常工作的代码也能在 SCSS 中正常工作。也就是说,对于一个 Sass 用户,只需要理解 Sass 扩展部分如何工作的,就能完全理解 SCSS。大部分扩展,例如变量、parent references 和 指令都是一致的;唯一不同的是,SCSS 需要使用分号和花括号而不是换行和缩进。 例如,以下这段简单的 Sass 代码:

#sidebar
  width: 30%
  background-color: #faa

只需添加花括号和分号就能转换为 SCSS 语法:

#sidebar {
  width: 30%;
  background-color: #faa;
}

另外,SCSS 对空白符号不敏感。上面的代码也可以书写成下面的样子:

#sidebar {width: 30%; background-color: #faa}

还有一些不同是比较复杂的。这些将在下面进行详细讲解。建议先看看Sass 3 语法差异。在继续学习 SCSS 之前请务必理解下面这些内容。

Nested Selectors

To nest selectors, simply define a new ruleset inside an existing ruleset:

#sidebar {
  a { text-decoration: none; }
}

Of course, white space is insignificant and the last trailing semicolon is optional so you can also do it like this:

#sidebar { a { text-decoration: none } }

Nested Properties

To nest properties, simply create a new property set after an existing property’s colon:

#footer {
  border: {
    width: 1px;
    color: #ccc;
    style: solid;
  }
}

This compiles to:

#footer {
  border-width: 1px;
  border-color: #cccccc;
  border-style: solid; }

Mixins

A mixin is declared with the @mixin directive:

@mixin rounded($amount) {
  -moz-border-radius: $amount;
  -webkit-border-radius: $amount;
  border-radius: $amount;
}

A mixin is used with the @include directive:

.box {
  border: 3px solid #777;
  @include rounded(0.5em);
}

This syntax is also available in the indented syntax, although the old = and + syntax still works.

This is rather verbose compared to the = and + characters used in Sass syntax. This is because the SCSS format is designed for CSS compatibility rather than conciseness, and creating new syntax when the CSS directive syntax already exists adds new syntax needlessly and could create incompatibilities with future versions of CSS.

Comments

Like Sass, SCSS supports both comments that are preserved in the CSS output and comments that aren’t. However, SCSS’s comments are significantly more flexible. It supports standard multiline CSS comments with /* */, which are preserved where possible in the output. These comments can have whatever formatting you like; Sass will do its best to format them nicely.

SCSS also uses // for comments that are thrown away, like Sass. Unlike Sass, though, // comments in SCSS may appear anywhere and last only until the end of the line.

For example:

/* This comment is
 * several lines long.
 * since it uses the CSS comment syntax,
 * it will appear in the CSS output. */
body { color: black; }

// These comments are only one line long each.
// They won't appear in the CSS output,
// since they use the single-line comment syntax.
a { color: green; }

is compiled to:

/* This comment is
 * several lines long.
 * since it uses the CSS comment syntax,
 * it will appear in the CSS output. */
body {
  color: black; }

a {
  color: green; }

@import

The @import directive in SCSS functions just like that in Sass, except that it takes a quoted string to import. For example, this Sass:

@import themes/dark
@import font.sass

would be this SCSS:

@import "themes/dark";
@import "font.sass";

快速上手Git Gitlab协同合作

简单记录,整理。

摘要

为方便大家快速上手Git,并使用Gitlab协同合作,特编写此手册,手册内容不会太丰富与深入。
主要包含如下内容:

  1. Git 使用教程
    1.1 安装
    1.2 常用命令
    1.3 版本控制
    1.4 分支与tag
  2. Gitlab 使用教程
    2.1 界面简介
    2.2 常用功能介绍
    2.3 注意事项
  3. 多人协作流程与规范
    3.1 永久与临时分支
    3.2 工作流图
    3.3 规范
  4. Code Review
    4.1 为什么要有Code Review
    4.2 如何进行?
  5. 参考资料

    后续会加入CI,自动部署等。

1. Git 使用教程

1.1 安装

建议安装最新版本,及1.7以上。

下载地址:Git下载页面
官方安装教程:安装教程

1.2 常用命令

在Linux和Mac下直接用终端操作即可;Windows下需要右键打开 “git bash”进行操作。

使用公司的gitlab库,需要忽略验证证书合法性
git config http.sslVerify false

a. 克隆代码库至本地
地址在gitlab.xsjcs.cn项目中获得,请选择https 地址
git clone https://gitlab.xsjcs.cn/powerking/log-sever.git

b. 修改文件并提交
git add file-name
git commit -m "注释"

注释一定要详细,不能是”test”,”update”之类的。并尽量采用英文说明。

c. 推送到远程分支,默认是所有
git push

d. 推送至主分支
git push origin master

更多命令请参考:

Git命用命令

Git命令速查

1.3 版本控制

通常我们在本地提交代码库是git add && git commit 命令,在需要提交到远程时才使用git push 。
因此git 的版本控制分为2块。本地和远程。

在本地命令操作中,还可以采用git reset HEAD 来撤销提交,以及git checkout 来恢复文件。

因此git 文件夹存在三个区域:

实际目录:实际修改的文件。
待提交区:暂存准备提交的内容,提交之后被清空。(也叫做index区)
已提交区:提交到本地git版本库的内容,有版本号。
对这三个区域的操作都可以在本地离线完成。

同时可以通过git status查看文件状态

文件总共四种状态:
与git repository一致
与git repository不一致,已缓存
与git repository不一致,未缓存
还未添加到git repository

通常我们在本地操作完成后,会提交到远程的自己的分支,或开发分支。因此就涉及分支的知识。

1.4 分支与tag

分支是用来将特性开发分开来的,在创建仓库时,master是默认主干。通常我们还会创建一个开发分支”Develop”,以及一个测试分支”testing”。每个开发人员需要开发新功能时,在本地再创建一个自己的分支”feature_a”,然后再将分支提交测试或开发,由相关人员测试并审核通过后,merge到主干。

创建一个feature_a 的分支,并切换到该分支:
git branch feature_a
git checkout feature_a
切换回主:
git checkout master
查看本地分支列表:
git branch -a
删除分支:
git branch -d feature_a

合并分支
合并分支前通常需要使用git diff查看提交的版本差异。在gitlab界面有diff界面可以帮助我们查看。如果没有异常可以配置自动合并,如果自动合并报冲突时,需要手动操作。
git add 标记相关信息
git merge 合并其它分支到当前分支,合并前需要先确认当前分支。

2. Gitlab 使用教程

Gitlab界面比较简洁,目前公司配置的gitlab不支持ssh方式。只能采用http(S)进行。但用户注册后,需要配置个人信息,特别是头像。建议都配置。

2.1 界面简介

貌似这个没啥好写的,特别个人头像即可。

2.2 常用功能介绍

创建Groups : 通常我们会给一个项目创建一个组。比如:网管中心、xoyobox、运维小组开发工具。
创建User: 目前开放注册,后续需要邮件申请。
将用户加入组:在创建组后,可以选择将不同的用户加入组进行协同开发。
创建Project: 项目可以选择归属那个组,在创建时,也可以选择导入。创建后,初始化信息注册选择http(s)协议。

2.3 注意事项

由于公司配置https 证书没有购买,当前还没有申请免费的key,所以需要配置忽略验证证书合法性:
git config http.sslVerify false

更多使用可参考:如何使用Gitlab

3. 多人协作流程与规范

为避免2个或多个人同时修改一个功能,或开发一个新的feature,需要有严格的规范或流程进行约束。
因此我们需要创建永久分支与临时分支。

3.1 永久与临时分支

永久分支:master develop testing
临时分支:在开发或发布时创建,使用一段时间后删除。
master: 主干分支,线上发布的稳定版本。以偶数为版本号。
develop:开发分支,将测试完成,或不需要测试的分支一起merge至master。发布时,以奇数为版本号。
testing:测试分支,供前期测试使用的分支,可以不加版本号。

几个重要的说明:

feature

作用:开发新功能
分支来源:develop
结束时:merge develop
说明:特性分支,用来为下一个版本开发新特性。一般只存在开发者本地。

release

作用:发布新版本
分支来源:develop
结束时:merge develop / master
说明:为新产品发布是做支持,一般用于发版,线上环境更新。需要有一定的版本更新说明,bugfix说明,等。提取出来后,只允许小的修改,不允许再增加新的feature。

hotfix

作用:修复发行版本的bug
分支来源:master
结束时:merge develop / master
说明:打补丁

3.2 工作流图

见图

3.3 规范

约定:

  1. master分支中的任何版本都可以立即部署
  2. 每次master变更都来自其它分支的master合并操作
  3. 对master修改必须要有review
  4. 不允许存在奇数版本

4. Code Review

4.1 为什么要有Code Review

不觉明厉

4.2 如何进行?

  1. 建议在gitlab界面进行
  2. 提交代码时需要注册分支及版本号
  3. 使用本地git flow 进行合并操作

5. 参考资料

Github-flow
Git_Gitlab

基于REM的EMs弹性布局, 页面布局孰优孰劣

页面布局的方式总是随着技术的更新和创意的涌现不断的更新换代。从最开始的 Fixed 固定布局,到因为宽屏设备和移动互联网的普及产生的响应式和自适应,再到「Mobile First」的设计理念,前端们在可用性方面做的努力越来越多。

REM 是一个在 CSS3 中被提出的新单位,相对 EM 变为了针对根元素 <html> 的 font-size 计算,使得便利性大为提升的弹性布局再次被提上话题。在介绍具体实现之前,不妨先说说为何要选择 EMs 进行布局。

脱离了表格布局的蛮荒时代后,越来越多的基本布局方式被应用在了实践中,当然也不乏多种配合。以下就是几个常用技术的对比。(响应式和自适应这两个名词经常被错误使用,例如 自适应网页设计(Responsive Web Design) 这篇文章

  • 固定 Fixed
    使用 px 和 pt 这样的绝对单位进行固定布局。在无论什么设备上保持固定的尺寸,在不适合的分辨率下可能导致大面积空白或横向滚动条。最经典,也是被证明极其不友好、维护困难的方法。
  • 流动 Fluid
    使用 % 百分比进行相对布局。可以根据可视区域 (viewport) 和父元素的实时尺寸进行调整,尽可能的适应各种分辨率。往往配合 max-width 等属性控制尺寸流动范围以免过大或者过小影响阅读。某些情况下可能导致错误的伸缩或者布局被破坏。
  • 弹性 Elastic
    使用 em 或 rem 单位进行相对布局。避免了根据 px 布局在高分辨率下几乎无法辨认的缺点,又相对 % 百分比更加灵活,同时可以支持浏览器的字体大小调整和缩放等的正常显示。需要一段时间适应而且不易从其他布局转换过来,但几乎是目前最好的布局方式。
  • 伸缩 Flexbox
    使用 CSS3 Flex 系列属性进行相对布局。对于富媒体和复杂排版的支持非常强大,但是还未普及并且兼容性较差。
  • 响应式 Responsive
    使用 @media 媒体查询 给不同尺寸和介质的设备切换不同的样式。在优秀的响应范围设计下可以给适配范围内的设备最好的体验,但是在同一个设备下实际还是固定的布局,并且因为浏览器的支持原因对介质的检测还不实用。
  • 自适应 Adaptive
    通常使用 @media 媒体查询 和网格系统 (Grid System) 配合相对布局单位进行布局,实际上就是利用响应式、流动等上述技术通过 CSS 给单一网页不同设备返回不同样式的技术综合统称。自适应几乎已经成为优秀页面布局的标准。

弹性布局在一众相对布局中毫无疑问拥有极大的优势。除了以上提到的几点之外,以下几点也是非常有用的特性:

  • 优秀的兼容性
    不同于 FlexBox 等初生标准,浏览器对于 em 的支持非常的好,同时对于 rem 的支持也比预料中稍佳。如果使用 LESS 或者 SASS 等 CSS 预处理器,还可以做对于低版本浏览器 (IE8-) 的 px 降级处理。CanIUse 的兼容表
  • 哇!我看不到像素点
    使用绝对尺寸单位进行布局的最大缺点,就是在动辄1080P的手机屏幕上将小到难以阅读,同时过高的分辨率也会使媒体查询无法发挥应有的功效。但是如果使用 em 字体大小进行布局,就可以方便的利用系统默认字号设定了。
  • 对于浏览器用户字体大小设置的支持
    对于视力障碍和残障人士,可以在浏览器的设置中更改字体的大小,但不同浏览器迥异的缩放模式经常使得使用固定尺寸单位的网站布局崩溃,而这种时候 EMs 单位可以保证完全一致自然的效果。
  • 对于页面缩放的响应式支持
    在平常阅读中也常有缩放页面的需要,弹性布局可以在缩放中正确的激活响应式。反观使用绝对单位判断的响应式,可能在部分浏览器中当缩放的实际显示空间不够时仍然使用为大可视区域设计的样式,容易导致布局崩溃。不过在现代浏览器中已经会激活对应的查询。
  • 保持一致的换行
    完全使用 EMs 单位进行布局的话,缩放过程中文字和图片不会产生流动,可以完美的保持布局的美观和稳定。

尽管如此,随之而来的还有一些美中不足的小问题。如果还有发现其他弊端,也欢迎 在此回复 。

  • 如何惹恼 Work Flow 上的其他人
    在完整的工作流程中,各种原型、视觉、切图很难全部使用 em 作为计量单位,只能在前端实现的时候转换。而且默认的 1em:16px 计算也较为不便,后面会提到一个巧妙的解决方法。
  • 麻烦的父级元素 font-size 继承
    如果使用 em 作为尺寸单位,因为 em 相对父元素 font-size 值进行计算的特性,如果中间有对元素的字体大小进行更改,子元素的全部布局就会出错。这点现在可以很方便的通过相对于根元素的 rem 单位计量来避免。
  • 不该放大的图片
    假如为图片使用了 em 设定尺寸,在响应不同设备的字体时就会按比例增大而导致模糊。但是如果使用常规的 px 设定尺寸,又会失去文字排版均一的好处。考虑到平常的设计中文字流动并没有影响,可以稍微牺牲可用性而用 px 设定图片尺寸。
  • 养成坏习惯容易,好习惯难
    从 ems 单位切换到 px 或者 pt 只需要简单的单位转换,而从绝对单位向弹性布局转换绝对不是一个好的体验。因此在项目开始时就应该确定好弹性布局的基础,否则后期迁移并不容易。

那么如何开始一个弹性布局的页面呢?不不不,除了使用 em 作为单位表示尺寸之外,还有一些可以用到的技巧:

  • 为根元素设置 font-size: 100%
    在 IE 上的文字缩放选项并不符合常规情况下的预期,即在特大和特小的情况下缩放不是平滑的,很容易导致文字被缩放到难以阅读的程度。此时就可以为 <html> 元素指定 100% 的字体大小,以即时响应用户的缩放。
  • 为文档元素设置 font-size: 62.5%
    先前已经提到过,尽管所有浏览器都一致的保持着 16px 的默认字号,但是 1:16 的比例明显十分不方便计算。将字号设为 10px 会使 Ems 布局前功尽弃,此时通过设置为 16px 的 62.5% 就可以很方便的利用十进制进行计算了。当然如果你选择使用的是 rem 为单位,需要牺牲低版本 IE 的兼容性将 <html> 的 font-size 设为 62.5% 。
  • 为媒体查询使用 ems
    对于前面提到的对 Retina 高清分辨率屏幕的支持,使用 em 为单位的媒体查询就是一个有用的技巧。当每行能容纳的文本少于某个值时进行响应而不是宽度为某个像素进行响应,将会大大改善响应式设计的使用体验。
  • 为 rem 使用预处理器
    随着 rem 的推出,弹性布局最大的麻烦之一得到解决。但是尽管 em 的支持已很有历史, rem 却仅支持最新的几个浏览器版本,在低版本浏览器上的显示效果将会是灾难级的。提前使用 SASS 等 CSS 预处理器为低版本浏览器准备好一个 px 为单位的降级很有必要,这里不再详述,可自行查找相关资料。

基本上只要明确了以上几点,就可以按平常的方法继续进行网页的布局。不过正因为弹性布局是一个为阅读体验而生的技术,在这方面稍加注意,还可以更好的发挥弹性布局的优势。

  • 让行高保持节奏
    这是一个提高阅读体验的绝妙方法 —— 让所有元素的行高始终保持为一个值的倍数,想想网页是平铺在一个有行线的笔记本上,让每个元素都完美的占据多格的中间而不压线。请注意,没有阅读体验的弹性布局一文不值。
  • 提供不同文字大小的样式
    很多站点都会为了照顾不同用户提供大中小的样式表,在弹性布局下的实现更加容易。如果用户不懂得更改浏览器的显示设定,仅需要提供 body 元素 font-size 不同的几个样式表,即可马上对整个网页进行缩放。
  • 不必关注像素,而是比例
    尽管为了配合视觉设计我们需要在实际过程中进行 px 到 em 的转换,但是因为缩放的存在,实际需要聚焦的核心不是尺寸本身而是整体布局的比例。只要确定正常视图下布局处在一个合理的大小和位置,剩下的交给 ems 就好了。
  • 脱离样式表可用
    这是和弹性布局无关的一条可用性建议。永远为网页保持合理的 DOM 结构,不为了样式服务颠倒顺序,让网页即使脱离样式表也十分完美。如此一来就算是在屏幕阅读器、字符浏览器等极端环境下,仍然可以保持最大化的体验。

尽管在中国并不十分流行,弹性布局仍然是一个极其优秀和体验良好的布局方式。互联网的发展促进了信息的传播,然而推广网页设计的无障碍化仍然需要很多的努力。在日新月异的网格、瀑布流等布局出现的今天,弹性布局依旧不失为追求简洁和阅读享受的网页设计师的一具利器。

最后吐槽一下,经过长时间的搜集资料和准备,花了两天晚上且中间间隔两周才把这篇文章写了出来。感觉依旧完全是在罗列要点,没有多少文采和趣味可言,不知何时写技术文章的文笔才能好一点呢……

phonegap安装 环境搭建与配置详解(3.4 完整版 提供下载地址)

phonegap 3.4  安装 环境搭建 完整版

刚刚接触 phonegap 因为配环境遇到各种各样问题.花了一下午时间才完成,所以写一个篇文章希望能给大家节约点时间.

      本文主讲windows系统下的phonegap的环境搭建 ,以android视角为主.ios用户可参考;

首先介绍搭建环境的基本准备:

1 java JDK   (搜索一下…….)

2 android SDK 最新版(我当时的版本是 API 19  点击打开链接)

3 Ant 打包工具  (百度一个或者 点击打开链接)

4 eclipse   (建议使用google的  因为内置ADT     点击打开链接 )

5 ADT (ecplise 里的插件,安卓开发工具插件     下载上面的链接,内部集成了ADT)

6 Node.js   (点击打开链接)

7 sublime  点击打开链接 ;是我开发js h5 css 的工具;如果大家有好的开发软件希望能告诉我一下谢谢

下图是Node.js安装成功后

SouthEas

将以上配置好环境变量  (配置方法略 点击 )

特别提一下需要配环境变量的东西:  java JDK  ; android SDK;Ant ; 

贴上我的 path 供大家参考:

 (建议配成 ;%ANT_HOME%\bin;  去掉\bin)

F:\工具\Ant\ant-1.8\bin;     

C:\Develop\sdk\sdk\platform-tools;C:\Develop\sdk\sdk\tools;%Android%\.;C:\Develop\nodejs;%JAVA_HOME%\bin;C:\Develop\nodejs\

拥有以上工具后 

接下来开始phonegap的安装了

 phonegap 官网 点击

在控制台运行命令:

npm install -g phonegap                                     ( Mac使用: sudo npm install -g phonegap )

//等待安装   完成后安装 cordova:

 npm install -g cordova                                       ( Mac使用: sudo npm install -g cordova )

SouthEast

SouthEast

安装完成后
检验语句:

phonegap -version

cordova -version

SouthEast

SouthEast

在命令行 使用:

[html] view plaincopy::__IHACKLOG_REMOTE_IMAGE_AUTODOWN_BLOCK__::1
  1. phonegap create my-app  
  2. cd my-app  
  3. phonegap run android  

第一个 phonegap写的程序就出现了

在my-app 目录下出现5个文件夹     打包好的工程放在platforms里面

SouthEast

文件夹详解:

www              : 文件夹  开发的 HTML5 ; CSS ; JS 文件都拷贝到这下面

plugins          : 文件夹  存放的是phonegap插件  以后 文件,摄像头等插件都下载到这里,在下篇文章中介绍用法 

merges          : 我也没用过  以后知道了再补上

platforms      : 文件夹 存放的是编译好后的android文件   ,(如果这个文件夹为空,需要你在命令行编译一次才能生成. 如上面 phonegap run android)

.cordova        : 存放的是配置文件 

将此文件夹导入 eclipse 就可以使用

phonegap 将以第三方库的形式导入

如果src文件报错 检查是否是   phonegap的功能没有导入进来

导入eclipse后  文本结构….下图打的camera 和 vibration 是 相机与铃声的插件  下章节介绍

SouthEast

(图 1)

下图是     phonegap的启动页面  调用 super.loadUrl(); 方法

[java] view plaincopy::__IHACKLOG_REMOTE_IMAGE_AUTODOWN_BLOCK__::3
  1. public class baozi extends CordovaActivity   
  2. {  
  3.     @Override  
  4.     public void onCreate(Bundle savedInstanceState)  
  5.     {  
  6.         super.onCreate(savedInstanceState);  
  7.         super.init();  
  8.         // Set by <content src=”index.html” /> in config.xml  
  9. //        super.loadUrl(Config.getStartUrl());  
  10.         super.loadUrl(“file:///android_asset/www/index.html”);  
  11.             
  12.           
  13.     }  
  14. }  

在 super.loadUrl(”  “); 中填写你的启动页面

参数: ” file:///android_asset/www/index.html “

指的是( 图  1)的  assets目录下 www 文件夹下的  index.html

贴上一张 工程导入后的属性图

SouthEast

工程下载    将phonegap的platforms导入到eclipse中

如果报错clear一下  查看导的lib包 有没有报错

如果还有错  那么就是您选用了  google的API   改成最新版的android  API 就好了

如果导入工程遇到问题 可以查阅我此篇文章

Blog:  http://blog.csdn.net/aaawqqq/article/details/20463183

Phonegap解决错误:Error initializing Cordova:Class not found:

 

http://blog.csdn.net/aaawqqq/article/details/21243869

新一代Web packs UI 组件系统 Polymer

怎么看都像是未来趋势啊

在今年的Google I/O大会上,Google发布了Polymer,它是一个使用Web组件构建Web应用的类库,同时也使用了为Web构建可重用组件的新的HTML 5标准。Polymer为大部分Web组件技术提供了polyfills功能,它能让开发者在所有的浏览器支持新特性前创建自己的可重用组件。此外,Polymer提供了一系列的部件的例子,其中包括天气、时钟、股票行情和线型图。 
Web组件让开发者能创建自定义和可重用的HTML 标记。下面的例子中,是一个<my-own-tag>标记组件的框架:

<element name="my-own-tag">
 <template>
   HTML elements here
 </template>
 <script>
   // JavaScript implementing logic
 </script>
</element>

鉴于许多Web框架通过暴露JavaScript API来构建用户界面,而构建用户界面实际上就是生成一堆div和spans标记,Web 组件是原生浏览器的解决方案因此不依赖于一个完整的框架。因此,与现在的一般依赖某个Javscript框架的HTML组件相比,Web组件希望能减少碎片

尽管Web组件是一项有趣的新技术,但在浏览器们都支持它们(并且大部分用户都开始使用这些浏览器们)之前,其中的大部分功能还派不上用场。解决这个问题的一种方法是使用polyfills(译者注:polyfills原指一种墙面填料)。polyfill指的是一段代码,它能实现期望最终由浏览器自身实现的功能。如果浏览器本身已经实现了该功能,则polyfill什么都不做。否则,它模拟其实现而不依赖API。例如,webshims库实现了HTML5中各种功能,包括canvas、HTML5表格和在某些尚不支持地理位置定位的浏览器中实现地理位置定位功能。

Polymer中的polyfills为需要使用Web组件成功构建应用提供了多种Web技术,包括:

  • HTML imports:种在其他HTML document中引入和重用HTML document的方法。
  • 自定义元素:让开发者定义和使用自定义DOM元素。
  • Shadow DOM:在DOM中提供的封装。
  • 模型驱动视图(Model Driven Views):提供象AngularJS的数据绑定。
  • ·Web动画:实现复杂动画的API。
  • ·Pointer事件:对鼠标触摸和手写笔事件的封装

这些polyfills可以分开使用而不需要使用Polymer的其他部分。此外,Polymer提供:

  • polymer.js: Polymer的核心运行引擎,能轻易创建自定义属性和事件。
  • 一系列可重用的可视和非可视元素。


Polymer不是第一个尝试实现Web组件相关标准的项目。Mozilla在此之前启动了X-Tag项目——针对自定义元素标准的polyfill。Web UI package 使用Google的Dart语言编写了Model Driven View技术从而实现了自定义元素。

用户可以在YouTube上观看Google I/O大会关于Polymer的演讲。如果用户想了解更多关于Web组件的信息,可以观看Google I/O上Web组件的演讲。另外,用户可以在Polymer的网站查看导学文章和其他相关文档。

查看英文原文:Use Web Components Today With Google’s Polymer

阅读 : Sketch 3 的新变化

Sketch 3 的新变化

满足一切所想,并且超过期待

我从2014年2月底就开始使用 Sketch 3 。在此为大家介绍其中一些新的特性,告诉你要玩转新版软件,值得注意的地方。

过去的一年里,我写过几篇文章、在谷歌举办了一些内部研讨会,一直在推广 Sketch 软件。许多人(不仅仅是设计师们)把自己的工具切换到Sketch上。通过这次更新, Bohemian Coding 身体力行地表达了他们的座右铭:倾听、制作、发布

以快到惊人的节奏,每天他们都在推送推送大量的更新和修正,而这是个仅由2名工程师、3名设计师组成的团队。

事实上,他们几乎解决了我在 第一篇博客 中列出的、所有希望它们改进的问题。

让我们沉浸其中吧!

新的用户界面

新的用户界面[+]查看原图

用户界面焕然一新:新的图标、搜索栏如今不再隐藏、可以过滤图层和切片、对齐工具挪到了检查器面板、可供单击的翻转按钮。大工具条下面不再有小工具条了。这些细小的变化,给人感觉非常的清新。

各就各位,各司其职

检查器面板

检查器面板现在只有一级深度,字体和颜色选择器不需要再进第二层了。这里很多其他的功能都改变了位置。逻辑非常简单:所有的在 Sketch 2 中放错位置的东西,都归到了它们应该在的地方。

画板

创建画板的方式发生了一点点改变。

Sketch 3 的新变化 – 画板

曾经这是让人非常困扰的事情之一。现在你可以为所有的画板选择背景色,在导出时可以选择是否导出背景色。不用再在画板底层画一个锁定矩形当背景了,这真是大快人心。

为画板选择背景色

你可以在“画板设置( Artboard Settings )”检查器里找到这个选项

插入

插入菜单多了新内容[+]查看原图

插入菜单多了新内容。一些在 Sketch 2 的界面中漏掉的功能已经被合情合理地加进这个菜单了。

共享的元素

工具条中的元件按钮

要定制工具条,右击工具条,选择“定制工具条( Customize Toolbar )”

像很多其他功能一样,共享元素重新恢复了。而且这次更明显、也更实用。

他们还加入了呼声最高的功能之一:元件。你现在可以很轻松地跨页面创建、编辑和共享元素。

元件

每次在解释为什么切换到 Sketch 时,我经常遇见的问题是:“有像 Fireworks 的元件功能么?”我知道这确实是一个大家最想要的功能,而 Bohemian 的程序员没有失信于它们的用户。他们以一种聪明、高效的方式把它实现了。

就像你想象的那样,它会使你的生活简单很多。

Sketch 3 的新变化 – 元件

图层样式

创建和更改图层样式的界面现在变得非常友好。这个功能在 Sketch2 中就在手边但是非常难用。没有办法命名或者辨别相似的样式。

Sketch 3 的新变化 – 图层样式

样式链接

在左边,当一个形状被链接,它的图标会变成紫色。

文字样式

Sketch 3 的新变化 – 文字样式

和之前的非常相像,只是更好用了。就像视频中展示的哪样,仍然有一些使用上的限制。

导出

导出功能被重新构思,更贴近你的工作流。它不再是一个分离的操作模式。你可以象操作设计元素一样设置切片和切片参数。切片的创建和导出从没有这么简单过。新的切片工具让我意识到,以前为了创建一个特殊尺寸的画板来导出设计,我花费了多少时间。

Sketch 3 的新变化 – 导出

非常酷的新功能之一就是你可以导出多个预先设定的尺寸,或者设置你自己的导出尺寸。如果你同时给 Andriod 设备做设计,这个功能将会节省你很多时间,省去很多麻烦。对于未来的任何设备分辨率它也是非常灵活的。这里添加了一个选项,允许你自定义文件名字的后缀。

多尺寸导出[+]查看原图

我没这么用过,但你可以将同一个尺寸导出为不同的格式。我想这个功能非常有用,便于你在更复杂的产品、特别是 Web 设计中,要同时保存 PNG 、 JPG 和 SVG 等多种格式。

UI 元素

Teehanlax 宣布 他们著名的 iOS7 GUI 模板将会被内置到 Sketch 3 中。你可以在模板( Template )菜单中找到它。第一页说明了这个文档的结构,第二页重新将全部可用的元件摆在一起。你还可以在 Web Design 模板中找到面向网页的元件。

UI元素模板[+]查看原图

矢量和位图编辑

矢量编辑[+]查看原图

矢量和位图编辑工具同样被移动到检查器面板中。这样就直接多了,而且有更多的空间来用图标解释点编辑工具。至于位图编辑工具也有了新的选项,但还是一些基本功能,并且不再隐藏。如果你需要,现在有了一个好用的魔术棒工具。

位图编辑

反选、剪切、填充选区、多边形选区

最后一个功能很有趣,不过表现恐怕不尽人意。位图矢量化,这是一项非常复杂的处理过程,所以不要期望一张非常复杂的图片能转换成可以无限缩放的文件。

颜色选择器

颜色选择器

纯色、线性渐变、径向渐变、锥形渐变、图案填充、噪点填充

你会发现,熟悉的颜色选择器工具变成了一个弹出层。之前在重新摆放调色盘时会出现讨厌的颜色随机乱序问题,也得到了修正。

其他改进

所有这些我刚才描述的是你们用眼睛可以看到的,不过我们经常忘记谈论性能。举例来说,“画板预览列表”过去很慢,不过已经彻底地改进了。预览的缓慢速度经常让我灰心丧气。这个问题看上去已经解决掉了。载入大文件也明显快了很多。

将来的改进?

我有一些想法可以使我们的生活变的简单。其中的一些可能已经以插件的形式存在了,然而还是让我列举出来,这些很酷的功能有:

  • 共享元件:想象你在一个团队里工作,大家在忙同一个项目。你知道维护一个基本设计资源库是多棘手的事,我想我们这样解决问题:创建一个设计资源库,在这里提交你的图标,然后同事们都能使用。

  • 应用内购商店:作为一间小型创业公司,要面对很多难题,其中之一就是如何获得持续的现金流。基于共享元件的思路,我们可以想象一个应用内购商店,在这里出售图标集、样式、渐变、网格, UI 元素等。

  • 自动标注:如果已经做过类似的事情,你就知道这是工作流中必要的一环,但很花时间,是不是有什么自动化的方法来实现。想象你可以导出你的模型,其中包括了网格布局以及所需要的数值:字体尺寸、颜色、元素尺寸和边距。值得一提的是我刚写完这段,有人已经 做出插件 了!

  • 按钮元件:现在元件有了,如果能创建按钮模板就好了,可以在里面输入文字、同时持固定的边距。有一个 插件 已经做了这项工作,不过还是希望可以和元件更好地整合起来。

  • 批量命名:现在搜索变得给力了,给图层命名就非常重要。RenameIt 插件已经做了这项工作,不过如果成为内置功能会更酷。

Mongoose学习参考文档——基础篇

一、快速通道

1.1 名词解释

  • Schema : 一种以文件形式存储的数据库模型骨架,不具备数据库的操作能力

  • Model : 由Schema发布生成的模型,具有抽象属性和行为的数据库操作对

  • Entity : 由Model创建的实体,他的操作也会影响数据库

注意

1.本学习文档采用严格命名方式来区别不同对象,例如:

varPersonSchema;//Person的文本属性varPersonModel;//Person的数据库模型varPersonEntity;//Person实体

2.SchemaModelEntity的关系请牢记,Schema生成ModelModel创造EntityModelEntity都可对数据库操作造成影响,但ModelEntity更具操作性。

1.2 准备工作

1.首先你必须安装MongoDBNodeJS

2.在项目只能够创建一个数据库连接,如下:

var mongoose =require('mongoose');//引用mongoose模块var db = mongoose.createConnection('localhost','test');//创建一个数据库连接

3.打开本机localhosttest数据库时,我们可以监测是否有异常

    db.on('error',console.error.bind(console,'连接错误:'));
    db.once('open',function(){//一次打开记录});

注意

  成功开启数据库后,就可以执行数据库相应操作,假设以下代码都在回调中处理

4.定义一个Schema

varPersonSchema=new mongoose.Schema({
      name:String//定义一个属性name,类型为String});

5.将该Schema发布为Model

varPersonModel= db.model('Person',PersonSchema);//如果该Model已经发布,则可以直接通过名字索引到,如下://var PersonModel = db.model('Person');//如果没有发布,上一段代码将会异常

6.用Model创建Entity

var personEntity =newPersonModel({name:'Krouky'});//打印这个实体的名字看看
    console.log(personEntity.name);//Krouky

7.我们甚至可以为此Schema创建方法

//为Schema模型追加speak方法PersonSchema.methos.speak =function(){
      console.log('我的名字叫'+this.name);}varPersonModel= db.model('Person',PersonSchema);var personEntity =newPersonModel({name:'Krouky'});
    personEntity.speak();//我的名字叫Krouky

8.Entity是具有具体的数据库操作CRUD

    personEntity.save();//执行完成后,数据库就有该数据了

9.如果要执行查询,需要依赖Model,当然Entity也是可以做到的

PersonModel.find(function(err,persons){//查询到的所有person});

注意

  1. 具体的如何配置SchemaModel以及ModelEntity的相关操作,我们会在后面进行

  2. ModelEntity都有能影响数据库的操作,但仍有区别,后面我们也会做解释

二、新手指引

  如果您还不清楚Mongoose是如何工作的,请参看第一章快速通道快速浏览他的用法吧

1. Schema——纯洁的数据库原型

1.1 什么是Schema

  • 我理解Schema仅仅只是一断代码,他书写完成后程序依然无法使用,更无法通往数据库端
  • 他仅仅只是数据库模型在程序片段中的一种表现,或者是数据属性模型

1.2 如何定义Schema

varBlogSchema=newSchema({
      title:String,
      author:String//new Schema()中传入一个JSON对象,该对象形如 xxx:yyyy ,/xxx是一个字符串,定义了属性,yyy是一个Schema.Type,定义了属性类型});

1.3 什么是Schema.Type

  Schema.Type是由Mongoose内定的一些数据类型,基本数据类型都在其中,他也内置了一些Mongoose特有的Schema.Type。当然,你也可以自定义Schema.Type,只有满足Schema.Type的类型才能定义在Schema内。

1.4 Schema.Types

  NodeJS中的基本数据类型都属于Schema.Type,另外Mongoose还定义了自己的类型

//举例:varExampleSchema=newSchema({
      name:String,
      binary:Buffer,
      living:Boolean,
      updated:Date,
      age:Number,
      mixed:Schema.Types.Mixed,//该混合类型等同于nested
      _id:Schema.Types.ObjectId,//主键
      _fk:Schema.Types.ObjectId,//外键
      array:[],
      arrOfString:[String],
      arrOfNumber:[Number],
      arrOfDate:[Date],
      arrOfBuffer:[Buffer],
      arrOfBoolean:[Boolean],
      arrOfMixed:[Schema.Types.Mixed],
      arrOfObjectId:[Schema.Types.ObjectId]
      nested:{
        stuff:String,}});

1.5 关于Buffer

  BufferArrayBufferNodejs两种隐藏的对象,相关内容请查看NodeJS-API

1.6 关于Mixed

  Schema.Types.MixedMongoose定义个混合类型,该混合类型如果未定义具体形式。因此,如果定义具体内容,就直接使用{}来定义,以下两句等价

varAnySchema=newSchema({any:{}});varAnySchema=newSchema({any:Schema.Types.Mixed});

  混合类型因为没有特定约束,因此可以任意修改,一旦修改了原型,则必须调用markModified()

    person.anything ={x:[3,4,{y:'change'}]}
    person.markModified('anything');//传入anything,表示该属性类型发生变化
    person.save();

1.7 关于ObjectId

  主键,一种特殊而且非常重要的类型,每个Schema都会默认配置这个属性,属性名为_id,除非自己定义,方可覆盖

var mongoose =require('mongoose');varObjectId= mongoose.Schema.Types.ObjectId;varStudentSchema=newSchema({});//默认会有_id:ObjectIdvarTeacherSchema=newSchema({id:ObjectId});//只有id:ObjectId

  该类型的值由系统自己生成,从某种意义上几乎不会重复,生成过程比较复杂,有兴趣的朋友可以查看源码。

1.8 关于Array

  ArrayJavaScript编程语言中并不是数组,而是集合,因此里面可以存入不同的值,以下代码等价:

varExampleSchema1=newSchema({array:[]});varExampleSchema2=newSchema({array:Array});varExampleSchema3=newSchema({array:[Schema.Types.Mixed]});varExampleSchema4=newSchema({array:[{}]});

1.9 附言

  Schema不仅定义了文档结构使用性能,还可以有扩展插件实例方法静态方法复合索引文档生命周期钩子

  Schema可以定义插件,并且插件具有良好的可拔插性,请有兴趣的读者继续往后阅读或者查阅官方资料。

2. Schema的扩展

2.1 实例方法

  有的时候,我们创造的Schema不仅要为后面的ModelEntity提供公共的属性,还要提供公共的方法。

  下面例子比快速通道的例子更加高级,可以进行高级扩展:

varPersonSchema=newSchema({name:String,type:String});//查询类似数据PersonSchema.methods.findSimilarTypes =function(cb){returnthis.model('Person').find({type:this.type},cb);}

  使用如下:

varPersonModel= mongoose.model('Person',PersonSchema);var krouky =newPersonSchema({name:'krouky',type:'前端工程师'});
    krouky.findSimilarTypes(function(err,persons){//persons中就能查询到其他前端工程师});

2.2 静态方法

  静态方法在Model层就能使用,如下:

PersonSchema.statics.findByName =function(name,cb){this.find({name:newRegExp(name,'i'),cb});}varPersonModel= mongoose.model('Person',PersonSchema);PersonModel.findByName('krouky',function(err,persons){//找到所有名字叫krouky的人});

2.3 索引

  索引或者复合索引能让搜索更加高效,默认索引就是主键索引ObjectId,属性名为_id索引会作为一个专题来讲解

2.4 虚拟属性

  Schema中如果定义了虚拟属性,那么该属性将不写入数据库,例如:

varPersonSchema=newSchema({
      name:{
        first:String,last:String}});varPersonModel= mongoose.model('Person',PersonSchema);var krouky =newPersonModel({
      name:{first:'krouky',last:'han'}});

  如果每次想使用全名就得这样

    console.log(krouky.name.first +' '+ krouky.name.last);

  显然这是很麻烦的,我们可以定义虚拟属性

PersonSchema.virtual('name.full').get(function(){returnthis.name.first +' '+this.name.last;});

  那么就能用krouky.name.full来调用全名了,反之如果知道full,也可以反解firstlast属性

PersonSchema.virtual('name.full').set(function(name){var split = name.split(' ');this.name.first = split[0];this.name.last= split[1];});varPersonModel= mongoose.model('Person',PersonSchema);var krouky =newPersonModel({});
    krouky.name.full ='krouky han';//会被自动分解
    console.log(krouky.name.first);//krouky

2.5 配置项

  在使用new Schema(config)时,我们可以追加一个参数options来配置Schema的配置,形如:

varExampleSchema=newSchema(config,options);

  或者使用

varExampleSchema=newSchema(config);ExampleSchema.set(option,value);

  可供配置项有:safestrictcappedversionKeyautoIndex

2.5.1 safe——安全属性(默认安全)

  一般可做如下配置:

newSchema({...},{safe:true});

  当然我们也可以这样

newSchema({...},{safe:{j:1,w:2,wtimeout:10000}});

  j表示做1份日志,w表示做2个副本(尚不明确),超时时间10秒

2.5.2 strict——严格配置(默认启用)

  确保Entity的值存入数据库前会被自动验证,如果你没有充足的理由,请不要停用,例子:

varThingSchema=newSchema({a:String});varThingModel= db.model('Thing',SchemaSchema);var thing =newThing({iAmNotInTheThingSchema:true});
    thing.save();//iAmNotInTheThingSchema这个属性将无法被存储

  如果取消严格选项,iAmNotInTheThingSchema将会被存入数据库

  该选项也可以在构造实例时使用,例如:

varThingModel= db.model('Thing');var thing1 =newThingModel(doc,true);//启用严格var thing2 =newThingModel(doc,false);//禁用严格

注意:

  strict也可以设置为throw,表示出现问题将会抛出错误

2.5.3 shardKey

  需要mongodb做分布式,才会使用该属性

2.5.4 capped——上限设置

  如果有数据库的批量操作,该属性能限制一次操作的量,例如:

newSchema({...},{capped:1024});//一次操作上线1024条数据

  当然该参数也可是JSON对象,包含size、max、autiIndexId属性

newSchema({...},{capped:{size:1024,max:100,autoIndexId:true}});
2.5.5 versionKey——版本锁

  版本锁是Mongoose默认配置(__v属性)的,如果你想自己定制,如下:

newSchema({...},{versionKey:'__someElse'});

  此时存入数据库的版本锁就不是__v属性,而是__someElse,相当于是给版本锁取名字。

  具体怎么存入都是由MongooseMongoDB自己决定,当然,这个属性你也可以去除

newSchema({...},{versionKey:false});

  除非你知道你在做什么,并且你知道这样做的后果

2.5.6 autoIndex——自动索引

  该内容将在索引章节单独讲解

3. Documents

  Document是与MongoDB文档一一对应的模型,Document可等同于Entity,具有属性和操作性

注意:

  Document的`CRUD都必须经过严格验证的,参看2.5.2 Schema的strict严格配置

3.1 查询

  查询内容过多,专题讲解

3.2 更新

  有许多方式来更新文件,以下是常用的传统方式:

PersonModel.findById(id,function(err,person){
      person.name ='MDragon';
      person.save(function(err){});});

  这里,利用Model模型查询到了person对象,该对象属于Entity,可以有save操作,如果使用Model`操作,需注意:

PersonModel.findById(id,function(err,person){
      person.name ='MDragon';var _id = person._id;//需要取出主键_iddelete person._id;//再将其删除PersonModel.update({_id:_id},person,function(err){});//此时才能用Model操作,否则报错});

  update第一个参数是查询条件,第二个参数是更新的对象,但不能更新主键,这就是为什么要删除主键的原因。

  当然这样的更新很麻烦,可以使用$set属性来配置,这样也不用先查询,如果更新的数据比较少,可用性还是很好的:

PersonModel.update({_id:_id},{$set:{name:'MDragon'}},function(err){});

  需要注意,DocumentCRUD操作都是异步执行,callback第一个参数必须是err,而第二个参数各个方法不一样,updatecallback第二个参数是更新的数量,如果要返回更新后的对象,则要使用如下方法

Person.findByIdAndUpdate(_id,{$set:{name:'MDragon'}},function(err,person){
      console.log(person.name);//MDragon});

  类似的方法还有findByIdAndRemove,如同名字,只能根据id查询并作update/remove操作,操作的数据仅一条

3.3 新增

  如果是Entity,使用save方法,如果是Model,使用create方法

//使用Entity来增加一条数据var krouky =newPersonModel({name:'krouky'});
    krouky.save(callback);//使用Model来增加一条数据varMDragon={name:'MDragon'};PersonModel.create(MDragon,callback);

  两种新增方法区别在于,如果使用Model新增时,传入的对象只能是纯净的JSON对象,不能是由Model创建的实体,原因是:由Model创建的实体krouky虽然打印是只有{name:'krouky'},但是krouky属于Entity,包含有Schema属性和Model数据库行为模型。如果是使用Model创建的对象,传入时一定会将隐藏属性也存入数据库,虽然3.x追加了默认严格属性,但也不必要增加操作的报错

3.4 删除

  和新增一样,删除也有2种方式,但EntityModel都使用remove方法

4.Sub Docs

  如同SQL数据库中2张表有主外关系,Mongoose将2个Document的嵌套叫做Sub-Docs(子文档)

  简单的说就是一个Document嵌套另外一个Document或者Documents:

varChildSchema1=newSchema({name:String});varChildSchema2=newSchema({name:String});varParentSchema=newSchema({
      children1:ChildSchema1,//嵌套Document
      children2:[ChildSchema2]//嵌套Documents});

  Sub-Docs享受和Documents一样的操作,但是Sub-Docs的操作都由父类去执行

varParentModel= db.model('Parent',parentSchema);var parent =newParentModel({
      children2:[{name:'c1'},{name:'c2'}]});
    parent.children2[0].name ='d';
    parent.save(callback);

  parent在执行保存时,由于包含children2,他是一个数据库模型对象,因此会先保存chilren2[0]chilren2[1]

  如果子文档在更新时出现错误,将直接报在父类文档中,可以这样处理:

ChildrenSchema.pre('save',function(next){if('x'===this.name)returnnext(newError('#err:not-x'));next();});var parent =newParentModel({children1:{name:'not-x'}});
    parent.save(function(err){
      console.log(err.message);//#err:not-x});

4.1 查询子文档

  如果childrenparent的子文档,可以通过如下方法查询到children

var child = parent.children.id(id);

4.2 新增、删除、更新

  子文档是父文档的一个属性,因此按照属性的操作即可,不同的是在新增父类的时候,子文档是会被先加入进去的。

  如果ChildrenSchema是临时的一个子文档,不作为数据库映射集合,可以这样:

varParentSchema=newSchema({
      children:{
        name:String}});//其实就是匿名混合模式

5.Model

5.1 什么是Model

  Model模型,是经过Schema构造来的,除了Schema定义的数据库骨架以外,还具有数据库行为模型,他相当于管理数据库属性、行为的类

5.2 如何创建Model

  你必须通过Schema来创建,如下:

//先创建SchemavarTankSchema=newSchema({
      name:'String',
      size:'String'});//通过Schema创建ModelvarTankModel= mongoose.model('Tank',TankSchema);

5.2 操作Model

  该模型就能直接拿来操作,具体查看API,例如:

var tank ={'something',size:'small'};TankModel.create(tank);

注意:

  你可以使用Model来创建EntityEntity实体是一个特有Model具体对象,但是他并不具备Model的方法,只能用自己的方法。

//通过Model创建Entityvar tankEntity =newTankModel('someother','size:big');
  tankEntity.save();

6.Query

  查询是数据库中运用最多也是最麻烦的地方,这里对Query解读的并不完善,仅仅是自己的一点领悟而已。

6.1 查询的方式

  通常有2种查询方式,一种是直接查询,一种是链式查询(2种查询都是自己命名的)

6.1.1 直接查询

  在查询时带有回调函数的,称之为直接查询,查询的条件往往通过API来设定,例如:

PersonModel.findOne({'name.last':'dragon'},'some select',function(err,person){//如果err==null,则person就能取到数据});

  具体的查询参数,请查询API

6.1.2 链式查询

  在查询时候,不带回调,而查询条件通过API函数来制定,例如:

var query =PersonModel.findOne({'name.last':'dragon'});
    query.select('some select');
    query.exec(function(err,pserson){//如果err==null,则person就能取到数据});

  这种方式相对直接查询,分的比较明细,如果不带callback,则返回queryquery没有执行的预编译查询语句,该query对象执行的方法都将返回自己,只有在执行exec方法时才执行查询,而且必须有回调。

  因为query的操作始终返回自身,我们可以采用更形象的链式写法

Person.find({ occupation:/host/}).where('name.last').equals('Ghost').where('age').gt(17).lt(66).where('likes').in(['vaporizing','talking']).limit(10).sort('-occupation').select('name occupation').exec(callback);

7.Validation

  数据的存储是需要验证的,不是什么数据都能往数据库里丢或者显示到客户端的,数据的验证需要记住以下规则:

  • 验证始终定义在SchemaType
  • 验证是一个内部中间件
  • 验证是在一个Document被保存时默认启用的,除非你关闭验证
  • 验证是异步递归的,如果你的SubDoc验证失败,Document也将无法保存
  • 验证并不关心错误类型,而通过ValidationError这个对象可以访问

7.1 验证器

  1. required 非空验证
  2. min/max 范围验证(边值验证)
  3. enum/match 枚举验证/匹配验证
  4. validate 自定义验证规则

  以下是综合案例:

varPersonSchema=newSchema({
      name:{
        type:'String',
        required:true//姓名非空},
      age:{
        type:'Nunmer',
        min:18,//年龄最小18
        max:120//年龄最大120},
      city:{
        type:'String',enum:['北京','上海']//只能是北京、上海人},
      other:{
        type:'String',
        validate:[validator,err]//validator是一个验证函数,err是验证失败的错误信息}});

7.2 验证失败

  如果验证失败,则会返回err信息,err是一个对象该对象属性如下

    err.errors                //错误集合(对象)
    err.errors.color          //错误属性(Schema的color属性)
    err.errors.color.message  //错误属性信息
    err.errors.path             //错误属性路径
    err.errors.type             //错误类型
    err.name                //错误名称
    err.message                 //错误消息

  一旦验证失败,ModelEntity都将具有和err一样的errors属性

8.Middleware中间件

8.1 什么是中间件

  中间件是一种控制函数,类似插件,能控制流程中的init、validatesaveremove`方法

8.2 中间件的分类

  中间件分为两类

8.2.1 Serial串行

  串行使用pre方法,执行下一个方法使用next调用

var schema =newSchema(...);
    schema.pre('save',function(next){//做点什么next();});
8.2.2 Parallel并行

  并行提供更细粒度的操作

var schema =newSchema(...);
    schema.pre('save',function(next,done){//下一个要执行的中间件并行执行next();
      doAsync(done);});

8.3 中间件特点

  一旦定义了中间件,就会在全部中间件执行完后执行其他操作,使用中间件可以雾化模型,避免异步操作的层层迭代嵌套

8.4 使用范畴

  1. 复杂的验证
  2. 删除有主外关联的doc
  3. 异步默认
  4. 某个特定动作触发异步任务,例如触发自定义事件和通知

  例如,可以用来做自定义错误处理

    schema.pre('save',function(next){var err =newEerror('some err');next(err);});
    entity.save(function(err){
      console.log(err.message);//some err});

http://cnodejs.org/topic/504b4924e2b84515770103dd