嵌套Flex布局下子元素撑开父元素的问题

偶然遇见一个奇怪的嵌套Flex问题,当子Flex元素里面的内容宽度过大时,即使指定了overflow:auto,仍然会撑开父元素,导致布局乱掉。一个简单的示例如下:

HTML如下:

<div class="main"<div class="left"Sidebar</div<div class="right"<div class="label"Label
    </div<div class="overflow"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
    </div</div</div

CSS如下:

.main {
  display: flex;
  width: 100%;
}
.left 

两个键盘事件的兼容问题

最近碰到两个键盘事件的问题,以前一直没怎么注意。

中文输入法的回车问题

很多输入框都支持Enter回车键提交,但是在中文输入法下,用回车输入英文的时候会直接触发Enter提交行为。此时可以使用KeyboardEventisComposing属性可以判断当前是否是处于输入过程中,即是否在compositionstartcompositionend之间,如果isComposingtrue,忽略此时的Enter即可。在FirefoxChrome中都无此问题,但是在Safari下,此时的isComposing会为false,无法正常处理此时的Enter

迫于无奈,只好看下Event中是否还有其他属性可以使用,试试keycode和被抛弃的keyCode

console.log(e.key, e.code, e.keyCode, e.isComposing)

Chrome / Edge 结果如下:

Firefox

在Web Components中使用自定义字体

自定义字体是个好东西啊,FontAwesome/Remixicon等优秀的图标都是用自定义字体来实现的,非常省事好用。如此让人上瘾的东西,可惜碰到了web components之后麻烦就来了。

首先,web components是自隔离的,父页面中的样式是不能作用于组件的,所以按照常规方法是把样式嵌入到组件中。非常遗憾的是,css加载是没问题的,但是它并没有于我们预期想象的一样把图标显示出来。

这个看起来就像是字体缺失,打开网路请求检查一下,的确就是没有字体请求!但是,令人意外的是,如果在父页面中引入自定义字体,在组件内部使用自定义字体,居然是行得通的!

所以这个丑陋的方案就出来了,把他们拆成两个部分:

  1. 字体定义部分放在父页面中,通过父页面来请求自定义字体;
  2. 样式部分放在web components中,因为样式是隔离的。

当然,我们可以通过js来在父页面中注入自定义字体:

const FONT_FACES = `@font-face

在React中分离Shadow DOM样式及使用Sass

Shadow DOM已经比较成熟了,基本上所有的现代浏览器都已经支持了,可以参考Can I Use。在React中使用shadow DOM也不是什么新鲜事,也有一些关于shadow DOM的第三方库,但是在CSS方面,几乎都是使用了styled components的方式。我个人不太喜欢这种css和js混在一起方式,而且这种方式下也没法使用scss了。

开始看了下style-laoder的文档,里面有个选项insert,可以传入一个function,这样你可以在里面进行你想要的操作,比如找到shadow DOM的shadow root,然后把你的style插入进去:

rules: [
  // Other webpack modules
  ...
  {
    test: /\.css$/,
    use: [
      {
        loader: require.resolve('style-loader'),
        options: {
          insertInto: function

useSignal()——前端框架的未来?

Angular以及Qwik的作者MIŠKO HEVERY写了篇文章:useSignal()才是Web框架的未来(useSignal() is the Future of Web Frameworks),也引起一些讨论。包括Qwik在内的多个框架也已经实现了useSignal(),这些框架还有Vue、Preact、Solid以及Svelte等。

实际上signals并不是一个全新的概念,大约十年前的框架Knockout就曾经使用过。那为什么最近突然又重提此项技术?这主要得益于当今更加先进的编译技巧以及与jsx的深度集成,使signals的开发体验变得更好了。

什么是signal

如果了解过React的话,signal其实和useState非常类似,也是一种用来存储应用状态的方式。但是和useState存在一些区别:

useState是返回一个值以及一个set方法,而useSignal则是返回一个getter和一个…

ChatGPT答Server-Sent Events

关于Server-Sent Events,试着问了ChatGPT几个问题,以下内容由ChatGPT回答。

Server-Sent Events相比WebSocket有什么不同?

Server-Sent Events(SSE)和 WebSocket 都是用于实现服务器向客户端实时传输数据的技术,但它们有一些不同之处:

协议:WebSocket 是一种全双工的协议,它允许客户端和服务器之间进行双向通信。相比之下,SSE 是一种半双工协议,只允许服务器向客户端发送数据。

连接:WebSocket 建立一次连接,客户端和服务器之间可以进行多次双向通信。相比之下,SSE 使用普通的 HTTP 连接,并且只能由服务器向客户端发送消息。

数据格式:WebSocket 可以传输各种格式的数据,例如文本、二进制和 JSON 等。SSE 只能传输文本数据,通常采用纯文本格式。

适用场景:WebSocket 适合于需要实时、双向通信的应用场景,例如在线游戏或即时聊天。相比之下,SSE

服务器发送事件(Server-Sent Events)

什么是Server-Sent Events

从名字可以看出,服务器发送事件(Server-Sent Events)是一种服务端向客户端推送消息的方法。服务器发送事件规范(Server-Sent Event)描述了一个内置的类EventSource,它可以用来与服务器保持链接并且可以从服务器接收时间。

WebSocket类似,这个链接是持久的,但是两者有一些不同:

WebSocketEventSource
通信方向双向:客户和服务器都可以交换信息单向:只有服务器能发送数据
消息类型可以发送文本以及二进制消息只能发送文本消息
网络协议WebSocket协议常规HTTP协议

从上表可以看出,Server-Sent Event(以下简称SSE)相比WebSocket是一种更轻量的消息推送方式。SSE使用常规HTTP协议,并且支持断线重连 ,无需额外实现。SSE使用相对来说更简单——在服务器端,只需要按照一定格式返回消息;在客户端中,只需要为一些事件类型绑定监听函数,和处理其他普通的事件没多大区别。…

json.Unmarshal不区分大小写的坑

这个坑隐藏得很深,绝大多数情况下都不会碰到。在转换JSON的过程中,Unmarshal会按字段名来转换,碰到同名但大小写不一样的字段会当做同一字段处理。在官方文档中亦有说明(加粗部分):

To unmarshal JSON into a struct, Unmarshal matches incoming object keys to the keys used by Marshal (either the struct field name or its tag), preferring an exact match but also accepting a case-insensitive match. By default, object keys which don’t have a corresponding struct field are ignored (see Decoder.DisallowUnknownFields for an alternative).

精确匹配最好,但是也接受大小写不敏感的匹配。只能说“包容性”太好了,但我认为这并不是一个好的设计。…

Tags:

用ChatGPT写了段无法通过编译的Go代码

这几天ChatGPT突然之间火得一塌糊涂。这个AI能够写小说、剧本、散文,回答各种问题,当然它肯定也能写代码,还能扮演Linux虚拟机来执行各种命令、编译代码。由于它过于强大,有人用它来回答stackoverflow上的各种问题,导致官方采取临时措施,把这个AI给禁止了。不得不说,它回答这些问题比google要好用多了。

我也折腾了一个账号,上去试了试。作为程序员,我让ChatGPT用Go写了段快速排序的代码,总体看起来还是很不错的:

func quickSort(arr []int) []int {
  // base case: if the length of the array is 0 or 1, it is already sorted
  if len(arr) < 2 {
    return arr
  }

  // choose the pivot element as the middle element of the array
  pivot := arr[len(arr)

Go指南练习11-Web爬虫

这个是A Tour of Go这个教程里面的最后一个练习,如下:

在这个练习中,我们将会使用 Go 的并发特性来并行化一个 Web 爬虫。

修改 Crawl 函数来并行地抓取 URL,并且保证不重复。

提示:你可以用一个 map 来缓存已经获取的 URL,但是要注意 map 本身并不是并发安全的!

原题代码模板如下:

package main

import (
	"fmt"
)

type Fetcher interface {
	// Fetch 返回 URL 的 body 内容,并且将在这个页面上找到的 URL 放到一个 slice 中。
	Fetch(url string) (body string, urls []string, err error)
}

// Crawl 使用 fetcher 从某个 URL 开始递归的爬取页面,直到达到最大深度。
func Crawl(url string, depth int, fetcher Fetcher) {
	// TODO: 并行的抓取 URL。
Tags: