整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

使用 JS 来动态操作 css,你知道几种方法?

avaScript 可以说是交互之王,它作为脚本语言加上许多 Web Api 进一步扩展了它的特性集,更加丰富界面交互的可操作性。这类 API 的例子包括WebGL APICanvas APIDOM API,还有一组不太为人所知的 CSS API

由于JSX和无数JS框架的出现,使通过JS APIDOM交互的想法真正流行起来,但是在 CSS 中使用类似技术似乎并没有很多。当然,存在像CSS-in-JS这类解决方案,但是最流行的解决方案还是基于转译(transpilation),无需额外运行即可生成 CSS。这肯定对性能有好处,因为CSS API的使用可能导致额外的重绘,这与DOM API的使用一样。但这不是咱们想要的。如果哪天公司要求咱们,既要操纵 DOM 元素的样式和 CSS 类,还要像使用 HTML 一样使用 JS 创建完整的样式表,该怎么办?

内联样式

在咱们深入一些复杂的知识之前,先回来顾一下一些基础知识。例如,咱们可以通过修改它的.style属性来编辑给定的HTMLElement的内联样式。

const el = document.createElement('div')

el.style.backgroundColor = 'red'
// 或者 
el.style.cssText = 'background-color: red'
// 或者
el.setAttribute('style', 'background-color: red')

直接在.style对象上设置样式属性将需要使用驼峰式命名作为属性键,而不是使用短横线命名。如果咱们需要设置更多的内联样式属性,则可以通过设置.style.cssText属性,以更加高效的方式进行设置 。

我自己是一名从事了多年开发的web前端老程序员,目前辞职在做自己的web前端私人定制课程,今年年初我花了一个月整理了一份最适合2019年学习的web前端学习干货,各种框架都有整理,送给每一位前端小伙伴,想要获取的可以关注我的头条号并在后台私信我:前端,即可免费获取

请记住给cssText设置后原先的css样式被清掉了,因此,要求咱们一次死一堆样式 。

如果这种设置内联样式过于繁琐,咱们还可以考虑将.style与Object.assign()一起使用,以一次设置多个样式属性。

// ...
Object.assign(el.style, {
 backgroundColor: "red",
 margin: "25px"
})

这些“基本知识”比咱们想象的要多得多。.style对象实现CSSStyleDeclaration接口。这说明它带还有一些有趣的属性和方法,这包括刚刚使用的.cssText,还包括.length(设置属性的数量),以及.item()、.getPropertyValue()和.setPropertyValue()之类的方法:

// ...
const propertiesCount = el.style.length
for(let i = 0; i < propertiesCount; i++) {
 const name = el.style.item(i) // 'background-color'
 const value = el.style.getPropertyValue(name) // 're'
 const priority = el.style.getPropertyPriority(name) // 'important'

 if(priority === 'important') {
 el.style.removeProperty()
 }
}

这里有个小窍门-在遍历过程中.item()方法具有按索引访问形式的备用语法。

// ...
el.style.item(0) === el.style[0]; // true

CSS 类

接着,来看看更高级的结构——CSS类,它在检索和设置时具有字符串形式是.classname。

// ...
el.className = "class-one class-two";
el.setAttribute("class", "class-one class-two");

设置类字符串的另一种方法是设置class属性(与检索相同)。但是,就像使用.style.cssText属性一样,设置.className将要求咱们在字符串中包括给定元素的所有类,包括已更改和未更改的类。

当然,可以使用一些简单的字符串操作来完成这项工作,还有一种就是使用较新的.classList属性,这个属性,IE9 不支持它,而 IE10 和 IE11 仅部分支持它

classlist属性实现了DOMTokenList,有一大堆有用的方法。例如.add()、.remove()、.toggle()和.replace()允许咱们更改当前的 CSS 类集合,而其他的,例如.item()、.entries()或.foreach()则可以简化这个索引集合的遍历过程。

// ...
const classNames = ["class-one", "class-two", "class-three"];
classNames.forEach(className => {
 if(!el.classList.contains(className)) {
 el.classList.add(className);
 }
});

Stylesheets

一直以来,Web Api 还有一个StyleSheetList接口,该接口由document.styleSheets属性实现。document.styleSheets 只读属性,返回一个由 StyleSheet 对象组成的 StyleSheetList,每个 StyleSheet 对象都是一个文档中链接或嵌入的样式表。

for(styleSheet of document.styleSheets){
 console.log(styleSheet);
}

通过打印结果咱们可以知道,每次循环打印的是 CSSStyleSheet 对象,每个 CSSStyleSheet 对象由下列属性组成:

属性描述media获取当前样式作用的媒体。disabled打开或禁用一张样式表。href返回 CSSStyleSheet 对象连接的样式表地址。title返回 CSSStyleSheet 对象的title值。type返回 CSSStyleSheet 对象的type值,通常是text/css。parentStyleSheet返回包含了当前样式表的那张样式表。ownerNode返回CSSStyleSheet对象所在的DOM节点,通常是<link>或<style>。cssRules返回样式表中所有的规则。ownerRule如果是通过@import导入的,属性就是指向表示导入的规则的指针,否则值为null。IE不支持这个属性。

** CSSStyleSheet对象方法: **

方法描述insertRule()在当前样式表的 cssRules 对象插入CSS规则。deleteRule()在当前样式表删除 cssRules 对象的CSS规则。

有了StyleSheetList的全部内容,咱们来CSSStyleSheet本身。在这里就有点意思了, CSSStyleSheet扩展了StyleSheet接口,并且只有这种只读属性,如.ownerNode,.href,.title或.type,它们大多直接从声明给定样式表的地方获取。回想一下加载外部CSS文件的标准HTML代码,咱们就会明白这句话是啥意思:

<head>
<link rel="stylesheet" type="text/css" href="style.css" title="Styles">
</head>

现在,咱们知道HTML文档可以包含多个样式表,所有这些样式表都可以包含不同的规则,甚至可以包含更多的样式表(当使用@import时)。CSSStyleSheet有两个方法:、.insertrule()和.deleterule() 来增加和删除 Css 规则。

// ...
const ruleIndex = styleSheet.insertRule("div {background-color: red}");
styleSheet.deleteRule(ruleIndex);

.insertRule(rule,index):此函数可以在cssRules规则集合中插入一个指定的规则,参数rule是标示规则的字符串,参数index是值规则字符串插入的位置。

deleteRule(index):此函数可以删除指定索引的规规则,参数index规定规则的索引。

CSSStyleSheet也有自己的两个属性:.ownerRule和.cssRule。虽然.ownerRule与@import相关,但比较有趣的是.cssRules。简单地说,它是CSSRuleList的CSSRule,可以使用前面提到的.insertrule()和.deleterule()方法修改它。请记住,有些浏览器可能会阻止咱们从不同的来源(域)访问外部CSSStyleSheet的.cssRules属性。

那么什么是 CSSRuleList?

CSSRuleList是一个数组对象包含着一个有序的CSSRule对象的集合。每一个CSSRule可以通过rules.item(index)的形式访问, 或者rules[index]。这里的rules是一个实现了CSSRuleList接口的对象, index是一个基于0开始的,顺序与CSS样式表中的顺序是一致的。样式对象的个数是通过rules.length表达。

对于CSSStyleRule对象:

每一个样式表CSSStyleSheet对象可以包含若干CSSStyleRule对象,也就是css样式规则,如下:

<style type="text/css">
 h1{color:red}
 div{color:green}
</style>

在上面的代码中style标签是一个CSSStyleSheet样式表对象,这个样式表对象包含两个CSSStyleRule对象,也就是两个css样式规则。

CSSStyleRule对象具有下列属性:

1.type:返回0-6的数字,表示规则的类型,类型列表如下:

0:CSSRule.UNKNOWN_RULE。

1:CSSRule.STYLE_RULE (定义一个CSSStyleRule对象)。

2:CSSRule.CHARSET_RULE (定义一个CSSCharsetRule对象,用于设定当前样式表的字符集,默认与当前网页相同)。

3:CSSRule.IMPORT_RULE (定义一个CSSImportRule对象,就是用@import引入其他的样式表)

4:CSSRule.MEDIA_RULE (定义一个CSSMediaRule对象,用于设定此样式是用于显示器,打印机还是投影机等等)。

5:CSSRule.FONT_FACE_RULE (定义一个CSSFontFaceRule对象,CSS3的@font-face)。

6:CSSRule.PAGE_RULE (定义一个CSSPageRule对象)。

2.cssText:返回一个字符串,表示的是当前规则的内容,例如:

div{color:green}

3.parentStyleSheet:返回所在的CSSStyleRule对象。

4.parentRule:如果规则位于另一规则中,该属性引用另一个CSSRule对象。

5.selectorText:返回此规则的选择器,如上面的div就是选择器。

6.style:返回一个CSSStyleDeclaration对象。

// ...
const ruleIndex = styleSheet.insertRule("div {background-color: red}");
const rule = styleSheet.cssRules.item(ruleIndex);

rule.selectorText; // "div"
rule.style.backgroundColor; // "red"

实现

现在,咱们对 CSS 相关的 JS Api有了足够的了解,可以创建咱们自己的、小型的、基于运行时的CSS-in-JS实现。咱们的想法是创建一个函数,它传递一个简单的样式配置对象,生成一个新创建的CSS类的哈希名称供以后使用。

实现流程很简单,咱们需要一个能够访问某种样式表的函数,并且只需使用.insertrule()方法和样式配置就可以运行了。先从样式表部分开始:

function createClassName(style) {
 // ...
 let styleSheet;
 for (let i = 0; i < document.styleSheets.length; i++) {
 if (document.styleSheets[i].CSSInJS) {
 styleSheet = document.styleSheets[i];
 break;
 }
 }
 if (!styleSheet) {
 const style = document.createElement("style");
 document.head.appendChild(style);
 styleSheet = style.sheet;
 styleSheet.CSSInJS = true;
 }
 // ...
}

如果你使用的是ESM或任何其他类型的JS模块系统,则可以在函数外部安全地创建样式表实例,而不必担心其他人对其进行访问。但是,为了演示例,咱们将stylesheet上的.CSSInJS属性设置为标志的形式,通过标志来判断是否要使用它。

现在,如果如果还需要创建一个新的样式表怎么办? 最好的选择是创建一个新的<style/>标记,并将其附加到HTML文档的<head/>上。这会自动将新样式表添加到document.styleSheets列表,并允许咱们通过<style/>标记的.sheet属性对其进行访问,是不是很机智?

function createRandomName() {
 const code = Math.random().toString(36).substring(7);
 return `css-${code}`;
}

function phraseStyle(style) {
 const keys = Object.keys(style);
 const keyValue = keys.map(key => {
 const kebabCaseKey = 
 key.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
 const value = 
 `${style[key]}${typeof style[key] === "number" ? "px" : ""}`;

 return `${kebabCaseKey}:${value};`;
 });

 return `{${keyValue.join("")}}`;
}

除了上面的小窍门之外。自然,咱们首先需要一种为CSS类生成新的随机名称的方法。然后,将样式对象正确地表达为可行的CSS字符串的形式。这包括驼峰命名和短横线全名之间的转换,以及可选的像素单位(px)转换的处理。

function createClassName(style) {
 const className = createRandomName();
 let styleSheet;
 // ...
 styleSheet.insertRule(`.${className}${phraseStyle(style)}`);
 return className;
}

完整代码如下:

HTML

<div id="el"></div>

JS

function createRandomName() {
 const code = Math.random().toString(36).substring(7);
 return `css-${code}`;
}

function phraseStyle(style) {
 const keys = Object.keys(style);
 const keyValue = keys.map(key => {
 const kebabCaseKey = key.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
 const value = `${style[key]}${typeof style[key] === "number" ? "px" : ""}`;
 return `${kebabCaseKey}:${value};`;
 });
 return `{${keyValue.join("")}}`;
}

function createClassName(style) {
 const className = createRandomName();
 let styleSheet;
 for (let i = 0; i < document.styleSheets.length; i++) {
 if (document.styleSheets[i].CSSInJS) {
 styleSheet = document.styleSheets[i];
 break;
 }
 }
 if (!styleSheet) {
 const style = document.createElement("style");
 document.head.appendChild(style);
 styleSheet = style.sheet;
 styleSheet.CSSInJS = true;
 }
 styleSheet.insertRule(`.${className}${phraseStyle(style)}`);
 return className;
}

const el = document.getElementById("el");

const redRect = createClassName({
 width: 100,
 height: 100,
 backgroundColor: "red"
});

el.classList.add(redRect);

运行效果:

总结

正如本文咱们所看到的,使用 JS 操作CSS 是一件非常有趣的事,咱们可以挖掘很多好用的 API,上面的例子只是冰山一角,在CSS API(或者更确切地说是API)中还有更多方法,它们正等着被揭开神秘面纱。



原文:https://css-tricks.com/an-introduction-and-guide-to-the-css-object-model-cssom/

者:kevinylzhao,腾讯音乐前端开发工程师

浏览器缓存策略对于前端开发同学来说不陌生,大家都有一定的了解,但如果没有系统的归纳总结,可能三言两语很难说明白,甚至说错,尤其在面试过程中感触颇深,很多候选人对这类基础知识竟然都是一知半解,说出几个概念就没了,所以重新归纳总结下,温故而知新。


Web 缓存介绍

  • Web 缓存是指一个 Web 资源(如 html 页面,图片,js,数据等)存在于 Web 服务器和客户端(浏览器)之间的副本。
  • 缓存会根据进来的请求保存输出内容的副本;当下一个请求来到的时候,如果是相同的 URL,缓存会根据缓存机制决定是直接使用副本响应访问请求,还是向源服务器再次发送请求。

Web 缓存的好处

  • 减少网络延迟,加快页面打开速度
  • 减少网络带宽消耗
  • 降低服务器压力
  • ...

HTTP 的缓存机制

简化的流程如下

根据什么规则缓存

  1. 新鲜度(过期机制):也就是缓存副本有效期。一个缓存副本必须满足以下条件,浏览器会认为它是有效的,足够新的:
  • 含有完整的过期时间控制头信息(HTTP 协议报头),并且仍在有效期内;
  • 浏览器已经使用过这个缓存副本,并且在一个会话中已经检查过新鲜度;
  1. 校验值(验证机制):服务器返回资源的时候有时在控制头信息带上这个资源的实体标签 Etag(Entity Tag),它可以用来作为浏览器再次请求过程的校验标识。如果发现校验标识不匹配,说明资源已经被修改或过期,浏览器需求重新获取资源内容。

HTTP 缓存的两个阶段

浏览器缓存一般分为两类:强缓存(也称本地缓存)和协商缓存(也称弱缓存)。

本地缓存阶段

浏览器发送请求前,会先去缓存里查看是否命中强缓存,如果命中,则直接从缓存中读取资源,不会发送请求到服务器。否则,进入下一步。

协商缓存阶段

当强缓存没有命中时,浏览器一定会向服务器发起请求。服务器会根据 Request Header 中的一些字段来判断是否命中协商缓存。如果命中,服务器会返回 304 响应,但是不会携带任何响应实体,只是告诉浏览器可以直接从浏览器缓存中获取这个资源。如果本地缓存和协商缓存都没有命中,则从直接从服务器加载资源。

启用&关闭缓存

按照本地缓存阶段和协商缓存阶段分类:

  1. 使用 HTML Meta 标签    Web 开发者可以在 HTML 页面的节点中加入标签,如下:

上述代码的作用是告诉浏览器当前页面不被缓存,事实上这种禁用缓存的形式用处很有限:

a. 仅有 IE 才能识别这段 meta 标签含义,其它主流浏览器仅识别“Cache-Control: no-store”的 meta 标签。

b. 在 IE 中识别到该 meta 标签含义,并不一定会在请求字段加上 Pragma,但的确会让当前页面每次都发新请求(仅限页面,页面上的资源则不受影响)。

  1. 使用缓存有关的 HTTP 消息报头 这里需要了解 HTTP 的基础知识。一个 URI 的完整 HTTP 协议交互过程是由 HTTP 请求和 HTTP 响应组成的。有关 HTTP 详细内容可参考《Hypertext Transfer Protocol — HTTP/1.1》、《HTTP 权威指南》等。

在 HTTP 请求和响应的消息报头中,常见的与缓存有关的消息报头有:

