2016年7月

关于设计转码,有一个更新被大家所认可的名称,叫作“切图”,在本文中我没有使用“切图”二字的原因在于,在我所理解的设计转码工作中,并不只是切图这么简单。

长久以来我们怎么做?

自从出现Web这个事物开始,每一个Web页面就会经历从产品需求到设计到出图到转码的这么一个过程,虽然技术变革给我们带来了很多炫酷的工具以帮助我们更加快速、方便的进行这样的工作,但是最终工具终归是工具,人,这一动作的主体永远都无法去掉:

  1. 产品提出需求,制作产品交互原型;
  2. 设计师根据产品的交互原型制作精美的设计图;
  3. 切图工作者将设计图转换成HTML静态页面。

上面是我们最常见的工作流程,而用到的工具最多的还是 Photoshop,对于切图工作者,用到得最多的又是 Photoshop 里面的 切片工具,它能快速的将一整张PSD图切割为很小的块,然后导出,再从导出的图片里面选取我们需要的使用即可(而在以前,很多人更是直接使用了 Photoshop 导出的HTML进行修改即直接应用到最终的产品代码中去)。

长久以来我们又有什么样的问题?

按上面这种工作流程,看似很平常不过了,也特别符合我们心理预期的工作流程,但是,却有很多问题:

  1. 交互原型在很大程度上已经给设计定型了,比如交互原型里面会指出哪里有按钮,哪里是一个列表,哪里有一个表格,哪里放一个Banner等;
  2. 设计师很多时候仅仅只是美化交互原型,比如将按钮改个配色,调整一下元素的尺寸,画一个漂亮的Banner,精细的设计师会让自己的设计图精确到一个像素,这就是我们常说的像素级精确的设计;
  3. 而切图工作者在将设计转码的过程中,为了保证还原度,很多时候也很无奈的只能使用切图工具将设计图导出为一些图片切片,然后再用代码拼接到整个页面中,硬性的将Photoshop里面的图层对应到CSS里面的Layers中,然后定位也像设计图版的像素级的去调整。

这种方式所带来的最大的问题,并不是最终成品的效果不好,而是,整个工期太长,尤其是在响应式布局以及移动设备流行之后,更是在绝大多数情况下,压根就无法满足生产的需要了。

后来大家都又想过什么样的解决办法?

说起前面这些问题的解决办法,我想最多的,还是都没有解决最终问题,因为工作流程都没有想过要去改变,还是产品-设计-转码这样的流程,那这样的流程就决定了永远都存在切图这一个工种,而解决的办法就是提升这个流程中每一个环节的工作效率,比如各种各样的在线或者线下的工具,用于将导入的PSD自动按图层、分组等导出;或者制定PSD文件的制作标准(比如图层如何分组、名称应该如何定等),但是问题依旧存在。

对于新手,可能还是先使用Photoshop切出图片,然后再一边写着HTML一边写着CSS,最后缓慢的完成一个产品,而我自己也总结了一套自己的切图方式,还算比较快速:

  1. 先浏览所有设计图,找出设计图中通用的布局与元素样式,先将这些基础的元素转为代码(此时基本上不需要切图,因为绝大多数情况下都能直接使用CSS样式化出来同样或者特别接近的效果);
  2. 使用上一步完成的基础的样式库一般都完成所有页面的布局与样式工作;
  3. 再对每一页的特殊元素进行特殊处理。

这个方式在技术上一般是下面这样的书写步骤:

  1. 先看图直接完成所有元素与布局的HTML结构;
  2. 完成HTML结构之后,再完成CSS样式;
  3. HTML中,基础元素全部使用 class 而不是ID
  4. ID 直接应用到整个Page。

关于上面所用方式的一段代码示例

<body id="page-name-id">
  <header>
    <h1>网页名称</h1>
    <nav>
      <a href="index.html" title="网站名称">首页</a>
      <a href="about.html" title="关于我们">关于</a>
    </nav>
  </header>
  <div class="columns">
    <article class="news-item">
      <h2>文章标题</h2>
      <p>内容</p>
    </article>
    <aside>
      ...
    </aside>
  </div>
</body>

而后,CSS中有可能有两份

body {...}
header {...}
article {...}
h2 { ... }
article h2 { ... }
...

然后对于某个单独的页面

#page-name-id article {...}

这上面这些工作都完成之后,就到了切图的工作了,但是与以前的切图工作不再一样的是,不再是使用切片工具将整个图都切出来,而是按需要将元素取出来,在很多,一张设计图只需要取出图标、背景、Banner等元素即可。

