编写高质量代码--Web前端开发修炼之道

编写高质量代码:
网站重构、团队合作、html、css、javascript

附录:写在规则前、命名、分工、注释、html/css/javascript规范

2018.4.21 六 22:52




2010.5 第一版

2017.8.28 一 23:11 .doc


2017.9.17 日 09:00 转为.md

$_PS: 感觉标题不够用,所以升为一级标题;也是按章节区分,升到一级加深权重

第一章 从网站重构说起

1 糟糕的页面实现,头疼的维护工作

1989诞生至今。。

2 Web标准——结构、样式和行为的分离

仅仅只是开始

3 前端的现状

维护难:浏览器、技术、团队合作

4 打造高品质的前端代码,提高代码的可维护性—-精简、重用、有序

所谓高质量的代码,在Web标准的思想指导下,在实现结构、样式和行为分离的基础,还要做到三点:

第二章 团队合作

1 揭秘前端开发工程师

1css基本:基本兼容浏览器。2Javascript:原生,类库,Ajax;3后台语言:不需要多深,当然越深越有帮助

2 欲精一行,必先通十行

“粗粒度”的精,专精很难—一专多能才现实,必要

3 增加代码可读性—-注释

直接团队合作,间接团队合作 “好的代码,注释占1/3”—虽然夸张

4 提高重用性—–公共组件和私有组件的维护 4.2和5.2(四,五章)

公共:只读,少数写,必要时(注释,API文档,演示Demo)

5 冗余和精简的矛盾—-选择集中还是分散

一次打包:jQuery
小块按需加载:YUI
平衡点,只可能尽量减少冗余,不可能根除

6 磨刀不误砍柴工—-前期的构思很重要

规范的指定、公共组件的设计、复杂功能的技术方案
占整个项目30%~60的时间,都算正常

7 制定规范

8 团队合作的最大难度不是技术,是人

自己能独立 都是小问题, ,要学会与人相处

第三章 高质量的HTML

1 标签的语义

标签的设计都有语义,初了div,span

2 为什么要使用语义化标签

Web标准,css只是一部分,HTML才是最重要的,结构才是重点,样式只是修饰结构
先确定语义的标签,再选合适的css

3 如何确定你的标签是否语义良好

简单方法:去掉样式,看网页结构是否组织良好有序,是否仍然有很好的可读性

4 常见模块你真的很了解吗

4.1 标题和内容:三个div—》一个h2包一个a,但a不是h—》用div包h2,a

4.2 表单 fieldset legend lable—for

4.3 表格 caption thead tbody tfood th

4.4 其他:1尽可能少用语义div和span;2语义不明显,div,和p。尽量p,默认有上下间距,可读性更好,兼容特殊终端;3不使用纯样式标签:b,font,u等,改css。默认strong:加粗,em:斜体

第四章 高质量的CSS

1 怪异模式和DTD

2 如何组织CSS

API:控制样式,对、错

框架:进行组织,好、比较好、很烂、非常棒 多种角度:功能、区块。。

Base.css:原子类,与具体UI无关-精简通用,高度可移植性,行对稳定,基本不需维护

Common.css:模块,组件,UI组件风格保持相同,一个或者common_form,common_images

Page.css:页面,page1,page2,若不多一个page文件,能用上面两尽量不用这。
多人,避免冲突:通常命名规则

(非并列,而是层叠)

3 推荐的base.css:

两大类:reset 和通用原子类 一些非常巧的命名和设计———–非常的棒
reset,文字排版,定位,长度高度,边距

P89 00:24


2017.8.29 二 22:24

4 模块化CSS——-在CSS中引入面向对象编程思想

4.1 如何划分模块—

单一职责:1,模块与模块之间尽量不要包含相同的部分,如果包含相同的部分,尽量将它们提取出来,拆分成一个独立的模块;
2,模块应在保证数量尽可能少的原则下,做到尽可能简单,以提高重用性

4.2 CSS的命名—-命名空间的概念

英文,驼峰+划线(单独并不是最好的实践),:last-child ie6没有需单独加一个类名;
2)直接挂last—-滥用子选择符—-》不轻易使用自选择符,故timeListLastItem
3)但命名看不出从属,封装性不好,—》timeList-lastItem

