Vue响应式原理剖析(data、watch、computed)

能用 Vue 改写的应用,终将会用 Vue 来改写。—— 尤大大(没说过)

都 2020 年了,我想下面三句话不过分吧:

  • Vue 是一个非常优秀的前端框架
  • 每个前端开发都应该会一点 Vue
  • 不会 Vue 的前端不是优秀的前端

其实 Vue 的 API 是非常容易上手的,官方文档读一遍就能开发了,分分钟实现一个 TODO App。但只会用 Vue 其实是远远不够的,每一个 Vue 开发者都应该了解 Vue 响应式原理(datawatchcomputed),否则永远只是知其然,不知其所以然。

为了让大家彻底搞懂,本文采用渐进式的分析方式,即从零开始一行行写代码,最终完整实现一个具备响应式简版 Vue。 好了,大家把 vscode 打开,新建一个 vue.js 空文件,开始撸吧!

Read More

你真的懂作用域吗?

作用域是 JS 中非常基础的概念,在 ES5 中只有全局作用域和函数作用域,在 ES6 中增加了块级作用域。可是,你真的懂作用域吗?

先不要着急回答,先看下面三道题。做不出来或做错了的话,就是不懂作用域,都做对了,作用域大概懂了三分之一吧,因为还有很多概念在里面呢!

题目一

请分别说出下面代码的执行结果:

1
2
console.log(fn)
function fn() {}
1
2
3
4
console.log(fn)
if(true) {
function fn() {}
}
1
2
3
4
console.log(fn)
if(false) {
function fn() {}
}

Read More

Flutter布局报错

今天在 flutter 在 ListView 里面的 itemBuilder 写布局,发现报错了:

1
RenderFlex children have non-zero flex but incoming height constraints are unbounded.

这个报错的 item 的布局就是 Column.children 里面有个 Row,然后这个 Row.children 里面有个 Column,然后给这个 Column 设置 crossAxisAlignmentCrossAxisAlignment.stretch

查了资料说报错原因是 ListView 垂直方向的计算是包裹子 View 的,也就是说子 View 必须有一个明确的高度,或者尽可能小的高度,而不能是无限高。可以用 IntrinsicHeight 组件包裹 Row,这个 Row 就能根据子控件的高度,智能调整自身高度,就不会报错了。

腾讯云ssh登录超慢

腾讯云 ssh 登录超级缓慢,等了10几秒之后才登陆成功,然后提示:

1
There were 58431 failed login attempts since the last successful login.

而阿里云都是秒登,心想腾讯云真垃圾。后来网上查了一下说,上面统计的是上次成功登录之后有多少次失败登录的尝试,统计数据来源于文件 /var/log/btmp,我的这个文件有 5G,于是就把它给删了,登陆瞬间变快,秒登。

ES6函数作用域

ES6 中的函数(非箭头函数)跟 ES5 的函数是有本质区别的,核心在于作用域,先看一道题:

1
2
3
4
5
6
7
let x = 0
function b(y = x, x) {
x = 3
console.log(x, y)
var y = 4
}
b()

应该打印出什么呢?大家不妨亲自运行一下,看看跟自己想的是否一致。这里总结了两点 ES6 函数中比较特殊的地方:

Read More

Dart扩展方法

dart 可以向任意类型添加扩展方法,语法如下:

1
2
3
extension <extension name> on <type> {
// 这里定义扩展方法
}

举例:

1
2
3
4
5
extension NumberParsing on String {
double parseDouble() {
return double.parse(this);
}
}

使用:

1
2
3
4
5
6
void main() {
//使用String类的方法
print('3.14'.split("."));
//使用扩展方法
print('3.14'.parseDouble());
}

有一点值得注意的是不能使用 dynamic 类型的变量调用扩展方法,但类型推断是可以的:

1
2
3
4
var v = '3.14'; // 变量 v 推断为 String 类型
print(v.parseDouble()); // 输出 : 3.14
dynamic d = '3.14';
print(d.parseDouble()); // 运行时异常 : NoSuchMethodError

Flutter flex布局组件

Flex 布局是目前 web 和移动端最流行的布局方式,在 Flutter 中,也有对应的组件,它们就是:

容器组件

  • Row:水平方向上创建一个 flex 容器。
  • Column:垂直方向上创建一个 flex 容器。
  • Flex:直接创建一个 flex 容器,不指定方向,它是 Row 和 Column 组件的父类。

    1
    2
    class Row extends Flex 
    class Column extends Flex

    Flex 有个 direction 属性能够控制容器布局主轴方向,例如指定 Axis.horizontal 时跟 Row 一样的效果。

Read More

模板引擎实现原理(Vue篇)

在 Vue 框架里面内置了一个模板引擎,用于编译 Vue 专有语法,例如:

1
2
3
4
5
6
7
8
9
10
<div id="app">
你好,{{ message }}!
<p v-if="seen" styles="color: red; fontSize: 16px">条件渲染</p>
<button v-on:click="reverseMessage">反转消息</button>
<ol>
<li v-for="todo in todos" class="color-gray ml-2">
{{ todo.text }}
</li>
</ol>
</div>

这里面有 v-ifv-on:clickv-for 等特殊的语法,Vue 需要把这些内容提取出来,转换成响应式的函数或者对应的 DOM 事件。

在 Vue 中同样是用正则来提取这些内容的,它的转化流程如下:

  • 通过正则把模板转换成 AST 抽象语法树
  • 用 AST 生成 JS 代码
  • new Function 配合 with 来执行 JS 代码

Read More

异步请求之后渲染页面

在 Flutter 中,经常遇到先进行网络请求,然后用请求成功返回的结果来渲染页面的场景。如果网络请求速度比较慢的话,需要在等待网络返回结果的时候,给用户渲染一个等待的页面。有两种方式:

  1. 使用 FutureBuilder 组件

    封装好了这类组件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    new FutureBuilder(
    future: _future, // Future 对象或 null
    builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
    switch (snapshot.connectionState) {
    case ConnectionState.none: return new Text('Press button to start');
    case ConnectionState.waiting: return new Text('Awaiting result...');
    default:
    if (snapshot.hasError)
    return new Text('Error: ${snapshot.error}');
    else
    return new Text('Result: ${snapshot.data}');
    }
    },
    )

Read More