高效前端编程实践

2,285 阅读4分钟

最近在阅读《高效前端:Web高效编程与优化实践》这本书,书中介绍了前端高效编程的优化实践和前端基础。本文将结合个人的理解介绍部分高效编程的例子。

能用HTML/CSS解决的问题就不要用JS

自定义radio/checkbox的样式

表单中原生的radio/checkbox的样式各个浏览器都不太一致。要想统一样式,一种做法是自己div/span去画,然后去监听单击事件。这种做法就是逻辑控制完全要自己写,还有原生事件change也无法使用。

这里可以通过CSS提供伪类checked来实现自定义样式。原理是把一个checkbox和一个用来自定义样式的span写在一个label里面,checkbox始终隐藏。

<style>
input[type=checkbox]{
    display: none;
}
/*未选中的checkbox的样式*/
.checkbox{ /* 实现略 */ }
input[type=checkbox]:checked + .checkbox{ /* 实现略 */ }
</style>
<label for="apple">
    <input type="checkbox" id="apple">
    <span class="checkbox"></span>
</label>

需要根据个数显示不同样式

有1~3个items要显示在同一行, 但是item的个数不一定,就一个的话item占宽100%,两个时各占50%,三个时各占33%。显然你可以用js来计算,但是这样有点繁琐。

我们可以通过CSS3的first-childnth-last-child来实现个数的区分

<style>
li {
    width: 100%
}
li:first-child:nth-last-child(2),
li:first-child:nth-last-child(2) ~ li{
    width: 50%
}
li:first-child:nth-last-child(3),
li:first-child:nth-last-child(3) ~ li{
    width: 33%
}
</style>
<ul>
    <li>1</li>
    <li>2</li>
    <li>3</li>
</ul>

用CSS画一个三角形

这个技巧应该是比较常见,通过把宽高设置为0,同时只设置一个边的border来画三角形。下面提供一些其他三角形画法:

// 斜边在左边的三角形
border-top: 50px solid transparent;
border-bottom: 50px solid transparent;
border-left: 50px solid #000;

// 直角三角形
border-left: 60px solid transparent;
border-right: 0 solid transparent;
border-bottom: 40px solid #000;

// 等边三角形
border-left: 28px solid transparent;
border-right: 28px solid transparent;
border-bottom: 40px solid #000;

减少前端代码耦合

JS/CSS/HTML的耦合

不推荐直接在JS里面更改样式属性, 应该通过增删类来控制样式,除了scroll和mousemove

策略模式

// common
function popCallback(popType){
    switch(popType){
        case: "favHouse":
            favHouse();
            break;
        case: "saveSearch":
            saveSearch();
            break;
    }
}
// strategy
var popCallback = {
    favHouse: function(){ /*do sth.*/ },
    saveSearch: function(){ /*do sth.*/ }
}
if(typeof popCallback[popType] === "function"){
    popCallback[popType]();
}

JS书写优化

按强类型风格写代码

这边其实也可以在项目中静态类型检查器(Flow、TypeScript)来优化代码。书中有介绍几点还不错建议:

  • 定义变量的时候要指明类型
var num = 0,
    str = '',
    obj = null;
  • 不要随意改变变量的类型
// bad
var num = 5;
num = "-" + num;
// good 
var num = 5;
var sign = "-" + num;
  • 函数的返回类型应该是确定的
// bad
function getPrice(count){
    if(count < 0) return "";
    else return count * 100;
}
// good
function getPrice(count){
    if(count < 0) return -1;
    else return count * 100;
}

减少作用域查找

全局作用域比较复杂,所以查找属性比较慢。局部作用的查找是很快的

// bad
var url = "";
if(window.location.protocal === "https:"){
    url = "wss://xxx.com" + window.location.pathname + window.location.search;
}

// good 缓存成局部变量
var url = "";
var location = window.location;
if(location.protocal === "https:"){
    url = "wss://xxx.com" + location.pathname + location.search;
}

避免==的使用

我们的代码中应该避免==的使用,应该使用===,这样可以避免js类型转换带来的一些意外的结果。

==建议的使用场景是判断变量是否为空的时候,即if(obj == null)

使用ES6简化代码

  • 使用箭头函数取代小函数
var nums = [4, 8, 1, 9, 0];
nums.sort((a, b) => b - a);
  • 字符串拼接
var tpl =
` <div>
    <span>1</span>
  </div>
`;

var url = `/list?page=${page}&type=${type}`;
  • 块级作用域变量
var tasks = [];
for(let i = 0; i <= 4; i++){
    tasks.push(function(){
        console.log("i is " + i);
    });
}
for(var j = 0; j < tasks.length; j++){
    tasks[j]();
}

增强用户的体验

加Loding效果

常见的Loading都有图片加载、AJAX请求、上传文件进度条。还有一个最近流行的骨架屏(skeleton loading)

样式、文案

这部分可以去看下一些UI库的基本理念和设计原则,如antd-design

用好Chrome Devtools

Chrome Devtools调试建议可以看下F12里面的官方文档。

打印

  • console.table打印对象数组
  • console.dir能递归打印对象的所有属性,打印一个DOM结点

检查没有用的CSS/JS

devtools的Coverage标签栏,没有用到的用红色表示, 用到的用绿色表示

研究重绘

devtools有一个Renders可以用来研究重绘

总结

书中的优化实践点还是很多的,我这边就介绍部分相对比较常用的。其实优化实践给出了比较好的方案,但是实际还是要结合具体情况来选择方案的。