9月底,新轮子又来了,Vue Command Palette
是一个为 Vue 而生的快速、无样式、可组合的 Command Palette(CMDK)组件库。
这个组件的诞生的灵感来自上个月观察到一个比较火的 React
类库项目 cmdk
cmdk
是一个为 React
而生的快速、无样式、可组合的 CMDK
组件,由 Linear
工程师 Paco Coursey
和他的设计师小伙伴合力开发的,一周内获得 3k Star。
其特点是无样式的,只提供基础的功能框架,可组合的组件 API,便于扩展,这样一来,你可以基于它二次开发,编写成任何你想要的样子。
官网也做的比较用心,编写了四种样式作为例子,有 Raycast
、Linear
、Vercel
、Framer
发现 Vue 生态内缺少一款好用的 CMDK 类库,于是决定自己造一个(chaoxi)。
如果你还不知道什么是 CMDK,这里简单介绍下。
CMDK
是一种用户体验CMDK 是 CMD + K
的缩写,CMD 代表 Mac 系统中的键位 ⌘ ,对应 Command。CMD + K 是组合键,需要同时按下或者先后按下。
其实 CMDK 这种用户体验我们或多或少都接触过,Mac 自带的 聚焦搜索
就是这样的一个工具 ⌘ + Space
即可唤起它进行搜索,或者作为开发者查阅一些文档的时候,都会带有搜索的功能,有时候会发现都是嵌入的 algolia search
, 再或者在使用 VSCode 的时候打开的命令面板(⇧ + ⌘ + P)
在去年发现 Raycast
这个 App 之后,生产力明显上升,Raycast 可以自定义很多快捷方式,可以结合一些工具打造顺滑的工作流,比如 Raycast 结合 GitHub 去 Create Issue,结合 Linear 去 Create Issue 等等。
所以我认为一个好的工具类、文档类的站点,应当内置一个好用的 CMDK 功能,可以大幅提升效率,以下工具都是一些实现比较好的代表。
Vercel
GitHub
Raycast
Linear
Framer
Algolia
你不妨也去试试,没准儿在哪个你正在访问的网站悄悄的支持着 CMDK,你敲一下 ⌘ + K 就能唤起呢。
Vue 中的命名空间组件这次的组件设计有别于以往的组件开发方式,使用了 Vue 中的命名空间组件
的编写方式,在了解命名空间组件之前,我们先了解一下复合组件
。
cmdk
类库提到了它的组件设计借鉴了《React Hooks: Compound Components》这篇文章中提到的 React 中的 复合组件
设计模式。
那什么是 复合组件
呢,它是一种组件的设计模式,一般适用于有两个或者多个组件一起工作,通常一个组件是父组件、而其他的是子组件。
我们在使用的大部分 UI 类库都会采用复合组件的设计模式去编写复杂组件,比如我们常用的 Select
、Menu
、Table
等等组件到实现方式都是复合组件。
令我好奇的是 cmdk
这个 React 类库中采用的是 <父组件.子组件 />
的引入方式,例如 cmdk
官网的例子:
import { Command } from 'cmdk';
<Command.Dialog open={open} onOpenChange={setOpen}>
<Command.Input />
<Command.List>
{loading && <Command.Loading>Hang on…</Command.Loading>}
<Command.Empty>No results found.</Command.Empty>
<Command.Group heading="Fruits">
<Command.Item>Apple</Command.Item>
<Command.Item>Orange</Command.Item>
<Command.Separator />
<Command.Item>Pear</Command.Item>
<Command.Item>Blueberry</Command.Item>
</Command.Group>
<Command.Item>Fish</Command.Item>
</Command.List>
</Command.Dialog>
上面代码中出现的 <Command.Dialog>
、<Command.List>
等组件引入方式,是在 Vue 中很少采用的方式,我在想为什么不可以呢,于是想去试试。
举个例子:
例如 HTML 中的 <select>
和 <option>
标签:
<select>
<option value="value1">key1</option>
<option value="value2">key2</option>
<option value="value3">key3</option>
</select>
常规组件通常在 Vue 中实现,我们需要编写两个组件,假设是 MySelect
作为父级组件,MyOption
作为子组件
<template>
<fieldset>
<legend>currentValue: {{selected}}</legend>
<MySelect v-model="selected">
<MyOption :value="1">One</MyOption>
<MyOption :value="2">Two</MyOption>
<MyOption :value="3">Three</MyOption>
</MySelect>
</fieldset>
</template>
<script setup>
import { ref } from 'vue'
import MySelect from './MySelect.vue'
import MyOption from './MyOption.vue'
const selected = ref('1')
</script>