Thinking in Component Tree

blue red and green letters illustration

在开发前端应用的时候,我比较推荐在真正开始写代码之前试着画一画组件树 / 状态树。

在很多时候,可能你的设计师已经帮你做好了组件树,但在某些场景下,你的设计时并不会帮你拆解组件树,或者是你是直接和产品经理对接,他不会帮你拆解组件树。

这个时候,相比于写代码,我更推荐你先拆解组件树,在完成组件树之后,再开始你的 Coding。

d2b5ca33bd970f64a6301fa75ae2eb22 5

Figma / Sketch 之类的软件提供的分组能力、图层的能力,可以帮助你将组件合理的拆解、分组、归类。当你完成树的建设之后,可以试试看将不同的模块拆解,每个模块是否可以独立正常的运转。如果不可以,则说明你的状态拆解的可能是有问题的。

当你完成拆解之后,只需要按照你拆解出来的树组织你的 Component 即可。

使用 idb-kayval 作为前端数据存储

text

在前端留存一些状态,是在前端场景下提升性能的常规操作。最近我有一个场景需要在前端留存一个状态,借着这个机会,试了试 IndexedDB 来作为数据存储,拓展一下新的方向。

关于 Indexed DB

Chrome 在中提供了多种不同的存储,按下 F12 ,打开 DevTools ,找到应用 – 存储,你就会看到目前 Chrome 支持的多种存储方式。常用的主要就是本次存储空间(Local Storage)、会话存储空间(Session Storage)和 Indexed DB。这次我用的便是 Indexed DB。

d2b5ca33bd970f64a6301fa75ae2eb22 1

开发使用建议

由于 Indexed DB 提供的 API 整体比较裸,在实际应用开发时,可能并不好用,你可以根据自己的需要,选择使用不同的第三方开发库来开发你的应用。在这篇文章中,我使用了 idb-keyval 来作为我的开发库。

d2b5ca33bd970f64a6301fa75ae2eb22 3

用法

首先,使用 yarn add idb-keyval 来安装依赖,安装完成后,可以参考如下代码来在你的项目中引入 indexedDB.

import { set,get,keys } from 'idb-keyval';


// 下面演示了一个 get_books 函数,会将内容存储在 IndexedDB 的 your-keys 当中。
// 如果存在缓存,则直接使用缓存,不存在,则进行数据获取
function get_books(){
   // 使用 keys 获取当前 IndexedDB 当中的所有 Key,用于判断当前是否有缓存结果。
   const exists_keys = await keys();
   if(exists_keys.indexOf('your-keys') !== -1){
    console.log("use cached glossary")
    return await get('your-keys');
   }

   // fetch data
   let data = fetch_data();
   
   await set('your-keys',data)
   return data;
}
Code language: PHP (php)

使用前后的效果

在性能上,使用 Indexed DB 之后,根据你的数据获取的难度,会有不同的性能提升。比如这里我不使用缓存,单次数据获取需要花费 800ms,借助于 Indexed DB,时间可以被控制在 10ms 以内,从而得到一个不错性能。

d2b5ca33bd970f64a6301fa75ae2eb22 2

使用 glean 插件优化你的 React 项目

9a1f326b911de6c1629837f3b57551e5

React 相比于 Vue 的好处是你可以相对轻松的将一个组件抽离出来,这使得开发者可以根据自己的需要进行抽象。

但手动抽象组件还是相对较麻烦,于是我便搜索有没有一些方便的插件,可以帮助我更好快的完成组件的抽象。于是乎便找到了 Wix 出的 glean 插件。

glean 插件可以将任意层级的组件抽出为一个全新的函数,并在之前的位置引用你的函数,因此,你可以先非常快的构建出一个完整的 UI 界面,再基于这个界面,进行不同层次的抽象。或者是在开发界面时,随时根据需要来完成界面的抽象。

tz4sh
官方提供的 Demo

在实际使用过程中,你可以将 glean 插件提供的命令设置为快捷方式,从而实现更快的抽象组件,或者是点击组件前的黄色小灯泡💡来完成组件的抽象。

d2b5ca33bd970f64a6301fa75ae2eb22 9
黄色小灯泡

在油猴脚本中实现新增按钮和按钮的点击效果

text

在油猴脚本中,有些时候,我们需要在界面当中添加一个新的按钮。这个时候我们可以使用 document.getElementById("id").innerHTML=xxx 来指定某个元素中的内容是特定的 HTML,从而实现添加一个新的按钮。

但在这个按钮上绑定事件则不是通过简单的指定 button 的 onclick 来完成的。核心原因是默认情况下,你在油猴脚本中所写的函数只运行在油猴脚本中的 Scope ,而 button 则是运行在 Document 的 Scope 下。直接绑定事件在触发时会无法找到对应的函数。

一个好的办法是为你新增的 Button 带上 ID,并通过 ID 找到对应的 Element 并添加事件绑定来实现。

参考代码如下:

// ==UserScript==
// @name         示例代码
// @namespace    https://www.ixiqin.com
// @version      0.0.1
// @description  示例代码
// @author       bestony
// @license      MIT
// ==/UserScript==

(function () {
  'use strict';
  window.addEventListener('load', function () {
    function viewAuthor() {
      // button click event
    }

    var targetElement =document.getElementById("xxx")

    targetElement[0].innerHTML = targetElement[0].innerHTML + ` &nbsp;<a id="view-author">查看作者</a>`

    var link = document.getElementById("view-author");
    if (link) {
      link.addEventListener("click", viewAuthor, false);
    }
  }, false);
})();
Code language: JavaScript (javascript)

