├── LICENSE ├── Makefile ├── README.md ├── arts ├── basic-workflow.sketch ├── build-workflow.sketch ├── future-stacks.sketch └── primard.sketch ├── build ├── author.html ├── head.html ├── metadata.xml ├── share.html ├── stats.html └── title.txt ├── chapters ├── 00-prelude.md ├── p1-0.md ├── p1-1-keys.md ├── p1-2-new-framework.md ├── p1-3-builder.md ├── p1-4-architecture.md ├── p1-5-automation.md ├── p1-6-pattern.md ├── p2-0.md ├── p2-1-growth.md ├── p2-3-next-jquery.md ├── p2-3-soft-skill.md ├── p3-0.md ├── p3-1-depth.md ├── p3-2-future.md ├── p3-3-turn-in.md └── p3-4-turn-out.md ├── css └── vendor.css ├── ebook.md ├── epub.css ├── images ├── PhantomCSS.png ├── basic-workflow.png ├── build-workflow.png ├── eks-example.jpg ├── front-end-workflow-presentation.jpg ├── future-stacks.png ├── gartner-hype-cycle.png ├── refe.png ├── tech-decide.png └── webpack-react-process.png ├── img ├── cover.jpg └── favicon.ico ├── index.html ├── listings-setup.tex ├── log └── coral.log ├── material ├── Hybrid-Automation-Testing-Scenario.jpg ├── agile_pyramid2.jpg ├── chaplin-lifecycle.png ├── crossbrowser.png └── test-serv-copy.png ├── style.css └── template └── template.tex /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Fengda Huang 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | include_dir=build 2 | source=chapters/*.md 3 | title='前端进阶指南' 4 | filename='ebook' 5 | 6 | 7 | all: html epub rtf pdf mobi 8 | 9 | markdown: 10 | awk 'FNR==1{print ""}{print}' $(source) > $(filename).md 11 | sed -i 's@](../images@](images@g' $(filename).md 12 | 13 | html: markdown 14 | pandoc -s $(filename).md -t html5 -o index.html -c style.css \ 15 | --include-in-header $(include_dir)/head.html \ 16 | --include-before-body $(include_dir)/author.html \ 17 | --include-before-body $(include_dir)/share.html \ 18 | --include-after-body $(include_dir)/stats.html \ 19 | --title-prefix $(title) \ 20 | --normalize \ 21 | --smart \ 22 | --toc 23 | 24 | epub: markdown 25 | pandoc -s $(filename).md --normalize --smart -t epub -o $(filename).epub \ 26 | --epub-metadata $(include_dir)/metadata.xml \ 27 | --epub-stylesheet epub.css \ 28 | --epub-cover-image img/cover.jpg \ 29 | --title-prefix $(title) \ 30 | --normalize \ 31 | --smart \ 32 | --toc 33 | 34 | rtf: markdown 35 | pandoc -s $(filename).md -o $(filename).rtf \ 36 | --title-prefix $(title) \ 37 | --normalize \ 38 | --smart 39 | 40 | pdf: markdown 41 | # OS X: http://www.tug.org/mactex/ 42 | # Then find its path: find /usr/ -name "pdflatex" 43 | # Then symlink it: ln -s /path/to/pdflatex /usr/local/bin 44 | pandoc -s $(filename).md -o $(filename).pdf \ 45 | --title-prefix $(title) \ 46 | --listings -H listings-setup.tex \ 47 | --template=template/template.tex \ 48 | --normalize \ 49 | --smart \ 50 | --toc \ 51 | --latex-engine=`which xelatex` 52 | 53 | mobi: epub 54 | # Symlink bin: ln -s /path/to/kindlegen /usr/local/bin 55 | kindlegen $(filename).epub -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 前端进阶指南 2 | === 3 | 4 | > 《[我的职业是前端工程师](https://github.com/phodal/fe)》姐妹篇《前端进阶指南》 5 | 6 | 2017 年 1 月份,看完村上春树的新书《我的职业是一个小说家》,我便萌发了写一个《[我的职业是前端工程师](https://github.com/phodal/fe)》系列文章的想法——以个人视角来看前端领域的各种技术。整个系列的文章大概有 15 篇左右,从我是如何成为一个前端工程师,到各种前端框架的知识。 7 | 8 | **在完成《[我的职业是前端工程师](https://github.com/phodal/fe)》后,我便想写一个前端进阶指南,可是期间发生了一些事情,便放弃了这个想法~。现在,这本电子书就这么未完待续** 9 | 10 | 关注我的微信公众号(扫描下面的二维码或搜索 Phodal). 11 | 12 | ![QRCode](http://articles.phodal.com/qrcode.jpg) 13 | 14 | 目录 15 | --- 16 | * [前端进阶指南](#前端进阶指南) 17 | * [什么是前端](#什么是前端) 18 | * [本书内容](#本书内容) 19 | * [硬技能篇](#硬技能篇) 20 | * [前端知识要点](#前端知识要点) 21 | * [前端应用的生命周期](#前端应用的生命周期) 22 | * [入门](#入门) 23 | * [中级篇](#中级篇) 24 | * [高级篇](#高级篇) 25 | * [工程化](#工程化) 26 | * [兼容性](#兼容性) 27 | * [前端特定](#前端特定) 28 | * [软件工程](#软件工程) 29 | * [调试](#调试) 30 | * [测试](#测试) 31 | * [性能与优化](#性能与优化) 32 | * [设计](#设计) 33 | * [SEO](#seo) 34 | * [快速学习新的框架](#快速学习新的框架) 35 | * [快速学习是基本能力](#快速学习是基本能力) 36 | * [如何学习新框架:守-破-离](#如何学习新框架守-破-离) 37 | * [守:应用业务知识](#守应用业务知识) 38 | * [破:学习框架核心](#破学习框架核心) 39 | * [离:探索更多可能性](#离探索更多可能性) 40 | * [小结](#小结) 41 | * [选择合适的前端框架](#选择合适的前端框架) 42 | * [Angular,一站式提高生产力](#angular一站式提高生产力) 43 | * [React,组件化提高复用](#react组件化提高复用) 44 | * [Vue.js,简单也是提高效率](#vue.js简单也是提高效率) 45 | * [构建系统:资深分界线](#构建系统资深分界线) 46 | * [为什么构建很重要](#为什么构建很重要) 47 | * [构建工具](#构建工具) 48 | * [构建流程](#构建流程) 49 | * [构建示例](#构建示例) 50 | * [自动刷新](#自动刷新) 51 | * [转译](#转译) 52 | * [预处理](#预处理) 53 | * [什么是前端的架构能力](#什么是前端的架构能力) 54 | * [“标准”的 SPA 构架实践](#标准的-spa-构架实践) 55 | * [前后端分离](#前后端分离) 56 | * [无状态 API](#无状态-api) 57 | * [workflow](#workflow) 58 | * [前后端分离的工作方式](#前后端分离的工作方式) 59 | * [风格指南:StyleGuide](#风格指南styleguide) 60 | * [演进](#演进) 61 | * [最佳实践:框架](#最佳实践框架) 62 | * [jQuery + TinyMCE](#jquery-tinymce) 63 | * [jQuery + Vue](#jquery-vue) 64 | * [自动化提高效率](#自动化提高效率) 65 | * [自动化测试加快上线流程](#自动化测试加快上线流程) 66 | * [测试](#测试-1) 67 | * [ui 测试](#ui-测试) 68 | * [截屏测试,](#截屏测试) 69 | * [自动构建](#自动构建) 70 | * [自动化部署](#自动化部署) 71 | * [持续集成](#持续集成) 72 | * [前端应用的架构与设计模式](#前端应用的架构与设计模式) 73 | * [散弹式架构 -> jQuery](#散弹式架构---jquery) 74 | * [分层结构 MV*](#分层结构-mv) 75 | * [处理数据 pipe and filter](#处理数据-pipe-and-filter) 76 | * [数据显示 观察者模式](#数据显示-观察者模式) 77 | * [数据通讯](#数据通讯) 78 | * [消息通讯](#消息通讯) 79 | * [数据通讯:shared repository](#数据通讯shared-repository) 80 | * [数据通讯:local storage](#数据通讯local-storage) 81 | * [软技能篇](#软技能篇) 82 | * [在做业务的过程中提升技术](#在做业务的过程中提升技术) 83 | * [测试](#测试-2) 84 | * [代码可读性](#代码可读性) 85 | * [有意图的提升](#有意图的提升) 86 | * [持续学习:走出下一个『jQuery』](#持续学习走出下一个jquery) 87 | * [jQuery 已经落后了?下一个 jQuery 已经出现了](#jquery-已经落后了下一个-jquery-已经出现了) 88 | * [持续学习](#持续学习) 89 | * [掌握思想](#掌握思想) 90 | * [后端技能](#后端技能) 91 | * [软技能](#软技能) 92 | * [知识管理](#知识管理) 93 | * [Debug: 发现问题](#debug-发现问题) 94 | * [扩展篇](#扩展篇) 95 | * [前端知识体系的广度与深度](#前端知识体系的广度与深度) 96 | * [前端与后台的对比](#前端与后台的对比) 97 | * [用户体验设计](#用户体验设计) 98 | * [前端的广度](#前端的广度) 99 | * [前端的趋势](#前端的趋势) 100 | * [微服务与微前端](#微服务与微前端) 101 | * [BFF](#bff) 102 | * [状态管理](#状态管理) 103 | * [跨平台](#跨平台) 104 | * [UI 生成](#ui-生成) 105 | * [转型前端指南](#转型前端指南) 106 | * [改变](#改变) 107 | * [后台转前端的挑战](#后台转前端的挑战) 108 | * [其他编程领域转前端](#其他编程领域转前端) 109 | * [其他行业转前端](#其他行业转前端) 110 | * [劝退](#劝退) 111 | * [立意已决](#立意已决) 112 | * [前端跨行指南](#前端跨行指南) 113 | * [移动开发:混合开发](#移动开发混合开发) 114 | * [桌面应用](#桌面应用) 115 | * [VR](#vr) 116 | * [硬件](#硬件) 117 | * [其它?](#其它) 118 | 119 | LICENSE 120 | --- 121 | 122 | [![Phodal's Article](http://brand.phodal.com/shields/article-small.svg)](https://www.phodal.com/) [![Phodal's Book](http://brand.phodal.com/shields/book-small.svg)](https://www.phodal.com/) 123 | 124 | 125 | © 2017 [Phodal Huang](https://www.phodal.com). This code is distributed under the Creative Commons Attribution-Noncommercial-No Derivative Works 3.0 License. See `LICENSE` in this directory. 126 | 127 | [待我代码编成,娶你为妻可好](http://www.xuntayizhan.com/blog/ji-ke-ai-qing-zhi-er-shi-dai-wo-dai-ma-bian-cheng-qu-ni-wei-qi-ke-hao-wan/) 128 | -------------------------------------------------------------------------------- /arts/basic-workflow.sketch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/fed/2ef56a5a9431c5144b1017e9fd962e3b8ba3ac32/arts/basic-workflow.sketch -------------------------------------------------------------------------------- /arts/build-workflow.sketch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/fed/2ef56a5a9431c5144b1017e9fd962e3b8ba3ac32/arts/build-workflow.sketch -------------------------------------------------------------------------------- /arts/future-stacks.sketch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/fed/2ef56a5a9431c5144b1017e9fd962e3b8ba3ac32/arts/future-stacks.sketch -------------------------------------------------------------------------------- /arts/primard.sketch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/fed/2ef56a5a9431c5144b1017e9fd962e3b8ba3ac32/arts/primard.sketch -------------------------------------------------------------------------------- /build/author.html: -------------------------------------------------------------------------------- 1 |

2 |

前端进阶

3 |

Phodal

4 |

-------------------------------------------------------------------------------- /build/head.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /build/metadata.xml: -------------------------------------------------------------------------------- 1 | 前端进阶 2 | Phodal 3 | Creative Commons Attribution Non-Commercial Share Alike 3.0 4 | zh-CN -------------------------------------------------------------------------------- /build/share.html: -------------------------------------------------------------------------------- 1 |
2 | -------------------------------------------------------------------------------- /build/stats.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/fed/2ef56a5a9431c5144b1017e9fd962e3b8ba3ac32/build/stats.html -------------------------------------------------------------------------------- /build/title.txt: -------------------------------------------------------------------------------- 1 | % 前端进阶 2 | % Phodal -------------------------------------------------------------------------------- /chapters/00-prelude.md: -------------------------------------------------------------------------------- 1 | # 前端进阶指南 2 | 3 | ## 什么是前端 4 | 5 | 作为一本前端进阶的书,没有理由去强调一下**什么是前端**?可是,当你说前端的时候,我也说前端的时候,我们说的是同一个前端吗? 6 | 7 | 我理解下的前端,指广泛意义上的前端。又可以称为『客户端』,泛指:与用户做交互的应用。如桌面浏览器上的浏览器、图形用户界面,移动设备上的应用程序、浏览器,又或者是各种智能、联网设备的交互都可以归属于前端。 8 | 9 | 因而,在这种意义上来说,前端要做的不仅仅是 Web,还可以是混合应用,原生应用等等。 10 | 11 | 这就意味着: 12 | 13 | - 你可以使用 CSS Layout + React Native 编写移动程序 14 | - 你可以使用 Electron 来编写桌面应用 15 | - 你可以使用 React VR 来编写 VR 应用 16 | - 等等 17 | 18 | 这种时候,前端指的是,我们使用 **样式(类CSS) + 类JavaScript + 模板(HTML、XML等** 编写的应用。 19 | 20 | 如果那些用 JavaScript 编写的应用,也划分到前端的范畴,那么: 21 | 22 | - 你还可以使用 JavaScript 与 Ruff、 Tessel 对硬件进行编程 23 | - 你还可以使用 Node.js 来编写后台应用,又或者是 BFF (backend for frontend)层 24 | 25 | 在这里,我们将前端定义为 类CSS + 类 JavaScript + 模板。因为没有图形应用的应用,难以直观的与用户进行交互,做不了『客户端』应用。在这一定义下,这一类型的应用有,桌面应用、桌面网页、移动网页、移动应用等等,现在发展的有 VR 技术等等。 26 | 27 | ## 本书内容 28 | 29 | 30 | -------------------------------------------------------------------------------- /chapters/p1-0.md: -------------------------------------------------------------------------------- 1 | # 硬技能篇 2 | -------------------------------------------------------------------------------- /chapters/p1-1-keys.md: -------------------------------------------------------------------------------- 1 | # 前端知识要点 2 | 3 | 罗列一下,一些必要的知识点 4 | 5 | 6 | 希望读者都是知道的,以便于 7 | 8 | 作为一个领域,它拥有相当多的知识点。 9 | 10 | 如果读者已经知道了这些,那么可以跳过这一章的内容。 11 | 12 | ## 前端应用的生命周期 13 | 14 | ![前端应用的生命周期](../images/refe.png) 15 | 16 | ### 入门 17 | 18 | 在我理解下的基础知识,就是我们可以写一些基本的样式,并能对页面的元素进行操作。举例来说,就是我们用Spring和JSP写了一个博客,然后我们可以用jQuery来对页面进行一些简单的操作,并可以调用一些API。因此,我们需要基本的HTML / CSS知识。只是要写好CSS并不是一件简单的事,这需要很多实战经验。随后,我们还需要有JavaScript的经验,要不怎么做前端呢? 19 | 20 | 同时,我们还需要对DOM有一些基础的了解,才能做一些基本的操作,如修改颜色等等。在这种情况下,最简单的方案就是使用jQuery这样的工具。不过,如果可以自己操作DOM是再好不过的了。 21 | 22 | ### 中级篇 23 | 24 | 中级篇就更有意思了,现在我们就需要对页面进行更复杂的操作。Ajax和JSON这两个技能是必须的,当我们要动态的改变页面的元素时,我们就需要从远程获取最新的数据结果。并且我们也需要提交表单到服务器,RESTful就是必须要学会的技能。未来我们还需要Fetch API,ReactiveX这些技能。 25 | 26 | 除此我们还需要掌握好HTML的语义化,像DIV / CSS这也会必须会的技能,我们应该还会使用模板引擎和SCSS / SASS。而这个层面来说,我们开始使用Node.js来完成前端的构建等等的一系列动作,这时候必须学会使用命令行这类工具。并且,在这时候我们已经开始构建单页面应用了。 27 | 28 | ### 高级篇 29 | 30 | JavaScript是一门易上手的语言,也充满了相当多的糟粕的用法。几年前人们使用CoffeeScript编成成JavaScript来编写更好的前端代码,现在人们有了ES6、TypeScript和WebPack来做这些事。尽管现在浏览器支持不完善,但是他们是未来。同样的还有某些CSS3的特性,其对于某些浏览器来说也是不支持的。而这些都是基于语言本来说的,要写好代码,我们还需要掌握面向对象编程、函数式编程、MVC / MVVM / MV*这些概念。作为一合格的工程师,我们还需要把握好安全性(如跨域),做好 授权(如HTTP Basic、JWT等等)。 31 | 32 | ### 工程化 33 | 34 | 这个标题好像是放错了,这部分的内容主要都是自动构建的内容。首先,我们需要有基本的构建工具,无论你是使用gulp、grunt,还是只使用npm,这都不重要。重要的是,你可以自动化的完成构建的工具,编译、静态代码分析(JSLint、CSS Lint、TSLint)、对代码质量进行分析(如Code Climate,可以帮你检测出代码中的Bad Smell)、运行代码中的测试,并生成测试覆盖率的报告等等。这一切都需要你有一个自动构建的工作流。 35 | 36 | ### 兼容性 37 | 38 | 虽然我们离兼容IE6的时代已越来越远了,但是我们仍然有相当多的兼容性工作要做。基本的兼容性测试就是跨浏览器的测试,即Chrome,IE,Firefox,Safari等等。除此还有在不同的操作系统上对同一浏览器的测试,某些情况下可能表现不一致。如不同操作系统的字体大小,可能会导致一些细微的问题。而随着移动设备的流行,我们还需要考虑下不同Android版本下的浏览器内核的表现不致,有时候还要一下不成器的Windows Phone。除此,还有同一个浏览器的不同版本问题,常见于IE。。 39 | 40 | ### 前端特定 41 | 42 | 除了正常的编码之外,前端还有一些比较有意思的东西,如CSS3和JavaScript动画。使用Web字体,可惜这个不太适合汉字使用。还有Icon字体,毕竟这种字体是矢量的。不过Icon字体还有一些问题,如浏览器对其的抗锯齿优化,还有一个痛是你得准备四种不同类型的字体文件。因此,产生了一种东西SVG Sprite,在以前这就是CSS Sprite,只是CSS Sprite不能缩放。最后,我们还需要掌握一些基本的图形和图表框架的使用。 43 | 44 | ### 软件工程 45 | 46 | 这一点上和大部分语言的项目一样,我们需要使用版本管理软件,如git、svn,又或者是一些内部的工具。总之你肯定要有一个,而不是 2016.07.31.zip这种文件。然后,你还需要一些依赖管理工具,对于那些使用Webpack、Browserify来将代码编写成前端代码的项目来说,npm还是挺好用的。不过就个人来说,对于传统的项目来说我总觉得bower有些难用。我们还需要模块化我们的源码文件,才能使其他人更容易开始项目。 47 | 48 | ### 调试 49 | 50 | 作为一个工程师来说,调试是必备的技能。大部分浏览器都自带有调试工具,他们都不错——如果你使用过的话。在调试的过程中,直接用Console就可以输出值、计算值等等。如果你的项目在构建的过程中有一些问题,你就需要debugger这一行代码了。在一些调用远程API的项目里,我们还需要一些更复杂的工具,即抓包工具。在调试移动设备时,像Wireshark、Charles这一类的工具,就可以让我们看到是否有一些异常的请求。当然在这个时候,还有一个不错的工具就是像Chrome自带的远程设备调试。对于移动网站来说,还要有Responsive视图。 51 | 52 | ### 测试 53 | 54 | 我遇到的很多前端工程师都是不写测试的,于是我便把它单独地抽了出现。对于一个前端项目来说,正常情况下,我们要有单元测试、功能测试,还有要一些UI测试来验证页面间是否可以跳转。对于依赖于第三方服务的应用来说,还要有一个Mock的服务来方便我们测试。如果是前后端分离的项目,我们还需要有集成测试。 55 | 56 | ### 性能与优化 57 | 58 | 要对Web应用进行性能优化,可能不是一件容易的事,有时候我们还知道哪些地方可以优化。这时候人们就可以使用Yahoo的YSlow,或者我最喜欢的Google PageSpeed来检测页面的一些问题,如有没有开启GZip、有没有压缩、合并、Minify JS代码等等。我们还应该借助于NetWork这一类的工具,查看页面加载时,一些比较漫的资源文件,并对其进行优化。在一些情况下,我们还需要借助如Chrome的Timline、Profiel等工具来查看可以优化的地方。 59 | 60 | ### 设计 61 | 62 | 前端工程师还需要具备基本的UI技能。多数情况下拿到的只是一张图,如果是一个完整的页面,我们就需要快速分割页面布局。而依赖于不同的页面布局,如响应式、网格、FlexBox布局也会有不同的设计。而有些时候,我们就需要自己规划,制作一个基本的线框图(Wireframe)等等。 63 | 64 | ### SEO 65 | 66 | 如果以搜索引擎作为流量来源,我们还需要考虑页面的内容,除非你用的是竞争排名。像Sitemap可能就不是我们考虑的内容,而我们还要考虑很多点。首先,我们需要保证页面的内容是对于搜索引擎是可见的,并且对应的页面还要有基本的Title、Description和Keyword。然后在一些关键的字体,如栏目标题等等可以用H2之类的大字的地方就不要放过。同时在页面设计的过程中,我们还需要考虑一些内部链接的建设。它即可以提供页面的可见度,又可以提高排名。最后,如果你是面向的是Google等支持结构化数据的搜索引擎,你还需要考虑一下MicroData / MicroFormat这一类东西。 67 | -------------------------------------------------------------------------------- /chapters/p1-2-new-framework.md: -------------------------------------------------------------------------------- 1 | # 快速学习新的框架 2 | 3 | 今天很流行的 Web 框架,半年以后,可能就会在市场上被『淘汰』——技术选型的时候,不被开发人员推荐;又或者它已经推出了全新的版本,使用了全新的 API,我们便需要更新现有应用。 4 | 5 | 前端框架丰富多彩的今天,快速学习新的框架是**每个前端程序员的必备技能**。 6 | 7 | ## 快速学习是基本能力 8 | 9 | 后端程序员,开始一个新的 Web 项目时: 10 | 11 | - 使用 Java 语言,八成会选用 Spring 框架。 12 | - 使用 Ruby 语言,八成会选用 Rails 框架。 13 | - 使用 Scala 语言,八成会先用 Play 框架。 14 | 15 | 而只使用 JavaScript 的前端程序员,开始一个前端项目时。你有几成的把握,能判断他/她出会使用哪个框架? 16 | 17 | 后端程序员在有限的时间内,只会使用固定的技术栈,固定的框架。对于大部分的公司来说,使用相同的后台语言,是一个更好的选择——即可以减少带成本,又可以沉淀下技术积累。 18 | 19 | 而前端则不一样,不同的项目都有各自的需求,因此采用使用不同的技术栈。简单的,可以直接使用原生的 JavaScript 完成,又或者是使用 jQuery 完成开发。稍微复杂一点的项目,采用容易上手的 Vue.js 是一个不错的选择。更复杂的项目,便可以使用 Angular,可以方便后台程序员转到前端。 20 | 21 | 因此,工作一定年限的程序员,都使用过不同的框架。可是,不同的程序员上手新框架的速度,总会存在一定的差异。 22 | 23 | 那么,怎样才能快速上手一个新的框架呢? 24 | 25 | 学习新的前端框架,要么该框架很火——即**热闹驱动开发**(Hype Driven Development,HDD),要么你们将采用该框架。在采用新框架的动机里,有一种是:技术演进。使用新的技术、框架,来替换现有的框架。旧的框架在某些地方上,存在着明显的缺陷。 26 | 27 | 这种情形下,业务知识本身是不变的,只是要由框架本身来应对业务的变化。因此,使用新的技术来替换旧有的框架,就相当的容易——重写,我们甚至可以直接复制、粘贴,大量原有的代码。只是,仅仅做到重写业务逻辑是不够的。我们还要掌握新的框架的核心,并探索更多的可能性。 28 | 29 | ## 如何学习新框架:守-破-离 30 | 31 | 我在学校的时候,看到一个关于编程语言的学习建议:**学习三种以上的编程语言,并且它们最好是三种不同类型的语言**。如面向过程的编程语言 C 、脚本语言 JavaScript、Python,面向对象的编程语言 Java、再加上个近年来火热的函数式编程语言,到底也就差不多了。当我们学习了一门语言,再上手一门相似风格的语言,也是相当轻松地一件事。当我们学习了不同类型的几种语言,未来就可以轻松地绝大多数的语言。 32 | 33 | 相似的,学习使用 Web 框架也是如此的。现在,对于我而来,使用一个『新框架的姿势』是: 34 | 35 | - 买本中文书或者找个教程、官方的 Guide,花个十几分钟了解一下框架的『知识图谱』。 36 | - 直接找个官方的示例,运行一下 Demo。 37 | - 上手写写应用。 38 | - 查看官方文档,看看自己是不是漏掉了什么重要的东西。 39 | 40 | 它与我在公司接受培训的时候,学习到的『守破离』观点相似。在保留原来业务的情况下,一步步向前演进。 41 | 42 | ### 守:应用业务知识 43 | 44 | 在现有的业务上,使用新的框架是一件容易的事。拿上一份框架的说明书、一份需求文档、一个搜索引擎,就可以很容易地复制出一个产品。唯一的门槛是,你需要会读懂这些内容。这有点像新的知识阶级,只是门槛不再是识字与否,而在于是否能懂编程的知识。 45 | 46 | 正如维基百科上,对于『守』的介绍一样: 47 | 48 | > 最初阶段须遵从老师教诲,认真练习基础,达到熟练的境界。 49 | 50 | 新手期的我们,拿到一个新的框架,要一下子对它了运用自如,是一件很难的事。我们只能在一个又一个的练习中,尝试去掌握框架的知识。如,原先我们使用的是 Backbone + jQuery 完成的前端应用,现在要切换到 Vue.js。我们要做的便是尝试使用 Vue.js,并不断地练习一些相关的用法。而在熟练之后,我们也会练习我们的基本套路,如在上文中说到的『新框架的姿势』。 51 | 52 | 而如果不考虑练习本身的时间因素,便只剩下的一个问题是:**如何找到一个合适的练习项目**。然而,这样的项目在 GitHub 上有很多。可是即使它能满足我们的需求,我们有时候也不知道怎么练习? 53 | 54 | 我想问题的关键在于:我们手上没有一个已经成型的业务系统。因此,我建议大家可以从创建一个博客开始做起,先使用现有的技术,再使用新的技术,慢慢的一点点往上添加内容。如我的博客,最早是基于 Django + Bootstrap,慢慢的我添加了一些新的东西: 55 | 56 | - 用于为搜索提供建议的 AutoSuggest 57 | - 移动应用 API 及博客搜索 API 58 | - 微信搜索支持功能 59 | - 支持 Google AMP 来快速加载页面 60 | - Google Micro Data 61 | 62 | 尽管越来越多的功能,有一些已经不再维护、关闭了。可是,它让我有机会去练习一些新的技术,掌握一些技术背后的思想,得到一些框架相关的结论。而不是每次与别人讨论时,说:xx 说 xx 框架有这样的问题,而是我试过这个框架,它有这样的问题。 63 | 64 | ### 破:学习框架核心 65 | 66 | > 基础熟练后,试着突破原有规范让自己得到更高层次的进化。 67 | 68 | 转换技术栈,本身没有什么技术含量,但是能帮助稳固知识。当我们已经熟悉使用这个框架完成业务时,便可以细入相关思想。 69 | 70 | 了解这个框架的能力,生成一份与框架有关的索引,也可以用脑图的形势来整理这些内容。 71 | 72 | 如: 73 | 74 | ![嵌入式系统工程师图谱](../images/eks-example.jpg) 75 | 76 | 举例,如 Angular + TypeScript,还有其他更多的可能性 77 | 78 | 同时,我们还应该理解框架背后的原理。不一定深入,但是觉得去探究。如: 79 | 80 | - MV* 思想 81 | - 双向数据绑定的基本原理 82 | 83 | 这些都在我的知乎专栏上《我的职业是前端工程师》有深入的介绍,有时候的读者建议多阅读相关的内容。 84 | 85 | ### 离:探索更多可能性 86 | 87 | > 在更高层次得到新的认识并总结,自创新招数另辟出新境界。 88 | 89 | 在那之上,创造出一些新的框架。 90 | 91 | 如 Redux,最早是运行的 React.js 之上。Angular 2 出来了后,有了 xx。小程序出来后,有了 xx。 92 | 93 | 同理于此,当出现微信小程序的一两个星期内,我写了几篇原理相关的文章,并介绍了如何创建一个属于自己的小程序应用框架 WINV。又或者是我在对 Virtual Dom 有一定的了解后,便深入 Virtual Dom 的代码,写了一个基于 Virtual Dom 的测试辅助框架 [Luffa](http://github.com/phodal/luffa)。 94 | 95 | 而这些,只有我们理解他们的原理之后,我们才可能做到这样的事。 96 | 97 | ## 小结 98 | 99 | 寻找心流 100 | 101 | 这些方法适用于大部分的人,但是不一定适合你。你只需要寻找到适合你的路,然后学习。 102 | 103 | ## 选择合适的前端框架 104 | 105 | 在《全栈应用开发:精益实践》一书中,我曾提到过影响技术选型的几个因素: 106 | 107 | ![选型因素](../images/tech-decide.png) 108 | 109 | **锤子定律:寻找更大视野** 110 | 111 | **年轻的时候,学会了 A 框架,总觉得 Z 网站用 A 框架来实现会更好**,一定不会像今天这样经常崩溃、出Bug。**时间一长,有时候就会发现,Z 网站使用 A 不合适,他们的问题并不是框架的问题,而是运维的问题。 112 | 113 | 在《咨询的奥秘》一书中,提到一个有意思的定律“锤子定律”(又称为工具定律)——**圣诞节收到一把锤子的孩子,会发现所有东西都需要敲打**。 出现这种情况的主要原因是,**开发者对一个熟悉的工具过度的依赖**。 114 | 115 | 认真观察,就会发现这个现象随处可见。当一个新手程序员学会了某个最新的框架,通常来说这个框架有着更多的优点,这个时候最容易出现的想法是:**替换现有的框架**。可是,现有的框架并没有什么大的问题。并且凭估不充分时,新的框架则存在更多的风险。 116 | 117 | 并且,对于某个熟悉工具的过度依赖,特别容易影响到技术决策——看不到更多的可能性。这时候,我们就需要头脑风暴。但是这种情况下,头脑风暴很难帮助解决问题。在这个时候,拥有更多项目、框架经验的人,可能会做出更好的选择。 118 | 119 | ### Angular,一站式提高生产力 120 | 121 | 与 Backbone 同一时代诞生的 Angular 便是一个大而全的 MVC 框架。在这个框架里,它提供了我们所需要的各种功能,如模块管理、双向绑定等等。它涵盖了开发中的各个层面,并且层与层之间都经过了精心调适。 122 | 123 | 我们所需要做的便是遵循其设计思想,来一步步完善我们的应用。Angular.js 的创建理念是:即声明式编程应该用于构建用户界面以及编写软件构件,而命令式编程非常适合来表示业务逻辑。 124 | 125 | 我开始使用 Angular.js 的原因是,我使用 Ionic 来创建混合应用。出于对制作移动应用的好奇,我创建了一个又一个的移动应用,也在这时学会了 Angular.js。对于我而言,选择合适的技术栈,远远比选择流行的技术栈要重要得多,这也是我喜欢使用 Ionic 的原因。当我们在制作一个应用,它对性能要求不是很高的时候,那么我们应该选择开发速度更快的技术栈。 126 | 127 | 对于复杂的前端应用来说,基于 Angular.js 应用的运行效率,仍然有大量地改进空间。在应用运行的过程中,需要不断地操作 DOM,会造成明显的卡顿。对于 WebView 性能较差或早期的移动设备来说,这就是一个致命伤。 128 | 129 | 幸运的是在 2016 年底,Angular 团队推出了 Angular 2,它使用 Zone.js 实现变化的自动检测、 130 | 131 | 而迟来的 Angular 2 则受**奥斯本效应**[^osborne]的影响,逼得相当多的开发者们开始转向其它的框架。 132 | 133 | [^osborne]: 颇受欢迎的个人电脑厂商奥斯本,其公司的创新式便携电脑还没有上市,就宣布他们要推出的更高档的机器,而又迟迟无法交货,消费者闻风纷纷停止下单订购现有机种,最后导致奥斯本因收入枯竭而宣布破产。 134 | 135 | ### React,组件化提高复用 136 | 137 | 从 Backbone 和 Angular.js 的性能问题上来看,我们会发现 DOM 是单页面应用急需改善的问题——主要是DOM 的操作非常慢。而在单页面应用中,我们又需要处理大量的 DOM,性能就更是问题了。于是,采用 Virtual DOM 的 React 的诞生,让那些饱受性能苦恼的开发者欢迎。 138 | 139 | 传统的 DOM 操作是直接在 DOM 上操作的,当需要修改一系列元素中的值时,就会直接对 DOM 进行操作。而采用 Virtual DOM 则会对需要修改的 DOM 进行比较(DIFF),从而只选择需要修改的部分。也因此对于不需要大量修改 DOM 的应用来说,采用 Virtual DOM 并不会有优势。开发者就可以创建出可交互的 UI。 140 | 141 | 除了编写应用时,不需要对 DOM 进行直接操作,提高了应用的性能。React 还有一个重要思想是组件化,即 UI 中的每个组件都是独立封装的。与此同时,由于这些组件独立于 HTML,使它们不仅仅可以运行在浏览器里,还能作为原生应用的组件来运行。 142 | 143 | 同时,在 React 中还引入了 JSX 模板,即在 JS 中编写模板,还需要使用 ES 6。令人遗憾的是 React 只是一个 View 层,它是为了优化 DOM 的操作而诞生的。为了完成一个完整的应用,我们还需要路由库、执行单向流库、web API 调用库、测试库、依赖管理库等等,这简直是一场噩梦。因此为了完整搭建出一个完整的 React 项目,我们还需要做大量的额外工作。 144 | 145 | 大量的人选择 React 还有一个原因是:React Native、React VR 等等,可以让 React 运行在不同的平台之上。我们还能通过 React 轻松编写出原生应用,还有 VR 应用。 146 | 147 | 在看到 Angular 2 升级以及 React 复杂性的时候,我相信有相当多的开发者转而选择 Vue.js。 148 | 149 | ### Vue.js,简单也是提高效率 150 | 151 | 引自官网的介绍,Vue.js 是一套构建用户界面的渐进式框架,专注于MVVM 模型的 ViewModel 层。Vue.js 不仅简单、容易上手、配置设施齐全,同时拥有中文文档。 152 | 153 | 对于使用 Vue.js 的开发者来说,我们仍然可以使用 熟悉的 HTML 和 CSS 来编写代码。并且,Vue.js 也使用了 Virtual DOM、Reactive 及组件化的思想,可以让我们集中精力于编写应用,而不是应用的性能。 154 | 155 | 对于没有 Angular 和 React 经验的团队,并且规模不大的前端项目来说,Vue.js 是一个非常好的选择。 156 | 157 | 虽然 Vue.js 的生态与 React 相比虽然差上一截,但是配套设施还是相当齐全的,如 Vuex 、 VueRouter。只是,这些组件配套都由官方来提供、维护,甚至连 awesome-vue 也都是官方项目,总觉得有些奇怪。 158 | 159 | 除此,Vue.js 中定义了相当多的规矩,这种风格似乎由 jQuery 时代遗留下来的。照着这些规矩来写代码,让人觉得有些不自在。 160 | 161 | 和 React 相似的是,Vue.js 也有相应的 Native 方案 Weex,仍然值得我们期待。 162 | -------------------------------------------------------------------------------- /chapters/p1-3-builder.md: -------------------------------------------------------------------------------- 1 | # 构建系统:资深分界线 2 | 3 | Yeoman 生成脚手架,并且现在的主流前端框架都提供了相似的工 4 | 5 | 打包 -> 压缩 -> 上传 -> 解压 -> 替换 -> 重启 6 | 7 | 重点在于:提高工作效率 8 | 9 | ## 为什么构建很重要 10 | 11 | 过去我们打开编辑器、浏览器、修改代码、刷新页面,如下图所示: 12 | 13 | ![前端应用的开发流程](../images/basic-workflow.png ) 14 | 15 | 这个过程仍然没有发生太大的变化,只是很多的步骤都被自动化了: 16 | 17 | 我们只需要修改代码,诸如 watchman 这样的工具就检测到修改,而 Browsersync 则可以帮助我们自动刷新页面。 18 | 19 | ## 构建工具 20 | 21 | 取决于你所使用的技术栈 22 | 23 | SASS、SCSS 因不同的情况而异 24 | 25 | webpack 26 | 27 | npm 28 | 29 | grunt / gulp 30 | 31 | ## 构建流程 32 | 33 | ![前端构建流程](../images/build-workflow.png) 34 | 35 | LiveReload 36 | 37 | Bower 38 | 39 | concat -> init -> lint -> min -> qunit -> server -> test -> watch 40 | 41 | ### 构建示例 42 | 43 | 如下是混合应用框架 Ionic 执行 ``ionic serve`` 时的启动日志: 44 | 45 | ``` 46 | [11:43:58] ionic-app-scripts 1.3.4 47 | [11:43:58] watch started ... 48 | [11:43:58] build dev started ... 49 | [11:43:58] clean started ... 50 | [11:43:58] clean finished in 1 ms 51 | [11:43:58] copy started ... 52 | [11:43:58] transpile started ... 53 | [11:44:03] transpile finished in 5.17 s 54 | [11:44:03] preprocess started ... 55 | [11:44:03] deeplinks started ... 56 | [11:44:03] deeplinks finished in 132 ms 57 | [11:44:03] preprocess finished in 132 ms 58 | [11:44:03] webpack started ... 59 | [11:44:03] copy finished in 5.49 s 60 | [11:44:26] webpack finished in 22.94 s 61 | [11:44:26] sass started ... 62 | [11:44:29] sass finished in 3.21 s 63 | [11:44:29] postprocess started ... 64 | [11:44:29] postprocess finished in 85 ms 65 | [11:44:29] lint started ... 66 | [11:44:29] build dev finished in 31.57 s 67 | [11:44:29] watch ready in 31.69 s 68 | ``` 69 | 70 | 这个过程中,它会完成如下的步骤: 71 | 72 | watch -> build dev -> clean -> copy -> transpile -> preprocess (deeplinks) -> webpack (copy) -> sass -> postprocess -> build dev 73 | 74 | ### 自动刷新 75 | 76 | ### 转译 77 | 78 | ### 预处理 79 | 80 | -------------------------------------------------------------------------------- /chapters/p1-4-architecture.md: -------------------------------------------------------------------------------- 1 | # 什么是前端的架构能力 2 | 3 | > 远离最佳实践,除非你能接受其带来的成本 4 | 5 | 当我们谈及『前端的架构』时,我们讨论的是复杂前端应用的架构——如果只是一个 jQuery + Bootstrap 完成的应用,那么它的架构想必是『散弹式』的应用,没有复杂的逻辑可言。 6 | 7 | ## “标准”的 SPA 构架实践 8 | 9 | 复杂的前端应用,多数是 SPA(单页面应用),这就意味着系统的架构是前后端分离的。可前后端分离并意味着, 10 | 11 | ### 前后端分离 12 | 13 | ### 无状态 API 14 | 15 | ## workflow 16 | 17 | ### 前后端分离的工作方式 18 | 19 | 实现上,它主要关注点是:API 的设计。API 设计应该由前端开发者来驱动的。后台只提供前端想要的数据,而不是反过来的。后台提供数据,前端从中选择需要的内容。 20 | 21 | - 使用文档规范 API 22 | - 契约测试:基于持续集成与自动化测试 23 | - 前端测试与 API 适配器 24 | 25 | ## 风格指南:StyleGuide 26 | 27 | 与之前的构建系统相比,StyleGuide 便是一种无法用工具强制执行的规范。尽管可以采用工具来做类似的事情,但是并非应该强制去做。 28 | 29 | - 代码规范 30 | - 函数限制。Java -> 30 行 31 | 32 | ## 演进 33 | 34 | 当前技术栈,未来技术栈,切换。 35 | 36 | 使用了 Backbone,性能上出现一些瓶颈。 37 | 38 | 是不是要重写服务。 39 | 40 | 后台不能满足一些需求,考虑使用 BFF 吗 41 | 42 | 选用合适的策略,并保证没有问题。 43 | 44 | 45 | ## 最佳实践:框架 46 | 47 | 在这个领域,并不存在最佳的实践。首先的问题是,要找出我们真正想实现的功能,在这之后再去完成下一个步骤。而不是先找行业中最好的实践,再将这些实践应用 48 | 49 | jQuery 在简单的前端页面里,仍然是最好的选择。 50 | 51 | ### jQuery + TinyMCE 52 | 53 | ### jQuery + Vue 54 | 55 | 不久前,我需要一个 UI 框架及前端框架来实现简单的逻辑功能,并且它还应该相当的小。因此,我首先排队了 jQuery + Bootstrap,它们在体积上不太符合我的要求。 56 | 57 | - 发出一个 Ajax 请求,验证 Token 58 | - 如果返回的 Token 是有效的,则生成 59 | 60 | 提炼出核心技术, 61 | 62 | 对于大的公司来讲,都会要求拥有自己的核心技术。 63 | 64 | 在网上,各式各样的前端开发最佳实践层出不穷, 65 | 66 | 最意味着,在某些方面已经是到了极致。 67 | -------------------------------------------------------------------------------- /chapters/p1-5-automation.md: -------------------------------------------------------------------------------- 1 | # 自动化提高效率 2 | 3 | ## 自动化测试加快上线流程 4 | 5 | ### 测试 6 | 7 | 测试页面的输出结果,保证元素的准确性~ 8 | 9 | stub: 结果,返回预期的结果。 10 | 11 | mock: 行为,预期方法被调用。 12 | 13 | ### ui 测试 14 | 15 | React Test Renderer 16 | 17 | ``` 18 | 25 | 26 | 36 | ... 37 | ``` 38 | 39 | ### 截屏测试, 40 | 41 | 对于那些 UI 改动较小的系统来说,这 42 | 43 | 而我们知道页面截图尽管可以作为版本管理的一部分,但是一个不可比对的结果 44 | 45 | 而诸如,react-test-render, Virtual Dom 测试 46 | 47 | 那么,对于普通的 HTML 结构的 48 | 49 | ![PhantomCSS](images/PhantomCSS.png) 50 | 51 | ## 自动构建 52 | 53 | 在之前的构建系统一节里,我们讲了 xx。剩下要做的就是生成打包好的源码 54 | 55 | Gulp、Grunt 56 | 57 | ## 自动化部署 58 | 59 | 只需要一些 持续集成 的基础,如 Jenkins 60 | 61 | ### 持续集成 62 | 63 | -------------------------------------------------------------------------------- /chapters/p1-6-pattern.md: -------------------------------------------------------------------------------- 1 | # 前端应用的架构与设计模式 2 | 3 | 4 | ## 散弹式架构 -> jQuery 5 | 6 | 项目达到一定的程度,jQuery 便有些难以管理,我们不知道哪个地方还操作了 DOM。修改了 A 处的 selector,可能会影响 B 处的 selector。 7 | 8 | 这样的修改方式称为『散弹式架构』,它来自于 散弹式修改(shotgun surgery,出处《重构:改善既有代码的设计》), 9 | 10 | 在使用 Backbone 的过程中,如果你采用了继承 View 的方式,你也会遇到这种遇到问题。 11 | 12 | ## 分层结构 MV* 13 | 14 | 典型的 SPA 应该会具有的模式,如 Angular,Vue.js 15 | 16 | ## 处理数据 pipe and filter 17 | 18 | fetch、ajax、RxJS 从 API 处获取到数据 19 | 20 | 这个时候的数据首先会被转换为 JSON,再过滤到需要的字段,再对字段进行特殊的处理,如 HtmlEncoded,最后再 Render 到元素上。 21 | 22 | 当我们从服务器 23 | 24 | ## 数据显示 观察者模式 25 | 26 | 双向绑定,即观察者模式,又可以称为发布订阅模式(Publish/Subscribe) 27 | 28 | ## 数据通讯 29 | 30 | 除了常规的数据获取,还有在不同的框架间传输数据,如 React Native 和 WebView 的 postMessage,Cordova 的 WebView 与原生插件间 31 | 32 | ### 消息通讯 33 | 34 | ### 数据通讯:shared repository 35 | 36 | 其他消息通讯 37 | 38 | ### 数据通讯:local storage 39 | 40 | ??? black board 41 | -------------------------------------------------------------------------------- /chapters/p2-0.md: -------------------------------------------------------------------------------- 1 | # 软技能篇 -------------------------------------------------------------------------------- /chapters/p2-1-growth.md: -------------------------------------------------------------------------------- 1 | # 在做业务的过程中提升技术 2 | 3 | > “三个月经验,重复了五年” 4 | 5 | ## 测试 6 | 7 | ## 代码可读性 8 | 9 | > 与性能相比,可读性更加重要——绝大多数的软件,并不是写完就结束周期了。当然,倒掉的创业公司的软件除外。 10 | 11 | 12 | ## 有意图的提升 13 | 14 | 在一家大的公司里,不同的人总会有不同的运气: 15 | 16 | 运气好的人遇上一个好的项目,升职加薪,从此就走上了人生的巅峰。 17 | 运气差的人摊上一个差的项目,升不了职,少加了薪,并且还获得不了技术成长。 18 | 我刚毕业那会儿,所在团队的主要工作是,维护一个『又老又旧』的系统。比起写业务代码更不幸的是,我们的主要工作是修 Bug,bug,buG, bUg。 19 | 20 | 那一年多里,尽管都是维护旧系统和少量的新需求,我们还是在飞速的成长~~。而来源主要是: 21 | 22 | - 组内技术活动 23 | - 花时间投入练习 24 | - 假想项目的重构 25 | 26 | 当你在有限的条件下,还能做出一定的成绩,到底还是相当有成就感的。 27 | 28 | 如果你觉得你的项目技术栈老旧,那么你一定在脑子里使用了 N 种技术栈,对他们进行重构了。并且当你有一些时间可以分配到上面,如下班前的一个小时时间,又或者黑客马拉松等等。那么,你一定会开始去做这样的事。 29 | 30 | 与上面的技术活动相比,这是一个对于业务(我的意思是,对于公司来说)更有价值,并且更容易说服别人的方式。 31 | 32 | - 学习别的项目的技术栈,然后将之应用到现有的系统上。 33 | - 使用一个新的技术栈练习, 以此作为技术支撑,在未来替换现有的系统。 34 | -------------------------------------------------------------------------------- /chapters/p2-3-next-jquery.md: -------------------------------------------------------------------------------- 1 | # 持续学习:走出下一个『jQuery』 2 | 3 | 不,仍然没有, 4 | 5 | jQuery 的最大问题在于,简单如果上手,如 Vue 有可能便会流行,然后成为下一个 jQuery 6 | 7 | ## jQuery 已经落后了?下一个 jQuery 已经出现了 8 | 9 | 预测未来,不,我不可能。 10 | 11 | 对于,大公司或者内部系统的开发者来说,由于框架能满足应用的开发,因此很容易长期采用一个框架。当然,这本身并不是问题,你有了一份的工作,一个稳定的。可是,你可能会失去学习的勇气与能力。 12 | 13 | ## 持续学习 14 | 15 | ## 掌握思想 16 | 17 | - 路由:页面跳转与模块关系 18 | - 数据:获取与鉴权 19 | - 数据展示:模板引擎 20 | - 交互:事件与状态管理 21 | 22 | ## 后端技能 23 | 24 | 阅读后端代码的能力 25 | -------------------------------------------------------------------------------- /chapters/p2-3-soft-skill.md: -------------------------------------------------------------------------------- 1 | # 软技能 2 | 3 | 原本打算写一些时间管理,及 4 | 5 | 篇幅所限 6 | 7 | ## 知识管理 8 | 9 | 将输入的知识变为输出 10 | 11 | 以输出的方式来输入。 12 | 13 | ## Debug: 发现问题 14 | 15 | 编程时,我们大部分时候都是在解决问题,即求解已知的问题。 16 | 17 | 除此,我们还需要花费很多的时间在 Debug 上,即如何去发现问题所在。 18 | 19 | 最后,如果仍然不能解决问题,那么就找个人、地方提问吧。 20 | -------------------------------------------------------------------------------- /chapters/p3-0.md: -------------------------------------------------------------------------------- 1 | # 扩展篇 -------------------------------------------------------------------------------- /chapters/p3-1-depth.md: -------------------------------------------------------------------------------- 1 | # 前端知识体系的广度与深度 2 | 3 | ## 前端与后台的对比 4 | 5 | 后台对于深度要求高,而前端对于广度要求高。 6 | 7 | - 用户体验设计 8 | 9 | 前端:用户喜爱的产品 10 | 11 | 基础 HTML + JS + CSS 12 | 13 | 广度 -> 用户体验、浏览器差异 -> 知识碎片 14 | 15 | jQuery + Backbone + xxx 16 | 17 | 后台:高并发高可用 18 | 19 | 纠结于 事务一致 锁 20 | 21 | Spring + Mybatis + Flyway 22 | 23 | 数据库 + ORM + MVC 24 | 25 | 论技术上的深度,自然是后台更深 26 | 27 | 论用户体验上,自然是前端更深 两种很难衡量 28 | 29 | 常见问题:Ops 运维 -> 环境问题 30 | 31 | 32 | 对于前端来说,广度 First -> 深度。熟悉框架的相似之处,并且完成任务。 33 | 34 | 对于后端来说,选定语言,基本上就已经选好一切了,Java -> Spring,Scala -> Play,Ruby -> Rails 35 | 36 | ## 用户体验设计 37 | 38 | 39 | ## 前端的广度 40 | 41 | 在中大型规模的公司里,会有建议使用的后台语言,他们也主要使用一个后台语言。因为它已经可以很稳定地运行 42 | 43 | 除非,旧的语言在应用上存在一些缺陷。或者,正在尝试使用新的技术。 44 | 45 | 而对于前端来说,如果不能选择使用自己的轮子,那么就会是一片混乱。他们会使用不同的框架,不同的团队都有不同的业务场景。 46 | 47 | 48 | -------------------------------------------------------------------------------- /chapters/p3-2-future.md: -------------------------------------------------------------------------------- 1 | # 前端的趋势 2 | 3 | ![未来趋势](../images/future-stacks.png) 4 | 5 | ## 微服务与微前端 6 | 7 | > 对于后台采用微服务架构来说,在一个不同的组成部分中,使用不同的技术栈是一种不错的体验;而对于一个前端团队来说,在同一个系统的使用不同的技术栈就不是一种不错的体验。 8 | 9 | 可以使用 Web 存储技术,如 LocalStorage 来转移状态。又或者是诸如 Redux 的方式 10 | 11 | ## BFF 12 | 13 | ## 状态管理 14 | 15 | Redux 16 | 17 | ## 跨平台 18 | 19 | Angular 可以移动应用和桌面Web应用,可是它并没有像 React 有那么广泛的用途。 20 | 21 | React、React VR、React Native 22 | 23 | ## UI 生成 24 | 25 | 过去有 DreamWeaver 这样的软件,现在也有一些强大的 UI 工具,可以直接将设计转化为代码。 26 | 27 | -------------------------------------------------------------------------------- /chapters/p3-3-turn-in.md: -------------------------------------------------------------------------------- 1 | # 转型前端指南 2 | 3 | 职业转型,放弃你现在的工作、相关行业经验,进入一个“新的环境”。这就意味着,当你想转到前端时,你需要面临一系列的挑战。你的老板并不会关心你的过程是怎样的,只要你能达到当前的能力要求,并有能力适应未来的变化即可。 4 | 5 | > 跳槽穷半年,转行穷三年。 6 | 7 | 在过去的两三年里,随着前端领域的火热,市场上有越来越多的、不同行业的人加入了前端大军。人们出于不同的目的,选择上了前端开发。 8 | 9 | 有的是,大学里喜欢上前端这个行业,在找工作的时候,便选择了相应的岗位;有的是,不喜欢传统的编译型语言,如电子信息工程;有的是,大学上的专业找不到合适的工作,诸如数学等,并且有些专业与编程相比,拥有同等的逻辑能力要求;有的是,看前端行业很赚钱,便报了个培训班,来到了这个行业。 10 | 11 | 前端这个职业吧,入门快,上手也简单。简单的网页吧,拉上几个初学者便也能完成。可一旦遇上复杂的前端应用,就会暴露出各种各样的问题。于是,那些原先由非编程领域转行过来的人,便容易招至不满。 12 | 13 | 究其原因吧,是因为能力上达不到要求。我们到是可以看看,有多少人会转向人工智能,下一个行业热点。 14 | 15 | ## 改变 16 | 17 | 一点点慢慢改变,时间长,成本高,但是痛苦小 18 | 19 | 主要问题: 20 | 21 | - 生活压力 22 | - 经济来源 23 | 24 | change -> 改变 -> 痛苦 25 | 26 | 1. 实验 -> 尝试写代码 -> 意义 27 | 2. 培训或者 workshop 28 | 3. 人脉 <-> 相似的人 29 | 4. 意义 <-> 30 | 31 | 编程世界,比现实世界简单,有严格的对错。 32 | 33 | 如果你是一个没有编程经验的新手,那么你应该去报一个培训班。他可以在短期内帮你提高技术,但是与之相对应的,会带来一些问题。培训机构出来的学员,都存在一定的简历造假。由于数量众多,质量上参差不齐,导致人们普遍对培训机构出来的学员,存在一定的能力怀疑。说到底,你只能把培训机构当成一个入门,它距离你找到一份工作,还有相当大差距。 34 | 35 | 但是,你是真心的喜欢编程这个职业吗? 36 | 37 | 我见过一些后来者,他们在开始的时候问一些愚蠢的问题,慢慢的他们意识到这些问题,都是自己搜索就能解决的。他们会加入一些小组,来提高自己。建立一些信心,并去回答一些别人的问题。 38 | 39 | ## 后台转前端的挑战 40 | 41 | Angular 2 -> 是一个不错的选择 42 | 43 | - 强类型语言 TypeScript 44 | - 依赖注入等等的设计模式思维 45 | 46 | 唯一遗憾的是,它不使用 XML 来配置 47 | 48 | Node.js 应用也是一个不错的选择 49 | 50 | ## 其他编程领域转前端 51 | 52 | 移动端到 React Native,再到 React 53 | 54 | ## 其他行业转前端 55 | 56 | ### 劝退 57 | 58 | 编程并不是一件容易的事,如果你有业余兴趣便还好,如果没有的话,就算了。 59 | 60 | 主要原因:它并不是一个赚钱的行业,你是在时间换金钱。。 61 | 62 | 不妨考虑,投资,或者产生一个千万级的 idea,再找个风投 63 | 64 | 万一,你又一次选错行了呢? 65 | 66 | ### 立意已决 67 | 68 | 首先,打开浏览器、下载 IDE、然后写一行 HTML 试一试 69 | 70 | 简单的入门书,如 Head First HTML 71 | 72 | 找一个小的项目 73 | 74 | - 成功的复制一些小网站到本地 75 | - 然后,再是模拟一些小的项目 76 | 77 | 1. 不要预期薪水可以达到市场水平。没有人关心你是谁,你只要能干活,并且小公司、外包公司可能是一个更简单的入门。 78 | 79 | 外包公司 -> 门槛低 -> 相对比较多的成功案例 80 | 81 | 寻找合适的工作 -> 起步类型 82 | 83 | 查看相应类型的工作,看看工作介绍 84 | 85 | 事实上,按照『技术成熟曲线』理论,前端正在进入低谷期。而人工智能才是,现在,乃至未来一段时间的 IT 高薪领域。 86 | 87 | ![Gartner 技术成熟曲线](../images/gartner-hype-cycle.png) 88 | 89 | 如果你真的喜欢前端,那么:Just do it! 90 | 91 | 如果你爱请深爱~。 92 | 93 | -------------------------------------------------------------------------------- /chapters/p3-4-turn-out.md: -------------------------------------------------------------------------------- 1 | # 前端跨行指南 2 | 3 | JavaScript 应用领域 4 | 5 | 挑战:要学会新的领域的知识,以及其对应的语言知识。如开发混合应用时,在 iOS 方面,你需要有些许 Objective-C 或者 Swift 的开发能力,在 Android 方面,你还需要些许的 Java 经验。 6 | 7 | ## 移动开发:混合开发 8 | 9 | ## 桌面应用 10 | 11 | ## VR 12 | 13 | ## 硬件 14 | 15 | ## 其它? 16 | 17 | -------------------------------------------------------------------------------- /css/vendor.css: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | .acodecode { 4 | cursor: pointer 5 | } 6 | .acodecodeactive { 7 | cursor: default 8 | } 9 | .codecodecode { 10 | position: fixed; 11 | z-index: 100; 12 | left: 2%; 13 | bottom: -30px; 14 | width: 96%; 15 | height: 0; 16 | max-height: 270px; 17 | text-align: left 18 | } 19 | .codecodecode>div { 20 | box-shadow: 0 0 3px #444 21 | } 22 | .codecodecontrols { 23 | height: 30px; 24 | margin-top: -30px; 25 | background-color: #fff; 26 | background-color: rgba(255, 255, 255, .8); 27 | border-radius: 8px 8px 0 0 28 | } 29 | .codecodecontrols a { 30 | float: left; 31 | line-height: 30px; 32 | margin-left: 6px; 33 | font-family: Arial; 34 | font-size: 12px 35 | } 36 | .codecodecontrols .closeCodeCode { 37 | float: right; 38 | margin-right: 6px 39 | } 40 | .acodecode.codecode, .codecode { 41 | border-radius: 0 !important; 42 | position: relative !important; 43 | width: 100% !important; 44 | margin: 0 !important; 45 | overflow: auto !important; 46 | cursor: default !important 47 | } 48 | div.codecode [id^=highlighter] div.bar.show, div.codecode [id^=highlighter] div.toolbar { 49 | display: none !important 50 | } 51 | h1, h2, h3, h4, h5, h6, p { 52 | margin-top: 0; 53 | padding-right: 15px; 54 | padding-left: 15px; 55 | text-align: left; 56 | font-family: Georgia 57 | } 58 | h1 { 59 | text-align: left 60 | } 61 | h2.booktitle { 62 | font-size: 1.5em; 63 | color: #666 64 | } 65 | .subhead-link { 66 | font-size: .75em; 67 | margin-left: -15px; 68 | margin-top: 5px; 69 | float: left; 70 | visibility: hidden 71 | } 72 | .subhead-link:hover { 73 | text-decoration: none; 74 | visibility: visible 75 | } 76 | h1:hover .subhead-link, h2:hover .subhead-link, h3:hover .subhead-link, h4:hover .subhead-link { 77 | visibility: visible 78 | } 79 | .container { 80 | background: #FFF 81 | } 82 | header { 83 | background: #fff 84 | } 85 | .content { 86 | padding: 10px 0; 87 | text-align: left 88 | } 89 | .footer { 90 | background: #fff 91 | } 92 | .fltrt { 93 | float: right; 94 | margin-left: 8px 95 | } 96 | .fltlft { 97 | float: left; 98 | margin-right: 8px 99 | } 100 | .clearfloat { 101 | clear: both; 102 | height: 0; 103 | font-size: 1px; 104 | line-height: 0 105 | } 106 | .copyright { 107 | text-align: left 108 | } 109 | .booktitle { 110 | text-align: center; 111 | line-height: 41px; 112 | border-bottom: 1px solid #fff; 113 | padding: 0; 114 | font-size: 2.2em 115 | } 116 | .booktitle.author { 117 | font-size: 24px 118 | } 119 | #contents-list { 120 | background: none repeat scroll 0 0 #EEE; 121 | border: 3px solid #DDD; 122 | padding: 1em 1em 1em 3em 123 | } 124 | .subitem { 125 | margin-left: 25px 126 | } 127 | #references-list { 128 | word-wrap: break-word 129 | } 130 | pre { 131 | display: block; 132 | line-height: 18px; 133 | background-color: #f5f5f5; 134 | -webkit-border-radius: 4px; 135 | -moz-border-radius: 4px; 136 | border-radius: 4px; 137 | white-space: pre; 138 | white-space: pre-wrap; 139 | word-break: break-all; 140 | word-wrap: break-word 141 | } 142 | div.syntaxhighlighter { 143 | padding: 1em 0 144 | } 145 | .syntaxhighlighter a, .syntaxhighlighter code, .syntaxhighlighter div, .syntaxhighlighter table, .syntaxhighlighter table caption, .syntaxhighlighter table tbody, .syntaxhighlighter table td, .syntaxhighlighter table thead, .syntaxhighlighter table tr, .syntaxhighlighter textarea { 146 | -moz-border-radius: 0 !important; 147 | -webkit-border-radius: 0 !important; 148 | background: none !important; 149 | border: 0 !important; 150 | bottom: auto !important; 151 | float: none !important; 152 | height: auto !important; 153 | left: auto !important; 154 | line-height: 1.1em !important; 155 | margin: 0 !important; 156 | outline: 0 !important; 157 | overflow: visible !important; 158 | padding: 0 !important; 159 | position: static !important; 160 | right: auto !important; 161 | text-align: left !important; 162 | top: auto !important; 163 | vertical-align: baseline !important; 164 | width: auto !important; 165 | box-sizing: content-box !important; 166 | font-family: Consolas, "Bitstream Vera Sans Mono", "Courier New", Courier, monospace !important; 167 | font-weight: 400 !important; 168 | font-style: normal !important; 169 | font-size: 1em !important; 170 | min-height: inherit !important; 171 | min-height: auto !important 172 | } 173 | .syntaxhighlighter { 174 | width: 100% !important; 175 | margin: 1em 0 !important; 176 | position: relative !important; 177 | overflow: auto !important; 178 | font-size: 1em !important 179 | } 180 | .syntaxhighlighter.source { 181 | overflow: hidden !important 182 | } 183 | .syntaxhighlighter .bold { 184 | font-weight: 700 !important 185 | } 186 | .syntaxhighlighter .italic { 187 | font-style: italic !important 188 | } 189 | .syntaxhighlighter .line { 190 | white-space: pre !important 191 | } 192 | .syntaxhighlighter table { 193 | width: 100% !important 194 | } 195 | .syntaxhighlighter table caption { 196 | text-align: left !important; 197 | padding: .5em 0 .5em 1em !important 198 | } 199 | .syntaxhighlighter table td.code { 200 | width: 100% !important 201 | } 202 | .syntaxhighlighter table td.code .container { 203 | position: relative !important 204 | } 205 | .syntaxhighlighter table td.code .container textarea { 206 | box-sizing: border-box !important; 207 | position: absolute !important; 208 | left: 0 !important; 209 | top: 0 !important; 210 | width: 100% !important; 211 | height: 100% !important; 212 | border: 0 !important; 213 | background: #fff !important; 214 | padding-left: 1em !important; 215 | overflow: hidden !important; 216 | white-space: pre !important 217 | } 218 | .syntaxhighlighter table td.gutter .line { 219 | text-align: right !important; 220 | padding: 0 .5em 0 1em !important 221 | } 222 | .syntaxhighlighter table td.code .line { 223 | padding: 0 1em !important 224 | } 225 | .syntaxhighlighter.nogutter td.code .container textarea, .syntaxhighlighter.nogutter td.code .line { 226 | padding-left: 0 !important 227 | } 228 | .syntaxhighlighter.show { 229 | display: block !important 230 | } 231 | .syntaxhighlighter.collapsed table { 232 | display: none !important 233 | } 234 | .syntaxhighlighter.collapsed .toolbar { 235 | padding: .1em .8em 0 !important; 236 | font-size: 1em !important; 237 | position: static !important; 238 | width: auto !important; 239 | height: auto !important 240 | } 241 | .syntaxhighlighter.collapsed .toolbar span { 242 | display: inline !important; 243 | margin-right: 1em !important 244 | } 245 | .syntaxhighlighter.collapsed .toolbar span a { 246 | padding: 0 !important; 247 | display: none !important 248 | } 249 | .syntaxhighlighter.collapsed .toolbar span a.expandSource { 250 | display: inline !important 251 | } 252 | .syntaxhighlighter .toolbar { 253 | position: absolute !important; 254 | right: 1px !important; 255 | top: 1px !important; 256 | width: 11px !important; 257 | height: 11px !important; 258 | font-size: 10px !important; 259 | z-index: 10 !important 260 | } 261 | .syntaxhighlighter .toolbar span.title { 262 | display: inline !important 263 | } 264 | .syntaxhighlighter .toolbar a { 265 | display: block !important; 266 | text-align: center !important; 267 | text-decoration: none !important; 268 | padding-top: 1px !important 269 | } 270 | .syntaxhighlighter .toolbar a.expandSource { 271 | display: none !important 272 | } 273 | .syntaxhighlighter.ie { 274 | font-size: .9em !important; 275 | padding: 1px 0 !important 276 | } 277 | .syntaxhighlighter.ie .toolbar { 278 | line-height: 8px !important 279 | } 280 | .syntaxhighlighter.ie .toolbar a { 281 | padding-top: 0 !important 282 | } 283 | .syntaxhighlighter.printing .line.alt1 .content, .syntaxhighlighter.printing .line.alt2 .content, .syntaxhighlighter.printing .line.highlighted .number, .syntaxhighlighter.printing .line.highlighted.alt1 .content, .syntaxhighlighter.printing .line.highlighted.alt2 .content { 284 | background: none !important 285 | } 286 | .syntaxhighlighter.printing .line .number { 287 | color: #bbb !important 288 | } 289 | .syntaxhighlighter.printing .line .content { 290 | color: #000 !important 291 | } 292 | .syntaxhighlighter.printing .toolbar { 293 | display: none !important 294 | } 295 | .syntaxhighlighter.printing a { 296 | text-decoration: none !important 297 | } 298 | .syntaxhighlighter.printing .plain, .syntaxhighlighter.printing .plain a { 299 | color: #000 !important 300 | } 301 | .syntaxhighlighter.printing .comments, .syntaxhighlighter.printing .comments a { 302 | color: #008200 !important 303 | } 304 | .syntaxhighlighter.printing .string, .syntaxhighlighter.printing .string a { 305 | color: #00f !important 306 | } 307 | .syntaxhighlighter.printing .keyword { 308 | color: #069 !important; 309 | font-weight: 700 !important 310 | } 311 | .syntaxhighlighter.printing .preprocessor { 312 | color: gray !important 313 | } 314 | .syntaxhighlighter.printing .variable { 315 | color: #a70 !important 316 | } 317 | .syntaxhighlighter.printing .value { 318 | color: #090 !important 319 | } 320 | .syntaxhighlighter.printing .functions { 321 | color: #ff1493 !important 322 | } 323 | .syntaxhighlighter.printing .constants { 324 | color: #06c !important 325 | } 326 | .syntaxhighlighter.printing .script { 327 | font-weight: 700 !important 328 | } 329 | .syntaxhighlighter.printing .color1, .syntaxhighlighter.printing .color1 a { 330 | color: gray !important 331 | } 332 | .syntaxhighlighter.printing .color2, .syntaxhighlighter.printing .color2 a { 333 | color: #ff1493 !important 334 | } 335 | .syntaxhighlighter.printing .color3, .syntaxhighlighter.printing .color3 a { 336 | color: red !important 337 | } 338 | .syntaxhighlighter.printing .break, .syntaxhighlighter.printing .break a { 339 | color: #000 !important 340 | } 341 | .syntaxhighlighter, .syntaxhighlighter .line.alt1, .syntaxhighlighter .line.alt2 { 342 | background-color: #1b2426 !important 343 | } 344 | .syntaxhighlighter .line.highlighted.alt1, .syntaxhighlighter .line.highlighted.alt2 { 345 | background-color: #323e41 !important 346 | } 347 | .syntaxhighlighter .line.highlighted.number, .syntaxhighlighter table caption { 348 | color: #b9bdb6 !important 349 | } 350 | .syntaxhighlighter .gutter { 351 | color: #afafaf !important 352 | } 353 | .syntaxhighlighter .gutter .line { 354 | border-right: 3px solid #435a5f !important 355 | } 356 | .syntaxhighlighter .gutter .line.highlighted { 357 | background-color: #435a5f !important; 358 | color: #1b2426 !important 359 | } 360 | .syntaxhighlighter.printing .line .content { 361 | border: 0 !important 362 | } 363 | .syntaxhighlighter.collapsed { 364 | overflow: visible !important 365 | } 366 | .syntaxhighlighter.collapsed .toolbar { 367 | color: #5ba1cf !important; 368 | background: #000 !important; 369 | border: 1px solid #435a5f !important 370 | } 371 | .syntaxhighlighter.collapsed .toolbar a { 372 | color: #5ba1cf !important 373 | } 374 | .syntaxhighlighter.collapsed .toolbar a:hover { 375 | color: #5ce638 !important 376 | } 377 | .syntaxhighlighter .toolbar { 378 | color: #fff !important; 379 | background: #435a5f !important; 380 | border: 0 !important 381 | } 382 | .syntaxhighlighter .toolbar a { 383 | color: #fff !important 384 | } 385 | .syntaxhighlighter .toolbar a:hover { 386 | color: #e0e8ff !important 387 | } 388 | .syntaxhighlighter .plain, .syntaxhighlighter .plain a { 389 | color: #b9bdb6 !important 390 | } 391 | .syntaxhighlighter .comments, .syntaxhighlighter .comments a { 392 | color: #878a85 !important 393 | } 394 | .syntaxhighlighter .string, .syntaxhighlighter .string a { 395 | color: #5ce638 !important 396 | } 397 | .syntaxhighlighter .keyword { 398 | color: #5ba1cf !important 399 | } 400 | .syntaxhighlighter .preprocessor { 401 | color: #435a5f !important 402 | } 403 | .syntaxhighlighter .variable { 404 | color: #ffaa3e !important 405 | } 406 | .syntaxhighlighter .value { 407 | color: #090 !important 408 | } 409 | .syntaxhighlighter .functions { 410 | color: #ffaa3e !important 411 | } 412 | .syntaxhighlighter .constants { 413 | color: #e0e8ff !important 414 | } 415 | .syntaxhighlighter .script { 416 | font-weight: 700 !important; 417 | color: #5ba1cf !important; 418 | background-color: none !important 419 | } 420 | .syntaxhighlighter .color1, .syntaxhighlighter .color1 a { 421 | color: #e0e8ff !important 422 | } 423 | .syntaxhighlighter .color2, .syntaxhighlighter .color2 a { 424 | color: #fff !important 425 | } 426 | .syntaxhighlighter .color3, .syntaxhighlighter .color3 a { 427 | color: #ffaa3e !important 428 | } 429 | .sausage-set { 430 | position: fixed; 431 | right: 0; 432 | top: 0; 433 | width: 15px; 434 | height: 100%; 435 | border-left: solid 2px #fff; 436 | border-right: solid 2px #fff; 437 | background-color: #fff; 438 | font-family: 'Helvetica Neue', Arial, sans-serif 439 | } 440 | .sausage { 441 | position: absolute; 442 | left: 0; 443 | width: 100%; 444 | height: 100%; 445 | background-color: #f1f1f1; 446 | text-decoration: none; 447 | -moz-border-radius: 8px; 448 | -webkit-border-bottom-left-radius: 8px; 449 | -webkit-border-top-left-radius: 8px; 450 | -webkit-border-bottom-right-radius: 8px; 451 | -webkit-border-top-right-radius: 8px; 452 | -moz-box-shadow: inset 0 1px 2px 4px rgba(0, 0, 0, .025); 453 | -webkit-box-shadow: inset 0 1px 2px 4px rgba(0, 0, 0, .025); 454 | cursor: pointer 455 | } 456 | .sausage-current, .sausage-hover { 457 | background-color: #f2e4ed; 458 | -moz-box-shadow: inset 0 1px 2px 4px rgba(51, 63, 70, .025) 459 | } 460 | .sausage-span { 461 | position: absolute; 462 | right: 24px; 463 | top: 5px; 464 | z-index: 2; 465 | display: none; 466 | width: 100px; 467 | padding: 2px 3px; 468 | color: #000; 469 | background-color: #fff; 470 | border: solid 2px #906; 471 | font-size: 10px; 472 | line-height: 12px; 473 | font-weight: 700; 474 | text-align: center; 475 | -moz-border-radius: 7px; 476 | -webkit-border-bottom-left-radius: 7px; 477 | -webkit-border-top-left-radius: 7px; 478 | -webkit-border-bottom-right-radius: 7px; 479 | -webkit-border-top-right-radius: 7px; 480 | -moz-box-shadow: 1px 1px 1px 1px rgba(0, 0, 0, .05); 481 | -webkit-box-shadow: 1px 1px 1px 1px rgba(0, 0, 0, .05) 482 | } 483 | .sausage-current .sausage-span, .sausage-hover .sausage-span { 484 | display: block 485 | } 486 | a, abbr, acronym, address, article, aside, blockquote, body, caption, code, dd, del, dfn, dialog, div, dl, dt, em, fieldset, figure, footer, form, h1, h2, h3, h4, h5, h6, header, hgroup, html, iframe, img, label, legend, li, nav, object, ol, p, pre, q, section, span, table, tbody, td, tfoot, th, thead, tr, ul { 487 | margin: 0; 488 | padding: 0; 489 | border: 0; 490 | font-weight: inherit; 491 | font-style: inherit; 492 | font-size: 100%; 493 | font-family: inherit; 494 | vertical-align: baseline 495 | } 496 | article, aside, dialog, figure, footer, header, hgroup, nav, section { 497 | display: block 498 | } 499 | body { 500 | line-height: 1.5 501 | } 502 | table { 503 | border-collapse: separate; 504 | border-spacing: 0 505 | } 506 | caption, td, th { 507 | text-align: left; 508 | font-weight: 400 509 | } 510 | table, td, th { 511 | vertical-align: middle 512 | } 513 | blockquote:after, blockquote:before, q:after, q:before { 514 | content: "" 515 | } 516 | blockquote, q { 517 | quotes: "" "" 518 | } 519 | a img { 520 | border: 0 521 | } 522 | .search, body, input[type=submit], input[type=text] { 523 | font-family: Palatino, "Palatino Linotype", Georgia, Times, "Times New Roman", serif 524 | } 525 | html { 526 | font-size: 100.01% 527 | } 528 | h1, h2, h3, h4, h5, h6 { 529 | font-weight: 400; 530 | color: #000 531 | } 532 | h1 { 533 | font-size: 3em; 534 | line-height: 1; 535 | margin-bottom: .5em 536 | } 537 | h2 { 538 | font-size: 2em; 539 | margin-bottom: .75em 540 | } 541 | h3 { 542 | font-size: 1.5em; 543 | line-height: 1 544 | } 545 | h4 { 546 | font-size: 1.2em; 547 | line-height: 1.25; 548 | margin-bottom: 1.25em 549 | } 550 | h5 { 551 | font-size: 1em; 552 | font-weight: 700; 553 | margin-bottom: 1.5em 554 | } 555 | h6 { 556 | font-size: 1em; 557 | font-weight: 700 558 | } 559 | h1 img, h2 img, h3 img, h4 img, h5 img, h6 img { 560 | margin: 0 561 | } 562 | p { 563 | margin: 0 0 1.5em 564 | } 565 | p img.left { 566 | float: left; 567 | margin: 1.5em 1.5em 1.5em 0; 568 | padding: 0 569 | } 570 | p img.right { 571 | float: right; 572 | margin: 1.5em 0 1.5em 1.5em 573 | } 574 | strong { 575 | font-weight: 700 576 | } 577 | dfn, em { 578 | font-style: italic 579 | } 580 | dfn { 581 | font-weight: 700 582 | } 583 | sub, sup { 584 | line-height: 0 585 | } 586 | address { 587 | margin: 0 0 1.5em; 588 | font-style: italic 589 | } 590 | del { 591 | color: #666 592 | } 593 | li ol, li ul { 594 | margin: 0 595 | } 596 | ol, ul { 597 | margin: 0 1.5em 1.5em 0; 598 | padding-left: 3.333em 599 | } 600 | ul { 601 | list-style-type: disc 602 | } 603 | ol { 604 | list-style-type: decimal 605 | } 606 | dl { 607 | margin: 0 0 1.5em 608 | } 609 | dl dt { 610 | font-weight: 700 611 | } 612 | dd { 613 | margin-left: 1.5em 614 | } 615 | table { 616 | margin-bottom: 1.4em 617 | } 618 | th { 619 | font-weight: 700 620 | } 621 | thead th { 622 | background: #c3d9ff 623 | } 624 | caption, td, th { 625 | padding: 4px 10px 4px 5px 626 | } 627 | tfoot { 628 | font-style: italic 629 | } 630 | body { 631 | font-size: 100%; 632 | color: #000; 633 | background: #F6f6F6 url(../images/base.png) repeat 0 0 634 | } 635 | h3 { 636 | border-bottom: 1px solid #CCC; 637 | margin-bottom: .5em; 638 | padding-bottom: .5em 639 | } 640 | .lead { 641 | font-size: 1.5em 642 | } 643 | .stage_links { 644 | color: #777 645 | } 646 | a, a:link, a:visited { 647 | color: #906; 648 | text-decoration: none 649 | } 650 | a:active, a:focus, a:hover { 651 | color: #E106B2; 652 | text-decoration: underline 653 | } 654 | hr.space { 655 | background: #fff; 656 | color: #fff; 657 | visibility: hidden 658 | } 659 | hr { 660 | background: #CCC; 661 | color: #CCC; 662 | clear: both; 663 | float: none; 664 | width: 100%; 665 | height: .1em; 666 | margin: 0 0 1.45em; 667 | border: 0 668 | } 669 | hr.bold { 670 | height: 1px; 671 | background-color: #906; 672 | color: #906 673 | } 674 | blockquote { 675 | overflow: hidden; 676 | margin: 0 0 1.5em; 677 | padding: 0 1.5em; 678 | color: #000; 679 | font-style: normal 680 | } 681 | blockquote p { 682 | margin-bottom: .5em 683 | } 684 | .attribution { 685 | font-style: italic; 686 | text-align: right; 687 | color: #777 688 | } 689 | table { 690 | width: 100% 691 | } 692 | code { 693 | padding: 2px 4px; 694 | color: #D14; 695 | background-color: #F7F7F9; 696 | border: 1px solid #E1E1E8; 697 | font-family: Menlo, Monaco, Consolas, "Courier New", monospace; 698 | font-size: 12px; 699 | -webkit-border-radius: 3px; 700 | -moz-border-radius: 3px; 701 | border-radius: 3px 702 | } 703 | .caption, caption { 704 | caption-side: bottom; 705 | background: 0 0; 706 | font-style: italic 707 | } 708 | tr.even td { 709 | background: #F4F4F4 710 | } 711 | tfoot td { 712 | border-top: 1px solid #EAEAEA; 713 | font-weight: 700; 714 | font-style: normal 715 | } 716 | abbr, acronym { 717 | border: 0 718 | } 719 | abbr[title]:hover { 720 | border-bottom: 1px dotted #666; 721 | cursor: help 722 | } 723 | .red { 724 | background: red 725 | } 726 | .highlight { 727 | background: #EEC3C3 728 | } 729 | .blocks:after, .clearfix:after, .container:after, .edition_list:after, .editions:after, .inner:after { 730 | content: "\0020"; 731 | display: block; 732 | height: 0; 733 | clear: both; 734 | visibility: hidden; 735 | overflow: hidden 736 | } 737 | .blocks, .clearfix, .container, .edition_list, .editions, .inner { 738 | display: block 739 | } 740 | .clear { 741 | clear: both 742 | } 743 | .container { 744 | max-width: 940px; 745 | margin: 0 auto; 746 | padding: 0 16px; 747 | text-align: left 748 | } 749 | .gttr { 750 | margin-right: 2.9%; 751 | float: left 752 | } 753 | .last { 754 | float: left 755 | } 756 | .sidebar { 757 | width: 32%; 758 | float: right; 759 | margin-right: 0 760 | } 761 | .content_footer { 762 | clear: both 763 | } 764 | .span10, .span2, .span3, .span4, .span6, .span8 { 765 | margin-right: 2.3%; 766 | float: left 767 | } 768 | .span2 { 769 | width: 14.6341% 770 | } 771 | .span3 { 772 | width: 23.1707% 773 | } 774 | .span4 { 775 | width: 31.7073% 776 | } 777 | .span6 { 778 | width: 48.7805% 779 | } 780 | .span8 { 781 | width: 65.853658% 782 | } 783 | .span10 { 784 | width: 73.17073% 785 | } 786 | .blocks, .editions { 787 | margin: 1.5em 0; 788 | clear: both 789 | } 790 | .editions { 791 | margin-bottom: 0 792 | } 793 | .last { 794 | margin-right: 0 !important 795 | } 796 | .lyt_img { 797 | max-width: 100% 798 | } 799 | .page_header { 800 | overflow: hidden; 801 | padding: 0 0 .2em; 802 | margin: 1.5em 0 803 | } 804 | .logo { 805 | width: 49.5%; 806 | float: left; 807 | margin-bottom: 0 808 | } 809 | .logo span { 810 | display: block; 811 | font-style: italic; 812 | font-size: .5em 813 | } 814 | .logo a, .logo a:link, .logo a:visited { 815 | color: #000 816 | } 817 | .logo a:active, .logo a:focus, .logo a:hover { 818 | color: #906; 819 | text-decoration: none 820 | } 821 | .search_box { 822 | width: 50%; 823 | float: right 824 | } 825 | .search { 826 | width: auto; 827 | float: right; 828 | vertical-align: middle 829 | } 830 | .edition_list, .info_bubble, .inner, .stage { 831 | padding: 1em 1.5em; 832 | background: #FFF; 833 | -moz-border-radius: 3px; 834 | -webkit-border-radius: 3px; 835 | border-radius: 3px; 836 | -moz-box-shadow: 0 0 8px #999; 837 | -webkit-box-shadow: 0 0 8px #999; 838 | box-shadow: 0 0 8px #999 839 | } 840 | .stage { 841 | margin-bottom: 1.5em; 842 | padding: 3em 50% 1.5em 3em 843 | } 844 | .edition_list { 845 | margin: 0 0 1em; 846 | clear: both; 847 | overflow: hidden 848 | } 849 | .edition_list p { 850 | margin-bottom: 0; 851 | font-style: italic 852 | } 853 | .edition_list h2 { 854 | margin-bottom: 0; 855 | font-size: 1.8em; 856 | line-height: 1.5; 857 | font-weight: 700 858 | } 859 | .edition_list ul { 860 | margin: 0; 861 | padding: 0; 862 | list-style: none; 863 | display: inline 864 | } 865 | .edition_list ul li { 866 | display: inline; 867 | margin-right: 1em; 868 | padding-right: 1em; 869 | border-right: 1px solid #F6f6F6 870 | } 871 | .edition_list ul li:last-child { 872 | margin-right: 0; 873 | padding-right: 0; 874 | border-right: 0 875 | } 876 | .info_bubble { 877 | padding-bottom: 1em; 878 | color: #FFF; 879 | text-shadow: 1px 1px 0 #000; 880 | background: #906; 881 | position: relative; 882 | overflow: visible 883 | } 884 | .info_bubble p { 885 | margin-bottom: 0 886 | } 887 | .info_bubble.startpage { 888 | padding-bottom: 1em; 889 | min-height: 9em; 890 | height: auto !important; 891 | height: 9em; 892 | z-index: 0 893 | } 894 | .info_bubble.startpage span { 895 | position: absolute; 896 | display: block; 897 | bottom: 1em; 898 | left: -2em; 899 | width: 40px; 900 | height: 40px; 901 | z-index: 100 902 | } 903 | .blocks>div { 904 | margin-bottom: 1.5em 905 | } 906 | .footer { 907 | margin: 1.5em 0 0; 908 | padding: 1.5em 0 0; 909 | overflow: hidden 910 | } 911 | #buy { 912 | position: relative 913 | } 914 | #offers { 915 | position: absolute; 916 | bottom: 0; 917 | font-size: .625em; 918 | margin: 0; 919 | padding: 0; 920 | list-style: none; 921 | display: none 922 | } 923 | .save_a_tree h3 { 924 | display: none; 925 | line-height: 1.5; 926 | border-bottom: 0 927 | } 928 | #offers li { 929 | display: inline; 930 | margin-right: 1em; 931 | padding-right: 1em; 932 | border-right: 1px solid #F6f6F6 933 | } 934 | #offers li:last-child { 935 | margin-right: 0; 936 | padding-right: 0; 937 | border-right: 0 938 | } 939 | .shopping_cart_button_line, .shopping_cart_button_line_bottom { 940 | border-top: 1px solid #CCC; 941 | margin-top: .5em; 942 | padding: .5em 1px 0; 943 | overflow: hidden; 944 | clear: both 945 | } 946 | .shopping_cart_button_line_bottom { 947 | margin-bottom: 7em 948 | } 949 | .shopping_cart_button_line:first-child { 950 | border-top: 0 951 | } 952 | div.header { 953 | font-size: 1.5em; 954 | line-height: 1; 955 | border-bottom: 1px solid #CCC; 956 | margin-bottom: .5em; 957 | padding-bottom: .5em; 958 | color: #000; 959 | text-shadow: 1px 1px 0 #FFF 960 | } 961 | .product_title { 962 | font-style: italic; 963 | margin-bottom: 1.5em 964 | } 965 | .product_price { 966 | float: left 967 | } 968 | .price { 969 | color: #666 970 | } 971 | .product_buy_link { 972 | float: right; 973 | line-height: 1 974 | } 975 | .ebook_formats, .safari_read_now, .whatisthis { 976 | font-size: .75em 977 | } 978 | .safari_read_now { 979 | float: right; 980 | line-height: 2 981 | } 982 | input[type=submit], input[type=text] { 983 | font-size: 1em; 984 | -moz-border-radius: .5em; 985 | -webkit-border-radius: .5em; 986 | border-radius: .5em; 987 | vertical-align: middle 988 | } 989 | input[type=text] { 990 | width: 140px; 991 | margin: .5em 0; 992 | padding: .5em .5em .3em; 993 | border: 1px solid #F1F1F0; 994 | color: #666; 995 | -moz-box-shadow: inset 3px 3px 2px #999; 996 | -webkit-box-shadow: inset 3px 3px 2px #999; 997 | box-shadow: inset 3px 3px 2px #999 998 | } 999 | input[type=text]:active, input[type=text]:focus, input[type=text]:hover { 1000 | background: #FFF; 1001 | color: #000; 1002 | outline: 0 1003 | } 1004 | input[type=submit] { 1005 | width: auto; 1006 | margin: 0; 1007 | padding: .28em .5em; 1008 | background: #906; 1009 | color: #FFF; 1010 | border: 0; 1011 | text-transform: uppercase; 1012 | cursor: pointer; 1013 | text-shadow: 1px 1px 0 #000; 1014 | -moz-box-shadow: 0 0 2px #999; 1015 | -webkit-box-shadow: 0 0 2px #999; 1016 | box-shadow: 0 0 2px #999 1017 | } 1018 | input[type=submit]:active, input[type=submit]:focus, input[type=submit]:hover { 1019 | color: #FFF; 1020 | background: #E106B2; 1021 | text-shadow: 1px 1px 0 #000; 1022 | -moz-box-shadow: 0 0 3px #333; 1023 | -webkit-box-shadow: 0 0 3px #333; 1024 | box-shadow: 0 0 3px #333 1025 | } 1026 | a.anchor { 1027 | color: #000 1028 | } 1029 | a.anchor:hover { 1030 | text-decoration: none 1031 | } 1032 | .figure { 1033 | padding-top: 1.5em 1034 | } 1035 | .caption, .figure { 1036 | display: block; 1037 | margin-bottom: 1.5em; 1038 | text-align: center 1039 | } 1040 | .figure * { 1041 | text-align: left 1042 | } 1043 | .caption { 1044 | font-size: .875em 1045 | } 1046 | .figure .caption { 1047 | text-align: center 1048 | } 1049 | .figure img { 1050 | margin-bottom: .5em; 1051 | max-width: 100% 1052 | } 1053 | .attribution::before { 1054 | content: "" 1055 | } 1056 | .sidebar ul { 1057 | font-size: .9em; 1058 | padding-left: 2em; 1059 | list-style-type: square 1060 | } 1061 | .disabled, .footer a, .footer a:active, .footer a:focus, .footer a:hover, .footer a:link, .footer a:visited, .info_bubble a, .info_bubble a:active, .info_bubble a:focus, .info_bubble a:hover, .info_bubble a:link, .info_bubble a:visited { 1062 | color: #BBB 1063 | } 1064 | .buybuttonswidget { 1065 | padding-bottom: 10px; 1066 | background: #FFF 1067 | } 1068 | @media (max-width:320px) { 1069 | .container { 1070 | max-width: 300px 1071 | } 1072 | #reviews { 1073 | display: none 1074 | } 1075 | } 1076 | @media (min-width:768px) and (max-width:1024px) { 1077 | .container { 1078 | max-width: 740px; 1079 | width: 740px 1080 | } 1081 | } 1082 | @media (min-width:1025px) { 1083 | .container { 1084 | width: 740px 1085 | } 1086 | } -------------------------------------------------------------------------------- /ebook.md: -------------------------------------------------------------------------------- 1 | 2 | # 前端进阶指南 3 | 4 | ## 什么是前端 5 | 6 | 作为一本前端进阶的书,没有理由去强调一下**什么是前端**?可是,当你说前端的时候,我也说前端的时候,我们说的是同一个前端吗? 7 | 8 | 我理解下的前端,指广泛意义上的前端。又可以称为『客户端』,泛指:与用户做交互的应用。如桌面浏览器上的浏览器、图形用户界面,移动设备上的应用程序、浏览器,又或者是各种智能、联网设备的交互都可以归属于前端。 9 | 10 | 因而,在这种意义上来说,前端要做的不仅仅是 Web,还可以是混合应用,原生应用等等。 11 | 12 | 这就意味着: 13 | 14 | - 你可以使用 CSS Layout + React Native 编写移动程序 15 | - 你可以使用 Electron 来编写桌面应用 16 | - 你可以使用 React VR 来编写 VR 应用 17 | - 等等 18 | 19 | 这种时候,前端指的是,我们使用 **样式(类CSS) + 类JavaScript + 模板(HTML、XML等** 编写的应用。 20 | 21 | 如果那些用 JavaScript 编写的应用,也划分到前端的范畴,那么: 22 | 23 | - 你还可以使用 JavaScript 与 Ruff、 Tessel 对硬件进行编程 24 | - 你还可以使用 Node.js 来编写后台应用,又或者是 BFF (backend for frontend)层 25 | 26 | 在这里,我们将前端定义为 类CSS + 类 JavaScript + 模板。因为没有图形应用的应用,难以直观的与用户进行交互,做不了『客户端』应用。在这一定义下,这一类型的应用有,桌面应用、桌面网页、移动网页、移动应用等等,现在发展的有 VR 技术等等。 27 | 28 | ## 本书内容 29 | 30 | 31 | 32 | # 硬技能篇 33 | 34 | # 前端知识要点 35 | 36 | 罗列一下,一些必要的知识点 37 | 38 | 39 | 希望读者都是知道的,以便于 40 | 41 | 作为一个领域,它拥有相当多的知识点。 42 | 43 | 如果读者已经知道了这些,那么可以跳过这一章的内容。 44 | 45 | ## 前端应用的生命周期 46 | 47 | ![前端应用的生命周期](images/refe.png) 48 | 49 | ### 入门 50 | 51 | 在我理解下的基础知识,就是我们可以写一些基本的样式,并能对页面的元素进行操作。举例来说,就是我们用Spring和JSP写了一个博客,然后我们可以用jQuery来对页面进行一些简单的操作,并可以调用一些API。因此,我们需要基本的HTML / CSS知识。只是要写好CSS并不是一件简单的事,这需要很多实战经验。随后,我们还需要有JavaScript的经验,要不怎么做前端呢? 52 | 53 | 同时,我们还需要对DOM有一些基础的了解,才能做一些基本的操作,如修改颜色等等。在这种情况下,最简单的方案就是使用jQuery这样的工具。不过,如果可以自己操作DOM是再好不过的了。 54 | 55 | ### 中级篇 56 | 57 | 中级篇就更有意思了,现在我们就需要对页面进行更复杂的操作。Ajax和JSON这两个技能是必须的,当我们要动态的改变页面的元素时,我们就需要从远程获取最新的数据结果。并且我们也需要提交表单到服务器,RESTful就是必须要学会的技能。未来我们还需要Fetch API,ReactiveX这些技能。 58 | 59 | 除此我们还需要掌握好HTML的语义化,像DIV / CSS这也会必须会的技能,我们应该还会使用模板引擎和SCSS / SASS。而这个层面来说,我们开始使用Node.js来完成前端的构建等等的一系列动作,这时候必须学会使用命令行这类工具。并且,在这时候我们已经开始构建单页面应用了。 60 | 61 | ### 高级篇 62 | 63 | JavaScript是一门易上手的语言,也充满了相当多的糟粕的用法。几年前人们使用CoffeeScript编成成JavaScript来编写更好的前端代码,现在人们有了ES6、TypeScript和WebPack来做这些事。尽管现在浏览器支持不完善,但是他们是未来。同样的还有某些CSS3的特性,其对于某些浏览器来说也是不支持的。而这些都是基于语言本来说的,要写好代码,我们还需要掌握面向对象编程、函数式编程、MVC / MVVM / MV*这些概念。作为一合格的工程师,我们还需要把握好安全性(如跨域),做好 授权(如HTTP Basic、JWT等等)。 64 | 65 | ### 工程化 66 | 67 | 这个标题好像是放错了,这部分的内容主要都是自动构建的内容。首先,我们需要有基本的构建工具,无论你是使用gulp、grunt,还是只使用npm,这都不重要。重要的是,你可以自动化的完成构建的工具,编译、静态代码分析(JSLint、CSS Lint、TSLint)、对代码质量进行分析(如Code Climate,可以帮你检测出代码中的Bad Smell)、运行代码中的测试,并生成测试覆盖率的报告等等。这一切都需要你有一个自动构建的工作流。 68 | 69 | ### 兼容性 70 | 71 | 虽然我们离兼容IE6的时代已越来越远了,但是我们仍然有相当多的兼容性工作要做。基本的兼容性测试就是跨浏览器的测试,即Chrome,IE,Firefox,Safari等等。除此还有在不同的操作系统上对同一浏览器的测试,某些情况下可能表现不一致。如不同操作系统的字体大小,可能会导致一些细微的问题。而随着移动设备的流行,我们还需要考虑下不同Android版本下的浏览器内核的表现不致,有时候还要一下不成器的Windows Phone。除此,还有同一个浏览器的不同版本问题,常见于IE。。 72 | 73 | ### 前端特定 74 | 75 | 除了正常的编码之外,前端还有一些比较有意思的东西,如CSS3和JavaScript动画。使用Web字体,可惜这个不太适合汉字使用。还有Icon字体,毕竟这种字体是矢量的。不过Icon字体还有一些问题,如浏览器对其的抗锯齿优化,还有一个痛是你得准备四种不同类型的字体文件。因此,产生了一种东西SVG Sprite,在以前这就是CSS Sprite,只是CSS Sprite不能缩放。最后,我们还需要掌握一些基本的图形和图表框架的使用。 76 | 77 | ### 软件工程 78 | 79 | 这一点上和大部分语言的项目一样,我们需要使用版本管理软件,如git、svn,又或者是一些内部的工具。总之你肯定要有一个,而不是 2016.07.31.zip这种文件。然后,你还需要一些依赖管理工具,对于那些使用Webpack、Browserify来将代码编写成前端代码的项目来说,npm还是挺好用的。不过就个人来说,对于传统的项目来说我总觉得bower有些难用。我们还需要模块化我们的源码文件,才能使其他人更容易开始项目。 80 | 81 | ### 调试 82 | 83 | 作为一个工程师来说,调试是必备的技能。大部分浏览器都自带有调试工具,他们都不错——如果你使用过的话。在调试的过程中,直接用Console就可以输出值、计算值等等。如果你的项目在构建的过程中有一些问题,你就需要debugger这一行代码了。在一些调用远程API的项目里,我们还需要一些更复杂的工具,即抓包工具。在调试移动设备时,像Wireshark、Charles这一类的工具,就可以让我们看到是否有一些异常的请求。当然在这个时候,还有一个不错的工具就是像Chrome自带的远程设备调试。对于移动网站来说,还要有Responsive视图。 84 | 85 | ### 测试 86 | 87 | 我遇到的很多前端工程师都是不写测试的,于是我便把它单独地抽了出现。对于一个前端项目来说,正常情况下,我们要有单元测试、功能测试,还有要一些UI测试来验证页面间是否可以跳转。对于依赖于第三方服务的应用来说,还要有一个Mock的服务来方便我们测试。如果是前后端分离的项目,我们还需要有集成测试。 88 | 89 | ### 性能与优化 90 | 91 | 要对Web应用进行性能优化,可能不是一件容易的事,有时候我们还知道哪些地方可以优化。这时候人们就可以使用Yahoo的YSlow,或者我最喜欢的Google PageSpeed来检测页面的一些问题,如有没有开启GZip、有没有压缩、合并、Minify JS代码等等。我们还应该借助于NetWork这一类的工具,查看页面加载时,一些比较漫的资源文件,并对其进行优化。在一些情况下,我们还需要借助如Chrome的Timline、Profiel等工具来查看可以优化的地方。 92 | 93 | ### 设计 94 | 95 | 前端工程师还需要具备基本的UI技能。多数情况下拿到的只是一张图,如果是一个完整的页面,我们就需要快速分割页面布局。而依赖于不同的页面布局,如响应式、网格、FlexBox布局也会有不同的设计。而有些时候,我们就需要自己规划,制作一个基本的线框图(Wireframe)等等。 96 | 97 | ### SEO 98 | 99 | 如果以搜索引擎作为流量来源,我们还需要考虑页面的内容,除非你用的是竞争排名。像Sitemap可能就不是我们考虑的内容,而我们还要考虑很多点。首先,我们需要保证页面的内容是对于搜索引擎是可见的,并且对应的页面还要有基本的Title、Description和Keyword。然后在一些关键的字体,如栏目标题等等可以用H2之类的大字的地方就不要放过。同时在页面设计的过程中,我们还需要考虑一些内部链接的建设。它即可以提供页面的可见度,又可以提高排名。最后,如果你是面向的是Google等支持结构化数据的搜索引擎,你还需要考虑一下MicroData / MicroFormat这一类东西。 100 | 101 | # 快速学习新的框架 102 | 103 | 今天很流行的 Web 框架,半年以后,可能就会在市场上被『淘汰』——技术选型的时候,不被开发人员推荐;又或者它已经推出了全新的版本,使用了全新的 API,我们便需要更新现有应用。 104 | 105 | 前端框架丰富多彩的今天,快速学习新的框架是**每个前端程序员的必备技能**。 106 | 107 | ## 快速学习是基本能力 108 | 109 | 后端程序员,开始一个新的 Web 项目时: 110 | 111 | - 使用 Java 语言,八成会选用 Spring 框架。 112 | - 使用 Ruby 语言,八成会选用 Rails 框架。 113 | - 使用 Scala 语言,八成会先用 Play 框架。 114 | 115 | 而只使用 JavaScript 的前端程序员,开始一个前端项目时。你有几成的把握,能判断他/她出会使用哪个框架? 116 | 117 | 后端程序员在有限的时间内,只会使用固定的技术栈,固定的框架。对于大部分的公司来说,使用相同的后台语言,是一个更好的选择——即可以减少带成本,又可以沉淀下技术积累。 118 | 119 | 而前端则不一样,不同的项目都有各自的需求,因此采用使用不同的技术栈。简单的,可以直接使用原生的 JavaScript 完成,又或者是使用 jQuery 完成开发。稍微复杂一点的项目,采用容易上手的 Vue.js 是一个不错的选择。更复杂的项目,便可以使用 Angular,可以方便后台程序员转到前端。 120 | 121 | 因此,工作一定年限的程序员,都使用过不同的框架。可是,不同的程序员上手新框架的速度,总会存在一定的差异。 122 | 123 | 那么,怎样才能快速上手一个新的框架呢? 124 | 125 | 学习新的前端框架,要么该框架很火——即**热闹驱动开发**(Hype Driven Development,HDD),要么你们将采用该框架。在采用新框架的动机里,有一种是:技术演进。使用新的技术、框架,来替换现有的框架。旧的框架在某些地方上,存在着明显的缺陷。 126 | 127 | 这种情形下,业务知识本身是不变的,只是要由框架本身来应对业务的变化。因此,使用新的技术来替换旧有的框架,就相当的容易——重写,我们甚至可以直接复制、粘贴,大量原有的代码。只是,仅仅做到重写业务逻辑是不够的。我们还要掌握新的框架的核心,并探索更多的可能性。 128 | 129 | ## 如何学习新框架:守-破-离 130 | 131 | 我在学校的时候,看到一个关于编程语言的学习建议:**学习三种以上的编程语言,并且它们最好是三种不同类型的语言**。如面向过程的编程语言 C 、脚本语言 JavaScript、Python,面向对象的编程语言 Java、再加上个近年来火热的函数式编程语言,到底也就差不多了。当我们学习了一门语言,再上手一门相似风格的语言,也是相当轻松地一件事。当我们学习了不同类型的几种语言,未来就可以轻松地绝大多数的语言。 132 | 133 | 相似的,学习使用 Web 框架也是如此的。现在,对于我而来,使用一个『新框架的姿势』是: 134 | 135 | - 买本中文书或者找个教程、官方的 Guide,花个十几分钟了解一下框架的『知识图谱』。 136 | - 直接找个官方的示例,运行一下 Demo。 137 | - 上手写写应用。 138 | - 查看官方文档,看看自己是不是漏掉了什么重要的东西。 139 | 140 | 它与我在公司接受培训的时候,学习到的『守破离』观点相似。在保留原来业务的情况下,一步步向前演进。 141 | 142 | ### 守:应用业务知识 143 | 144 | 在现有的业务上,使用新的框架是一件容易的事。拿上一份框架的说明书、一份需求文档、一个搜索引擎,就可以很容易地复制出一个产品。唯一的门槛是,你需要会读懂这些内容。这有点像新的知识阶级,只是门槛不再是识字与否,而在于是否能懂编程的知识。 145 | 146 | 正如维基百科上,对于『守』的介绍一样: 147 | 148 | > 最初阶段须遵从老师教诲,认真练习基础,达到熟练的境界。 149 | 150 | 新手期的我们,拿到一个新的框架,要一下子对它了运用自如,是一件很难的事。我们只能在一个又一个的练习中,尝试去掌握框架的知识。如,原先我们使用的是 Backbone + jQuery 完成的前端应用,现在要切换到 Vue.js。我们要做的便是尝试使用 Vue.js,并不断地练习一些相关的用法。而在熟练之后,我们也会练习我们的基本套路,如在上文中说到的『新框架的姿势』。 151 | 152 | 而如果不考虑练习本身的时间因素,便只剩下的一个问题是:**如何找到一个合适的练习项目**。然而,这样的项目在 GitHub 上有很多。可是即使它能满足我们的需求,我们有时候也不知道怎么练习? 153 | 154 | 我想问题的关键在于:我们手上没有一个已经成型的业务系统。因此,我建议大家可以从创建一个博客开始做起,先使用现有的技术,再使用新的技术,慢慢的一点点往上添加内容。如我的博客,最早是基于 Django + Bootstrap,慢慢的我添加了一些新的东西: 155 | 156 | - 用于为搜索提供建议的 AutoSuggest 157 | - 移动应用 API 及博客搜索 API 158 | - 微信搜索支持功能 159 | - 支持 Google AMP 来快速加载页面 160 | - Google Micro Data 161 | 162 | 尽管越来越多的功能,有一些已经不再维护、关闭了。可是,它让我有机会去练习一些新的技术,掌握一些技术背后的思想,得到一些框架相关的结论。而不是每次与别人讨论时,说:xx 说 xx 框架有这样的问题,而是我试过这个框架,它有这样的问题。 163 | 164 | ### 破:学习框架核心 165 | 166 | > 基础熟练后,试着突破原有规范让自己得到更高层次的进化。 167 | 168 | 转换技术栈,本身没有什么技术含量,但是能帮助稳固知识。当我们已经熟悉使用这个框架完成业务时,便可以细入相关思想。 169 | 170 | 了解这个框架的能力,生成一份与框架有关的索引,也可以用脑图的形势来整理这些内容。 171 | 172 | 如: 173 | 174 | ![嵌入式系统工程师图谱](images/eks-example.jpg) 175 | 176 | 举例,如 Angular + TypeScript,还有其他更多的可能性 177 | 178 | 同时,我们还应该理解框架背后的原理。不一定深入,但是觉得去探究。如: 179 | 180 | - MV* 思想 181 | - 双向数据绑定的基本原理 182 | 183 | 这些都在我的知乎专栏上《我的职业是前端工程师》有深入的介绍,有时候的读者建议多阅读相关的内容。 184 | 185 | ### 离:探索更多可能性 186 | 187 | > 在更高层次得到新的认识并总结,自创新招数另辟出新境界。 188 | 189 | 在那之上,创造出一些新的框架。 190 | 191 | 如 Redux,最早是运行的 React.js 之上。Angular 2 出来了后,有了 xx。小程序出来后,有了 xx。 192 | 193 | 同理于此,当出现微信小程序的一两个星期内,我写了几篇原理相关的文章,并介绍了如何创建一个属于自己的小程序应用框架 WINV。又或者是我在对 Virtual Dom 有一定的了解后,便深入 Virtual Dom 的代码,写了一个基于 Virtual Dom 的测试辅助框架 [Luffa](http://github.com/phodal/luffa)。 194 | 195 | 而这些,只有我们理解他们的原理之后,我们才可能做到这样的事。 196 | 197 | ## 小结 198 | 199 | 寻找心流 200 | 201 | 这些方法适用于大部分的人,但是不一定适合你。你只需要寻找到适合你的路,然后学习。 202 | 203 | ## 选择合适的前端框架 204 | 205 | 在《全栈应用开发:精益实践》一书中,我曾提到过影响技术选型的几个因素: 206 | 207 | ![选型因素](images/tech-decide.png) 208 | 209 | **锤子定律:寻找更大视野** 210 | 211 | **年轻的时候,学会了 A 框架,总觉得 Z 网站用 A 框架来实现会更好**,一定不会像今天这样经常崩溃、出Bug。**时间一长,有时候就会发现,Z 网站使用 A 不合适,他们的问题并不是框架的问题,而是运维的问题。 212 | 213 | 在《咨询的奥秘》一书中,提到一个有意思的定律“锤子定律”(又称为工具定律)——**圣诞节收到一把锤子的孩子,会发现所有东西都需要敲打**。 出现这种情况的主要原因是,**开发者对一个熟悉的工具过度的依赖**。 214 | 215 | 认真观察,就会发现这个现象随处可见。当一个新手程序员学会了某个最新的框架,通常来说这个框架有着更多的优点,这个时候最容易出现的想法是:**替换现有的框架**。可是,现有的框架并没有什么大的问题。并且凭估不充分时,新的框架则存在更多的风险。 216 | 217 | 并且,对于某个熟悉工具的过度依赖,特别容易影响到技术决策——看不到更多的可能性。这时候,我们就需要头脑风暴。但是这种情况下,头脑风暴很难帮助解决问题。在这个时候,拥有更多项目、框架经验的人,可能会做出更好的选择。 218 | 219 | ### Angular,一站式提高生产力 220 | 221 | 与 Backbone 同一时代诞生的 Angular 便是一个大而全的 MVC 框架。在这个框架里,它提供了我们所需要的各种功能,如模块管理、双向绑定等等。它涵盖了开发中的各个层面,并且层与层之间都经过了精心调适。 222 | 223 | 我们所需要做的便是遵循其设计思想,来一步步完善我们的应用。Angular.js 的创建理念是:即声明式编程应该用于构建用户界面以及编写软件构件,而命令式编程非常适合来表示业务逻辑。 224 | 225 | 我开始使用 Angular.js 的原因是,我使用 Ionic 来创建混合应用。出于对制作移动应用的好奇,我创建了一个又一个的移动应用,也在这时学会了 Angular.js。对于我而言,选择合适的技术栈,远远比选择流行的技术栈要重要得多,这也是我喜欢使用 Ionic 的原因。当我们在制作一个应用,它对性能要求不是很高的时候,那么我们应该选择开发速度更快的技术栈。 226 | 227 | 对于复杂的前端应用来说,基于 Angular.js 应用的运行效率,仍然有大量地改进空间。在应用运行的过程中,需要不断地操作 DOM,会造成明显的卡顿。对于 WebView 性能较差或早期的移动设备来说,这就是一个致命伤。 228 | 229 | 幸运的是在 2016 年底,Angular 团队推出了 Angular 2,它使用 Zone.js 实现变化的自动检测、 230 | 231 | 而迟来的 Angular 2 则受**奥斯本效应**[^osborne]的影响,逼得相当多的开发者们开始转向其它的框架。 232 | 233 | [^osborne]: 颇受欢迎的个人电脑厂商奥斯本,其公司的创新式便携电脑还没有上市,就宣布他们要推出的更高档的机器,而又迟迟无法交货,消费者闻风纷纷停止下单订购现有机种,最后导致奥斯本因收入枯竭而宣布破产。 234 | 235 | ### React,组件化提高复用 236 | 237 | 从 Backbone 和 Angular.js 的性能问题上来看,我们会发现 DOM 是单页面应用急需改善的问题——主要是DOM 的操作非常慢。而在单页面应用中,我们又需要处理大量的 DOM,性能就更是问题了。于是,采用 Virtual DOM 的 React 的诞生,让那些饱受性能苦恼的开发者欢迎。 238 | 239 | 传统的 DOM 操作是直接在 DOM 上操作的,当需要修改一系列元素中的值时,就会直接对 DOM 进行操作。而采用 Virtual DOM 则会对需要修改的 DOM 进行比较(DIFF),从而只选择需要修改的部分。也因此对于不需要大量修改 DOM 的应用来说,采用 Virtual DOM 并不会有优势。开发者就可以创建出可交互的 UI。 240 | 241 | 除了编写应用时,不需要对 DOM 进行直接操作,提高了应用的性能。React 还有一个重要思想是组件化,即 UI 中的每个组件都是独立封装的。与此同时,由于这些组件独立于 HTML,使它们不仅仅可以运行在浏览器里,还能作为原生应用的组件来运行。 242 | 243 | 同时,在 React 中还引入了 JSX 模板,即在 JS 中编写模板,还需要使用 ES 6。令人遗憾的是 React 只是一个 View 层,它是为了优化 DOM 的操作而诞生的。为了完成一个完整的应用,我们还需要路由库、执行单向流库、web API 调用库、测试库、依赖管理库等等,这简直是一场噩梦。因此为了完整搭建出一个完整的 React 项目,我们还需要做大量的额外工作。 244 | 245 | 大量的人选择 React 还有一个原因是:React Native、React VR 等等,可以让 React 运行在不同的平台之上。我们还能通过 React 轻松编写出原生应用,还有 VR 应用。 246 | 247 | 在看到 Angular 2 升级以及 React 复杂性的时候,我相信有相当多的开发者转而选择 Vue.js。 248 | 249 | ### Vue.js,简单也是提高效率 250 | 251 | 引自官网的介绍,Vue.js 是一套构建用户界面的渐进式框架,专注于MVVM 模型的 ViewModel 层。Vue.js 不仅简单、容易上手、配置设施齐全,同时拥有中文文档。 252 | 253 | 对于使用 Vue.js 的开发者来说,我们仍然可以使用 熟悉的 HTML 和 CSS 来编写代码。并且,Vue.js 也使用了 Virtual DOM、Reactive 及组件化的思想,可以让我们集中精力于编写应用,而不是应用的性能。 254 | 255 | 对于没有 Angular 和 React 经验的团队,并且规模不大的前端项目来说,Vue.js 是一个非常好的选择。 256 | 257 | 虽然 Vue.js 的生态与 React 相比虽然差上一截,但是配套设施还是相当齐全的,如 Vuex 、 VueRouter。只是,这些组件配套都由官方来提供、维护,甚至连 awesome-vue 也都是官方项目,总觉得有些奇怪。 258 | 259 | 除此,Vue.js 中定义了相当多的规矩,这种风格似乎由 jQuery 时代遗留下来的。照着这些规矩来写代码,让人觉得有些不自在。 260 | 261 | 和 React 相似的是,Vue.js 也有相应的 Native 方案 Weex,仍然值得我们期待。 262 | 263 | # 构建系统:资深分界线 264 | 265 | Yeoman 生成脚手架,并且现在的主流前端框架都提供了相似的工 266 | 267 | 打包 -> 压缩 -> 上传 -> 解压 -> 替换 -> 重启 268 | 269 | 重点在于:提高工作效率 270 | 271 | ## 为什么构建很重要 272 | 273 | 过去我们打开编辑器、浏览器、修改代码、刷新页面,如下图所示: 274 | 275 | ![前端应用的开发流程](images/basic-workflow.png ) 276 | 277 | 这个过程仍然没有发生太大的变化,只是很多的步骤都被自动化了: 278 | 279 | 我们只需要修改代码,诸如 watchman 这样的工具就检测到修改,而 Browsersync 则可以帮助我们自动刷新页面。 280 | 281 | ## 构建工具 282 | 283 | 取决于你所使用的技术栈 284 | 285 | SASS、SCSS 因不同的情况而异 286 | 287 | webpack 288 | 289 | npm 290 | 291 | grunt / gulp 292 | 293 | ## 构建流程 294 | 295 | ![前端构建流程](images/build-workflow.png) 296 | 297 | LiveReload 298 | 299 | Bower 300 | 301 | concat -> init -> lint -> min -> qunit -> server -> test -> watch 302 | 303 | ### 构建示例 304 | 305 | 如下是混合应用框架 Ionic 执行 ``ionic serve`` 时的启动日志: 306 | 307 | ``` 308 | [11:43:58] ionic-app-scripts 1.3.4 309 | [11:43:58] watch started ... 310 | [11:43:58] build dev started ... 311 | [11:43:58] clean started ... 312 | [11:43:58] clean finished in 1 ms 313 | [11:43:58] copy started ... 314 | [11:43:58] transpile started ... 315 | [11:44:03] transpile finished in 5.17 s 316 | [11:44:03] preprocess started ... 317 | [11:44:03] deeplinks started ... 318 | [11:44:03] deeplinks finished in 132 ms 319 | [11:44:03] preprocess finished in 132 ms 320 | [11:44:03] webpack started ... 321 | [11:44:03] copy finished in 5.49 s 322 | [11:44:26] webpack finished in 22.94 s 323 | [11:44:26] sass started ... 324 | [11:44:29] sass finished in 3.21 s 325 | [11:44:29] postprocess started ... 326 | [11:44:29] postprocess finished in 85 ms 327 | [11:44:29] lint started ... 328 | [11:44:29] build dev finished in 31.57 s 329 | [11:44:29] watch ready in 31.69 s 330 | ``` 331 | 332 | 这个过程中,它会完成如下的步骤: 333 | 334 | watch -> build dev -> clean -> copy -> transpile -> preprocess (deeplinks) -> webpack (copy) -> sass -> postprocess -> build dev 335 | 336 | ### 自动刷新 337 | 338 | ### 转译 339 | 340 | ### 预处理 341 | 342 | 343 | # 什么是前端的架构能力 344 | 345 | > 远离最佳实践,除非你能接受其带来的成本 346 | 347 | 当我们谈及『前端的架构』时,我们讨论的是复杂前端应用的架构——如果只是一个 jQuery + Bootstrap 完成的应用,那么它的架构想必是『散弹式』的应用,没有复杂的逻辑可言。 348 | 349 | ## “标准”的 SPA 构架实践 350 | 351 | 复杂的前端应用,多数是 SPA(单页面应用),这就意味着系统的架构是前后端分离的。可前后端分离并意味着, 352 | 353 | ### 前后端分离 354 | 355 | ### 无状态 API 356 | 357 | ## workflow 358 | 359 | ### 前后端分离的工作方式 360 | 361 | 实现上,它主要关注点是:API 的设计。API 设计应该由前端开发者来驱动的。后台只提供前端想要的数据,而不是反过来的。后台提供数据,前端从中选择需要的内容。 362 | 363 | - 使用文档规范 API 364 | - 契约测试:基于持续集成与自动化测试 365 | - 前端测试与 API 适配器 366 | 367 | ## 风格指南:StyleGuide 368 | 369 | 与之前的构建系统相比,StyleGuide 便是一种无法用工具强制执行的规范。尽管可以采用工具来做类似的事情,但是并非应该强制去做。 370 | 371 | - 代码规范 372 | - 函数限制。Java -> 30 行 373 | 374 | ## 演进 375 | 376 | 当前技术栈,未来技术栈,切换。 377 | 378 | 使用了 Backbone,性能上出现一些瓶颈。 379 | 380 | 是不是要重写服务。 381 | 382 | 后台不能满足一些需求,考虑使用 BFF 吗 383 | 384 | 选用合适的策略,并保证没有问题。 385 | 386 | 387 | ## 最佳实践:框架 388 | 389 | 在这个领域,并不存在最佳的实践。首先的问题是,要找出我们真正想实现的功能,在这之后再去完成下一个步骤。而不是先找行业中最好的实践,再将这些实践应用 390 | 391 | jQuery 在简单的前端页面里,仍然是最好的选择。 392 | 393 | ### jQuery + TinyMCE 394 | 395 | ### jQuery + Vue 396 | 397 | 不久前,我需要一个 UI 框架及前端框架来实现简单的逻辑功能,并且它还应该相当的小。因此,我首先排队了 jQuery + Bootstrap,它们在体积上不太符合我的要求。 398 | 399 | - 发出一个 Ajax 请求,验证 Token 400 | - 如果返回的 Token 是有效的,则生成 401 | 402 | 提炼出核心技术, 403 | 404 | 对于大的公司来讲,都会要求拥有自己的核心技术。 405 | 406 | 在网上,各式各样的前端开发最佳实践层出不穷, 407 | 408 | 最意味着,在某些方面已经是到了极致。 409 | 410 | # 自动化提高效率 411 | 412 | ## 自动化测试加快上线流程 413 | 414 | ### 测试 415 | 416 | 测试页面的输出结果,保证元素的准确性~ 417 | 418 | stub: 结果,返回预期的结果。 419 | 420 | mock: 行为,预期方法被调用。 421 | 422 | ### ui 测试 423 | 424 | React Test Renderer 425 | 426 | ``` 427 | 434 | 435 | 445 | ... 446 | ``` 447 | 448 | ### 截屏测试, 449 | 450 | 对于那些 UI 改动较小的系统来说,这 451 | 452 | 而我们知道页面截图尽管可以作为版本管理的一部分,但是一个不可比对的结果 453 | 454 | 而诸如,react-test-render, Virtual Dom 测试 455 | 456 | 那么,对于普通的 HTML 结构的 457 | 458 | ![PhantomCSS](images/PhantomCSS.png) 459 | 460 | ## 自动构建 461 | 462 | 在之前的构建系统一节里,我们讲了 xx。剩下要做的就是生成打包好的源码 463 | 464 | Gulp、Grunt 465 | 466 | ## 自动化部署 467 | 468 | 只需要一些 持续集成 的基础,如 Jenkins 469 | 470 | ### 持续集成 471 | 472 | 473 | # 前端应用的架构与设计模式 474 | 475 | 476 | ## 散弹式架构 -> jQuery 477 | 478 | 项目达到一定的程度,jQuery 便有些难以管理,我们不知道哪个地方还操作了 DOM。修改了 A 处的 selector,可能会影响 B 处的 selector。 479 | 480 | 这样的修改方式称为『散弹式架构』,它来自于 散弹式修改(shotgun surgery,出处《重构:改善既有代码的设计》), 481 | 482 | 在使用 Backbone 的过程中,如果你采用了继承 View 的方式,你也会遇到这种遇到问题。 483 | 484 | ## 分层结构 MV* 485 | 486 | 典型的 SPA 应该会具有的模式,如 Angular,Vue.js 487 | 488 | ## 处理数据 pipe and filter 489 | 490 | fetch、ajax、RxJS 从 API 处获取到数据 491 | 492 | 这个时候的数据首先会被转换为 JSON,再过滤到需要的字段,再对字段进行特殊的处理,如 HtmlEncoded,最后再 Render 到元素上。 493 | 494 | 当我们从服务器 495 | 496 | ## 数据显示 观察者模式 497 | 498 | 双向绑定,即观察者模式,又可以称为发布订阅模式(Publish/Subscribe) 499 | 500 | ## 数据通讯 501 | 502 | 除了常规的数据获取,还有在不同的框架间传输数据,如 React Native 和 WebView 的 postMessage,Cordova 的 WebView 与原生插件间 503 | 504 | ### 消息通讯 505 | 506 | ### 数据通讯:shared repository 507 | 508 | 其他消息通讯 509 | 510 | ### 数据通讯:local storage 511 | 512 | ??? black board 513 | 514 | # 软技能篇 515 | 516 | # 在做业务的过程中提升技术 517 | 518 | > “三个月经验,重复了五年” 519 | 520 | ## 测试 521 | 522 | ## 代码可读性 523 | 524 | > 与性能相比,可读性更加重要——绝大多数的软件,并不是写完就结束周期了。当然,倒掉的创业公司的软件除外。 525 | 526 | 527 | ## 有意图的提升 528 | 529 | 在一家大的公司里,不同的人总会有不同的运气: 530 | 531 | 运气好的人遇上一个好的项目,升职加薪,从此就走上了人生的巅峰。 532 | 运气差的人摊上一个差的项目,升不了职,少加了薪,并且还获得不了技术成长。 533 | 我刚毕业那会儿,所在团队的主要工作是,维护一个『又老又旧』的系统。比起写业务代码更不幸的是,我们的主要工作是修 Bug,bug,buG, bUg。 534 | 535 | 那一年多里,尽管都是维护旧系统和少量的新需求,我们还是在飞速的成长~~。而来源主要是: 536 | 537 | - 组内技术活动 538 | - 花时间投入练习 539 | - 假想项目的重构 540 | 541 | 当你在有限的条件下,还能做出一定的成绩,到底还是相当有成就感的。 542 | 543 | 如果你觉得你的项目技术栈老旧,那么你一定在脑子里使用了 N 种技术栈,对他们进行重构了。并且当你有一些时间可以分配到上面,如下班前的一个小时时间,又或者黑客马拉松等等。那么,你一定会开始去做这样的事。 544 | 545 | 与上面的技术活动相比,这是一个对于业务(我的意思是,对于公司来说)更有价值,并且更容易说服别人的方式。 546 | 547 | - 学习别的项目的技术栈,然后将之应用到现有的系统上。 548 | - 使用一个新的技术栈练习, 以此作为技术支撑,在未来替换现有的系统。 549 | 550 | # 持续学习:走出下一个『jQuery』 551 | 552 | 不,仍然没有, 553 | 554 | jQuery 的最大问题在于,简单如果上手,如 Vue 有可能便会流行,然后成为下一个 jQuery 555 | 556 | ## jQuery 已经落后了?下一个 jQuery 已经出现了 557 | 558 | 预测未来,不,我不可能。 559 | 560 | 对于,大公司或者内部系统的开发者来说,由于框架能满足应用的开发,因此很容易长期采用一个框架。当然,这本身并不是问题,你有了一份的工作,一个稳定的。可是,你可能会失去学习的勇气与能力。 561 | 562 | ## 持续学习 563 | 564 | ## 掌握思想 565 | 566 | - 路由:页面跳转与模块关系 567 | - 数据:获取与鉴权 568 | - 数据展示:模板引擎 569 | - 交互:事件与状态管理 570 | 571 | ## 后端技能 572 | 573 | 阅读后端代码的能力 574 | 575 | # 软技能 576 | 577 | 原本打算写一些时间管理,及 578 | 579 | 篇幅所限 580 | 581 | ## 知识管理 582 | 583 | 将输入的知识变为输出 584 | 585 | 以输出的方式来输入。 586 | 587 | ## Debug: 发现问题 588 | 589 | 编程时,我们大部分时候都是在解决问题,即求解已知的问题。 590 | 591 | 除此,我们还需要花费很多的时间在 Debug 上,即如何去发现问题所在。 592 | 593 | 最后,如果仍然不能解决问题,那么就找个人、地方提问吧。 594 | 595 | # 扩展篇 596 | 597 | # 前端知识体系的广度与深度 598 | 599 | ## 前端与后台的对比 600 | 601 | 后台对于深度要求高,而前端对于广度要求高。 602 | 603 | - 用户体验设计 604 | 605 | 前端:用户喜爱的产品 606 | 607 | 基础 HTML + JS + CSS 608 | 609 | 广度 -> 用户体验、浏览器差异 -> 知识碎片 610 | 611 | jQuery + Backbone + xxx 612 | 613 | 后台:高并发高可用 614 | 615 | 纠结于 事务一致 锁 616 | 617 | Spring + Mybatis + Flyway 618 | 619 | 数据库 + ORM + MVC 620 | 621 | 论技术上的深度,自然是后台更深 622 | 623 | 论用户体验上,自然是前端更深 两种很难衡量 624 | 625 | 常见问题:Ops 运维 -> 环境问题 626 | 627 | 628 | 对于前端来说,广度 First -> 深度。熟悉框架的相似之处,并且完成任务。 629 | 630 | 对于后端来说,选定语言,基本上就已经选好一切了,Java -> Spring,Scala -> Play,Ruby -> Rails 631 | 632 | ## 用户体验设计 633 | 634 | 635 | ## 前端的广度 636 | 637 | 在中大型规模的公司里,会有建议使用的后台语言,他们也主要使用一个后台语言。因为它已经可以很稳定地运行 638 | 639 | 除非,旧的语言在应用上存在一些缺陷。或者,正在尝试使用新的技术。 640 | 641 | 而对于前端来说,如果不能选择使用自己的轮子,那么就会是一片混乱。他们会使用不同的框架,不同的团队都有不同的业务场景。 642 | 643 | 644 | 645 | # 前端的趋势 646 | 647 | ![未来趋势](images/future-stacks.png) 648 | 649 | ## 微服务与微前端 650 | 651 | > 对于后台采用微服务架构来说,在一个不同的组成部分中,使用不同的技术栈是一种不错的体验;而对于一个前端团队来说,在同一个系统的使用不同的技术栈就不是一种不错的体验。 652 | 653 | 可以使用 Web 存储技术,如 LocalStorage 来转移状态。又或者是诸如 Redux 的方式 654 | 655 | ## BFF 656 | 657 | ## 状态管理 658 | 659 | Redux 660 | 661 | ## 跨平台 662 | 663 | Angular 可以移动应用和桌面Web应用,可是它并没有像 React 有那么广泛的用途。 664 | 665 | React、React VR、React Native 666 | 667 | ## UI 生成 668 | 669 | 过去有 DreamWeaver 这样的软件,现在也有一些强大的 UI 工具,可以直接将设计转化为代码。 670 | 671 | 672 | # 转型前端指南 673 | 674 | 职业转型,放弃你现在的工作、相关行业经验,进入一个“新的环境”。这就意味着,当你想转到前端时,你需要面临一系列的挑战。你的老板并不会关心你的过程是怎样的,只要你能达到当前的能力要求,并有能力适应未来的变化即可。 675 | 676 | > 跳槽穷半年,转行穷三年。 677 | 678 | 在过去的两三年里,随着前端领域的火热,市场上有越来越多的、不同行业的人加入了前端大军。人们出于不同的目的,选择上了前端开发。 679 | 680 | 有的是,大学里喜欢上前端这个行业,在找工作的时候,便选择了相应的岗位;有的是,不喜欢传统的编译型语言,如电子信息工程;有的是,大学上的专业找不到合适的工作,诸如数学等,并且有些专业与编程相比,拥有同等的逻辑能力要求;有的是,看前端行业很赚钱,便报了个培训班,来到了这个行业。 681 | 682 | 前端这个职业吧,入门快,上手也简单。简单的网页吧,拉上几个初学者便也能完成。可一旦遇上复杂的前端应用,就会暴露出各种各样的问题。于是,那些原先由非编程领域转行过来的人,便容易招至不满。 683 | 684 | 究其原因吧,是因为能力上达不到要求。我们到是可以看看,有多少人会转向人工智能,下一个行业热点。 685 | 686 | ## 改变 687 | 688 | 一点点慢慢改变,时间长,成本高,但是痛苦小 689 | 690 | 主要问题: 691 | 692 | - 生活压力 693 | - 经济来源 694 | 695 | change -> 改变 -> 痛苦 696 | 697 | 1. 实验 -> 尝试写代码 -> 意义 698 | 2. 培训或者 workshop 699 | 3. 人脉 <-> 相似的人 700 | 4. 意义 <-> 701 | 702 | 编程世界,比现实世界简单,有严格的对错。 703 | 704 | 如果你是一个没有编程经验的新手,那么你应该去报一个培训班。他可以在短期内帮你提高技术,但是与之相对应的,会带来一些问题。培训机构出来的学员,都存在一定的简历造假。由于数量众多,质量上参差不齐,导致人们普遍对培训机构出来的学员,存在一定的能力怀疑。说到底,你只能把培训机构当成一个入门,它距离你找到一份工作,还有相当大差距。 705 | 706 | 但是,你是真心的喜欢编程这个职业吗? 707 | 708 | 我见过一些后来者,他们在开始的时候问一些愚蠢的问题,慢慢的他们意识到这些问题,都是自己搜索就能解决的。他们会加入一些小组,来提高自己。建立一些信心,并去回答一些别人的问题。 709 | 710 | ## 后台转前端的挑战 711 | 712 | Angular 2 -> 是一个不错的选择 713 | 714 | - 强类型语言 TypeScript 715 | - 依赖注入等等的设计模式思维 716 | 717 | 唯一遗憾的是,它不使用 XML 来配置 718 | 719 | Node.js 应用也是一个不错的选择 720 | 721 | ## 其他编程领域转前端 722 | 723 | 移动端到 React Native,再到 React 724 | 725 | ## 其他行业转前端 726 | 727 | ### 劝退 728 | 729 | 编程并不是一件容易的事,如果你有业余兴趣便还好,如果没有的话,就算了。 730 | 731 | 主要原因:它并不是一个赚钱的行业,你是在时间换金钱。。 732 | 733 | 不妨考虑,投资,或者产生一个千万级的 idea,再找个风投 734 | 735 | 万一,你又一次选错行了呢? 736 | 737 | ### 立意已决 738 | 739 | 首先,打开浏览器、下载 IDE、然后写一行 HTML 试一试 740 | 741 | 简单的入门书,如 Head First HTML 742 | 743 | 找一个小的项目 744 | 745 | - 成功的复制一些小网站到本地 746 | - 然后,再是模拟一些小的项目 747 | 748 | 1. 不要预期薪水可以达到市场水平。没有人关心你是谁,你只要能干活,并且小公司、外包公司可能是一个更简单的入门。 749 | 750 | 外包公司 -> 门槛低 -> 相对比较多的成功案例 751 | 752 | 寻找合适的工作 -> 起步类型 753 | 754 | 查看相应类型的工作,看看工作介绍 755 | 756 | 事实上,按照『技术成熟曲线』理论,前端正在进入低谷期。而人工智能才是,现在,乃至未来一段时间的 IT 高薪领域。 757 | 758 | ![Gartner 技术成熟曲线](images/gartner-hype-cycle.png) 759 | 760 | 如果你真的喜欢前端,那么:Just do it! 761 | 762 | 如果你爱请深爱~。 763 | 764 | 765 | # 前端跨行指南 766 | 767 | JavaScript 应用领域 768 | 769 | 挑战:要学会新的领域的知识,以及其对应的语言知识。如开发混合应用时,在 iOS 方面,你需要有些许 Objective-C 或者 Swift 的开发能力,在 Android 方面,你还需要些许的 Java 经验。 770 | 771 | ## 移动开发:混合开发 772 | 773 | ## 桌面应用 774 | 775 | ## VR 776 | 777 | ## 硬件 778 | 779 | ## 其它? 780 | 781 | -------------------------------------------------------------------------------- /epub.css: -------------------------------------------------------------------------------- 1 | html, body, div, span, h1, h2, h3, h4, h5, h6, p, a, em, strong, b, u, i, pre, code, del, strike, abbr, acronym, address, q, cite, blockquote, big, small, sub, sup, tt, var, center, img, dfn, ins, kbd, s, samp, dl, dt, dd, ol, ul, li, fieldset, legend, label, table, caption, tbody, tfoot, thead, tr, th, td { 2 | margin: 0; 3 | padding: 0; 4 | border: 0; 5 | outline: 0; 6 | font-size: 100%; 7 | vertical-align: baseline; 8 | background: transparent; 9 | } 10 | @page { 11 | margin: 5px; 12 | } 13 | p { 14 | margin-bottom: 9px; 15 | line-height: 1.4; 16 | } 17 | a { 18 | color: #0069d6; 19 | } 20 | a:hover { 21 | color: #0050a3; 22 | text-decoration: none; 23 | } 24 | a img { 25 | border: none; 26 | } 27 | h1, h2, h3, h4, h5, h6 { 28 | color: #404040; 29 | line-height: 1.5; 30 | margin: 1em 0 0.5em; 31 | -webkit-hyphens: none; 32 | hyphens: none; 33 | adobe-hyphenate: none; 34 | } 35 | h1 { 36 | font-size: 220%; 37 | margin-bottom: 1.5em; 38 | } 39 | h2 { 40 | font-size: 190%; 41 | } 42 | h3 { 43 | font-size: 160%; 44 | } 45 | h4 { 46 | font-size: 140%; 47 | } 48 | h5 { 49 | font-size: 130%; 50 | } 51 | h6 { 52 | font-size: 120%; 53 | } 54 | hr { 55 | margin: 0 0 19px; 56 | border: 0; 57 | border-bottom: 1px solid #ccc; 58 | } 59 | blockquote { 60 | padding: 13px 13px 21px 15px; 61 | margin-bottom: 18px; 62 | font-family: georgia, serif; 63 | font-style: italic; 64 | } 65 | blockquote:before { 66 | content: "\201C"; 67 | font-size: 300%; 68 | margin-left: -10px; 69 | font-family: serif; 70 | color: #eee; 71 | } 72 | blockquote p { 73 | font-size: 120%; 74 | margin-bottom: 0; 75 | font-style: italic; 76 | } 77 | code, pre { 78 | font-family: monospace; 79 | } 80 | code { 81 | background-color: #fee9cc; 82 | color: rgba(0, 0, 0, 0.75); 83 | padding: 1px 3px; 84 | -webkit-border-radius: 5px; 85 | border-radius: 5px; 86 | font-size: 85%; 87 | } 88 | pre { 89 | display: block; 90 | padding: 14px; 91 | margin: 0 0 18px; 92 | font-size: 85%; 93 | line-height: 1.3; 94 | border: 1px solid #d9d9d9; 95 | white-space: pre-wrap; 96 | word-wrap: break-word; 97 | -webkit-hyphens: none; 98 | hyphens: none; 99 | adobe-hyphenate: none; 100 | } 101 | pre code { 102 | background-color: #fff; 103 | color: #737373; 104 | padding: 0; 105 | } 106 | code.sourceCode span.kw { 107 | color: #007020; 108 | font-weight: bold; 109 | } 110 | code.sourceCode span.dt { 111 | color: #902000; 112 | } 113 | code.sourceCode span.dv { 114 | color: #40a070; 115 | } 116 | code.sourceCode span.bn { 117 | color: #40a070; 118 | } 119 | code.sourceCode span.fl { 120 | color: #40a070; 121 | } 122 | code.sourceCode span.ch { 123 | color: #4070a0; 124 | } 125 | code.sourceCode span.st { 126 | color: #4070a0; 127 | } 128 | code.sourceCode span.co { 129 | color: #60a0b0; 130 | font-style: italic; 131 | } 132 | code.sourceCode span.ot { 133 | color: #007020; 134 | } 135 | code.sourceCode span.al { 136 | color: red; 137 | font-weight: bold; 138 | } 139 | code.sourceCode span.fu { 140 | color: #06287e; 141 | } 142 | code.sourceCode span.re { 143 | } 144 | code.sourceCode span.er { 145 | color: red; 146 | font-weight: bold; 147 | } 148 | body { 149 | font-family: serif; 150 | } -------------------------------------------------------------------------------- /images/PhantomCSS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/fed/2ef56a5a9431c5144b1017e9fd962e3b8ba3ac32/images/PhantomCSS.png -------------------------------------------------------------------------------- /images/basic-workflow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/fed/2ef56a5a9431c5144b1017e9fd962e3b8ba3ac32/images/basic-workflow.png -------------------------------------------------------------------------------- /images/build-workflow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/fed/2ef56a5a9431c5144b1017e9fd962e3b8ba3ac32/images/build-workflow.png -------------------------------------------------------------------------------- /images/eks-example.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/fed/2ef56a5a9431c5144b1017e9fd962e3b8ba3ac32/images/eks-example.jpg -------------------------------------------------------------------------------- /images/front-end-workflow-presentation.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/fed/2ef56a5a9431c5144b1017e9fd962e3b8ba3ac32/images/front-end-workflow-presentation.jpg -------------------------------------------------------------------------------- /images/future-stacks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/fed/2ef56a5a9431c5144b1017e9fd962e3b8ba3ac32/images/future-stacks.png -------------------------------------------------------------------------------- /images/gartner-hype-cycle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/fed/2ef56a5a9431c5144b1017e9fd962e3b8ba3ac32/images/gartner-hype-cycle.png -------------------------------------------------------------------------------- /images/refe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/fed/2ef56a5a9431c5144b1017e9fd962e3b8ba3ac32/images/refe.png -------------------------------------------------------------------------------- /images/tech-decide.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/fed/2ef56a5a9431c5144b1017e9fd962e3b8ba3ac32/images/tech-decide.png -------------------------------------------------------------------------------- /images/webpack-react-process.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/fed/2ef56a5a9431c5144b1017e9fd962e3b8ba3ac32/images/webpack-react-process.png -------------------------------------------------------------------------------- /img/cover.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/fed/2ef56a5a9431c5144b1017e9fd962e3b8ba3ac32/img/cover.jpg -------------------------------------------------------------------------------- /img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/fed/2ef56a5a9431c5144b1017e9fd962e3b8ba3ac32/img/favicon.ico -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 前端进阶指南 – 8 | 9 | 10 | 13 | 14 | 15 | 16 |

17 |

前端进阶

18 |

Phodal

19 |

20 |
21 | 152 |

前端进阶指南

153 |

什么是前端

154 |

作为一本前端进阶的书,没有理由去强调一下什么是前端?可是,当你说前端的时候,我也说前端的时候,我们说的是同一个前端吗?

155 |

我理解下的前端,指广泛意义上的前端。又可以称为『客户端』,泛指:与用户做交互的应用。如桌面浏览器上的浏览器、图形用户界面,移动设备上的应用程序、浏览器,又或者是各种智能、联网设备的交互都可以归属于前端。

156 |

因而,在这种意义上来说,前端要做的不仅仅是 Web,还可以是混合应用,原生应用等等。

157 |

这就意味着:

158 |
    159 |
  • 你可以使用 CSS Layout + React Native 编写移动程序
  • 160 |
  • 你可以使用 Electron 来编写桌面应用
  • 161 |
  • 你可以使用 React VR 来编写 VR 应用
  • 162 |
  • 等等
  • 163 |
164 |

这种时候,前端指的是,我们使用 样式(类CSS) + 类JavaScript + 模板(HTML、XML等 编写的应用。

165 |

如果那些用 JavaScript 编写的应用,也划分到前端的范畴,那么:

166 |
    167 |
  • 你还可以使用 JavaScript 与 Ruff、 Tessel 对硬件进行编程
  • 168 |
  • 你还可以使用 Node.js 来编写后台应用,又或者是 BFF (backend for frontend)层
  • 169 |
170 |

在这里,我们将前端定义为 类CSS + 类 JavaScript + 模板。因为没有图形应用的应用,难以直观的与用户进行交互,做不了『客户端』应用。在这一定义下,这一类型的应用有,桌面应用、桌面网页、移动网页、移动应用等等,现在发展的有 VR 技术等等。

171 |

本书内容

172 |

硬技能篇

173 |

前端知识要点

174 |

罗列一下,一些必要的知识点

175 |

希望读者都是知道的,以便于

176 |

作为一个领域,它拥有相当多的知识点。

177 |

如果读者已经知道了这些,那么可以跳过这一章的内容。

178 |

前端应用的生命周期

179 |
180 | 前端应用的生命周期
前端应用的生命周期
181 |
182 |

入门

183 |

在我理解下的基础知识,就是我们可以写一些基本的样式,并能对页面的元素进行操作。举例来说,就是我们用Spring和JSP写了一个博客,然后我们可以用jQuery来对页面进行一些简单的操作,并可以调用一些API。因此,我们需要基本的HTML / CSS知识。只是要写好CSS并不是一件简单的事,这需要很多实战经验。随后,我们还需要有JavaScript的经验,要不怎么做前端呢?

184 |

同时,我们还需要对DOM有一些基础的了解,才能做一些基本的操作,如修改颜色等等。在这种情况下,最简单的方案就是使用jQuery这样的工具。不过,如果可以自己操作DOM是再好不过的了。

185 |

中级篇

186 |

中级篇就更有意思了,现在我们就需要对页面进行更复杂的操作。Ajax和JSON这两个技能是必须的,当我们要动态的改变页面的元素时,我们就需要从远程获取最新的数据结果。并且我们也需要提交表单到服务器,RESTful就是必须要学会的技能。未来我们还需要Fetch API,ReactiveX这些技能。

187 |

除此我们还需要掌握好HTML的语义化,像DIV / CSS这也会必须会的技能,我们应该还会使用模板引擎和SCSS / SASS。而这个层面来说,我们开始使用Node.js来完成前端的构建等等的一系列动作,这时候必须学会使用命令行这类工具。并且,在这时候我们已经开始构建单页面应用了。

188 |

高级篇

189 |

JavaScript是一门易上手的语言,也充满了相当多的糟粕的用法。几年前人们使用CoffeeScript编成成JavaScript来编写更好的前端代码,现在人们有了ES6、TypeScript和WebPack来做这些事。尽管现在浏览器支持不完善,但是他们是未来。同样的还有某些CSS3的特性,其对于某些浏览器来说也是不支持的。而这些都是基于语言本来说的,要写好代码,我们还需要掌握面向对象编程、函数式编程、MVC / MVVM / MV*这些概念。作为一合格的工程师,我们还需要把握好安全性(如跨域),做好 授权(如HTTP Basic、JWT等等)。

190 |

工程化

191 |

这个标题好像是放错了,这部分的内容主要都是自动构建的内容。首先,我们需要有基本的构建工具,无论你是使用gulp、grunt,还是只使用npm,这都不重要。重要的是,你可以自动化的完成构建的工具,编译、静态代码分析(JSLint、CSS Lint、TSLint)、对代码质量进行分析(如Code Climate,可以帮你检测出代码中的Bad Smell)、运行代码中的测试,并生成测试覆盖率的报告等等。这一切都需要你有一个自动构建的工作流。

192 |

兼容性

193 |

虽然我们离兼容IE6的时代已越来越远了,但是我们仍然有相当多的兼容性工作要做。基本的兼容性测试就是跨浏览器的测试,即Chrome,IE,Firefox,Safari等等。除此还有在不同的操作系统上对同一浏览器的测试,某些情况下可能表现不一致。如不同操作系统的字体大小,可能会导致一些细微的问题。而随着移动设备的流行,我们还需要考虑下不同Android版本下的浏览器内核的表现不致,有时候还要一下不成器的Windows Phone。除此,还有同一个浏览器的不同版本问题,常见于IE。。

194 |

前端特定

195 |

除了正常的编码之外,前端还有一些比较有意思的东西,如CSS3和JavaScript动画。使用Web字体,可惜这个不太适合汉字使用。还有Icon字体,毕竟这种字体是矢量的。不过Icon字体还有一些问题,如浏览器对其的抗锯齿优化,还有一个痛是你得准备四种不同类型的字体文件。因此,产生了一种东西SVG Sprite,在以前这就是CSS Sprite,只是CSS Sprite不能缩放。最后,我们还需要掌握一些基本的图形和图表框架的使用。

196 |

软件工程

197 |

这一点上和大部分语言的项目一样,我们需要使用版本管理软件,如git、svn,又或者是一些内部的工具。总之你肯定要有一个,而不是 2016.07.31.zip这种文件。然后,你还需要一些依赖管理工具,对于那些使用Webpack、Browserify来将代码编写成前端代码的项目来说,npm还是挺好用的。不过就个人来说,对于传统的项目来说我总觉得bower有些难用。我们还需要模块化我们的源码文件,才能使其他人更容易开始项目。

198 |

调试

199 |

作为一个工程师来说,调试是必备的技能。大部分浏览器都自带有调试工具,他们都不错——如果你使用过的话。在调试的过程中,直接用Console就可以输出值、计算值等等。如果你的项目在构建的过程中有一些问题,你就需要debugger这一行代码了。在一些调用远程API的项目里,我们还需要一些更复杂的工具,即抓包工具。在调试移动设备时,像Wireshark、Charles这一类的工具,就可以让我们看到是否有一些异常的请求。当然在这个时候,还有一个不错的工具就是像Chrome自带的远程设备调试。对于移动网站来说,还要有Responsive视图。

200 |

测试

201 |

我遇到的很多前端工程师都是不写测试的,于是我便把它单独地抽了出现。对于一个前端项目来说,正常情况下,我们要有单元测试、功能测试,还有要一些UI测试来验证页面间是否可以跳转。对于依赖于第三方服务的应用来说,还要有一个Mock的服务来方便我们测试。如果是前后端分离的项目,我们还需要有集成测试。

202 |

性能与优化

203 |

要对Web应用进行性能优化,可能不是一件容易的事,有时候我们还知道哪些地方可以优化。这时候人们就可以使用Yahoo的YSlow,或者我最喜欢的Google PageSpeed来检测页面的一些问题,如有没有开启GZip、有没有压缩、合并、Minify JS代码等等。我们还应该借助于NetWork这一类的工具,查看页面加载时,一些比较漫的资源文件,并对其进行优化。在一些情况下,我们还需要借助如Chrome的Timline、Profiel等工具来查看可以优化的地方。

204 |

设计

205 |

前端工程师还需要具备基本的UI技能。多数情况下拿到的只是一张图,如果是一个完整的页面,我们就需要快速分割页面布局。而依赖于不同的页面布局,如响应式、网格、FlexBox布局也会有不同的设计。而有些时候,我们就需要自己规划,制作一个基本的线框图(Wireframe)等等。

206 |

SEO

207 |

如果以搜索引擎作为流量来源,我们还需要考虑页面的内容,除非你用的是竞争排名。像Sitemap可能就不是我们考虑的内容,而我们还要考虑很多点。首先,我们需要保证页面的内容是对于搜索引擎是可见的,并且对应的页面还要有基本的Title、Description和Keyword。然后在一些关键的字体,如栏目标题等等可以用H2之类的大字的地方就不要放过。同时在页面设计的过程中,我们还需要考虑一些内部链接的建设。它即可以提供页面的可见度,又可以提高排名。最后,如果你是面向的是Google等支持结构化数据的搜索引擎,你还需要考虑一下MicroData / MicroFormat这一类东西。

208 |

快速学习新的框架

209 |

今天很流行的 Web 框架,半年以后,可能就会在市场上被『淘汰』——技术选型的时候,不被开发人员推荐;又或者它已经推出了全新的版本,使用了全新的 API,我们便需要更新现有应用。

210 |

前端框架丰富多彩的今天,快速学习新的框架是每个前端程序员的必备技能

211 |

快速学习是基本能力

212 |

后端程序员,开始一个新的 Web 项目时:

213 |
    214 |
  • 使用 Java 语言,八成会选用 Spring 框架。
  • 215 |
  • 使用 Ruby 语言,八成会选用 Rails 框架。
  • 216 |
  • 使用 Scala 语言,八成会先用 Play 框架。
  • 217 |
218 |

而只使用 JavaScript 的前端程序员,开始一个前端项目时。你有几成的把握,能判断他/她出会使用哪个框架?

219 |

后端程序员在有限的时间内,只会使用固定的技术栈,固定的框架。对于大部分的公司来说,使用相同的后台语言,是一个更好的选择——即可以减少带成本,又可以沉淀下技术积累。

220 |

而前端则不一样,不同的项目都有各自的需求,因此采用使用不同的技术栈。简单的,可以直接使用原生的 JavaScript 完成,又或者是使用 jQuery 完成开发。稍微复杂一点的项目,采用容易上手的 Vue.js 是一个不错的选择。更复杂的项目,便可以使用 Angular,可以方便后台程序员转到前端。

221 |

因此,工作一定年限的程序员,都使用过不同的框架。可是,不同的程序员上手新框架的速度,总会存在一定的差异。

222 |

那么,怎样才能快速上手一个新的框架呢?

223 |

学习新的前端框架,要么该框架很火——即热闹驱动开发(Hype Driven Development,HDD),要么你们将采用该框架。在采用新框架的动机里,有一种是:技术演进。使用新的技术、框架,来替换现有的框架。旧的框架在某些地方上,存在着明显的缺陷。

224 |

这种情形下,业务知识本身是不变的,只是要由框架本身来应对业务的变化。因此,使用新的技术来替换旧有的框架,就相当的容易——重写,我们甚至可以直接复制、粘贴,大量原有的代码。只是,仅仅做到重写业务逻辑是不够的。我们还要掌握新的框架的核心,并探索更多的可能性。

225 |

如何学习新框架:守-破-离

226 |

我在学校的时候,看到一个关于编程语言的学习建议:学习三种以上的编程语言,并且它们最好是三种不同类型的语言。如面向过程的编程语言 C 、脚本语言 JavaScript、Python,面向对象的编程语言 Java、再加上个近年来火热的函数式编程语言,到底也就差不多了。当我们学习了一门语言,再上手一门相似风格的语言,也是相当轻松地一件事。当我们学习了不同类型的几种语言,未来就可以轻松地绝大多数的语言。

227 |

相似的,学习使用 Web 框架也是如此的。现在,对于我而来,使用一个『新框架的姿势』是:

228 |
    229 |
  • 买本中文书或者找个教程、官方的 Guide,花个十几分钟了解一下框架的『知识图谱』。
  • 230 |
  • 直接找个官方的示例,运行一下 Demo。
  • 231 |
  • 上手写写应用。
  • 232 |
  • 查看官方文档,看看自己是不是漏掉了什么重要的东西。
  • 233 |
234 |

它与我在公司接受培训的时候,学习到的『守破离』观点相似。在保留原来业务的情况下,一步步向前演进。

235 |

守:应用业务知识

236 |

在现有的业务上,使用新的框架是一件容易的事。拿上一份框架的说明书、一份需求文档、一个搜索引擎,就可以很容易地复制出一个产品。唯一的门槛是,你需要会读懂这些内容。这有点像新的知识阶级,只是门槛不再是识字与否,而在于是否能懂编程的知识。

237 |

正如维基百科上,对于『守』的介绍一样:

238 |
239 |

最初阶段须遵从老师教诲,认真练习基础,达到熟练的境界。

240 |
241 |

新手期的我们,拿到一个新的框架,要一下子对它了运用自如,是一件很难的事。我们只能在一个又一个的练习中,尝试去掌握框架的知识。如,原先我们使用的是 Backbone + jQuery 完成的前端应用,现在要切换到 Vue.js。我们要做的便是尝试使用 Vue.js,并不断地练习一些相关的用法。而在熟练之后,我们也会练习我们的基本套路,如在上文中说到的『新框架的姿势』。

242 |

而如果不考虑练习本身的时间因素,便只剩下的一个问题是:如何找到一个合适的练习项目。然而,这样的项目在 GitHub 上有很多。可是即使它能满足我们的需求,我们有时候也不知道怎么练习?

243 |

我想问题的关键在于:我们手上没有一个已经成型的业务系统。因此,我建议大家可以从创建一个博客开始做起,先使用现有的技术,再使用新的技术,慢慢的一点点往上添加内容。如我的博客,最早是基于 Django + Bootstrap,慢慢的我添加了一些新的东西:

244 |
    245 |
  • 用于为搜索提供建议的 AutoSuggest
  • 246 |
  • 移动应用 API 及博客搜索 API
  • 247 |
  • 微信搜索支持功能
  • 248 |
  • 支持 Google AMP 来快速加载页面
  • 249 |
  • Google Micro Data
  • 250 |
251 |

尽管越来越多的功能,有一些已经不再维护、关闭了。可是,它让我有机会去练习一些新的技术,掌握一些技术背后的思想,得到一些框架相关的结论。而不是每次与别人讨论时,说:xx 说 xx 框架有这样的问题,而是我试过这个框架,它有这样的问题。

252 |

破:学习框架核心

253 |
254 |

基础熟练后,试着突破原有规范让自己得到更高层次的进化。

255 |
256 |

转换技术栈,本身没有什么技术含量,但是能帮助稳固知识。当我们已经熟悉使用这个框架完成业务时,便可以细入相关思想。

257 |

了解这个框架的能力,生成一份与框架有关的索引,也可以用脑图的形势来整理这些内容。

258 |

如:

259 |
260 | 嵌入式系统工程师图谱
嵌入式系统工程师图谱
261 |
262 |

举例,如 Angular + TypeScript,还有其他更多的可能性

263 |

同时,我们还应该理解框架背后的原理。不一定深入,但是觉得去探究。如:

264 |
    265 |
  • MV* 思想
  • 266 |
  • 双向数据绑定的基本原理
  • 267 |
268 |

这些都在我的知乎专栏上《我的职业是前端工程师》有深入的介绍,有时候的读者建议多阅读相关的内容。

269 |

离:探索更多可能性

270 |
271 |

在更高层次得到新的认识并总结,自创新招数另辟出新境界。

272 |
273 |

在那之上,创造出一些新的框架。

274 |

如 Redux,最早是运行的 React.js 之上。Angular 2 出来了后,有了 xx。小程序出来后,有了 xx。

275 |

同理于此,当出现微信小程序的一两个星期内,我写了几篇原理相关的文章,并介绍了如何创建一个属于自己的小程序应用框架 WINV。又或者是我在对 Virtual Dom 有一定的了解后,便深入 Virtual Dom 的代码,写了一个基于 Virtual Dom 的测试辅助框架 Luffa

276 |

而这些,只有我们理解他们的原理之后,我们才可能做到这样的事。

277 |

小结

278 |

寻找心流

279 |

这些方法适用于大部分的人,但是不一定适合你。你只需要寻找到适合你的路,然后学习。

280 |

选择合适的前端框架

281 |

在《全栈应用开发:精益实践》一书中,我曾提到过影响技术选型的几个因素:

282 |
283 | 选型因素
选型因素
284 |
285 |

锤子定律:寻找更大视野

286 |

年轻的时候,学会了 A 框架,总觉得 Z 网站用 A 框架来实现会更好,一定不会像今天这样经常崩溃、出Bug。**时间一长,有时候就会发现,Z 网站使用 A 不合适,他们的问题并不是框架的问题,而是运维的问题。

287 |

在《咨询的奥秘》一书中,提到一个有意思的定律“锤子定律”(又称为工具定律)——圣诞节收到一把锤子的孩子,会发现所有东西都需要敲打。 出现这种情况的主要原因是,开发者对一个熟悉的工具过度的依赖

288 |

认真观察,就会发现这个现象随处可见。当一个新手程序员学会了某个最新的框架,通常来说这个框架有着更多的优点,这个时候最容易出现的想法是:替换现有的框架。可是,现有的框架并没有什么大的问题。并且凭估不充分时,新的框架则存在更多的风险。

289 |

并且,对于某个熟悉工具的过度依赖,特别容易影响到技术决策——看不到更多的可能性。这时候,我们就需要头脑风暴。但是这种情况下,头脑风暴很难帮助解决问题。在这个时候,拥有更多项目、框架经验的人,可能会做出更好的选择。

290 |

Angular,一站式提高生产力

291 |

与 Backbone 同一时代诞生的 Angular 便是一个大而全的 MVC 框架。在这个框架里,它提供了我们所需要的各种功能,如模块管理、双向绑定等等。它涵盖了开发中的各个层面,并且层与层之间都经过了精心调适。

292 |

我们所需要做的便是遵循其设计思想,来一步步完善我们的应用。Angular.js 的创建理念是:即声明式编程应该用于构建用户界面以及编写软件构件,而命令式编程非常适合来表示业务逻辑。

293 |

我开始使用 Angular.js 的原因是,我使用 Ionic 来创建混合应用。出于对制作移动应用的好奇,我创建了一个又一个的移动应用,也在这时学会了 Angular.js。对于我而言,选择合适的技术栈,远远比选择流行的技术栈要重要得多,这也是我喜欢使用 Ionic 的原因。当我们在制作一个应用,它对性能要求不是很高的时候,那么我们应该选择开发速度更快的技术栈。

294 |

对于复杂的前端应用来说,基于 Angular.js 应用的运行效率,仍然有大量地改进空间。在应用运行的过程中,需要不断地操作 DOM,会造成明显的卡顿。对于 WebView 性能较差或早期的移动设备来说,这就是一个致命伤。

295 |

幸运的是在 2016 年底,Angular 团队推出了 Angular 2,它使用 Zone.js 实现变化的自动检测、

296 |

而迟来的 Angular 2 则受奥斯本效应1的影响,逼得相当多的开发者们开始转向其它的框架。

297 |

React,组件化提高复用

298 |

从 Backbone 和 Angular.js 的性能问题上来看,我们会发现 DOM 是单页面应用急需改善的问题——主要是DOM 的操作非常慢。而在单页面应用中,我们又需要处理大量的 DOM,性能就更是问题了。于是,采用 Virtual DOM 的 React 的诞生,让那些饱受性能苦恼的开发者欢迎。

299 |

传统的 DOM 操作是直接在 DOM 上操作的,当需要修改一系列元素中的值时,就会直接对 DOM 进行操作。而采用 Virtual DOM 则会对需要修改的 DOM 进行比较(DIFF),从而只选择需要修改的部分。也因此对于不需要大量修改 DOM 的应用来说,采用 Virtual DOM 并不会有优势。开发者就可以创建出可交互的 UI。

300 |

除了编写应用时,不需要对 DOM 进行直接操作,提高了应用的性能。React 还有一个重要思想是组件化,即 UI 中的每个组件都是独立封装的。与此同时,由于这些组件独立于 HTML,使它们不仅仅可以运行在浏览器里,还能作为原生应用的组件来运行。

301 |

同时,在 React 中还引入了 JSX 模板,即在 JS 中编写模板,还需要使用 ES 6。令人遗憾的是 React 只是一个 View 层,它是为了优化 DOM 的操作而诞生的。为了完成一个完整的应用,我们还需要路由库、执行单向流库、web API 调用库、测试库、依赖管理库等等,这简直是一场噩梦。因此为了完整搭建出一个完整的 React 项目,我们还需要做大量的额外工作。

302 |

大量的人选择 React 还有一个原因是:React Native、React VR 等等,可以让 React 运行在不同的平台之上。我们还能通过 React 轻松编写出原生应用,还有 VR 应用。

303 |

在看到 Angular 2 升级以及 React 复杂性的时候,我相信有相当多的开发者转而选择 Vue.js。

304 |

Vue.js,简单也是提高效率

305 |

引自官网的介绍,Vue.js 是一套构建用户界面的渐进式框架,专注于MVVM 模型的 ViewModel 层。Vue.js 不仅简单、容易上手、配置设施齐全,同时拥有中文文档。

306 |

对于使用 Vue.js 的开发者来说,我们仍然可以使用 熟悉的 HTML 和 CSS 来编写代码。并且,Vue.js 也使用了 Virtual DOM、Reactive 及组件化的思想,可以让我们集中精力于编写应用,而不是应用的性能。

307 |

对于没有 Angular 和 React 经验的团队,并且规模不大的前端项目来说,Vue.js 是一个非常好的选择。

308 |

虽然 Vue.js 的生态与 React 相比虽然差上一截,但是配套设施还是相当齐全的,如 Vuex 、 VueRouter。只是,这些组件配套都由官方来提供、维护,甚至连 awesome-vue 也都是官方项目,总觉得有些奇怪。

309 |

除此,Vue.js 中定义了相当多的规矩,这种风格似乎由 jQuery 时代遗留下来的。照着这些规矩来写代码,让人觉得有些不自在。

310 |

和 React 相似的是,Vue.js 也有相应的 Native 方案 Weex,仍然值得我们期待。

311 |

构建系统:资深分界线

312 |

Yeoman 生成脚手架,并且现在的主流前端框架都提供了相似的工

313 |

打包 -> 压缩 -> 上传 -> 解压 -> 替换 -> 重启

314 |

重点在于:提高工作效率

315 |

为什么构建很重要

316 |

过去我们打开编辑器、浏览器、修改代码、刷新页面,如下图所示:

317 |
318 | 前端应用的开发流程
前端应用的开发流程
319 |
320 |

这个过程仍然没有发生太大的变化,只是很多的步骤都被自动化了:

321 |

我们只需要修改代码,诸如 watchman 这样的工具就检测到修改,而 Browsersync 则可以帮助我们自动刷新页面。

322 |

构建工具

323 |

取决于你所使用的技术栈

324 |

SASS、SCSS 因不同的情况而异

325 |

webpack

326 |

npm

327 |

grunt / gulp

328 |

构建流程

329 |
330 | 前端构建流程
前端构建流程
331 |
332 |

LiveReload

333 |

Bower

334 |

concat -> init -> lint -> min -> qunit -> server -> test -> watch

335 |

构建示例

336 |

如下是混合应用框架 Ionic 执行 ionic serve 时的启动日志:

337 |
[11:43:58]  ionic-app-scripts 1.3.4
338 | [11:43:58]  watch started ...
339 | [11:43:58]  build dev started ...
340 | [11:43:58]  clean started ...
341 | [11:43:58]  clean finished in 1 ms
342 | [11:43:58]  copy started ...
343 | [11:43:58]  transpile started ...
344 | [11:44:03]  transpile finished in 5.17 s
345 | [11:44:03]  preprocess started ...
346 | [11:44:03]  deeplinks started ...
347 | [11:44:03]  deeplinks finished in 132 ms
348 | [11:44:03]  preprocess finished in 132 ms
349 | [11:44:03]  webpack started ...
350 | [11:44:03]  copy finished in 5.49 s
351 | [11:44:26]  webpack finished in 22.94 s
352 | [11:44:26]  sass started ...
353 | [11:44:29]  sass finished in 3.21 s
354 | [11:44:29]  postprocess started ...
355 | [11:44:29]  postprocess finished in 85 ms
356 | [11:44:29]  lint started ...
357 | [11:44:29]  build dev finished in 31.57 s
358 | [11:44:29]  watch ready in 31.69 s
359 |

这个过程中,它会完成如下的步骤:

360 |

watch -> build dev -> clean -> copy -> transpile -> preprocess (deeplinks) -> webpack (copy) -> sass -> postprocess -> build dev

361 |

自动刷新

362 |

转译

363 |

预处理

364 |

什么是前端的架构能力

365 |
366 |

远离最佳实践,除非你能接受其带来的成本

367 |
368 |

当我们谈及『前端的架构』时,我们讨论的是复杂前端应用的架构——如果只是一个 jQuery + Bootstrap 完成的应用,那么它的架构想必是『散弹式』的应用,没有复杂的逻辑可言。

369 |

“标准”的 SPA 构架实践

370 |

复杂的前端应用,多数是 SPA(单页面应用),这就意味着系统的架构是前后端分离的。可前后端分离并意味着,

371 |

前后端分离

372 |

无状态 API

373 |

workflow

374 |

前后端分离的工作方式

375 |

实现上,它主要关注点是:API 的设计。API 设计应该由前端开发者来驱动的。后台只提供前端想要的数据,而不是反过来的。后台提供数据,前端从中选择需要的内容。

376 |
    377 |
  • 使用文档规范 API
  • 378 |
  • 契约测试:基于持续集成与自动化测试
  • 379 |
  • 前端测试与 API 适配器
  • 380 |
381 |

风格指南:StyleGuide

382 |

与之前的构建系统相比,StyleGuide 便是一种无法用工具强制执行的规范。尽管可以采用工具来做类似的事情,但是并非应该强制去做。

383 |
    384 |
  • 代码规范
  • 385 |
  • 函数限制。Java -> 30 行
  • 386 |
387 |

演进

388 |

当前技术栈,未来技术栈,切换。

389 |

使用了 Backbone,性能上出现一些瓶颈。

390 |

是不是要重写服务。

391 |

后台不能满足一些需求,考虑使用 BFF 吗

392 |

选用合适的策略,并保证没有问题。

393 |

最佳实践:框架

394 |

在这个领域,并不存在最佳的实践。首先的问题是,要找出我们真正想实现的功能,在这之后再去完成下一个步骤。而不是先找行业中最好的实践,再将这些实践应用

395 |

jQuery 在简单的前端页面里,仍然是最好的选择。

396 |

jQuery + TinyMCE

397 |

jQuery + Vue

398 |

不久前,我需要一个 UI 框架及前端框架来实现简单的逻辑功能,并且它还应该相当的小。因此,我首先排队了 jQuery + Bootstrap,它们在体积上不太符合我的要求。

399 |
    400 |
  • 发出一个 Ajax 请求,验证 Token
  • 401 |
  • 如果返回的 Token 是有效的,则生成
  • 402 |
403 |

提炼出核心技术,

404 |

对于大的公司来讲,都会要求拥有自己的核心技术。

405 |

在网上,各式各样的前端开发最佳实践层出不穷,

406 |

最意味着,在某些方面已经是到了极致。

407 |

自动化提高效率

408 |

自动化测试加快上线流程

409 |

测试

410 |

测试页面的输出结果,保证元素的准确性~

411 |

stub: 结果,返回预期的结果。

412 |

mock: 行为,预期方法被调用。

413 |

ui 测试

414 |

React Test Renderer

415 |
<Modal
416 |   animationType="fade"
417 |   hardwareAccelerated={false}
418 |   onRequestClose={[Function]}
419 |   transparent={true}
420 |   visible={false}
421 | >
422 |   <View>
423 |     <View
424 |       style={
425 |         Object {
426 |           "alignItems": "center",
427 |           "backgroundColor": "rgba(0,0,0,.1)",
428 |           "height": 1334,
429 |           "justifyContent": "center",
430 |         }
431 |       }
432 |     >
433 |   ...    
434 |

截屏测试,

435 |

对于那些 UI 改动较小的系统来说,这

436 |

而我们知道页面截图尽管可以作为版本管理的一部分,但是一个不可比对的结果

437 |

而诸如,react-test-render, Virtual Dom 测试

438 |

那么,对于普通的 HTML 结构的

439 |
440 | PhantomCSS
PhantomCSS
441 |
442 |

自动构建

443 |

在之前的构建系统一节里,我们讲了 xx。剩下要做的就是生成打包好的源码

444 |

Gulp、Grunt

445 |

自动化部署

446 |

只需要一些 持续集成 的基础,如 Jenkins

447 |

持续集成

448 |

前端应用的架构与设计模式

449 |

散弹式架构 -> jQuery

450 |

项目达到一定的程度,jQuery 便有些难以管理,我们不知道哪个地方还操作了 DOM。修改了 A 处的 selector,可能会影响 B 处的 selector。

451 |

这样的修改方式称为『散弹式架构』,它来自于 散弹式修改(shotgun surgery,出处《重构:改善既有代码的设计》),

452 |

在使用 Backbone 的过程中,如果你采用了继承 View 的方式,你也会遇到这种遇到问题。

453 |

分层结构 MV*

454 |

典型的 SPA 应该会具有的模式,如 Angular,Vue.js

455 |

处理数据 pipe and filter

456 |

fetch、ajax、RxJS 从 API 处获取到数据

457 |

这个时候的数据首先会被转换为 JSON,再过滤到需要的字段,再对字段进行特殊的处理,如 HtmlEncoded,最后再 Render 到元素上。

458 |

当我们从服务器

459 |

数据显示 观察者模式

460 |

双向绑定,即观察者模式,又可以称为发布订阅模式(Publish/Subscribe)

461 |

数据通讯

462 |

除了常规的数据获取,还有在不同的框架间传输数据,如 React Native 和 WebView 的 postMessage,Cordova 的 WebView 与原生插件间

463 |

消息通讯

464 |

数据通讯:shared repository

465 |

其他消息通讯

466 |

数据通讯:local storage

467 |

??? black board

468 |

软技能篇

469 |

在做业务的过程中提升技术

470 |
471 |

“三个月经验,重复了五年”

472 |
473 |

测试

474 |

代码可读性

475 |
476 |

与性能相比,可读性更加重要——绝大多数的软件,并不是写完就结束周期了。当然,倒掉的创业公司的软件除外。

477 |
478 |

有意图的提升

479 |

在一家大的公司里,不同的人总会有不同的运气:

480 |

运气好的人遇上一个好的项目,升职加薪,从此就走上了人生的巅峰。 运气差的人摊上一个差的项目,升不了职,少加了薪,并且还获得不了技术成长。 我刚毕业那会儿,所在团队的主要工作是,维护一个『又老又旧』的系统。比起写业务代码更不幸的是,我们的主要工作是修 Bug,bug,buG, bUg。

481 |

那一年多里,尽管都是维护旧系统和少量的新需求,我们还是在飞速的成长~~。而来源主要是:

482 |
    483 |
  • 组内技术活动
  • 484 |
  • 花时间投入练习
  • 485 |
  • 假想项目的重构
  • 486 |
487 |

当你在有限的条件下,还能做出一定的成绩,到底还是相当有成就感的。

488 |

如果你觉得你的项目技术栈老旧,那么你一定在脑子里使用了 N 种技术栈,对他们进行重构了。并且当你有一些时间可以分配到上面,如下班前的一个小时时间,又或者黑客马拉松等等。那么,你一定会开始去做这样的事。

489 |

与上面的技术活动相比,这是一个对于业务(我的意思是,对于公司来说)更有价值,并且更容易说服别人的方式。

490 |
    491 |
  • 学习别的项目的技术栈,然后将之应用到现有的系统上。
  • 492 |
  • 使用一个新的技术栈练习, 以此作为技术支撑,在未来替换现有的系统。
  • 493 |
494 |

持续学习:走出下一个『jQuery』

495 |

不,仍然没有,

496 |

jQuery 的最大问题在于,简单如果上手,如 Vue 有可能便会流行,然后成为下一个 jQuery

497 |

jQuery 已经落后了?下一个 jQuery 已经出现了

498 |

预测未来,不,我不可能。

499 |

对于,大公司或者内部系统的开发者来说,由于框架能满足应用的开发,因此很容易长期采用一个框架。当然,这本身并不是问题,你有了一份的工作,一个稳定的。可是,你可能会失去学习的勇气与能力。

500 |

持续学习

501 |

掌握思想

502 |
    503 |
  • 路由:页面跳转与模块关系
  • 504 |
  • 数据:获取与鉴权
  • 505 |
  • 数据展示:模板引擎
  • 506 |
  • 交互:事件与状态管理
  • 507 |
508 |

后端技能

509 |

阅读后端代码的能力

510 |

软技能

511 |

原本打算写一些时间管理,及

512 |

篇幅所限

513 |

知识管理

514 |

将输入的知识变为输出

515 |

以输出的方式来输入。

516 |

Debug: 发现问题

517 |

编程时,我们大部分时候都是在解决问题,即求解已知的问题。

518 |

除此,我们还需要花费很多的时间在 Debug 上,即如何去发现问题所在。

519 |

最后,如果仍然不能解决问题,那么就找个人、地方提问吧。

520 |

扩展篇

521 |

前端知识体系的广度与深度

522 |

前端与后台的对比

523 |

后台对于深度要求高,而前端对于广度要求高。

524 |
    525 |
  • 用户体验设计
  • 526 |
527 |

前端:用户喜爱的产品

528 |

基础 HTML + JS + CSS

529 |

广度 -> 用户体验、浏览器差异 -> 知识碎片

530 |

jQuery + Backbone + xxx

531 |

后台:高并发高可用

532 |

纠结于 事务一致 锁

533 |

Spring + Mybatis + Flyway

534 |

数据库 + ORM + MVC

535 |

论技术上的深度,自然是后台更深

536 |

论用户体验上,自然是前端更深 两种很难衡量

537 |

常见问题:Ops 运维 -> 环境问题

538 |

对于前端来说,广度 First -> 深度。熟悉框架的相似之处,并且完成任务。

539 |

对于后端来说,选定语言,基本上就已经选好一切了,Java -> Spring,Scala -> Play,Ruby -> Rails

540 |

用户体验设计

541 |

前端的广度

542 |

在中大型规模的公司里,会有建议使用的后台语言,他们也主要使用一个后台语言。因为它已经可以很稳定地运行

543 |

除非,旧的语言在应用上存在一些缺陷。或者,正在尝试使用新的技术。

544 |

而对于前端来说,如果不能选择使用自己的轮子,那么就会是一片混乱。他们会使用不同的框架,不同的团队都有不同的业务场景。

545 |

前端的趋势

546 |
547 | 未来趋势
未来趋势
548 |
549 |

微服务与微前端

550 |
551 |

对于后台采用微服务架构来说,在一个不同的组成部分中,使用不同的技术栈是一种不错的体验;而对于一个前端团队来说,在同一个系统的使用不同的技术栈就不是一种不错的体验。

552 |
553 |

可以使用 Web 存储技术,如 LocalStorage 来转移状态。又或者是诸如 Redux 的方式

554 |

BFF

555 |

状态管理

556 |

Redux

557 |

跨平台

558 |

Angular 可以移动应用和桌面Web应用,可是它并没有像 React 有那么广泛的用途。

559 |

React、React VR、React Native

560 |

UI 生成

561 |

过去有 DreamWeaver 这样的软件,现在也有一些强大的 UI 工具,可以直接将设计转化为代码。

562 |

转型前端指南

563 |

职业转型,放弃你现在的工作、相关行业经验,进入一个“新的环境”。这就意味着,当你想转到前端时,你需要面临一系列的挑战。你的老板并不会关心你的过程是怎样的,只要你能达到当前的能力要求,并有能力适应未来的变化即可。

564 |
565 |

跳槽穷半年,转行穷三年。

566 |
567 |

在过去的两三年里,随着前端领域的火热,市场上有越来越多的、不同行业的人加入了前端大军。人们出于不同的目的,选择上了前端开发。

568 |

有的是,大学里喜欢上前端这个行业,在找工作的时候,便选择了相应的岗位;有的是,不喜欢传统的编译型语言,如电子信息工程;有的是,大学上的专业找不到合适的工作,诸如数学等,并且有些专业与编程相比,拥有同等的逻辑能力要求;有的是,看前端行业很赚钱,便报了个培训班,来到了这个行业。

569 |

前端这个职业吧,入门快,上手也简单。简单的网页吧,拉上几个初学者便也能完成。可一旦遇上复杂的前端应用,就会暴露出各种各样的问题。于是,那些原先由非编程领域转行过来的人,便容易招至不满。

570 |

究其原因吧,是因为能力上达不到要求。我们到是可以看看,有多少人会转向人工智能,下一个行业热点。

571 |

改变

572 |

一点点慢慢改变,时间长,成本高,但是痛苦小

573 |

主要问题:

574 |
    575 |
  • 生活压力
  • 576 |
  • 经济来源
  • 577 |
578 |

change -> 改变 -> 痛苦

579 |
    580 |
  1. 实验 -> 尝试写代码 -> 意义
  2. 581 |
  3. 培训或者 workshop
  4. 582 |
  5. 人脉 <-> 相似的人
  6. 583 |
  7. 意义 <->
  8. 584 |
585 |

编程世界,比现实世界简单,有严格的对错。

586 |

如果你是一个没有编程经验的新手,那么你应该去报一个培训班。他可以在短期内帮你提高技术,但是与之相对应的,会带来一些问题。培训机构出来的学员,都存在一定的简历造假。由于数量众多,质量上参差不齐,导致人们普遍对培训机构出来的学员,存在一定的能力怀疑。说到底,你只能把培训机构当成一个入门,它距离你找到一份工作,还有相当大差距。

587 |

但是,你是真心的喜欢编程这个职业吗?

588 |

我见过一些后来者,他们在开始的时候问一些愚蠢的问题,慢慢的他们意识到这些问题,都是自己搜索就能解决的。他们会加入一些小组,来提高自己。建立一些信心,并去回答一些别人的问题。

589 |

后台转前端的挑战

590 |

Angular 2 -> 是一个不错的选择

591 |
    592 |
  • 强类型语言 TypeScript
  • 593 |
  • 依赖注入等等的设计模式思维
  • 594 |
595 |

唯一遗憾的是,它不使用 XML 来配置

596 |

Node.js 应用也是一个不错的选择

597 |

其他编程领域转前端

598 |

移动端到 React Native,再到 React

599 |

其他行业转前端

600 |

劝退

601 |

编程并不是一件容易的事,如果你有业余兴趣便还好,如果没有的话,就算了。

602 |

主要原因:它并不是一个赚钱的行业,你是在时间换金钱。。

603 |

不妨考虑,投资,或者产生一个千万级的 idea,再找个风投

604 |

万一,你又一次选错行了呢?

605 |

立意已决

606 |

首先,打开浏览器、下载 IDE、然后写一行 HTML 试一试

607 |

简单的入门书,如 Head First HTML

608 |

找一个小的项目

609 |
    610 |
  • 成功的复制一些小网站到本地
  • 611 |
  • 然后,再是模拟一些小的项目
  • 612 |
613 |
    614 |
  1. 不要预期薪水可以达到市场水平。没有人关心你是谁,你只要能干活,并且小公司、外包公司可能是一个更简单的入门。
  2. 615 |
616 |

外包公司 -> 门槛低 -> 相对比较多的成功案例

617 |

寻找合适的工作 -> 起步类型

618 |

查看相应类型的工作,看看工作介绍

619 |

事实上,按照『技术成熟曲线』理论,前端正在进入低谷期。而人工智能才是,现在,乃至未来一段时间的 IT 高薪领域。

620 |
621 | Gartner 技术成熟曲线
Gartner 技术成熟曲线
622 |
623 |

如果你真的喜欢前端,那么:Just do it!

624 |

如果你爱请深爱~。

625 |

前端跨行指南

626 |

JavaScript 应用领域

627 |

挑战:要学会新的领域的知识,以及其对应的语言知识。如开发混合应用时,在 iOS 方面,你需要有些许 Objective-C 或者 Swift 的开发能力,在 Android 方面,你还需要些许的 Java 经验。

628 |

移动开发:混合开发

629 |

桌面应用

630 |

VR

631 |

硬件

632 |

其它?

633 |
634 |
635 |
    636 |
  1. 颇受欢迎的个人电脑厂商奥斯本,其公司的创新式便携电脑还没有上市,就宣布他们要推出的更高档的机器,而又迟迟无法交货,消费者闻风纷纷停止下单订购现有机种,最后导致奥斯本因收入枯竭而宣布破产。

  2. 637 |
638 |
639 | 640 | 641 | -------------------------------------------------------------------------------- /listings-setup.tex: -------------------------------------------------------------------------------- 1 | % Contents of listings-setup.tex 2 | \usepackage{xcolor} 3 | 4 | \lstset{ 5 | basicstyle=\ttfamily, 6 | numbers=left, 7 | keywordstyle=\color[rgb]{0.13,0.29,0.53}\bfseries, 8 | stringstyle=\color[rgb]{0.31,0.60,0.02}, 9 | commentstyle=\color[rgb]{0.56,0.35,0.01}\itshape, 10 | numberstyle=\footnotesize, 11 | stepnumber=1, 12 | numbersep=5pt, 13 | backgroundcolor=\color[RGB]{248,248,248}, 14 | showspaces=false, 15 | showstringspaces=false, 16 | showtabs=false, 17 | tabsize=2, 18 | captionpos=b, 19 | breaklines=true, 20 | breakatwhitespace=true, 21 | breakautoindent=true, 22 | escapeinside={\%*}{*)}, 23 | linewidth=\textwidth, 24 | basewidth=0.5em, 25 | } -------------------------------------------------------------------------------- /log/coral.log: -------------------------------------------------------------------------------- 1 | [16:21:28] Starting 'compile'... 2 | [16:21:28] Starting 'compile.clean'... 3 | [16:21:28] Finished 'compile.clean' after 211 ms 4 | [16:21:28] Starting 'install.bower'... 5 | (node:25435) fs: re-evaluating native module sources is not supported. If you are using the graceful-fs module, please update it to a more recent version. 6 | bower angular-animate extra-resolution Unnecessary resolution: angular-animate#~1.5.3 7 | bower angular-sanitize extra-resolution Unnecessary resolution: angular-sanitize#1.5.3 8 | [16:21:29] Finished 'install.bower' after 961 ms 9 | [16:21:29] Starting 'plugin'... 10 | plugin => 尚未添加cordova plugin,如果需要,请编辑/plugins.conf.js文件 11 | [16:21:29] Finished 'plugin' after 2.57 ms 12 | [16:21:29] Starting 'install.plugin'... 13 | [16:21:29] Finished 'install.plugin' after 4.41 μs 14 | [16:21:29] Starting 'compile.jade'... 15 | [16:21:30] Finished 'compile.jade' after 466 ms 16 | [16:21:30] Starting 'compile.font.icon'... 17 | [16:21:31] gulp-svgicons2svgfont: Font created 18 | [16:21:33] Finished 'compile.font.icon' after 2.8 s 19 | [16:21:33] Starting 'compile.glyph.icon'... 20 | [16:21:33] Finished 'compile.glyph.icon' after 441 ms 21 | [16:21:33] Starting 'compile.sass'... 22 | [16:21:35] Finished 'compile.sass' after 1.98 s 23 | [16:21:35] Starting 'compile.coffee'... 24 | [16:21:35] Finished 'compile.coffee' after 309 ms 25 | [16:21:35] Starting 'compile.es6'... 26 | [16:21:40] Finished 'compile.es6' after 4.42 s 27 | [16:21:40] Starting 'compile.typescript'... 28 | [16:21:40] Finished 'compile.typescript' after 496 ms 29 | [16:21:40] Starting 'copy.css'... 30 | [16:21:40] Finished 'copy.css' after 61 ms 31 | [16:21:40] Starting 'copy.images'... 32 | [16:21:40] Finished 'copy.images' after 12 ms 33 | [16:21:40] Starting 'copy.assets'... 34 | [16:21:40] Finished 'copy.assets' after 791 μs 35 | [16:21:40] Starting 'copy.bower'... 36 | [16:21:41] Finished 'copy.bower' after 210 ms 37 | [16:21:41] Starting 'copy.root.files'... 38 | [16:21:41] Finished 'copy.root.files' after 11 ms 39 | [16:21:41] Starting 'wire.app.js'... 40 | [16:21:41] Starting 'wire.app.scss'... 41 | [16:21:41] gulp-inject 67 files into _app.scss. 42 | [16:21:41] Finished 'wire.app.scss' after 183 ms 43 | [16:21:41] gulp-inject 164 files into index.html. 44 | [16:21:41] Finished 'wire.app.js' after 447 ms 45 | [16:21:41] Starting 'wire.app'... 46 | [16:21:41] Finished 'wire.app' after 3.25 μs 47 | [16:21:41] Starting 'install.bower'... 48 | (node:25436) fs: re-evaluating native module sources is not supported. If you are using the graceful-fs module, please update it to a more recent version. 49 | bower angular-animate extra-resolution Unnecessary resolution: angular-animate#~1.5.3 50 | bower angular-sanitize extra-resolution Unnecessary resolution: angular-sanitize#1.5.3 51 | [16:21:42] Finished 'install.bower' after 947 ms 52 | [16:21:42] Starting 'wire.bower.js'... 53 | [16:21:42] Starting 'wire.bower.css'... 54 | [16:21:42] Finished 'wire.bower.css' after 140 ms 55 | [16:21:42] Finished 'wire.bower.js' after 194 ms 56 | [16:21:42] Starting 'wire.bower'... 57 | [16:21:42] Finished 'wire.bower' after 3.57 μs 58 | [16:21:42] Starting 'copy.html'... 59 | [16:21:42] Finished 'copy.html' after 250 ms 60 | [16:21:42] Starting 'compile.templates'... 61 | [16:21:43] Finished 'compile.templates' after 646 ms 62 | [16:21:43] Finished 'compile' after 15 s 63 | [16:21:43] Starting 'watch'... 64 | [16:21:43] Finished 'watch' after 30 ms 65 | [16:21:43] Starting 'serve'... 66 | [16:21:43] Finished 'serve' after 56 ms 67 | [16:21:43] Starting 'server'... 68 | [16:21:43] Finished 'server' after 11 μs 69 | [ 70 | -------------------------------------------------------------------------------- /material/Hybrid-Automation-Testing-Scenario.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/fed/2ef56a5a9431c5144b1017e9fd962e3b8ba3ac32/material/Hybrid-Automation-Testing-Scenario.jpg -------------------------------------------------------------------------------- /material/agile_pyramid2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/fed/2ef56a5a9431c5144b1017e9fd962e3b8ba3ac32/material/agile_pyramid2.jpg -------------------------------------------------------------------------------- /material/chaplin-lifecycle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/fed/2ef56a5a9431c5144b1017e9fd962e3b8ba3ac32/material/chaplin-lifecycle.png -------------------------------------------------------------------------------- /material/crossbrowser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/fed/2ef56a5a9431c5144b1017e9fd962e3b8ba3ac32/material/crossbrowser.png -------------------------------------------------------------------------------- /material/test-serv-copy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phodal/fed/2ef56a5a9431c5144b1017e9fd962e3b8ba3ac32/material/test-serv-copy.png -------------------------------------------------------------------------------- /style.css: -------------------------------------------------------------------------------- 1 | h1, 2 | h2, 3 | h3, 4 | h4, 5 | h5, 6 | h6, 7 | p, 8 | blockquote { 9 | margin: 0; 10 | padding: 0; 11 | } 12 | 13 | body { 14 | font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", Arial, sans-serif; 15 | font-size: 18px; 16 | line-height: 1.4; 17 | color: #000000; 18 | margin: 10px 13px 10px 13px; 19 | } 20 | 21 | a { 22 | color: #0069d6; 23 | } 24 | 25 | a:hover { 26 | color: #0050a3; 27 | text-decoration: none; 28 | } 29 | 30 | a img { 31 | border: none; 32 | } 33 | 34 | p { 35 | text-indent: 2em; 36 | margin-bottom: 12px; 37 | } 38 | 39 | h1, 40 | h2, 41 | h3, 42 | h4, 43 | h5, 44 | h6 { 45 | color: #404040; 46 | line-height: 36px; 47 | } 48 | 49 | h1 { 50 | margin-bottom: 32px; 51 | margin-top: 32px; 52 | font-size: 30px; 53 | color: #0050a3; 54 | } 55 | 56 | h1 a { 57 | margin-top: 100px; 58 | display: block; 59 | } 60 | 61 | h2 { 62 | font-size: 24px; 63 | margin-bottom: 28px; 64 | } 65 | 66 | h3 { 67 | font-size: 18px; 68 | margin-bottom: 24px; 69 | } 70 | 71 | h4 { 72 | font-size: 16px; 73 | } 74 | 75 | h5 { 76 | font-size: 14px; 77 | } 78 | 79 | h6 { 80 | font-size: 13px; 81 | } 82 | 83 | hr { 84 | margin: 0 0 19px; 85 | border: 0; 86 | border-bottom: 1px solid #ccc; 87 | } 88 | 89 | blockquote { 90 | padding: 2px 13px 21px 2px; 91 | margin-bottom: 12px; 92 | font-family: georgia,serif; 93 | font-style: italic; 94 | } 95 | 96 | blockquote:before { 97 | content: "\201C"; 98 | font-size: 40px; 99 | margin-left: -10px; 100 | font-family: georgia,serif; 101 | color: #eee; 102 | } 103 | 104 | blockquote p { 105 | font-size: 14px; 106 | font-weight: 300; 107 | line-height: 18px; 108 | margin-bottom: 0; 109 | font-style: italic; 110 | } 111 | 112 | code, pre { 113 | font-family: Monaco, Andale Mono, Courier New, monospace; 114 | } 115 | 116 | code { 117 | background-color: #fee9cc; 118 | color: rgba(0, 0, 0, 0.75); 119 | padding: 1px 3px; 120 | font-size: 12px; 121 | -webkit-border-radius: 3px; 122 | -moz-border-radius: 3px; 123 | border-radius: 3px; 124 | } 125 | 126 | pre { 127 | display: block; 128 | padding: 14px; 129 | margin: 0 0 18px; 130 | line-height: 16px; 131 | font-size: 11px; 132 | border: 1px solid #d9d9d9; 133 | white-space: pre-line; 134 | word-wrap: break-word; 135 | } 136 | 137 | pre code { 138 | background-color: #fff; 139 | color: #737373; 140 | font-size: 11px; 141 | padding: 0; 142 | white-space: pre-wrap; 143 | } 144 | 145 | 146 | figure img { 147 | display: block; 148 | margin: 0 auto; 149 | max-width: 100%; 150 | } 151 | 152 | figcaption { 153 | text-align: center; 154 | } 155 | 156 | ul li a { 157 | font-weight: bold; 158 | } 159 | 160 | ul li ul a { 161 | font-weight: normal; 162 | } 163 | 164 | @media screen and (min-width: 768px) { 165 | body { 166 | width: 748px; 167 | margin: 40px auto; 168 | } 169 | } 170 | 171 | 172 | table { 173 | margin: 10px auto; 174 | } 175 | 176 | thead { 177 | font-size: 120%; 178 | font-weight: 1000; 179 | cursor: pointer; 180 | background: #c9dff0 181 | } 182 | 183 | thead tr th { 184 | text-align: center; 185 | font-weight: bold; 186 | padding: 12px 30px; 187 | padding-left: 42px 188 | } 189 | 190 | thead tr th span { 191 | padding-right: 20px; 192 | background-repeat: no-repeat; 193 | background-position: 100% 100% 194 | } 195 | 196 | tbody tr td { 197 | padding: 15px 10px 198 | } 199 | 200 | tbody tr td.lalign { 201 | text-align: left 202 | } 203 | 204 | tbody tr:nth-child(even) { 205 | background: #fff 206 | } 207 | 208 | tbody tr:nth-child(odd) { 209 | background: #eee 210 | } 211 | 212 | td,th { 213 | border-left: 1px solid #cbcbcb; 214 | border-width: 0 0 0 1px; 215 | font-size: inherit; 216 | margin: 0; 217 | overflow: visible; 218 | padding: .5em 1em 219 | } 220 | 221 | 222 | 223 | /* 如果你的项目仅支持 IE9+ | Chrome | Firefox 等,推荐在 中添加 .borderbox 这个 class */ 224 | html.borderbox *, html.borderbox *:before, html.borderbox *:after { 225 | -moz-box-sizing: border-box; 226 | -webkit-box-sizing: border-box; 227 | box-sizing: border-box; 228 | } 229 | 230 | /* 重设 HTML5 标签, IE 需要在 js 中 createElement(TAG) */ 231 | article, aside, details, figcaption, figure, footer, header, menu, nav, section { 232 | display: block; 233 | } 234 | 235 | /* HTML5 媒体文件跟 img 保持一致 */ 236 | audio, canvas, video { 237 | display: inline-block; 238 | } 239 | 240 | /* 要注意表单元素并不继承父级 font 的问题 */ 241 | body, button, input, select, textarea { 242 | font: 300 1em/1.8 PingFang SC, Lantinghei SC, Microsoft Yahei, Hiragino Sans GB, Microsoft Sans Serif, WenQuanYi Micro Hei, sans-serif; 243 | } 244 | 245 | button::-moz-focus-inner, 246 | input::-moz-focus-inner { 247 | padding: 0; 248 | border: 0; 249 | } 250 | 251 | /* 去掉各Table cell 的边距并让其边重合 */ 252 | table { 253 | border-collapse: collapse; 254 | border-spacing: 0; 255 | } 256 | 257 | /* 去除默认边框 */ 258 | fieldset, img { 259 | border: 0; 260 | } 261 | 262 | /* 块/段落引用 */ 263 | blockquote { 264 | position: relative; 265 | color: #999; 266 | font-weight: 400; 267 | border-left: 1px solid #1abc9c; 268 | padding-left: 1em; 269 | margin: 1em 3em 1em 2em; 270 | } 271 | 272 | @media only screen and ( max-width: 640px ) { 273 | blockquote { 274 | margin: 1em 0; 275 | } 276 | } 277 | 278 | /* Firefox 以外,元素没有下划线,需添加 */ 279 | acronym, abbr { 280 | border-bottom: 1px dotted; 281 | font-variant: normal; 282 | } 283 | 284 | /* 添加鼠标问号,进一步确保应用的语义是正确的(要知道,交互他们也有洁癖,如果你不去掉,那得多花点口舌) */ 285 | abbr { 286 | cursor: help; 287 | } 288 | 289 | /* 一致的 del 样式 */ 290 | del { 291 | text-decoration: line-through; 292 | } 293 | 294 | address, caption, cite, code, dfn, em, th, var { 295 | font-style: normal; 296 | font-weight: 400; 297 | } 298 | 299 | /* 去掉列表前的标识, li 会继承,大部分网站通常用列表来很多内容,所以应该当去 */ 300 | ul, ol { 301 | list-style: none; 302 | } 303 | 304 | /* 对齐是排版最重要的因素, 别让什么都居中 */ 305 | caption, th { 306 | text-align: left; 307 | } 308 | 309 | q:before, q:after { 310 | content: ''; 311 | } 312 | 313 | /* 统一上标和下标 */ 314 | sub, sup { 315 | font-size: 75%; 316 | line-height: 0; 317 | position: relative; 318 | } 319 | 320 | :root sub, :root sup { 321 | vertical-align: baseline; /* for ie9 and other modern browsers */ 322 | } 323 | 324 | sup { 325 | top: -0.5em; 326 | } 327 | 328 | sub { 329 | bottom: -0.25em; 330 | } 331 | 332 | /* 让链接在 hover 状态下显示下划线 */ 333 | a { 334 | color: #1abc9c; 335 | } 336 | 337 | a:hover { 338 | text-decoration: underline; 339 | } 340 | 341 | a { 342 | border-bottom: 1px solid #1abc9c; 343 | } 344 | 345 | a:hover { 346 | border-bottom-color: #555; 347 | color: #555; 348 | text-decoration: none; 349 | } 350 | 351 | /* 默认不显示下划线,保持页面简洁 */ 352 | ins, a { 353 | text-decoration: none; 354 | } 355 | 356 | /* 专名号:虽然 u 已经重回 html5 Draft,但在所有浏览器中都是可以使用的, 357 | * 要做到更好,向后兼容的话,添加 class="typo-u" 来显示专名号 358 | * 关于 标签:http://www.whatwg.org/specs/web-apps/current-work/multipage/text-level-semantics.html#the-u-element 359 | * 被放弃的是 4,之前一直搞错 http://www.w3.org/TR/html401/appendix/changes.html#idx-deprecated 360 | * 一篇关于 标签的很好文章:http://html5doctor.com/u-element/ 361 | */ 362 | u, .typo-u { 363 | text-decoration: underline; 364 | } 365 | 366 | /* 标记,类似于手写的荧光笔的作用 */ 367 | mark { 368 | background: #fffdd1; 369 | border-bottom: 1px solid #ffedce; 370 | padding: 2px; 371 | margin: 0 5px; 372 | } 373 | 374 | /* 代码片断 */ 375 | pre, code, pre tt { 376 | font-family: Courier, 'Courier New', monospace; 377 | } 378 | 379 | pre { 380 | background: #f8f8f8; 381 | border: 1px solid #ddd; 382 | padding: 1em 1.5em; 383 | display: block; 384 | -webkit-overflow-scrolling: touch; 385 | } 386 | 387 | /* 一致化 horizontal rule */ 388 | hr { 389 | border: none; 390 | border-bottom: 1px solid #cfcfcf; 391 | margin-bottom: 0.8em; 392 | height: 10px; 393 | } 394 | 395 | /* 底部印刷体、版本等标记 */ 396 | small, .typo-small, 397 | /* 图片说明 */ 398 | figcaption { 399 | font-size: 0.9em; 400 | color: #888; 401 | } 402 | 403 | strong, b { 404 | font-weight: bold; 405 | color: #000; 406 | } 407 | 408 | /* 可拖动文件添加拖动手势 */ 409 | [draggable] { 410 | cursor: move; 411 | } 412 | 413 | .clearfix:before, .clearfix:after { 414 | content: ""; 415 | display: table; 416 | } 417 | 418 | .clearfix:after { 419 | clear: both; 420 | } 421 | 422 | .clearfix { 423 | zoom: 1; 424 | } 425 | 426 | /* 强制文本换行 */ 427 | .textwrap, .textwrap td, .textwrap th { 428 | word-wrap: break-word; 429 | word-break: break-all; 430 | } 431 | 432 | .textwrap-table { 433 | table-layout: fixed; 434 | } 435 | 436 | /* 提供 serif 版本的字体设置: iOS 下中文自动 fallback 到 sans-serif */ 437 | .serif { 438 | font-family: Palatino, Optima, Georgia, serif; 439 | } 440 | 441 | /* 保证块/段落之间的空白隔行 */ 442 | p, pre, ul, ol, dl, form, hr, table, 443 | .typo-p, .typo-pre, .typo-ul, .typo-ol, .typo-dl, .typo-form, .typo-hr, .typo-table, blockquote { 444 | margin-bottom: 1.2em 445 | } 446 | 447 | h1, h2, h3, h4, h5, h6 { 448 | font-family: PingFang SC, Verdana, Helvetica Neue, Microsoft Yahei, Hiragino Sans GB, Microsoft Sans Serif, WenQuanYi Micro Hei, sans-serif; 449 | font-weight: 100; 450 | color: #000; 451 | line-height: 1.35; 452 | } 453 | 454 | /* 标题应该更贴紧内容,并与其他块区分,margin 值要相应做优化 */ 455 | h1, h2, h3, h4, h5, h6, 456 | .typo-h1, .typo-h2, .typo-h3, .typo-h4, .typo-h5, .typo-h6 { 457 | margin-top: 1.2em; 458 | margin-bottom: 0.6em; 459 | line-height: 1.35; 460 | } 461 | 462 | h1, .typo-h1 { 463 | font-size: 2em; 464 | } 465 | 466 | h2, .typo-h2 { 467 | font-size: 1.8em; 468 | } 469 | 470 | h3, .typo-h3 { 471 | font-size: 1.6em; 472 | } 473 | 474 | h4, .typo-h4 { 475 | font-size: 1.4em; 476 | } 477 | 478 | h5, h6, .typo-h5, .typo-h6 { 479 | font-size: 1.2em; 480 | } 481 | 482 | /* 在文章中,应该还原 ul 和 ol 的样式 */ 483 | ul, .typo-ul { 484 | margin-left: 1.3em; 485 | list-style: disc; 486 | } 487 | 488 | ol, .typo-ol { 489 | list-style: decimal; 490 | margin-left: 1.9em; 491 | } 492 | 493 | li ul, li ol, .typo-ul ul, .typo-ul ol, .typo-ol ul, .typo-ol ol { 494 | margin-bottom: 0.8em; 495 | margin-left: 2em; 496 | } 497 | 498 | li ul, .typo-ul ul, .typo-ol ul { 499 | list-style: circle; 500 | } 501 | 502 | /* 同 ul/ol,在文章中应用 table 基本格式 */ 503 | table th, table td, .typo-table th, .typo-table td, table caption { 504 | border: 1px solid #ddd; 505 | padding: 0.5em 1em; 506 | color: #666; 507 | } 508 | 509 | table th, .typo-table th { 510 | background: #fbfbfb; 511 | } 512 | 513 | table thead th, .typo-table thead th { 514 | background: #f1f1f1; 515 | } 516 | 517 | table caption { 518 | border-bottom: none; 519 | } 520 | 521 | /* 去除 webkit 中 input 和 textarea 的默认样式 */ 522 | .typo-input, .typo-textarea { 523 | -webkit-appearance: none; 524 | border-radius: 0; 525 | } 526 | 527 | .typo-em, em, legend, caption { 528 | color: #000; 529 | font-weight: inherit; 530 | } 531 | 532 | /* 着重号,只能在少量(少于100个字符)且全是全角字符的情况下使用 */ 533 | .typo-em { 534 | position: relative; 535 | } 536 | 537 | .typo-em:after { 538 | position: absolute; 539 | top: 0.65em; 540 | left: 0; 541 | width: 100%; 542 | overflow: hidden; 543 | white-space: nowrap; 544 | content: "・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・"; 545 | } 546 | 547 | /* Responsive images */ 548 | img { 549 | max-width: 100%; 550 | } 551 | -------------------------------------------------------------------------------- /template/template.tex: -------------------------------------------------------------------------------- 1 | \documentclass[a4paper, 11pt]{article} 2 | \usepackage{geometry} % 設定邊界 3 | \geometry{ 4 | top=1in, 5 | inner=1in, 6 | outer=1in, 7 | bottom=1in, 8 | headheight=3ex, 9 | headsep=2ex 10 | } 11 | \usepackage{tabu} 12 | \usepackage[T1]{fontenc} 13 | \usepackage{lmodern} 14 | \usepackage{booktabs} 15 | \usepackage{amssymb,amsmath} 16 | \usepackage{ifxetex,ifluatex} 17 | \usepackage{fixltx2e} % provides \textsubscript 18 | % use upquote if available, for straight quotes in verbatim environments 19 | \IfFileExists{upquote.sty}{\usepackage{upquote}}{} 20 | \ifnum 0\ifxetex 1\fi\ifluatex 1\fi=0 % if pdftex 21 | \usepackage[utf8]{inputenc} 22 | $if(euro)$ 23 | \usepackage{eurosym} 24 | $endif$ 25 | \else % if luatex or xelatex 26 | \usepackage{fontspec} % 允許設定字體 27 | \usepackage{xeCJK} % 分開設置中英文字型 28 | \setCJKmainfont{STSong} % 設定中文字型 29 | \setmainfont[Mapping=tex-text]{Times New Roman}%\rmfamily 使用的字体,默认英文和数字的字体。 % 設定英文字型 30 | \setromanfont{Georgia} % 字型 31 | \setmonofont{Courier New} 32 | \linespread{1.2}\selectfont % 行距 33 | \XeTeXlinebreaklocale "zh" % 針對中文自動換行 34 | \XeTeXlinebreakskip = 0pt plus 1pt % 字與字之間加入0pt至1pt的間距,確保左右對整齊 35 | \parindent 0em % 段落縮進 36 | \setlength{\parskip}{20pt} % 段落之間的距離 37 | \ifxetex 38 | \usepackage{xltxtra,xunicode} 39 | \fi 40 | \defaultfontfeatures{Mapping=tex-text,Scale=MatchLowercase} 41 | \newcommand{\euro}{€} 42 | $if(mainfont)$ 43 | \setmainfont{$mainfont$} 44 | $endif$ 45 | $if(sansfont)$ 46 | \setsansfont{$sansfont$} 47 | $endif$ 48 | $if(monofont)$ 49 | \setmonofont{$monofont$} 50 | $endif$ 51 | $if(mathfont)$ 52 | \setmathfont{$mathfont$} 53 | $endif$ 54 | \fi 55 | % use microtype if available 56 | \IfFileExists{microtype.sty}{\usepackage{microtype}}{} 57 | $if(geometry)$ 58 | \usepackage[$for(geometry)$$geometry$$sep$,$endfor$]{geometry} 59 | $endif$ 60 | $if(natbib)$ 61 | \usepackage{natbib} 62 | \bibliographystyle{plainnat} 63 | $endif$ 64 | $if(biblatex)$ 65 | \usepackage{biblatex} 66 | $if(biblio-files)$ 67 | \bibliography{$biblio-files$} 68 | $endif$ 69 | $endif$ 70 | $if(listings)$ 71 | \usepackage{listings} 72 | $endif$ 73 | $if(lhs)$ 74 | \lstnewenvironment{code}{\lstset{language=Haskell,basicstyle=\small\ttfamily}}{} 75 | $endif$ 76 | $if(highlighting-macros)$ 77 | $highlighting-macros$ 78 | $endif$ 79 | $if(verbatim-in-note)$ 80 | \usepackage{fancyvrb} 81 | $endif$ 82 | $if(tables)$ 83 | \usepackage{longtable} 84 | $endif$ 85 | 86 | \usepackage{graphicx} 87 | \usepackage{caption} 88 | % We will generate all images so they have a width \maxwidth. This means 89 | % that they will get their normal width if they fit onto the page, but 90 | % are scaled down if they would overflow the margins. 91 | \makeatletter 92 | \def\maxwidth{\ifdim\Gin@nat@width>\linewidth\linewidth 93 | \else\Gin@nat@width\fi} 94 | \makeatother 95 | \let\Oldincludegraphics\includegraphics 96 | \renewcommand{\includegraphics}[1]{\Oldincludegraphics[width=\maxwidth]{#1}} 97 | \ifxetex 98 | \usepackage[setpagesize=false, % page size defined by xetex 99 | unicode=false, % unicode breaks when used with xetex 100 | xetex]{hyperref} 101 | \else 102 | \usepackage[unicode=true]{hyperref} 103 | \fi 104 | \hypersetup{breaklinks=true, 105 | bookmarks=true, 106 | pdfauthor={$author-meta$}, 107 | pdftitle={$title-meta$}, 108 | colorlinks=true, 109 | urlcolor=$if(urlcolor)$$urlcolor$$else$blue$endif$, 110 | linkcolor=$if(linkcolor)$$linkcolor$$else$magenta$endif$, 111 | pdfborder={0 0 0}} 112 | \urlstyle{same} % don't use monospace font for urls 113 | $if(links-as-notes)$ 114 | % Make links footnotes instead of hotlinks: 115 | \renewcommand{\href}[2]{#2\footnote{\url{#1}}} 116 | $endif$ 117 | $if(strikeout)$ 118 | \usepackage[normalem]{ulem} 119 | % avoid problems with \sout in headers with hyperref: 120 | \pdfstringdefDisableCommands{\renewcommand{\sout}{}} 121 | $endif$ 122 | \setlength{\parindent}{0pt} 123 | %\setlength{\parskip}{6pt plus 2pt minus 1pt} 124 | \setlength{\emergencystretch}{3em} % prevent overfull lines 125 | \usepackage{titling} 126 | \setlength{\droptitle}{-8em} % 將標題移動至頁面的上面 127 | 128 | \usepackage{fancyhdr} 129 | \usepackage{lastpage} 130 | \pagestyle{fancyplain} 131 | 132 | $if(numbersections)$ 133 | \setcounter{secnumdepth}{5} 134 | $else$ 135 | \setcounter{secnumdepth}{0} 136 | $endif$ 137 | $if(verbatim-in-note)$ 138 | \VerbatimFootnotes % allows verbatim text in footnotes 139 | $endif$ 140 | $if(lang)$ 141 | \ifxetex 142 | \usepackage{polyglossia} 143 | \setmainlanguage{$mainlang$} 144 | \else 145 | \usepackage[$lang$]{babel} 146 | \fi 147 | $endif$ 148 | $for(header-includes)$ 149 | $header-includes$ 150 | $endfor$ 151 | 152 | $if(title)$ 153 | \title{$title$} 154 | $endif$ 155 | \author{$for(author)$$author$$sep$ \and $endfor$} 156 | \date{$date$} 157 | 158 | %%%% 段落首行缩进两个字 %%%% 159 | \makeatletter 160 | \let\@afterindentfalse\@afterindenttrue 161 | \@afterindenttrue 162 | \makeatother 163 | \setlength{\parindent}{2em} %中文缩进两个汉字位 164 | 165 | 166 | %%%% 下面的命令重定义页面边距,使其符合中文刊物习惯 %%%% 167 | \addtolength{\topmargin}{-2pt} 168 | \setlength{\oddsidemargin}{0.63cm} % 3.17cm - 1 inch 169 | \setlength{\evensidemargin}{\oddsidemargin} 170 | \setlength{\textwidth}{14.66cm} 171 | \setlength{\textheight}{24.00cm} % 24.62 172 | 173 | %%%% 下面的命令设置行间距与段落间距 %%%% 174 | \linespread{1.4} 175 | % \setlength{\parskip}{1ex} 176 | \setlength{\parskip}{0.5\baselineskip} 177 | 178 | 179 | \begin{document} 180 | %%%% 定理类环境的定义 %%%% 181 | \newtheorem{example}{例} % 整体编号 182 | \newtheorem{algorithm}{算法} 183 | \newtheorem{theorem}{定理}[section] % 按 section 编号 184 | \newtheorem{definition}{定义} 185 | \newtheorem{axiom}{公理} 186 | \newtheorem{property}{性质} 187 | \newtheorem{proposition}{命题} 188 | \newtheorem{lemma}{引理} 189 | \newtheorem{corollary}{推论} 190 | \newtheorem{remark}{注解} 191 | \newtheorem{condition}{条件} 192 | \newtheorem{conclusion}{结论} 193 | \newtheorem{assumption}{假设} 194 | 195 | \newcommand{\tightlist}{% 196 | \setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}} 197 | 198 | %%%% 重定义 %%%% 199 | \renewcommand{\contentsname}{目录} % 将Contents改为目录 200 | \renewcommand{\abstractname}{摘要} % 将Abstract改为摘要 201 | \renewcommand{\refname}{参考文献} % 将References改为参考文献 202 | \renewcommand{\indexname}{索引} 203 | \renewcommand{\figurename}{图} 204 | \renewcommand{\tablename}{表} 205 | \renewcommand{\appendixname}{附录} 206 | 207 | $for(include-before)$ 208 | $include-before$ 209 | 210 | $endfor$ 211 | $if(toc)$ 212 | { 213 | \newpage 214 | \hypersetup{linkcolor=black} 215 | \setcounter{tocdepth}{$toc-depth$} 216 | \tableofcontents 217 | } 218 | \newpage 219 | $endif$ 220 | $body$ 221 | 222 | $if(natbib)$ 223 | $if(biblio-files)$ 224 | $if(biblio-title)$ 225 | $if(book-class)$ 226 | \renewcommand\bibname{$biblio-title$} 227 | $else$ 228 | \renewcommand\refname{$biblio-title$} 229 | $endif$ 230 | $endif$ 231 | \bibliography{$biblio-files$} 232 | 233 | $endif$ 234 | $endif$ 235 | $if(biblatex)$ 236 | \printbibliography$if(biblio-title)$[title=$biblio-title$]$endif$ 237 | 238 | $endif$ 239 | $for(include-after)$ 240 | $include-after$ 241 | 242 | $endfor$ 243 | \end{document} --------------------------------------------------------------------------------