解决问题的一种方法

我一直都是属于那种比较偷懒的人,如果想要解决切图的问题,那最好就是压根就不存在这个问题,但是如何可以让我们的工作流程中规避掉?

某一种方法

改变现有工作的工具以及工作方式个人感觉应该是最好不过的方式了,大概的思路是:

技术结构

  1. 版本管理: Git/Gitlab
  2. 文档编写: Markdown / Office Word
  3. 交互原型与设计: Sketch / Photoshop

基本工作流程

  1. 产品人员出产品需求文档,详细描述产品功能细节;
  2. 交互设计使用Sketch制作交互原型;
  3. 设计师使用直接美化Sketch交互原型,若有需要细化设计的图片,使用Photoshop单独制作并导入Sketch文档;
  4. 前端开发人员直接按照Sketch进行开发,不需要切图流程,直接使用Sketch导出所有资源文档,设计中关于颜色、尺寸的测量等直接以Sketch中的样式标注为准即可。

2016年7月9日-10日,参加了由北京野狼户外徒步登山队组织的北京首次夜穿库布齐沙漠的活动,包括来回车程在内,总共用了近36个小时,这是我人生中第一次进入沙漠,第一次穿越沙漠,还是夜穿,感觉很带劲儿。

我们是9日早上七点四十从北京西直门出发,经河北到内蒙古,大巴于9日下午6:40到达库布齐沙漠西侧,一直往东穿越至响沙湾景区,总路程18公里,历时12个小时后,于早上七点到达等候我们的大巴上回程。

_DSC0629.jpg

_DSC0618.jpg

_DSC0598.jpg

_DSC0697.jpg

_DSC0867.jpg

还人生中第一次拍下了自己的银河照,感觉还过得去吧。

_DSC0845.jpg

_DSC0846.jpg

_DSC0901.jpg

_DSC0889.jpg

全程视频记录

直接在下方难看,或者进入视频网站 http://v.qq.com/x/page/y0312n9l2c5.html 观看.

1.遍历数组法

最简单的去重方法, 实现思路:新建一新数组,遍历传入数组,值不在新数组就加入该新数组中;注意点:判断值是否在数组的方法“indexOf”是ECMAScript5 方法,IE8以下不支持,需多写一些兼容低版本浏览器代码,源码如下:

// 最简单数组去重法
function unique1(array){
  var n = []; //一个新的临时数组
  //遍历当前数组
  for(var i = 0; i < array.length; i++){
    //如果当前数组的第i已经保存进了临时数组,那么跳过,
    //否则把当前项push到临时数组里面
    if (n.indexOf(array[i]) == -1) n.push(array[i]);
  }
  return n;
}
// 判断浏览器是否支持indexOf ,indexOf 为ecmaScript5新方法 IE8以下(包括IE8, IE8只支持部分ecma5)不支持
if (!Array.prototype.indexOf){
  // 新增indexOf方法
  Array.prototype.indexOf = function(item){
    var result = -1, a_item = null;
    if (this.length == 0){
      return result;
    }
    for(var i = 0, len = this.length; i < len; i++){
      a_item = this[i];
      if (a_item === item){
        result = i;
        break;
      }  
    }
    return result;
  }
}

2.对象键值对法

该方法执行的速度比其他任何方法都快, 就是占用的内存大一些;实现思路:新建一js对象以及新数组,遍历传入数组时,判断值是否为js对象的键,不是的话给对象新增该键并放入新数组。注意点: 判断是否为js对象键时,会自动对传入的键执行“toString()”,不同的键可能会被误认为一样;例如: a[1]、a["1"] 。解决上述问题还是得调用“indexOf”。

// 速度最快, 占空间最多(空间换时间)
function unique2(array){
  var n = {}, r = [], len = array.length, val, type;
    for (var i = 0; i < array.length; i++) {
        val = array[i];
        type = typeof val;
        if (!n[val]) {
            n[val] = [type];
            r.push(val);
        } else if (n[val].indexOf(type) < 0) {
            n[val].push(type);
            r.push(val);
        }
    }
    return r;
}

3.数组下标判断法

还是得调用“indexOf”性能跟方法1差不多,实现思路:如果当前数组的第i项在当前数组中第一次出现的位置不是i,那么表示第i项是重复的,忽略掉。否则存入结果数组。

function unique3(array){
  var n = [array[0]]; //结果数组
  //从第二项开始遍历
  for(var i = 1; i < array.length; i++) {
    //如果当前数组的第i项在当前数组中第一次出现的位置不是i,
    //那么表示第i项是重复的,忽略掉。否则存入结果数组
    if (array.indexOf(array[i]) == i) n.push(array[i]);
  }
  return n;
}

4.排序后相邻去除法

虽然原生数组的”sort”方法排序结果不怎么靠谱,但在不注重顺序的去重里该缺点毫无影响。实现思路:给传入数组排序,排序后相同值相邻,然后遍历时新数组只加入不与前一值重复的值。

// 将相同的值相邻,然后遍历去除重复值
function unique4(array){
  array.sort(); 
  var re=[array[0]];
  for(var i = 1; i < array.length; i++){
    if( array[i] !== re[re.length-1])
    {
      re.push(array[i]);
    }
  }
  return re;
}

5.优化遍历数组法

源自外国博文,该方法的实现代码相当酷炫;实现思路:获取没重复的最右一值放入新数组。(检测到有重复值时终止当前循环同时进入顶层循环的下一轮判断)

// 思路:获取没重复的最右一值放入新数组
function unique5(array){
  var r = [];
  for(var i = 0, l = array.length; i < l; i++) {
    for(var j = i + 1; j < l; j++)
      if (array[i] === array[j]) j = ++i;
    r.push(array[i]);
  }
  return r;
}

最近面试比较多,收集整理了一些常见的面试题,还算不错。

1.创建JavaScript对象的两种方法是什么?

这是一个非常简单的问题,如果你用过JavaScript的话。你至少得知道一种方法。但是,尽管如此,根据我的经验,也有很多自称是JavaScript程序员的人说不知道如何回答这个问题。

  • 使用 new 关键字来调用函数。
  • open/close 花括号。
var o = {};

你也可以继续提问,“使用new关键字,什么情况下创建对象?”但是,由于我只是想淘汰一些人,所以这些问题我会等到真正面试的时候去问。

2.如何创建数组?

这和“如何创建对象”是相同级别的问题。然而,也有一些人回答得了第一个问题,却不能回答这个问题。

用下面的代码,简简单单就能创建一个数组:

var myArray = new Array();

创建数组是一个很复杂的过程。但是我希望能从应聘者口中听到使用方括号的答案。

var myArray = [];

当然,我们还可以继续问其他问题,比如如何 高效地删除JavaScript数组中的重复元素 等,但是由于我们只需要知道应聘人员是否值得进一步的观察,关于数组的问题我会到此结束。

3.什么是变量提升(Variable Hoisting)?

这个问题稍微难一点,我也并不要求对方一定得回答出来。但是,通过这个问题能够快速确定应聘者的技术水平:他们是否真的像他们声明得那样理解这门编程语言?

变量提升指的是,无论是哪里的变量在一个范围内声明的,那么JavaScript引擎会将这个声明移到范围的顶部。如果在函数中间声明一个变量,例如在某一行中赋值一个变量:

function foo() {
    // 此处省略若干代码
    var a = "abc";
}

实际上会这样运行代码:

function foo() {
    var a;
    // 此处省略若干代码
    a = "abc";
}

4.全局变量有什么风险,以及如何保护代码不受干扰?

全局变量的危险之处在于其他人可以创建相同名称的变量,然后覆盖你正在使用的变量。这在任何语言中都是一个令人头疼的问题。

预防的方法也有很多。其中最常用的方法是创建一个包含其他所有变量的全局变量:

var applicationName = {};

然后,每当你需要创建一个全局变量的时候,将其附加到对象上即可。

applicationName.myVariable = "abc";

还有一种方法是将所有的代码封装到一个自动执行的函数中,这样一来,所有声明的变量都声明在该函数的范围内。

(function(){
   var a = "abc";
})();

在现实中,这两种方法你可能都会用到。

5.如何通过JavaScript对象中的成员变量迭代?

for(var prop in obj){
    // bonus points for hasOwnProperty
    if(obj.hasOwnProperty(prop)){
        // do something here
    }
}

6.什么是闭包(Closure)?

闭包允许一个函数定义在另一个外部函数的作用域内,即便作用域内的其他东西都消失了,它仍可以访问该外部函数内的变量。如果应聘者能够说明,在 for/next 循环中使用闭包却不声明变量来保存迭代变量当前值的一些风险,那就应该给对方加分。

7.请描述你经历过的JavaScript单元测试。

关于这个问题,其实我们只是想看看应聘人员是否真的做过JavaScript单元测试。这是一个开放式问题,没有特定的正确答案,不过对方至少得能讲述进程中的一些事情。