上图中只是常用的消息报头,下面来看下不同字段之间的关系和区别:

  1. Cache-Control 与 Expires
  2. Cache-Control:HTTP1.1 提出的特性,为了弥补 Expires 缺陷加入的,提供了更精确细致的缓存功能。详细了解详细看几个常见的指令:_ max-age:功能和 Expires 类似,但是后面跟一个以“秒”为单位的相对时间,来供浏览器计算过期时间。_ no-cache:提供了过期验证机制。(在 Chrome 的 devtools 中勾选 Disable cache 选项,发送的请求会去掉 If-Modified-Since 这个 Header。同时设置 Cache-Control:no-cache Pragma:no-cache,每次请求均为 200)
    • no-store:表示当前请求资源禁用缓存;
    • public:表示缓存的版本可以被代理服务器或者其他中间服务器识别;
    • private:表示只有用户自己的浏览器能够进行缓存,公共的代理服务器不允许缓存。
  • Expires:HTTP1.0 的特性,标识该资源过期的时间点,它是一个绝对值,格林威治时间(Greenwich Mean Time, GMT),即在这个时间点之后,缓存的资源过期;优先级:Cache-Control 优先级高于 Expires,为了兼容,通常两个头部同时设置;浏览器默认行为:其实就算 Response Header 中沒有设置 Cache-Control 和 Expires,浏览器仍然会缓存某些资源,这是浏览器的默认行为,是为了提升性能进行的优化,每个浏览器的行为可能不一致,有些浏览器甚至没有这样的优化。
  1. Last-Modified 与 ETag
  2. Last-Modified(Response Header)与 If-Modified-Since(Request Header)是一对报文头,属于 http 1.0。If-Modified-Since 是一个请求首部字段,并且只能用在 GET 或者 HEAD 请求中。Last-Modified 是一个响应首部字段,包含服务器认定的资源作出修改的日期及时间。当带着 If-Modified-Since 头访问服务器请求资源时,服务器会检查 Last-Modified,如果 Last-Modified 的时间早于或等于 If-Modified-Since 则会返回一个不带主体的 304 响应,否则将重新返回资源。(注意:在 Chrome 的 devtools 中勾选 Disable cache 选项后,发送的请求会去掉 If-Modified-Since 这个 Header。)
  • ETag 与 If-None-Match 是一对报文头,属于 http 1.1。ETag 是一个响应首部字段,它是根据实体内容生成的一段 hash 字符串,标识资源的状态,由服务端产生。If-None-Match 是一个条件式的请求首部。如果请求资源时在请求首部加上这个字段,值为之前服务器端返回的资源上的 ETag,则当且仅当服务器上没有任何资源的 ETag 属性值与这个首部中列出的时候,服务器才会返回带有所请求资源实体的 200 响应,否则服务器会返回不带实体的 304 响应。
  • ETag 能解决什么问题?

a. Last-Modified 标注的最后修改只能精确到秒级,如果某些文件在 1 秒钟以内,被修改多次的话,它将不能准确标注文件的新鲜度;

b. 某些文件也许会周期性的更改,但是它的内容并不改变(仅仅改变的修改时间),但 Last-Modified 却改变了,导致文件没法使用缓存;

c. 有可能存在服务器没有准确获取文件修改时间,或者与代理服务器时间不一致等情形。

  • 优先级:ETag 优先级比 Last-Modified 高,同时存在时会以 ETag 为准。
缓存位置

浏览器可以在内存、硬盘中开辟一个空间用于保存请求资源副本。我们经常调试时在 DevTools Network 里看到 Memory Cache(內存缓存)和 Disk Cache(硬盘缓存),指的就是缓存所在的位置。请求一个资源时,会按照优先级(Service Worker -> Memory Cache -> Disk Cache -> Push Cache)依次查找缓存,如果命中则使用缓存,否则发起请求。这里先介绍 Memory Cache 和 Disk Cache。

200 from memory cache

表示不访问服务器,直接从内存中读取缓存。因为缓存的资源保存在内存中,所以读取速度较快,但是关闭进程后,缓存资源也会随之销毁,一般来说,系统不会给内存分配较大的容量,因此内存缓存一般用于存储较小文件。同时内存缓存在有时效性要求的场景下也很有用(比如浏览器的隐私模式)。

200 from disk cache

表示不访问服务器,直接从硬盘中读取缓存。与内存相比,硬盘的读取速度相对较慢,但硬盘缓存持续的时间更长,关闭进程之后,缓存的资源仍然存在。由于硬盘的容量较大,因此一般用于存储大文件。

下图可清晰看出差别:

200 from prefetch cache

在 preload 或 prefetch 的资源加载时,两者也是均存储在 http cache,当资源加载完成后,如果资源是可以被缓存的,那么其被存储在 http cache 中等待后续使用;如果资源不可被缓存,那么其在被使用前均存储在 memory cache。

CDN Cache

以腾讯 CDN 为例:X-Cache-Lookup:Hit From MemCache 表示命中 CDN 节点的内存;X-Cache-Lookup:Hit From Disktank 表示命中 CDN 节点的磁盘;X-Cache-Lookup:Hit From Upstream 表示没有命中 CDN。

整体流程

从上图能感受到整个流程,比如常见两种刷新场景:

  • 当 F5 刷新网页时,跳过强缓存,但是会检查协商缓存;
  • 当 Ctrl + F5 强制刷新页面时,直接从服务器加载,跳过强缓存和协商缓存

其他 Web 缓存策略

IndexDB

IndexedDB 就是浏览器提供的本地数据库,能够在客户端存储可观数量的结构化数据,并且在这些数据上使用索引进行高性能检索的 API。

异步 API 方法调用完后会立即返回,而不会阻塞调用线程。要异步访问数据库,要调用 window 对象 indexedDB 属性的 open() 方法。该方法返回一个 IDBRequest 对象 (IDBOpenDBRequest);异步操作通过在 IDBRequest 对象上触发事件来和调用程序进行通信。

常用异步 API 如下:

在 16 年曾基于 IndexDB 做过一整套缓存策略,有不错的优化效果:

Service Worker

SW 从 2014 年提出的草案到现在已经发展很成熟了,基于 SW 做离线缓存,让用户能够进行离线体验,消息推送体验,离线缓存能力涉及到 Cache 和 CacheStorage 的概念,篇幅有限,不展开了。

LocalStorage

localStorage 属性允许你访问一个 Document 源(origin)的对象 Storage 用于存储当前源的数据,除非用户人为清除(调用 localStorage api 或者清除浏览器数据), 否则存储在 localStorage 的数据将被长期保留。

SessionStorage

sessionStorage 属性允许你访问一个 session Storage 对象,用于存储当前会话的数据,存储在 sessionStorage 里面的数据在页面会话结束时会被清除。页面会话在浏览器打开期间一直保持,并且重新加载或恢复页面仍会保持原来的页面会话。

定义最优缓存策略

  • 使用一致的网址:如果您在不同的网址上提供相同的内容,将会多次获取和存储该内容。注意:URL 区分大小写!
  • 确定中继缓存可以缓存哪些资源:对所有用户的响应完全相同的资源很适合由 CDN 或其他中继缓存进行缓存;
  • 确定每个资源的最优缓存周期:不同的资源可能有不同的更新要求。审查并确定每个资源适合的 max-age;
  • 确定网站的最佳缓存层级:对 HTML 文档组合使用包含内容特征码的资源网址以及短时间或 no-cache 的生命周期,可以控制客户端获取更新的速度;
  • 更新最小化:有些资源的更新比其他资源频繁。如果资源的特定部分(例如 JS 函数或一组 CSS 样式)会经常更新,应考虑将其代码作为单独的文件提供。这样,每次获取更新时,剩余内容(例如不会频繁更新的库代码)可以从缓存中获取,确保下载的内容量最少;
  • 确保服务器配置或移除 ETag:因为 Etag 跟服务器配置有关,每台服务器的 Etag 都是不同的;
  • 善用 HTML5 的缓存机制:合理设计启用 LocalStorage、SessionStorage、IndexDB、SW 等存储,会给页面性能带来明显提升;
  • 结合 Native 的强大存储能力:善于利用客户端能力,定制合适的缓存机制,打造极致体验。

结语

通过了解浏览器各种缓存机制和存储能力特点,结合业务制定合适的缓存策略,善用缓存是基本功,可以用于时常审查负责的业务,可能就会发现个别业务并没有运用到位,共勉。

近又快到了金三银四的好日子了,有一天,小龙找到我说,小辉哥,我想跳槽了。原来公司加薪无望,目前只有 7.5k,12 薪,也没有年终奖,想换个环境试试,但是好像今年疫情之下,招聘市场并没有往年那么热门,目前觉得自己还没有办法去大厂。

在自己努力无果之后,想让我帮他操作一下,我咨询了一下小龙目前的情况,然后帮他物色了5、6个岗位,然后让他自己挑一个比较喜欢的:

小龙目前的情况:

1. 自考本科。
2. 24 岁。
3. 1 年多一点工作经验(我改为了 1 年半)。
4. 目前薪资 7.5,加上年终和绩效可以到 9.5。
5. 有 vue 一年多的使用经验,全家桶基本会。
6. webpack 用过,但是不熟,都是别人帮弄好的。
7. 自我感觉良好,对于自己的学习能力觉得还算可以,js,css,es6基础尚可。
8. nodejs 较弱,只停留在 CRUD 阶段,玩过一下 express做 blog。
9. 平时使用 git ,不过公司使用 svn。
10. 对待 996 还算可以认可,不过最好还是希望不要 996

这是他挑选的目标公司职位的招聘 jd 如下:

月薪:12-20k·12薪
经验要求:1-3年
学历:本科 
工作地区:广州天河区 XXXX  

工作职责:
1、负责web服务端,内部系统后端业务程序开发
2、负责web前端开发
3、参与现场调试
4、参与后端业务和底层模块接口开发及调试

工作要求 1:
1、熟悉vue框架,熟悉elementUI界面控件库
2、扎实的javascript语言,html,css基础;
3、熟悉使用linux基本应用和nodejs;
4、有前后端分离的项目实践经验,能使用上述技术搭建丰富交互的前端界面并和后端进行http,tcp的通讯;
5、熟悉typescript优先。

工作要求2:
1、做事认真负责,有良好的编码风格;
2、良好的沟通与表达能力,有团队协作精神。
3、有良好的学习方法和较强的学习能力;
4、喜欢迎难而上,爱好挑战困难;
5、有框架思维和多人合作编码能力。

我跟小龙说,这个 jd 对你目前来说会有点难度,不过如果你真的很想达到的话,也是可以的,花点心思,努努力就行了。 他说,没问题,成了请你吃饭哈~

接下来我会用详细说明一下小龙到底经历了什么。

 第一步:先让我们分析一下这个招聘要求jd
 第二步:确定需要突破的求职目标
 第三步:快速提升自身技能满足要求
 第四步:快速准备面试
 第五步:如何高效投简历
 第六步:如何优秀通过面试
 第七步:获得 offer

第一步:先让我们分析一下这个招聘要求jd

招聘要求也叫jd,英文是 job description,翻译为工作描述也可以

一个 jd 其实不简单:

  • 工资
  • 工作经验
  • 学历
  • 地点
  • 业务范围
  • 工作职责
  • 工作要求

一般一份工作是 1-3 年左右,所以说,你这是在选择一份未来 1-3 年时间消费,一份工作不仅要工资待遇适合你,工作节奏也要适合你,而且最好要跟你未来职业规划沾边才行,这样你的时间才会更有意义,你就可以用 1-3 年时间就可以顶别人 3-5 年了

看工资

月薪:12-20k·12薪,一般能在招聘要求里面写这么清晰的公司,素质都相对比较好,因为坦诚是一家公司很重要的一个品质。

漫天开价,落地还钱。我们拿一个最低的,再拿一个最高的,取一个平均值,(12+20)/2 =16,所以这个岗位的预期月薪工资一般都可以达到 16K,不过也要注意,他是 12 薪的,也就是说,一年只有 12 个月薪资,而有很多公司,一年可以发 13,14 甚至 16 个月,这里就是区别了。不过也可能对方没写出来,在现场面试的时候咨询 hr 就行了。

总体来说也算不错。要知道小龙之前是 7.5K 的。

但不排除有些公司不按套路出牌~

看工作经验

有句老话说,工作经验写 3 年,上班一年半,加班一年半,就是这么硬核,哈哈哈~

所以这里 1-3 年其实无伤大雅。只要不要偏离太夸张即可,例如你是应届毕业生,写工作 2 年,这样很容易穿帮的,不建议。

小龙工作一年半了,写 2 年也是非常合理的,如果准备充分,写个 3 年也问题不大。

看学历

一般中小公司是不卡学历,除非比较特殊要求的, 例如国企,事业单位,或者特殊岗位,例如算法,人工智能AI类。

有些时候,公司急用人,也可以从本科下降到大专, 这个也是可以理解的。

不过如果是大公司就不行,大公司必要的招聘考核指标就必须要本科,有些甚至是 985 以上的本科才行。

目前小龙虽然不是统招本科,但是好歹也是自考本科,也是国家承认的。

看公司地点

一般人很少留意这个公司地点,有些朋友虽然找到一个公司,待遇还不错,但是离自己家十万八千里远,每次上下班都像坐长途车一样,一天至少浪费了好几个小时在通勤上,你以为你工资高了,就是赚钱了,但是其实不然,你只不过是牺牲了其他东西,例如时间,精力。

在《通往财富自由之路》里,李笑来老师提到一个概念,就是注意力>时间>金钱。钱,是价值相对较低的,如果能拿他换到时间(进而换到你的注意力,让你可以在你关注的领域里得到成长),那才是真正有价值的。

我的建议就是,在财力允许的条件下,尽可能的让工作的地方离家近一点。

  1. 可以让你有更多自己的时间,来进行学习。
  2. 可以让你不容易累,人不是钢铁,也是需要休息的。

小龙挑这个企业离他宿舍还不算远,另外我发现这个软件园位于市中心,附近有比较多的不同大大小小的互联网企业,我建议他如果可以的话,就搬到这个软件园附近来住,一方面上班更近,一方面万一以后跳槽, 也不用折腾搬家多次,搬家的辛苦谁干谁知道~

看公司业务

一个是看公司是不是朝阳行业,另外一个是看公司业务是否跟时代脱节。

例如煤炭行业就是夕阳行业,不是朝阳行业。

例如柯达胶卷业务被数码相机取代,nokia非智能手机被苹果智能手机取代,这个就是公司业务根本时代脱节了。

一般来说,可以多留意一下社会龙头企业关注的东西,例如华为,腾讯,阿里,还有就是关注以下国家政策,发展芯片,发展 5G,人工智能等等。

小龙挑的这个企业做的是智能制造业和医疗器械相关的,属于今年国家重点推广领域,起码目前来看还可以,这些内容可以在企业官网找到。

看工作职责和工作要求

一个公司的招聘 jd 的工作职责和工作要求写的水平可以知道该公司的技术水平或者工作、职场氛围不会太差,

例如工作要求就写精通:

精通HTML5/CSS3/JS/TypeScript/Less/SVG/Canvas等前端技术
精通 Vue/Angular/React/BootStrap至少两种前端框架

就算是阿里 p7 也不敢写精通,外行看热闹,内行看门道。这种一看就是不懂技术的人写凑数或者领导为了高大上而写的。

而且如果职场政治氛围(pmp)太压抑,不利于新人成长。

再来看看小龙挑的这个公司,总体感觉还是比较实在,不会太过夸张,也没有用精通的字样:

工作职责:
 1、负责web服务端,内部系统后端业务程序开发
 2、负责web前端开发
 3、参与现场调试
 4、参与后端业务和底层模块接口开发及调试
 
 工作要求 1:
 1、熟悉vue框架,熟悉elementUI界面控件库
 2、扎实的javascript语言,html,css基础;
 
 3、熟悉使用linux基本应用和nodejs;
 
 4、有前后端分离的项目实践经验,能使用上述技术搭建丰富交互的前端界面并和后端进行http,tcp的通讯;
 
 5、熟悉typescript优先。
 
 工作要求2:
 1、做事认真负责,有良好的编码风格;
 2、良好的沟通与表达能力,有团队协作精神。
 3、有良好的学习方法和较强的学习能力;
 4、喜欢迎难而上,爱好挑战困难;
 5、有框架思维和多人合作编码能力。

第二步:确定需要突破的求职目标