1)Base,common层公共,一人负责,不会出现冲突,page多人合作加唯一标识符
2)base层命名简短,common就长了,还有标识符,比起文件大小,好处还是可接受范围
划线—从属关系的分隔符;模块视为类,从属模块的元素视为类的属性,通过命名上的直观,得到一种“封装”。

4.3 挂多个class还是新建class——–多用组合,少用继承

方案一:三个类——-非常冗余
方案二:三个类——–只是做了提取,去除了冗余;添加新的类,css修改好几处
方案三:提取更多粒度更小的类,通过类的组合实现;以后只需添加类

偏激的工程师甚至认为继承是错误的,是造成维护性差的罪魁祸首,主张完全使用继承
挂多个类,让html看起来过于臃肿,固然不好看,但好处不容忽视
$_PS:(自己认为综合项目—代码量,来考虑)

4.4 如何处理上下margin:

如果不确定模块的上下margin特别稳定,最好不要将它写到某块的类里,而是使用类的组合,单独为上下margin挂用于边距的原子类(如mt10)。模块最好不要混用margin-top和margin-bottom,使用一个

5 低权重原则——-避免滥用子选择器

1,权重,就近(定义的先后顺序,而不是挂class名的先后)
2,为了保证样式容易被覆盖,提高可维护性,css选择符需保证权重尽可能低
3,少使用子选择器,就需要多添加class(方便扩展),web标准盛行初期,很多工程师认为不好,能使用子选择器就尽量使用,使用大量class的做法叫“多class症”。在经过大量实践后,作者认为多class有太大坏处,相反,与使用子选择器相比,新添class反而更有利于维护
$_PS: 各有利弊,还是看项目代码,如果项目代码量少

6 CSS sprite

1, 初期:图片不会马上加载,空白。。合并;;后来,还可以减少http请求次数
2,看似简单,不易掌握:1合并只能是背景图片,img标签不可以2横向或纵向也不可以,只能竖直或水平排列。。 图片如何排列尽量紧凑,同时保证不会影响扩展性
3,问题:图片位置精确度要求高—测量影响开发速度;不易轻易改动,可能影响其他周边图片,降低了可维护性
4,最大好处:建设http请求数,减轻服务器的压力;代价:降低开发效率,增大维护难度
流量并不大的网站,好处并不明显,但付出代价却很大,并不划算。。所以,主要取决于网站流量

7 CSS的常见问题

7.1 编码风格:多行式,一行式

早期缺少调试工具——–主流是多行。随着,一行渐渐新主流。。。作者更推荐一行
(并不苟同)

7.2 id和class:一般情况尽量使用class,少用id(我觉得作者只是针对css样式来讲的)

7.3 CSS hack

1,IE条件注释:非ie,指定ie版本。微软官方推荐的方式,从向前兼容性方面考虑,最安全的,理论上是最好的。。。。虽然向后兼容性是最好的,缺点明显:同一css选择符样式分散到三个文件中控制,增加开发和维护成本
2,选择符前缀法:html–ie6,+html—ie7,样式集中起来,可维护性强很多。但不能保证以后的ie9,ie10不识别,向后兼容性上存在一点风险。。另外,不能用于内联样式上
3,样式属性前缀法:_——ie6, ——-ie6,7 {width:80px;width:70px;_width:60px;} 。。同样向后兼容有风险。。另外,可用于内联样式

总结:虽然ie条件注释,但后两流行,我们可根据需要选择使用

7.4 解决超链接访问后hover样式不出现的问题:lvha

P113 00:40


2017.8.30 三 23:16

7.5 hasLayout

IE专有属性,用于css解析引擎。有时候一些复杂css设置解析会出现bug,可能是没有自动触发haslayout,通过技巧手动触发,就可以 解决bug。

方法:1,width,height,relative。早起height:1%,(6,按min-height解析)ie7出现后,可以正常识别,就不适用了。
2,更好的zoom:1;(不会像height引入副作用-不用csshack)。少数特殊情况下,特别似乎使用dhtml是,会无效,用更强大的relative触发;尽管会有一些副作用。
设计初衷是辅助块级元素的盒模型解析。如用于行内,会引发一些特殊效果。

7.6 块级元素和行内元素的区别

。。。行内元素:水平方向margin,padding有效;竖直margin无效,padding虽然增大面积,但并没有和相邻元素拉开距离。

