如何封装第三方vue组件

终于算是正式接触 SPA 的前端工作了,最近在解决很多 Vue 组件的问题,其中就有一个针对第三方组件的定制化需求,花了不少时间来折腾。

# 解决 v-model 绑定

这次封装的就是 element 的前端 vue 框架,因为框架本身对 iOS 兼容性不好,所以需要二次封装。封装的是一个 select 组件。所以需要数据的双向绑定,官方教程也已经解释了。 v-model (opens new window) 本质上就是绑定一个值和监听相应的事件。 这次本质是封装的一个 input 元素,所以我们需要手动绑定 value 和监听事件。

<template>
  <el-select v-bind:value="value" v-on="$listeners"></el-select>
</template>
1
2
3

官方文档也解释了这个内置变量的用法vm-listeners (opens new window)

# 继承父元素的属性

父元素的属性继承可以使用v-bind="$attrs"来完成。所以完成组建的透明封装只需要加上三个指令。

<template>
  <el-select v-bind="$attrs" v-bind:value="value" v-on="$listeners">
  </el-select>
</template>
1
2
3
4

虽然知道答案之后很简单,但是探索的过程中还是比较花时间的。希望能帮助大家解决这个问题,如果有什么疏漏之处,也请大家指正。

JavaScript开发中的性能优化

最近工作比较清闲,5 月又换了一个工作环境。总结下最近看的有关 JavaScript 性能的知识,并记下来供未来的自己参考。希望自己能不忘初心,继续成长!

# 使用 requestAnimationFrame 来更新动画

使用requestAnimationFrame把动画渲染交给浏览器,可以保证渲染保持在 60FPS。应该避免使用setTimeout或者setInterval来实现动画,因为计时器和事件队列会消耗更多的资源,还会导致无用的页面重新绘制。

# 使用 Web Workers 来进行复杂的运算

可以把单纯的计算放在 Web Workers 中,这样不影响主页面的渲染和流畅,例如加密和矩阵变换的运算就可以完全放在 Web Workers 中来减少主线程的执行时间,避免浏览器渲染堵塞。

# 避免微优化 JavaScript

举个最简单的例子,我曾经在一本书上看到过一个提升程序效率的例子。大致是这样的:

var array = [1, 2, 3, ...100];

for (var i = 0; i < array.length; i++) {
  console.log(array[i]);
}
1
2
3
4
5

这里的array.length获取数组的长度,每次都要计算数组长度会消耗不少时间,优化之后的代码是这样的:

var array = [1, 2, 3, ...100];
var len = array.length;
for (var i = 0; i < len; i++) {
  console.log(array[i]);
}
1
2
3
4
5

通过缓存数组的长度来保证只计算一次。这就是典型的微优化,说实话这段代码我一直在用,直到最近读了其他的书才发现,现在的 JS 解释器早就优化了对数组长度的计算。无论是读取一次还是一万次消耗的时间都没有太大差别。微优化应该是 JS 引擎需要做的事情,我们不应该在实际开发中在这方面耗费过多的时间。

# 滑动事件优化

当用户监听滑动事件并执行相关动画操作的时候,记得使用window.requestAnimationFrame来优化动画的执行。

function onScroll(evt) {
  // Prevent multiple rAF callbacks.
  if (scheduledAnimationFrame) return;

  scheduledAnimationFrame = true;
  requestAnimationFrame(readAndUpdatePage);
}

function readAndUpdatePage() {
  // do something
  requestAnimationFrame(readAndUpdatePage);
}

window.addEventListener('scroll', onScroll);
1
2
3
4
5
6
7
8
9
10
11
12
13
14

参考:

Debounce Your Input Handlers (opens new window)

Optimize JavaScript Execution (opens new window)

JavaScript中的数据类型

隔了一个月,我又来发博客了。最近的工作老是在写 CSS 和 HTML。但是我更想学习 JS 啊!我一直都觉得 HTML 和 CSS 是属于设计范畴的,而 JS 才是真正属于工程师的逻辑范畴。 况且最近 Github 上有一个神奇的项目Screenshot-to-code-in-Keras (opens new window)可以把截图直接生成 HTML 代码,我觉得只是单纯的从 PSD 翻译成页面的工作迟早要被淘汰。

最近在读 You Don't Know JS 这本书。书上讲解了很多关于 JS 的细节知识,对于深入了解 JS 有很大帮助。所以想在读的过程中把一些觉得有意思的东西记下来,便于以后复习。

# 类型

JavaScript 中有七种内置类型:

  1. 空值(null)
  2. 未定义(undefined)
  3. 布尔值(boolean)
  4. 数字(number)
  5. 字符串(string)
  6. 对象(object)
  7. 符号(symbol, ES6 新增)

除了对象之外,通称基本类型。

# JavaScript 中的设计 BUG

typeof null === 'object'; // true
1

正确的返回结果应该是 null。但这个 BUG 由来已久,修复反而会出问题。所以我们需要使用复合条件来判断:

!a && typeof a === 'object';
1

接下来是NaN的问题:

var a = 2 / 'foo';
var b = 'foo';
a; // NaN
b; // "foo"
window.isNaN(a); // true
window.isNaN(b); // true
NaN === NaN; // false
1
2
3
4
5
6
7

很显然"foo"不是 NaN,但显然它也不是数字。这个 BUG 也存在很久了,在 ES6 时代,我们可以使用 Number.isNaN 来解决。 ES6 之前的 polyfill 是:

if (!Number.isNaN) {
  Number.isNaN = function(n) {
    return typeof n === 'number' && window.isNaN(n);
  };
}
1
2
3
4
5

并且 NaN 是 JS 中唯一一个不等于自身的值。

# 值和类型

JavaScript 中的变量是没有类型的,只有值才有。变量可以随时持有任何类型的值。

undefined 和 undeclared. 变量在未持有的时候为 undefined, 此时 typeof 返回 undefined. 大多数开发者倾向于将 undefined 等同于 undeclared(未声明),但在 JavaScript 中它们完全是两回事。已在作用域中声明但还没有赋值的变量,是 undefined 的。相反,还没有在作用域中声明过的变量,是 undeclared 的。

var a;
a; // undefined
b; // ReferenceError: b is not defined
typeof a; // "undefined"
typeof b; // "undefined"
1
2
3
4
5

虽然 b 是一个 undeclared 变量,但 typeof b 并没有报错。这是因为 typeof 有一个特殊的安全防范机制。防止因为未定义导致程序终止运行。

# 值和引用

在许多编程语言中,赋值和参数传递可以通过值复制(value-copy)或者引用复制(reference-copy)来完成,这取决与我们使用什么语法。但是 JavaScript 对值和引用的赋值 / 传递在语法上没有区别,完全根据值的类型来决定。

简单值(即标量基本类型值,scalar primitive)总是通过值复制的方式来赋值/传递,包括 null 、 undefined 、字符串、数字、布尔和 ES6 中的 symbol 。

复合值(compound value)——对象(包括数组和封装对象)和函数,则总是通过引用复制的方式来赋值/传递。由于引用指向的是值本身而非变量,所以一个引用无法更改另一个引用的指向。

var a = [1, 2, 3];
var b = a;
a; //[1,2,3]
b; // [1,2,3]

// 然后
b = [4, 5, 6];
a; // [1,2,3]
b; // [4,5,6]
1
2
3
4
5
6
7
8
9

b=[4,5,6] 并不影响 a 指向值 [1,2,3] ,除非 b 不是指向数组的引用,而是指向 a 的指针,但在 JavaScript 中不存在这种情况!

参考:

You Don't Know JS (opens new window)