关于vue.js:撸了一款-Vue-生态缺失的-CMDK-类库

12次阅读

共计 4565 个字符,预计需要花费 12 分钟才能阅读完成。

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 性能,能够大幅晋升效率,以下工具都是一些实现比拟好的代表。

  • Vercel
  • GitHub
  • Raycast
  • Linear
  • Framer
  • Algolia

你无妨也去试试,没准儿在哪个你正在拜访的网站悄悄的反对着 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>

💻 在演练场中尝试一下

命名空间组件

其实 Vue 官网文档也有阐明,把带 . 的组件叫做命名空间组件(Namespaced Components)。

命名空间组件:能够应用带 . 的组件标签,例如 <Foo.Bar> 来援用嵌套在对象属性中的组件。这在须要从单个文件中导入多个组件的时候十分有用

假如将下面例子中的组件改为命名空间组件,会是这样写:

<template>
  <fieldset>
    <legend>currentValue: {{selected}}</legend>
    <NSelect v-model="selected">
      <NSelect.Option :value="1">One</NSelect.Option>
      <NSelect.Option :value="2">Two</NSelect.Option>
      <NSelect.Option :value="3">Three</NSelect.Option>
    </NSelect>
  </fieldset>
</template>

<script setup>
import {ref} from 'vue'
import {NSelect} from './packages.js'

const selected = ref('1')
</script>

💻 在演练场中尝试一下

在验证了可行后,于是决定以 命名空间组件 的形式编写 Vue Command Palette

命名空间组件特点:

  • 导入一个根组件即可应用全副子组件
  • 能够选择性的引入子组件
  • 让整个组件库看起来更加有一体性

Vue Command Palette

vue-command-palette 组件就是以 命名空间组件 形式编写的,基本上实现了 cmdk 中大部分的性能。

预览

装置

yarn add vue-command-palette
# or
pnpm add vue-command-palette

应用

留神,此组件提供的是具备 CMDK 性能的骨架,没有任何款式,须要独自引入款式文件。

!-- <template> -->
<Command.Dialog :visible="visible" theme="custom">
  <template #header>
    <Command.Input placeholder="Type a command or search..." />
  </template>
  <template #body>
    <Command.List>
      <Command.Empty>No results found.</Command.Empty>

      <Command.Group heading="Letters">
        <Command.Item>a</Command.Item>
        <Command.Item>b</Command.Item>
        <Command.Separator />
        <Command.Item>c</Command.Item>
      </Command.Group>

      <Command.Item>Apple</Command.Item>
    </Command.List>
  </template>
</Command.Dialog>

引入一个 Command 根组件,即可选择性的去组合应用其余子组件

// <script lang="ts" setup>
import {ref} from 'vue'
import {Command} from 'vue-command-palette'

const visible = ref(false)

主题

cmdk 同样,组件库不提供任何款式,每个组件都以非凡申明的以 command- 结尾的 data-attribute 命名,你能够应用它作为选择器来定制款式。

比方:

div[command-root=""] {// your style}

vue-command-palette 能够传递一个名为 theme 的 Props,这样你能够在主题的 class 选择器 中编写你的款式。

比方:提供的 theme 为 my-theme

// my-theme.css
.my-theme {// your theme}

组件库尽管是无款式的,然而这样一来你就能够得心应手的定制主题,思考到对伸手党不太敌对,这里提供了几种主题仅供参考:

  • Vercel
  • Raycast
  • Linear
  • Algolia

嵌套子面板

有时候有一种需要是在命令面板中须要下钻拜访子菜单中的我的项目,这时候须要手动管制,倡议应用动静组件的形式实现

详见 Vercel 的例子

事件处理

Command.Item 的实现中提供了 @select 事件绑定,便于触发选中事件

参考实现

快捷键绑定

快捷键的绑定实现,这里参考了另一个 cmdk 类库 kbar 的实现形式,被动申明快捷键 shortcut 和响应事件 perform 的关系

const preferenceItems = [
  {
    icon: SunIcon,
    label: 'Toggle Dark Mode',
    shortcut: ['G', 'T'],
    perform: () => toggleDarkmode()
  }
]

参考实现

参考

  • cmdk
  • kbar

感激下面的组件库提供的灵感,实际上我可能是一个“组件库翻译者”,将 React 生态的 cmdk 搬运成了 Vue 生态的 vue-command-palette,或者当前你的 Vue 我的项目有好用的 CMDK 组件能够用了呢。

本年度其余独立我的项目

  • onetab.group:你的一站式标签 / 标签组管理器
  • tech-stack.tools:创造者的技术栈工具库
  • bookmark.style:你的链接有了新的款式
  • 撸了一款将链接转化为精美分享图的 Chrome 插件
  • 《前端技术栈周刊》公布

正文完
 0