油猴脚本不支持 Modules Javascript 导致空白脚本报错

text

最近在写一个油猴脚本时,因为懒得写 DOM 处理函数,我试图在油猴脚本当中引入 Zepto.js, 用于实现 DOM 操作。

d2b5ca33bd970f64a6301fa75ae2eb22

但在引入 Zepto 之后,发现即使是空白的脚本文件,在网页加载时依然会报错。经过排查发现,是我引入的 Zepto 文件导致的,进一步研究后发现,之所以有这个问题,是目前油猴脚本仍不支持 Modules ,因此,我引入 Zepto 就会报错。

想要解决这个问题倒是也简单,将 Zepto 替换为 JQuery 即可。本来想着用 Zepto 会轻量一点, 最后发现还是要上 JQuery。好在是目前 JQuery 提供了不含 Ajax 和 Effect 的 Slim 版本,倒是也不用担心引入的依赖文件特别的大。

warehouse — 一个简单易用的 JSON 数据库

black and yellow printed paper

在 Hexo 的 Github 组织下,有一个不明显,但却很有用的仓库 —— warehouse。

warehouse 是一个 JSON 数据库,基于 JSON 实现了各种类似于 SQL 的查询,可以帮助我们基于一个 JSON 文件来进行查询。在 Hexo 的静态生成过程中,warehouse 帮了大忙。

用官方的话来说,warehouse 就是 A JSON database with Models, Schemas, and a flexible querying interface.

在实际使用上,warehouse 确实如他所说的那边方便(虽然某些方法没有,但依然不影响他的使用很方便)。

Example

比如,如下代码就定义了 一个 Post 模型和对应的表。并实现了在这个表中插入一个新的数据。

var Database = require('warehouse');
var db = new Database();

var Post = db.model('posts', {
  title: String,
  created: {type: Date, default: Date.now}
});

Post.insert({
  title: 'Hello world'
}).then(function(post){
  console.log(post);
});
Code language: JavaScript (javascript)

如果你需要将这些数据保存为一个单独的文件,只需要修改初始化的参数,并执行 save 方法,就可以将 JSON 导出到指定的文件中

var db = new Database({
  path: "./test.json", // 将数据存储在 test.json 当中
});
db.save();
Code language: JavaScript (javascript)

类似的,如果数据已经构建好了,也只需要执行 load 方法,就可以加载数据。

var db = new Database({
  path: "./test.json", // 将数据存储在 test.json 当中
});
db.load();
Code language: JavaScript (javascript)

场景

如果你希望在内存当中对于 JSON 有一个更好的操作方式,那么 warehouse 是个不错的选择,不需要另外单独安装数据库,就可以实现类似于数据库的查询方式,体验还是非常好的。

如果你想了解更多,可以查看

记录一个令人血压飙升的前端项目

programming language

最近在看一个前端项目,里面出现了一些令人血压暴涨的骚操作。虽然可以用,但对我来说,确实是让我看到血压飙升。

1. 尽可能使用常规的指标

项目的诉求是实现页面的自适应化,在不同尺寸的屏幕上尽可能保持一致的显示。

为了实现这个诉求,我给他们的建议是使用 Bootstrap 之类的框架,在不同的屏幕上尽可能保持一致。使用 Bootstrap 之类的框架来完成。

最后研发团队选择采用了一个有用,但我看起来非常头疼的方法 —— 根据屏幕宽度计算 rem。通过这样的方式,实现了在不同的屏幕宽度下,都可以和设计稿的尺寸一比一。

但这样带来的问题是,rem 计算出的结果也是一个非常的大的值(当然也可以非常小),但依然不是一个常规的结果,需要你常常使用诸如 0.03 这样的数值来指定宽度和高度。

d2b5ca33bd970f64a6301fa75ae2eb22 38

我觉得,这样的写法并不是说不行,只是这样的写法其实会降低整个项目的可维护性。

2. 文件放置符合规范

其次,这个项目中还出现了一个问题是 —— 文件到处乱丢。在一些项目中,大家往往会有一些明确的文件路径的规范,比如样式文件应该放在哪里。在这个项目中,就出现了样式乱丢的情况。

d2b5ca33bd970f64a6301fa75ae2eb22 39
和 Component 放在一起
d2b5ca33bd970f64a6301fa75ae2eb22 40
符合规范统一放在 scss 文件中

这样的混乱的写法则会导致在实际开发的时候,如果想要调整样式,可能会出现调试失效,修改起来较为混乱的问题。

3. 一个项目中混用多个不同的尺寸单位

d2b5ca33bd970f64a6301fa75ae2eb22 41
另外一个文件采用 px 作为单位

刚刚有用 rem 的单位,另外就有一个文件采用的是 px 为单位,我非常担心在不同尺寸屏幕下出现的错位问题。

4. 放弃 Bootstrap 的样式类,转而改用手动撰写每一行样式

d2b5ca33bd970f64a6301fa75ae2eb22 42
其实完全可以用 position-absolute d-flex 等方法来覆盖

总结

这个项目从我目前的视角来看,依然还有很大的改进空间。且留下了不少的坑。在我看来,长期来看,这些代码将会留下不可维护的问题。希望他们后续慢慢修改和调整吧。唉。