我们来分析一下:

  1. 【基础】web 服务端开发,跟 nodejs 有关系,热门并且主流的 nodejs 框架是 express 和 egg和 koa. 对于快速学习了解的话,学习 koa 会比较好,文档相对齐全.对于快速上手部署,学习 egg 会比较好.目前多半使用egg 或者 koa 做的是 bff 中间层,express 则比较重。
  2. 【基础】参与后端业务和底层模块接口开发, 要么是通过 bff 去重新组合各个后台服务的接口,或者基于 nodejs 的 sdk 进行底层模块的对接。
  3. 【加分】对方有提到 tcp,不能很确定是需要有 nodejs 操作 tcp 的要求,我理解为加分题。
  4. 【基础】需要写 web 前端, 根据前后对应, 这里是用 vue 框架,并且是使用 elementsUI 框架,进而也知道做的多半是 pc 后台管理系统类项目,对应参考的我个人认为在 vue 方面,最好的开源参考学习例子是vue-element-admin。
  5. 【基础】熟悉 linux 基本应用,多半是要做一部分 linux 服务器部署 nodejs 和 nginx 的操作, 可能也会涉及到 docker 相关,因为 nodejs 在企业里面是部署到 linux 环境下运行的。
  6. 【基础】有前后端分离项目的实践经验,就是基于前后端分离做过项目,而前后端分离的关键点在于接口设计, 接口对接,http 接口,websocket 接口使用,jsonp 和 CORS 跨域和代理处理也包含在里面。
  7. 【加分】熟悉 typescript优先,这是加分送分题,证明你是有自学能力,并且能够时刻保持自己的技术栈进步。
  8. 【基础】扎实的 js css html 基础,其实就是普通前端基础,背背题,准备好常见的问题过一遍就行了。
  9. 【忽略】良好的沟通与表达能力,只要能够基本跟别人谈话,咬字清晰,我觉得就是达标了。
  10. 【忽略】有框架思维,这个比较虚,感觉像是凑数。
  11. 【基础】多人合作,则需要有 git 使用经验,例如 gitflow 也要熟悉,不过也可能对方使用老旧的 svn,也不要紧,熟悉一个,另外一个也差不多。
  12. 【忽略】其他什么做事认真,良好学习能力,迎难而上,就比较废了。

经过分析之后,我们可以确认:

  1. 【必须】nodejs 的方向一般有 3 个,bff 层,全栈开发,ssr,目前看 jd 描述,应该属于 bff 的可能性较大。
  2. 【必须】从egg 或者 koa里面选择其中一个刻意练习即可,egg 是 koa 的进化版,不过因为较新,所以网上的教程比较少, 选择突破 koa 会比较简单,突破 koa 之后,依然还是要过一遍 egg 的使用,因为 egg 在企业领域里面有比较成熟规范。
  3. 【必须】vue 需要熟练使用,指令,基本生命周期,组件封装,全家桶(vuex,axios等)使用也需要熟练的。 vue 看 2.5 即可,因为 3.0 跟 2.5 差别较大,目前很多公司还没完全切换,或者甚至不会换,目前很多公司都在使用的版本是 2.5.
  4. 【必须】vue-element-admin需要基本熟练理解核心设计点, i18 国际化解决方案,动态路由,权限验证,mock,懒加载等都相当重要,重点是理解整个系统从 0 到 1 的设计,需要完整分析一遍vue-element-admin的源代码。
  5. 【必须】需要补充 webpack的知识,因为串联整个前端或者 nodejs 端就是 webpack,不过熟练即可,webpack3或者 4都可以。
  6. 【必须】linux 需要基本会用,常用 26 个命令都要会,ubuntu 或者 redhat 系列任选其一即可。
  7. 【必须】网络协议部分,尤其是 http,websocket需要基础知识和实际例子介绍,跨域处理需要熟练,tcp 部分需要熟练理解原理,session, cookie,jwt 的也是相关内容。
  8. 【必须】前端基础 js css es6 html 都是需要熟练的,常见问题,闭包,异步,布局,作用域,面向对象这些都需要在大脑里面形成一个比较强的印象和理解,这里需要通过自己做过的实际项目和刷题结合才能形成的强印象理解。
  9. 至于没有提到的算法和数据结构,我个人更倾向于提升数据结构知识,在中小规模的公司里面,算法其实要求很低的,不然的话,我就觉得这个公司有点吹毛求疵了,会这个算法并不代表你个人能力真的很强,就好像数学题做得好,不一定总分数高,但是数据结构会贯穿整个程序员开发生涯,这个是毋庸置疑的。只要做到常见类型的数据结构都用过一遍即可。
  10. 【必须】git 使用熟练。
  11. (加分题)会用 docker
  12. (加分题)nodejs 操作 tcp,因为一般很少会直接操作 tcp。
  13. (加分题)typescript 基本会用

必须点满足了是 12K,加分点满足了是 16k。

这些就是我们需要短时间突破的目标。

  • nodejs---koa/egg
  • js 基础---es6,js,css,html
  • 数据结构
  • 网络协议
  • linux--包含 docker
  • webpack
  • vue

由于考虑的是短时间突破,没有算加分题的内容。

是不是突然有种,原来如此,不外如是的感觉,啊哈哈,战略和战术同样重要的。

第三步:快速提升自身技能满足要求

为了避免小龙担心目标太大而完成不了,所以我将大目标拆分成小目标,这个小目标也是根据小龙自己觉得可以才定的,有些人 1 天可以看完一本书,有些人则需要 2 天,视乎每个人的情况。

这就是:拆分大目标,直至到你觉得可以快速完成的小目标级别为止

小目标还有一个好处,每次完成一个小目标,不会太难,可以给你形成正反馈,让你可以渐进式进步,增强信心,从而坚持下

同时小目标也是你的前进之路的地图,每个小目标之间的联系构成了大目标,只要没有偏离小目标目标,大目标就不会偏离

我再次跟小龙确认过,他目前的情况:

  1. 每天只有 2 小时可以学习,因为还要上班,回到家已经很晚了。
  2. 不过每个星期六日可以全天学习,大概每天 8 小时左右。
  3. 比较弱的是 nodejs,linux 和网络协议和数据结构部分(神他喵的以前学校的计算机课白学了),比较熟练的是 vue,毕竟用了 1 年左右了,基本上都会,
  4. 对于一整个完整的 vue-admin后台实际没有一个人完成过,也是各种组合拼接出来,这里有点心虚。
  5. webpack 用过,但是不熟,都是别人帮弄好的。
  6. 自我感觉良好,对于自己的学习能力觉得还算可以,

我帮他拆分了一下目标,当时做了一个xmind,方便全局的看。

这里是需要看的材料:

  • 《高级Javascript程序设计》第3版 或者第四版
  • 《Javascript设计模式》
  • 《CSS世界》
  • 《剖析 Vue.js 内部运行机制》
  • 《使用 webpack 定制前端开发环境》
  • vue-element-admin 官网代码和 wiki
  • egg 官网代码和 wiki
  • 《Koa2进阶学习笔记》
  • linux 鸟哥
  • 等等等

跟自己约定每天,每周刻意练习的量

在一开始是没办法知道这个大目标需要多久能够完成的,也不知道这个小目标需要多久才能完成。只能通过跟自己约定每天,每周的完成程度。

虽然说小龙自我感知每天晚上会有 2 小时,每周六日有 8 小时是可以学习的,但是时间这个量化指标不是很准,有时候走神了,或者状态不好,时间到了,但是工作没做好。

这里我跟小龙加了一个仪式,让他每次完成一个小目标之前,发一个宣誓内容给我,内容如下:我是为了 XXX 而努力的,我会在 XXX 时间内,完成 XXX的学习,并且整理好笔记,我不糊弄自己,务必认真完成。

这是一种契约,跟自己的一个契约。契约的力量是很大的。

另外我需要他在日历本上打钩,记录自己今天是否已经完成了学习。 这是同样是一种契约。

不要过分高估自己的自律性,要客观评价自己的拖延症!

认真写笔记

好记性不如烂笔头,大脑的记忆需要多次反复刺激才会印象深刻,看一次,读一次,想一次,思考一次,写一次,你的记忆比别人就相当于高了 4 倍以上,因为一般人只会看一次而已。

笔记的内容不是简单写,会将某个知识点的的原理和实际例子都写一遍,并且会问一下自己,是不是真的懂了,逻辑是不是真的通了。

小龙同学有一个好处就是,每次总结都有很长的笔记,大概3000 字一篇,不过不好的地方就是有时候笔记花费时间有点太长。

想想我自己以前上学,写个 800 字文章都觉得天都塌了,偶买狗的!

笔记基本都是用 markdown 写,自动排版,方便写,方便看。如果过分追求格式和样子,反而失去了本来记笔记的意义。

这是他写过的笔记之一:

实际特训效果

实际记录到一共用了 20+10+6+10+6+6+6=64 个小时,而且这个是计算纯时间,实际消耗的时间其实是大于 64 个小时的,因为人不能免俗,有时候计划赶不上变化,按照公式,大概是80 个小时左右。

每天 2 小时,每个星期六和日是 8 小时,大概一个星期能花 26 个小时学习,当时我朋友的朋友学完并且在我检查确认大体已经掌握知识的结果后,最终大概用了4 个星期左右(有些时候有特殊时期中断了一下)。

不过也是需要建立在我强而有力的监督之下~啊哈哈哈。

 毛时间vs纯时间
 毛时间:你所花在工作上的时间统称为毛时间。
 纯时间:你真正专注于工作的时间称为纯时间。 
 一般来说,纯时间=毛时间的 80%**

这是我补充之前的 xmind 图的最终结果

至此,基本上小龙已经能够触达这个 offer 的门槛了,底气不会那么虚了。

第四步:快速准备面试

准备一个闪闪发光的 github 仓库或者 blog 地址

github 仓库是一个优秀程序员的名片。 --BY 鲁X

github 仓库可以存放你的代码或者你的 blog 学习心得笔记,比起虚无缥缈的说,能看得到的东西会更加让人产生信任感。

一个有内涵的 github 仓库或者 blog 可以让你在面试官的第一印象里面加很多分的。

首因效应由美国心理学家洛钦斯首先提出的,也叫首次效应、优先效应或第一印象效应,指交往双方形成的第一次印象对今后交往关系的影响,也即是“先入为主”带来的效果。

如果一个人在初次见面时给人留下良好的印象,那么人们就愿意和他接近,彼此也能较快地取得相互了解,并会影响人们对他以后一系列行为和表现的解释。

反之,对于一个初次见面就引起对方反感的人,即使由于各种原因难以避免与之接触,人们也会对之很冷淡,在极端的情况下,甚至会在心理上和实际行为中与之产生对抗状态。

这个仓库不能只是一个单纯的装饰物,最好可以将一个你觉得有意思的项目代码放进去,然后在面试的过程中给面试官边看边讲解,更加容易让对方认可你的能力。同理,blog 的文章也不能是全部转载或者流水账,要有体现出你认真 coding 的内味才行。

人靠衣装,佛靠金装。这个就是你的金装之一。

可以看看阮老师早期的 github,都是写了很多 demo 之类的。

刷题、刷题、刷题!

网上有大量的面经和面试题分享,我们要找热门的,因为面试官也是普通人,他不可能天天自己造题目,他也是参考网上的。

我们需要有题目和答案的是最好的,这样方便我们对照。


刷题有一个技巧,就是不断重复 3-5 遍,不断加深印象。有时候刷题不一定要知道题目的前因后果,在有限的时间里面,尽最大可能的让你大脑记忆多次才是王道。

另外我们这次先排除算法题,毕竟我们不是面向 1 线大厂,对算法要求不高,有选择性放弃,集中战斗力在其他更重要的地方。

刷题在面试前 2天来做即可。

最后我根据自己的经验和小龙目前的情况,给他整理了适合他的题目,并且让他至少刷 3 次,最后我通过抽查题目回答来确认他短期刷题的记忆已经足够了。

准备一个优秀(闪闪发光)的简历!

一份优秀的简历是为了让别人快速了解你的。如果你的简历写不好,即使你是天才也会蒙尘,社会的规则就是这样,人们知道的是用“是金子总会发光”来安慰自己,但往往忽略了你起码要让你的光进到别人的眼睛里面才行。

这是标准的简历格式:(记得不要搞乱顺序)

  • 基本资料:姓名、电话、邮箱、个人网站(GitHub)
  • 工作经历:公司名、在职时间、工作内容(简述负责、参与什么业务)
  • 项目经历:最重要的一点没有之一!展开描述
  • 专业技能: 在项目经历的基础上进行增加或者删减,围绕项目经历进行即可。
  • 教育经历:学校名、就读时间
  • 其它:简单描述任何你想让面试官知道的东西,比如社区影响力: GitHub 1000000 Star、掘金 Lv9 等等

例如这样:

基本简历格式有了,但是不够闪亮,那我们要怎么填充最主要的项目经验内容来让你的简历闪闪发光呢?

准备一个“优秀的”项目经验!

项目经验贵精不贵多,一般一个最核心的项目就够了, 如果一个都不能让面试官觉得你很优秀,那么再来多一个也于事无补,这种时候不需要量变引起质变,除非你的能力可以在 2 个项目里面都分别突出你的优秀,不然写一个就够了。

阮一峰老师给出了一些指导意见:

  • 以项目为主体,设计你的简历
  • 针对企业的需要,突出你的技能(如果新公司是用 vue 的,你写 react,这样就不好符合对方预期了)
  • 量化你的项目,给出数字

我在这个基础上补充了一下,结合鼎鼎大名的 STAR 方法来操作的。

STAR 法则其实是英文单词的缩写,完整的单词应该为situation、task、action和result。对应的中文为情境、任务、行动和结果。 STAR 法则通过故事的形式,表现出自己分析阐述问题的清晰性、条理性和逻辑性。

Situation: 事情是在什么情况下发生

Task: 你是如何明确你的任务

Action: 针对这样的情况分析,你采用了什么行动方式

Result: 结果怎样,在这样的情况下你学习到了什么

我们用这个大纲来写:

  • 项目标题:项目名称
  • 项目简介:这个项目是干啥的,有什么特别的地方,项目的背景是什么(Situation)
  • 项目成果:这个项目有什么价值,要有前后数字量化对比 (Result)
  • 项目方案:采用了什么样的方案,从而完成了上面的项目特点(Action)
  • 我的职责:越复杂的方案越不是一个人完成的,我在其中究竟干了什么(Task)
  • 项目技术栈:项目采用了哪些框架、工具开发

一般人是这样写的:(平淡,索然无味,没啥意思,千篇一律)

我负责的项目是一个xxx 电商平台的后台管理系统,使用的技术栈主vue框架全家桶系列和 egg 来做 bff 中间层,包括axios,router,vuex,element-ui框架开发,
大部分功能是基于element-ui进行业务逻辑组件的二次封装,主要有订单管理,微信退款,权限角色登陆等,接口部分又 egg 作为中间层进行代理处理。
这个项目前端和 nodejs方面由我负责,前端团队成员是 3 人。

这是改写后的:

项目标题:电商 xxx后台管理系统前后端分离改造项目
项目简介:
1. 这是一个负责年营业额五百万的 xxx 业务的后台管理系统。
2. 这个项目原来是纯 jsp 的模式开发的后台管理系统,随着业务发展,系统变得越来越庞大,该系统开发周期长,上线后bug 很多,维护修复问题时间长,系统处理响应速度很慢,导致业务受到了很大影响。
3. 该项目原来并没有自动化集成测试和自动化部署,都是人工手动测试和部署。
4. 在投入很多开发资源支持下,依然没有办法很好改善,与公司讨论后决定将系统进行前后端架构分离,前端使用 vue 进行 spa 单页面开发,并且使用 nodejs 作为 bff 层,后端只负责提供接口并且实行自动化集成开发,自动化集成测试和自动化部署模式。

项目成果:
1. 系统性能提高了:
   a. 页面响应速度从原来等待 5-6秒完成页面打开到现在3 秒内完成。
   b. 因为单页面应用,很多逻辑表单处理可以合并到前端交互处理,业务人员操作系统的时间大大减少,例如以前往往需要 2-3 个页面跳转完成处理,现在在一个页面即可完成,系统的易用性也大幅度提高,得到了业务部的一致好评。
2. 系统更稳定了:
   a. 上线后 bug 的数量比之前减少了70%,原来单功能的 bug 数量在 10 -15 左右,现在单功能 bug 数量是 5 以下。
3. 开发资源的投入减少了,开发周期缩短了:
   a. 原来后端开发人员 7 人,测试人员  3 人,现在只需要后端开发人员 2 个,测试人员 1 个,前端开发人员 2 个,nodejs 1 个。
   b. 原来平均单功能上线周期是 10 天,现在为平均单功能上线周期是 3 天。

项目方案:
1. 采用vue 作为主要的 spa 单页面架构模式,将页面的功能改为模块和组件来维护,基于 elementsUI 做基础样式和功能的条件下,设计和开发自己业务的组件和模块,进行统一组件化,模块化维护样式和功能,避免重复开发。
2. 样式使用 less 代替 stylus,less 在语法上更加标准,代码结构更加清晰,在多人协作和复杂样式情况下提高可维护性。
3. 采用 egg 做为 bff 层,主要是因为当时后端的接口质量相对较差,为了避免前端界面过多兼容接口逻辑处理而影响了性能和维护性的问题而加入的,另外在系统技术栈过渡的时候,采用局部业务逻辑分阶段更新,保证系统平滑过渡而避免对业务造成影响。
4. 使用 jenkins +webpack 进行前端和 nodejs 的代码自动化集成,自动化测试和自动化部署。
5. 改造时间历时 3 个月,分  3 个阶段完成:
   a. 第一阶段先建立自动化处理基础建设,并且对项目组人员进行指导,首先让团队达成一致的想法,并且建立相对应的开发规范。
   b. 第一阶段先使用非重点业务功能来进行改造,目的是试验 nodejs 和 vue 的开发模式被开发人员熟练,并且提前将实际落地的遇到的问题解决掉,为下一步核心业务过渡做准备。
   c. 第二阶段完成全平台业务逐步过渡,每过渡一个业务都需要进行全面测试确认没问题后,再开始进行下一个业务过渡。