7.7 display:inline-block和hasLayout

1,Ie6,7只有block,inline,none。通过触发hasLayout实现。
P换span,触发hasLayout并不完美,设置span,vertical-align:-10px。对齐方式
2,问题:1只能对行内2针对ie的hack,
vertical-align
3,还是可以的:Img,button有inline-block特性

7.8 relative、absolute和float

1,Relative,absolute,改变元素在文档流中的位置,可以激活left,z-index。默认都是z-index:0层—-文档流。让元素“浮”起来,z-大于0,relative会保留自己0层的占位,对其他0层的元素位置不影响;absolute完全脱离文档流,不在0层保留位置。
2,Float,不会“上浮”到另一个z层,仍然0层,不能top等精确控制,left“左右浮”;会改变正常的文档流排列,影响到周围元素
3,absolute,float隐式改变成inline-block,默认宽度并不占满父元素。显示设置display无效(float,ie6双边距,添加display:inline)

7.9 居中

1,水平居中

1)文本、图片等行内元素:text-align;
2)确定宽度的块级元素:margin:* auto
3)不确定宽度的块级:1table标签;2display:inline;问题:比起块级少一些功能;3父:float:left;子:relative,left:-50%;问题:relative副作用

2,竖直居中

1) 父元素高度不确定的文本、图片,块级:父设置相同的上下边距
2) 父高度确定的单行文本:父line-height=父height
3) 父高度确定的多行文本、图片、块级:1父元素为th、td,vertical。Display:talbe-cell。Ie6,7不支持模拟表格—直接使用。无义标签和深度;2不支持ie6,7不支持table-cell,hack,给父子两层分别top:absolute,50%、relative,-50% ;hack不利于维护,relative,absolute副作用

7.10 网格布局

Main内容比起sidebar更重要,无论sidebar和main在样式上谁先后,html要main在前加
方案一:将浮动和宽度绑定在同一个类中,会限制灵活性
方案二:利用组合
方案三:上面都是宽度固定,若不定宽:1将宽也抽象出来w25,w70;2利用子选择器.content-lr-7025 .main{f:l;w:70}.content-lr-7025 .main{f:r;w:25}.削弱了main,sidebar做为样式挂钩的能力,。。不由这两个抽象类提供,衍生类—父元素控制 。

相较,子更便于修改。但是通过预设大量分支实现的,不够轻便。。
组合类更易于扩展,更轻便。(但扩展太好,不利于维护)对某些经常使用的功能,多人合作,统一的格式可以避免五花八门,可以站在全局角度严格控制。。。。。。。。作者认为子选择器更适合。

宽度百分比,可以嵌套使用,提高重用性。布局极其灵活,content-xx-xxxx是全站统一管理的,非常稳定,—》专有名词 网格布局

7.11 z-index的相关问题以及Flash和IE6下的select元素

1,z-负数,单击无法弹出—被body挡住了。

z-相同,html标签中后出现的在先出现的之上
(多元素重叠,relative,absolute激活z-index;负边距),取决于后出现的html,后浮上

2,flash wmode=“window,opaque,transparent”。默认window优先非窗口类,z-无效,显示在最顶端。如同属非窗口,才判断z-,设为后两个值

3,select在ie6也是窗口,这是ie6 bug:和test同大小的iframe放在test下面,select上面,遮住select

7.12 插入png图片

1,Ie6对png透明支持并不好。透明地方浅蓝色。Ie私有的滤镜解决

–progid:DXImageTransform.Microsoft.AlphaImageLoader(src=’png图片路径’,sizingMethod=’crop’)

2,可用代码一次解决。问题:

全加载完之前,透明部分人浅蓝;遍历所有元素,效率不高;以背景插入,可能有position,repeat属性,而滤镜不支持,若设置,这两效果会丢失。

7.13 多版本IE并存方案—–CSS的调试利器IETester

与Mltiple IE不同(早期的时候)

$_PS:(下午看了下大网站的css样式(网易云音乐,youtube),和这个标准差不多;youtube虽然样式名看不懂,但是感觉差不多。。。。另外这两个网站,都为移动端提供的另一套样式或者html,路径都有变化yunyinyue.com/m,m.youbute.com)

P151 01:15


2017.9.10 日 22:30

第五章 高质量的JavaScript

1 养成良好的编程习惯

