学堂 学堂 学堂公众号手机端

撸了一款 Vue 生态缺失的 CMD+K 类库

lewis 4年前 (2021-10-14) 阅读数 4 #技术

9月底,新轮子又来了,Vue Command Palette 是一个为 Vue 而生的快速、无样式、可组合的 Command Palette(CMDK)组件库。

灵感来源

这个组件的诞生的灵感来自上个月观察到一个比较火的 React 类库项目 cmdk


cmdk 是一个为 React 而生的快速、无样式、可组合的 CMDK 组件,由 Linear 工程师 Paco Coursey 和他的设计师小伙伴合力开发的,一周内获得 3k Star。

其特点是无样式的,只提供基础的功能框架,可组合的组件 API,便于扩展,这样一来,你可以基于它二次开发,编写成任何你想要的样子。

官网也做的比较用心,编写了四种样式作为例子,有 RaycastLinearVercelFramer

发现 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 功能,可以大幅提升效率,以下工具都是一些实现比较好的代表。

VercelGitHubRaycastLinearFramerAlgolia

你不妨也去试试,没准儿在哪个你正在访问的网站悄悄的支持着 CMDK,你敲一下 ⌘ + K 就能唤起呢。

Vue 中的命名空间组件

这次的组件设计有别于以往的组件开发方式,使用了 Vue 中的命名空间组件 的编写方式,在了解命名空间组件之前,我们先了解一下复合组件

复合组件

cmdk 类库提到了它的组件设计借鉴了《React Hooks: Compound Components》这篇文章中提到的 React 中的 复合组件 设计模式。

那什么是 复合组件 呢,它是一种组件的设计模式,一般适用于有两个或者多个组件一起工作,通常一个组件是父组件、而其他的是子组件。

我们在使用的大部分 UI 类库都会采用复合组件的设计模式去编写复杂组件,比如我们常用的 SelectMenuTable 等等组件到实现方式都是复合组件。

令我好奇的是 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

举个例子:

例如 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>
版权声明

本文仅代表作者观点,不代表博信信息网立场。

热门