我的职责: 
我负责这个项目的前端架构设计,代码的review,代码和组件的规范设计,核心模块的编写,并且跟业务和产品进行沟通,管理和协调安排开发资源,带来团队成员有计划进行项目开发工作。

项目技术栈:
vue 2.5 版本,axios、vue-router、vuex、elements-UI、echart,Mocha、co-mocha、webpack、egg

工作经历其实就是项目经历的省略版,只要写好项目经历,进行缩短简略就可以得到工作经历了。

专业技能,其实就是你项目经历用到的技术栈在增加或者减少就行了。

第五步:如何高效投简历

因为我们是锁定目标的投简历,我们知道这家公司,所以不需要海投。

但是我们要知道他们公司的 hr 是怎么筛选简历的,从而思考我们的简历怎么可以脱颖而出。

这里需要我们做一下假设,假设你是 hr,你会怎么收集简历,怎么过滤简历,怎么阅读简历?

一般 hr 收集简历的操作:

  • 从招聘渠道收集简历,一般都会根据关键字策略自动发送到hr 的邮箱。
  • 有一个固定周期,定期查阅这个邮箱。
  • 如果使用 boss 直聘的话,直接打开 app 可以看到,或者可以直接通过联系用户,和获取用户简历。

一般招聘渠道有以下几个:

  • 猎聘(传统企业较多)
  • 51job前程无忧(传统企业较多)
  • 智联招聘(传统企业较多)
  • boss 直聘(互联网企业较多,最近比较流行,体验上也方便)
  • 拉勾网(互联网企业较多)
  • 内推(如果有内推就最好了)
  • 猎头(猎头一般做高端生意,一般职位是不会有猎头有兴趣的)
  • 公司邮箱

一般 hr 过滤简历的操作:

  • 用关键字过滤,例如招聘,应聘,XX 工程师,xx 学历作为文件的名字筛选匹配关键字,如果关键字没有,容易被忽略。
  • 有些时候简历会很多,如果没有关键字,根本察觉不到。

一般 hr 阅读简历的操作:

  • 一般不在周一看简历,因为周一会议很多,没时间。
  • 一般hr电脑 标配安装 office word,而且 word 文件也容易适配打印机打印。
  • hr都喜欢 word 打开简历,不太喜欢打开别的文件类型,嫌麻烦,可能有时候打不开。
  • 优先查看学历和年纪,然后再看工作(项目)内容的关键字是否有公司要求的内容,例如招聘前端,要有 vue 字样,如果发现了,就会再认真看看其他内容。

有见及此,可以大大提高简历被阅读,并且约谈面试的机会的:

  1. 错开简历投递“高峰”,HR周一会有很多琐碎的事情处理,通常周二周三发布启事,接下来的时间就会开始筛选简历、接触候选人。数据也显示,与周五上午9至10点发送的邮件相比,周四同一时段的邮件回复率要高出12%。至于一天中最佳的简历投递时间,同样也最好选在HR上班期间,上午9点到11点效果最好,下午则可以在13点半到15点半期间发送。
  2. 要有一份闪闪发光的简历,清晰,简洁,有亮点,简历格式用标准word格式来写,并且简历的文件名要这样写:“姓名_应聘资深前端工程师_2021-01”。
  3. 如果可以,个人经验比较推荐 boss 直聘,可以直接跟 hr 聊,可以直接发给 hr,hr 会当场查阅你的简历,而不是等邮件回复。
  4. 如果是发送邮件到对方公司邮箱的话,邮件主题要注明清楚:“三年开发经验应聘资深前端工程师_姓名”,邮件内容也要有标准礼貌。

如果是在 boss 直聘的话,需要先上传附件简历,然后再跟 hr 聊的时候可以发送过去

如果选择的是自己发送邮件的方式的话,邮件主题要注明清楚:“三年开发经验应聘资深前端工程师_姓名”

邮件格式如下(注意对齐):

张先生, 
      您好,我是XXX。我对贵公司的 XXX 职位很有兴趣,附件里面是我的简历,
      如果您对我的个人履历感兴趣,可以随时与我联系。谢谢。
 

感谢您的阅读,谢谢。
 

                                            应聘者:XXX  
                                            2021 年 1 月 29 日

公司邮箱可以在对方官网里面找,例如这个:

第六步:如何优秀通过面试

那么,面试机会来了,你一般约面试要约 1 天之后,这样让你容易放松一些,避免一上来就约隔天面试,过度紧张导致影响发挥。

我让小龙约面试是 2 天后。

大公司和小公司的面试流程

一般来说,一个基本面试流程是这样的:

  1. 开场白
  2. 候选人自我介绍
  3. 面试
  4. 附加信息
  5. 结束

大公司,例如人数往往超过 300 人以上的企业,流程基本一致,但是比较长。可能会有四面甚至五,六面的情况:

  1. 一面基础知识
  2. 二面项目经验
  3. 三面领导面
  4. 四面 hr 面

中小型公司,人数往往低于 300人的企业,流程就比较简

  1. 一面基础和项目知识
  2. 二面领导和 hr

中小公司比较注重实际实际项目技能,主要看你是否可以马上开始工作,对于一些基础知识并不太关注(不代表啥都不会),而主要关注你的项目细节,大公司,本身内部有比较完善培训流程和分工,所以对基础知识,算法都比较在意,虽然也会重视你的项目细节,但是他们更关注你的基础。

小龙这个公司我定义为中厂,属于中小厂类,所以我们将面试的重点放在项目细节上。

准备一场优质的模拟面试!

军事领域里面有一个东西叫沙盘模拟,战争沙盘模拟推演通过红、蓝两军在战场上的对抗与较量,发现双方战略战术上存在的问题,提高指挥员的作战能力,模拟推演跨越了通过实兵军演检验与培养高级将领的巨大成本障碍和时空限制,受到世界各国的普遍运用。

我们安排模拟面试的原因就是因为我们要提前演练,提前知道可能发生的任何情况,以便达到在真正面试现场减少出错,达到成功获得 offer 的终极目标

我们现在来帮小龙模拟整个面试流程:

  1. 准备着装
  2. 带好简历打印版,手机充好电,带好身份证
  3. 出门,提前 10 分钟到达对方公司
  4. 联系对方 hr
  5. 等待安排面试
  6. 做试题
  7. 开始面试
  8. 开场白
  9. 自我介绍
  10. 对方会根据你的简历和试题完成情况对你进行发问,一般会先问试题的一些问题,然后再问你简历项目的情况
  11. 面试进入尾声,对方会问,有什么你想要了解的
  12. 面试进入领导面
  13. 面试进入 hr 面
  14. 面试结束回家

大概整个流程是这样的,可能还有一些细节每个人有点区别。

这个模拟面试里面有很多地方需要注意或者提前准备,我这里挑一些比较重点的来说:

  1. 相关资料要提前准备好,避免出门丢三落四。
  2. 面试要准时,准时是一个基本职场素养。
  3. 自我介绍要引起对方注意。
  4. 与对方面试官,技术面,hr 面,领导面的一些注意事项
  5. 你要准备好最后你要有问题咨询对方面试官,这是一个表现出你对对方公司和职位有兴趣的一个好机会。

要准备无敌的自信

有些人会说,我们是跟面试官攀关系,要谦虚,要谦卑,要奉承对方,以此来换得对方的高兴,从而增加通过的成功率。

我认为,谦虚谦卑是对的,但是如果只是说只有这些,是不足够的,首先你要充满自信,让别人觉得你是有把握的,不能做贼心虚。

良好的自信心,一方面需要靠自身本事,另外一方面是靠自己的心理建设,要时刻跟自己说,这只是一个面试,仅仅是一个面试。

相信自己可以的,信任自己过往的努力和不放弃。

世界不曾亏欠每一个努力的人。

准备一个优秀的自我介绍

因为首因效应,我们需要有一个优秀的自我介绍去提升面试官对你的第一印象,而好的第一印象会贯穿你的整个面试过程,这是开门第一炮,必须打好

这里每个人都不一样,但是有些原则是要遵守的:

  • 注意时间不超过 3 分钟
  • 往岗位需求靠拢
  • 要有数字
  • 有特色,有起伏
  • 语言表达过程要流畅,不能吱吱呜呜的,断断续续的