1.1 团队合作—如何避免js冲突

用匿名函数将脚本包起来,可以有效控制全局变量,避免冲突隐患。
添加必要的注释,可以大大提高代码的可维护性,对于团队合作来说,更是十分必要的
让js不产生冲突,需要避免全局变量的泛滥,合理使用命名空间以及为代码添加必要的的注释。

  1. A和B,匿名函数;
  2. C用A,全局变量做桥梁;
  3. 还要用A,对象类型的全局,GLOBAL;
  4. 变量简单,容易相互覆盖=》不直接挂在G对象,而是此匿名函数的命名空间下(只考虑命名空间不冲突就可以了,属性名任意设置,不用担心会和哪个匿名函数里的某个G属性冲突。命名空间数量一般情况不会特别多,避免冲突相对容易====如果同一个匿名函数中的程序非常复杂,变量名很多,命名空间可进一步扩展,生成二级命名空间)。
  5. 生成命名空间非常常用功能==》定义为函数
  6. 可维护性不高,A改B的代码===》加注释

1.2 给程序一个统一的入口—-window.onload和DOMReady

各自游击,纪律性没有保障==》从功能上对程序划分:框架+应用。
Function init(){} 选择DOMReady 为避免写DOMReay兼容,init()放在最后,</body>
实际工作,三部分 if(init){ init() }

1.3 css放在页头,Javascript放在页尾

1.4 引入编译的概念—–文件压缩

Packer:http://dean.edwards.name/packer/
YUI Compressor:http://developer.yahoo.com/yui/compressor/ 也可压css
基于Javr的jar应用,先安装JDK,配环境通过命令行
Java –jar yuicompressor-x.y.z.jar myfile.js –o myfile-min.js
反压缩:http://jsbeautifier.org/

2 javascript的分层概念和Javascript库

2.1 Javascript如何分层 base common page (只有好坏,作者的经验)

2.2 base层

  1. 封装不同浏览器下js的差异,提供统一的接口:childNodes,透明度,event对象,冒泡,on attachEvent和addEventListener
  2. 扩展js语言底层的接口(虽然支持面向对象,但没有继承extend,类型判断,getElementByClassName):trim,isNumber isString isBoolean …..,get $, getElementByClassName,extend,

前面5.1.2 将网页js代码分两大部分:框架级和应用。Base框架,加命名空间:dom,event,lang

2.3 common层

不是简单的接口,而是相对庞大的组件:cookie,ajsx,drag,resize,animation,tab,tree,msg,colorPicker,calendar,richTextEditor….

没base通用,具体功能相关,不相关不加载;而且一个易用性,重用性,可扩展性好的组件,代码量偏高,按功能单独的文件common_cookie.js,common_drag.js,..按需加载
不仅依赖base,有时也依赖common其他, ,加载时注意顺序

2.4 page层 应用层

平时绝大部分工作在page层,分层后,轻松了。若前两个够丰富、稳定,精力就全在业务逻辑上了,一提高效率,另一提高代码重用率,减小网页大小

2.5 JavaScript库

Prototype,dojo,mootools,ext js,jquery,YUI

YUI2:三大部分:Core-b、Utilities-c、Widgets-c

jQuery:核心文件、jQuery UI

也可以自己写组件,考验工程师能力的事,高品质组件:跨浏览器兼容、组件易用、可重用、可扩展、代码组织有序,高内聚低耦合

长看到网上大量组件,依赖某js库。。。写好的库,。。。为什么不用呢,质,还可直接用第三方组件

5.2代码留下等待实现  

2017.9.11 一 00:41


2017.9.11 一 22:00

3 编程使用技巧 236

3.1 弹性

Get by id,如果再加两个==》数组,byTagName,弹出4444:闭包,_index属性;content结构里可能还有Tag===》3.2by class name

3.2 getElementById,getElementByTagName,getElementByName

但因为一个页面内,相同的id只能出现一次,所以不适合获取一组有“相似功能”的dom节点。
用标签名获得dom节点,让程序和html结构耦合太紧。

3.3 可复用性 这页面3个,那页面5个

同一个页面id只能出现一次,如果你的程序需要被多处复用,一定不能用id做为JavaScript获得dom节点挂钩。
组件需要指定一个根节点,以保持每个组件之间的独立性。

3.4 避免产生副作用 tab 高亮,灰底白字

如果挂了其他样式,会冲突 ,addClass

3.5 通过传参实现定制 第一个高亮,第二个不高亮,第三个高亮但区别

如果一个函数内某个因素很不稳定,我们可以将它从函数内部分离出来,以参数的形式传入,从而将不稳定因素和函数解耦。

3.6 控制this关键字的指向

3.7 预留回调接口 可增加tab的可扩展性

P231 2017.9.12 二 01:17


2017.9.12 二 22:17

3.8 编程中的DRY原则 auto,showItem

3.9 用hash对象传参 多余的null参数,

4 面向对象编程

4.1 面向过程编程和面向对象编程

过程:程序:“数据”—“处理函数”

三方面问题:1没有直接关联,需同时关注两者;
2暴露在同一作用域,没有私用,公有概念,都可以互相访问,初期开发快,后期,由于耦合紧,可能关联到其他地方,牵一发动全身。
3典型的计算机思维方式: 。

对象:对象:“属性”“行为”

只写了两个程序的代码,笔记没有做 

2017.9.13 三 00:51


北一103 2017.9.16 六 11:31

4.2 JavaScript的面向对象编程

4.2.1 Js定义类

函数:普通函数,类

Js定义类:不使用原型,使用原型,使用原型的hash对象写法
一般习惯把属性放构造函数,非原型,方便从构造函数接受参数

4.2.2 共有和私有

This定义共有,var私有;构造函数中的私有无法被原型中的方法访问,私有属性的作用域只在类的构造函数中

1.最简单方法:共有方法也写在构造函数中;问题:实例化时都会复制一份

把行为写在原型可以减少内存消耗

2.1 如果对属性和行为的私有性要求不高,常见做法是约定私有行为_siyou;
2.2.1 极端主义者,直接访问类的属性不好,所有属性都是私有,通过get,set获取和设置

2.2.2比较:set,get相关方法都要放在构造函数中-VS 所有方法都放在构造函数中,会占用更多内存。。但可以更好的保护属性:例如:Animal类的name只能为wangcai或xiaoqiang,type为只读
2.2.3 (你当然可以在编程的时候小心地注意那些属性有什么限制要求,不通过set,get方法对属性进行保护,任然使用this.xxx对属性直接读写,从而节省一点内存。
对于简单应用,作者推荐this.xxx来读写;更复杂的应用,对扩展性和健壮性要求很高,此时用set和get方法读取属性更合适)

另外,如果使用set设置属性,那么就有了监听valueChange的入口。(这才是本小小节主题)

真实世界中,我们的很多思维习惯都是状态驱动的,编程时监听属性的valueChange事件可以帮我们更接近真实世界的思维习惯

4.2.3 继承

Js中实例的属性和行为是由构造函数和原型两部分共同组成的。
Js继承要分别继承构造函数和原型中的属性和行为

1、继承构造函数:Animal.call(this,name);
2、继承原型:Bird.prototype=Animal.prototype;
解决传值,传址:
1简单方法:遍历数组或hash对象,将复杂数据拆成简单数据,然后分别赋值。。值得一提,数组的传值还可以用数组的concat和slice方法实现
2另一种方法prototype传值,New SomeFunction(prototype和function的关系:用作类的function)
Bird.prototype=new Animal();
Bird.prototype.constructor=Bird;因为上面的将Bird.prototype.constructor指向Animal,需纠正,重新指回Bird
3 封装上面函数 function extend(subClass,superClass)
extend(Bird,Animal);

4.3 用面向对象方式重写代码

PhonebookManger Tab

UML语言将类描述出来

面向对象和过程,优缺点 5.4.1比较过。当程序越复杂,这些优缺点会表现的越明显。早晚要跨过的一道坎

被耽搁的星期六 2017.9.16 六 11:00


2017.9.17 日 10:16

5 其他问题

5.1 prototype和内置类

(5.4.2 prototype和类的关系,进一步==》)

1、js提供了内置类:Array、String、Function等,它们提供了js的大部分基本数据类型。有属性和方法,比如

需说明:这些内置类不一定需要new实例,平时习惯更简单的方式:

1
2
3
var a=new String("sdfs");//通过new实例
var b="sdf";//通过""实例 String类对象
var d=[1,2,4];//通过[]实例 Array类对象

2、类就有原型,不论内置or自定义。通过修改内置类原型,让js基本对象有趣的功能:array–each,map等

扩展方法中this:无论在类的构造函数还是原型,都指向实例化的对象。

3、除了扩展,还可以重写

alert(a),自动调用a的toString。在需要字符串时,对象会隐式调用toString,包括我们自定义的对象[object Object]

4、js中包括内置类和自定义类,所有类的祖先 都是Object。如果相对所有对象都扩展,可修改Object类的原型实现

5、修改内置类的原型—方便,但有人排斥—-污染,多人合作对他人造成影响,修改了游戏规则。改进myArray:自定义类,将内置类的实例做为参数传给构造函数;

各有优缺点:。。。。。。但需要new实例化

小应用,不过多考虑可维护性,用前者–直接修改;
大中型,考虑维护性,后者。

5.2 标签的自定义属性

js和html标签存在映射关系,html标签在js中作为dom节点对象存在。

1、获取定义在html标签属性:1、DOM节点对象的getAttribute方法;2、DOM节点对象的属性

ie和firefox:getA 大部分一致,某些不同;node.XXXX结果会更一致。跨浏览器兼容性更好

2、相反在js中定义的属性,也可以映射到html标签中

3、除了常规属性,还有自定义属性。Firefox无法node.XXXX,只能 node.getAttribute(“XXX”)

作者建议:常规node.XXX,自定义node.getAttribute(“XXX”)

自定义属性很有用的技巧,不但可以保存普通字符串,还可以其他数据:数组,hash==》数据反序列化、json。

info=eval( "("+info+")" );

$_PS: 个人以为这不是好方法了,现在有更好的方式了,不用eval。

5.3 标签的内联事件和event对象

event IE:window的一个属性,在全局作用域下。Firefox:事件的参数

1、

document.getElementById("btn").onclick=function(){
    alert(arguments.length);//ie7 0;ff:1 ..ie9:1
} 

2、换成内联呢

<input type="button" id="btn" value="click me" onclick="handler()">

都弹出0
没有换成 btn.onclick=handler;
而是 btn.onclick=funciton(){handler();}

3、内联中,arguments[0],在ff下可以访问到event对象

<input type="button" id="btn" value="click me" onclick="alert(arguments[0].type)">  

4、不使用标签内联事件时,可以给处理函数传参,指定argumens[0]参数名

document.getElementById("btn").onclick=function(e){
    e=window.event||e;//兼容ie ff 
}

5、标签内联事件中,没办法指定参数名,没法直接写变量在ie,ff下兼容event对象了吗?

否。可以用event变量名,兼容指向event对象,只能是event,其他a,b,Event都不行。

<input type="button" id="btn" value="click me" onclick="alert(event.type)">  

ie,ff都可以正确弹出

6、标签内联事件中,甚至可以写注释,使用字符串

7、既用了标签内联事件,又用了DomNode.onXXX

后面的会覆盖前面的

8、attachEvent addEventListener

都弹出

5.4 利用事件冒泡机制

打分,星星 代码 没有写,用的是面向对象

5.5 改变DOM样式的三种方式

1、简单直接node.style.color=”red”;

同时多个样式。node.style.color=”red”;node.style.backgroundColor=”red”;..

2、node.className=”testStyle”

多个dom呢。批量span,除了id为test的color,其他都…

这两都是针对单个dom节点的操作,可以逐个设置。。都不支持批量处理==》

3、

function addStyleNode(str){
    var styleNode=document.createElement("style");
    styleNode.type="text/css";
    if(styleNode.styleSheet){
        styleNode.styleSheet.cssText=str;
    }else{
        styleNode.innerHTML=str;
    }
}
document.getElementsByTagName("head")[0].appendChild(styleNode);
addStyleNode("sapn{color:#fff;font-...}#test{}...");

思路:创建一个 <style>标签,然后往里填入css,再把它加入到页面里。
ff直接innerHTML;ie,只读的,通过styleSheet.cssText
$_PS: 这个第三点,不是很明白

附录A 写在规则前面的话

附录B 命名规则

附录C 分工安排

附录D 注释规则

附录E HTML规范

附录F CSS规范

附录G Javascript规范

2017.9.17 日 12:20

knowledge is no pay,reward is kindness
0%