例如,这个自我介绍可能已经比很多人的都要好了,但是没办法大幅度增加面试官的第一印象,我觉得是不足够的:

我有过2年前端开发经验经验,开发过的项目有A、B、C,这几个项目里面我最有印象的是 c,这是一个 xxx 业务系统的子系统,承载了年营业额 500w 的系统,这里我用到技术栈是 vue,xxxx。

我稍微修改一下:

我有过2年前端开发经验经验,开发过的项目有A、B、C,这几个项目里面我最有印象的是 c,这是一个 xxx 业务系统的子系统,本来只是一个小系统,没人想维护,最终分到了我的头上。

刚开始我发现它代码耦合很严重,很多代码都是是粗犷式开发,改一个地方,很多地方莫名其妙出错了,一个小系统的维护居然花了我好几天时间,然后我就生气了。

我对代码有些洁癖,通过几天时间我梳理了这个系统的整个前端逻辑,然后通过封装和模块组合,分层和解耦强联系业务逻辑,用一周时间,几乎重写了这个系统的前端,并且在重要的地方加入适量的注释和文档,整个系统的维护难度一下子就变得简单了很多。

后来这个系统成长为了年营业额 500w 的主业务系统,得到了公司的重视,我顺便还得了个xx年度最佳开发者奖。

另外还有一个技巧,我们可以通过自我介绍产生的第一印象去引导面试官的问题方向,这样就更容易在自己熟悉的方向上进行问题回答,更容易增加面试成功的概率

如何应对面试官拷问?

一般来说对方会根据你的面试题结果来咨询你,然后会根据你简历上写的项目信息来有选择性发问。

在简历编写期间,使用 STAR 方法可以更清楚梳理你的价值。但是在实际面试的时候,你还要补充上 PDCA 方法来让对方知道你的综合价值。

面试官更希望知道你遇到这些问题时候是怎么思考和实践的,因为这样才能更全面的知道一个人是否可以独立完成工作。

PDCA四个英文字母及其在PDCA循环中所代表的含义如下:
 1、 P(Plan)--计划,确定方针和目标,确定活动计划;
 2、 D(Do)--执行,实地去做,实现计划中的内容;
 3、 C(Check)--检查,总结执行计划的结果,注意效果,找出问题;
 4、 A(Action)--行动,对总结检查的结果进行处理,成功的经验加以肯定并适当推广、标准化;失败的教训加以总结,以免重现,未解决的问题放到下一个PDCA循环。

每一件事情先做计划,计划完了以后去实施,实施的过程中进行检查,检查结果以后,再把检查的结果进行改进,进行实施,进行改善,这样把没有改善的问题又放到下一个循环里面去,就形成一个一个的PDCA循环。

例如:之前写的xxx 电商平台的后台管理系统,对方根据 pdca 的方法来问,你是怎么做这个计划的,怎么做阶段完成,你印象最深刻的是哪个技术难点,然后你是怎么解决的?

这些都要准备好,才能百战百胜。

有几个原则可以参考一下:

  • 换位思考:如果你是面试官,你会怎样了解对方是否合适?
  • 开阔眼界:了解同类产品是怎么做的,看看业界是怎么处理的。
  • 使用10倍原则:每当情况复杂10倍,采取的策略就要改变,反思自己还能做些什么。
  • 不知道的问题,就说解题思路,把自己的想法说出来,不用考虑是否正确。

如何面对领导leader面

领导面主要是看你这个人的工作态度,人品,还有就是是否能够融入团队,可塑性(容易管理)是否足够强。

一些比较经典:

  • 问一下你怎么跟团队相处和合作?
  • 如何处理意见分歧的呢?
  • 对自己未来有什么职业规划?
  • 如何面对压力下工作?

提前准备好对应的答案之余,还要准备一些反问对方,因为对方是领导,领导喜欢被别人请教,从而增加自己的虚荣感

例如:

  • 关于团队协作:我非常享受和乐意跟团队相处和工作。我相信我会对团队的环境做出很大的贡献的,我既可以担当团队领导也可以成为团队成员,无论担当什么角色,我都会做的很好,……请问贵司团队大概是什么情况,如果我有幸进入贵司,我需要跟那些团队协作?
  • 关于处理意见分歧:一方面,我不想做没有原则的老好人,另一方面,大家都是朝夕相处的同事,我会照顾好对方的感受。我当时是这样做的……不过这个是我自己的做法,我都不知道是否做的正确,我可以从您那里得到一些指教么?
  • 关于职业规划:进入公司之后,我会积极融入团队,尽快适应公司环境。对于新知识和新技术,我也会制定自己的一个学习计划。在未来2-3年内,我希望能够争取做到自己在前端开发技术上没有短板,可以指导和帮助其他同事更好的完成工作。在3-5年内,我会努力的朝着管理层发展,提升自身管理才能,为公司做出更大的贡献。
  • 关于压力下工作:压力使我提升自己、获得进步。曾经有一次我需要在一周之内完成三个大项目,在排列好三个项目的优先等级后,我和同事们加班加点全神贯注的提前高效的完成了工作,并且在工作中没有出现任何不必要的失误。

如何面对 hr 面

一些比较经典的:

  • 如何面对加班
  • 你为什么离开上一家公司
  • 你期望的薪资是多少,你原来是是多少
  • 对自己未来有什么职业规划?(有些是领导面,有些是 hr 面)

提前准备好对应的答案就好了,例如:

  • 如果公司目前有重要的项目要跟进,需要整个团队加班完成,那么自己一定接受加班,配合整个团队的工作。
  • 自己岗位的工作在公司不受足够重视,想寻求更多的挑战。

需要注意的是,基本过了技术面之后,hr 这关比较容易,回答不能冒进,要中规中矩,不要以为过了技术面就稳了。

如果技术很喜欢你,但是 hr 不喜欢你,一样也是过不了

补充:无论是哪一面都要准备一个问题!

因为这样既可以让你知道多一些对方公司的事,方便你做最后的决策,另外还可以让你对方感受到了你的认真态度,也可以让对方更容易满足(被人请教),从而提高获得 offer 的概率

  • 一面:面试官一般是你的平级同事,可以多去了解实际的工作内容,便于后续对比 offer,例如:团队业务、日常工作、技术栈、协作、技术分析等
  • 二面:面试官一般是团队骨干或直属 leader,可以多去了解业务和产品的规划、技术建设、对应聘职位的定位与期待等;
  • 三面:面试官一般是部门 leader,这一步可以多了解技术之外的知识,比如面试官自己的成长经验、技术之外的能力、职位发展路线等;
  • Hr 面:这一步可以多去了解公司本身相关的事,比如:你在公司工作的最大的感受是什么?晋升机制是怎样的?等等

模拟面试的复盘

第一次模拟面试,出错百出,这很正常,太久没面试或者没怎么留意面试的工作的人都会这样。小龙的第一次模拟面试,我发现他连身份证都没准备~我给他一梭子之后他终于开始认真了~

把模拟面试遇到的问题进行复盘,记录下来,然后再模拟多一次,一般模拟 3 次左右就效果最好了。

  • 第一次模拟演练是为了暴露问题。
  • 第二次模拟演练是为了修正暴露的问题。
  • 第三次模拟演练是为了熟练演练流程。

尽可能地减少失误,如果遇到一个特别好的offer 的话,如果面试发挥失常是个人原因导致的,那就很伤感了。

万事俱备,去面试咯。

第七步:获得 offer

到了面试那天,小龙还是有点紧张,不过他说比之前好多了,之前是超级紧张,现在心里面多少有点谱了,(毕竟模拟面试了几次,套路都知道)

不过结果还不错,成功斩获了一个至少是 11k 的 offer,不过我觉得 12k 也很稳的。

其实拿 offer 也是很简单的嘛~~啊哈哈哈

看到这里,必须双手奉上相关文中提到过的资料,大家见好就收吧~

希望可以帮到你,我是小辉哥。

因为小时候不努力学编程,毕业去做了网管,以为跟互联网 IT 沾边,后来发现其实做开发才是,所以又努力掰了回来,期间刷过盘子,修过电脑,写过 php,玩过 java,舞过前端开发,练过项目经理,弄过产品经理,官职最强上至技术总监,收入从月入 800 到50k,我发现,百万年薪真的很难的,不过我毕竟也走到这里了,还不错。

我听说很多年轻(中青年)人对现在的环境感到很浮躁、很焦虑、很担忧,所以我就来看看能不能帮上忙~