跳转到内容

NovaColorPicker 取色器

NovaColorPicker 提供 HSV 面板、Hue/Alpha 滑条与 HEX/RGB/HSL 文本输入,默认通过 NovaDropdown 渲染浮层,并继承 NovaEnvironment 提供的主题与语言。可直接 import { NovaColorPicker } from 'nova-next' 使用;安装步骤请参阅 快速开始

示例

基础用法

最常见的 3 个受控取色器,展示 v-model 与默认触发器外观。

预览

#1890ff

#52c41a

#ff4d4f

源码
vue
<script setup lang="ts">
import { ref } from 'vue'
import '@jiangshengdev/nova-next/styles/themes.css'
import '@jiangshengdev/nova-next/styles/dropdown.css'
import '@jiangshengdev/nova-next/styles/color-picker.css'
import { NovaColorPicker } from '@jiangshengdev/nova-next'

const brandColor = ref('#1890ff')
const successColor = ref('#52c41a')
const dangerColor = ref('#ff4d4f')
</script>

<template>
  <div class="demo-column">
    <div class="demo-group">
      <NovaColorPicker v-model="brandColor" />
      <p class="demo-tip">{{ brandColor }}</p>
    </div>

    <div class="demo-group">
      <NovaColorPicker v-model="successColor" />
      <p class="demo-tip">{{ successColor }}</p>
    </div>

    <div class="demo-group">
      <NovaColorPicker v-model="dangerColor" />
      <p class="demo-tip">{{ dangerColor }}</p>
    </div>
  </div>
</template>

<style scoped>
.demo-column {
  display: flex;
  flex-wrap: wrap;
  gap: 12px 48px;
}

.demo-group {
  display: flex;
  flex-wrap: wrap;
  flex-direction: row;
  align-items: center;
  gap: 8px;
}

.demo-tip {
  margin: 0;
  font-size: 13px;
  font-family: ui-monospace, monospace;
}
</style>

透明度与格式

根据开关切换 Alpha 滑条,并在 HEX/RGB/HSL 三种输出间切换。

预览

输出格式
rgba(64, 158, 255, 0.8)
源码
vue
<script setup lang="ts">
import { ref, watch } from 'vue'
import '@jiangshengdev/nova-next/styles/themes.css'
import '@jiangshengdev/nova-next/styles/dropdown.css'
import '@jiangshengdev/nova-next/styles/color-picker.css'
import { NovaColorPicker, Color } from '@jiangshengdev/nova-next'

const color = ref('rgba(64, 158, 255, 0.8)')
const alphaEnabled = ref(true)
const format = ref<'hex' | 'rgb' | 'hsl'>('rgb')

// 当 alphaEnabled 或 format 改变时,重新格式化颜色值
watch([alphaEnabled, format], ([newAlphaEnabled], [oldAlphaEnabled]) => {
  const parsedColor = Color.parse(color.value)
  const { red, green, blue } = parsedColor

  if (!newAlphaEnabled) {
    // 移除透明通道
    const opaqueColor = new Color(red, green, blue)

    color.value = opaqueColor.toString(format.value)
  } else if (oldAlphaEnabled === false) {
    // 从关闭切换到开启,设置为 80% 透明
    const transparentColor = new Color(red, green, blue, 0.8)

    color.value = transparentColor.toString(format.value)
  } else {
    // 只是格式切换,保持透明通道
    color.value = parsedColor.toString(format.value)
  }
})
</script>

<template>
  <div class="demo-alpha">
    <div class="demo-controls">
      <div class="demo-control">
        <label class="demo-checkbox">
          <input v-model="alphaEnabled" type="checkbox" /> 透明通道
        </label>
      </div>
      <div class="demo-control">
        <span>输出格式</span>
        <label class="demo-radio"> <input v-model="format" type="radio" value="hex" /> HEX </label>
        <label class="demo-radio">
          <input v-model="format" type="radio" value="rgb" /> RGB(A)
        </label>
        <label class="demo-radio">
          <input v-model="format" type="radio" value="hsl" /> HSL(A)
        </label>
      </div>
    </div>
    <div class="demo-picker">
      <NovaColorPicker v-model="color" :alpha="alphaEnabled" :format="format" />
      <span class="demo-value">{{ color }}</span>
    </div>
  </div>
</template>

<style scoped>
.demo-alpha {
  display: flex;
  flex-wrap: wrap;
  flex-direction: column;
  gap: 12px;
}

.demo-controls {
  display: flex;
  flex-wrap: wrap;
  flex-direction: column;
  align-items: flex-start;
  gap: 8px;
  font-size: 13px;
}

.demo-control {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}

.demo-checkbox {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  cursor: pointer;
}

.demo-checkbox input[type='checkbox'] {
  margin: 0;
}

.demo-radio {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px;
  cursor: pointer;
}

.demo-radio input[type='radio'] {
  margin: 0;
}

.demo-picker {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}

.demo-value {
  font-family: ui-monospace, monospace;
  font-size: 13px;
}
</style>

预设色卡

使用 preset 提供常用与主题色列表,面板关闭后自动回写最新值。

预览

常用颜色
#40a9ff
主题色组合
#faad14
源码
vue
<script setup lang="ts">
import { ref } from 'vue'
import '@jiangshengdev/nova-next/styles/themes.css'
import '@jiangshengdev/nova-next/styles/dropdown.css'
import '@jiangshengdev/nova-next/styles/color-picker.css'
import { NovaColorPicker } from '@jiangshengdev/nova-next'

const color = ref('#40a9ff')
const accent = ref('#faad14')
const presetColors = ['#ff4d4f', '#ff7a45', '#ffa940', '#ffc53d', '#bae637', '#73d13d', '#40a9ff']
const themeColors = ['#1677ff', '#36cfc9', '#faad14', '#f5222d']
</script>

<template>
  <div class="demo-preset">
    <div class="demo-group">
      <span class="demo-label">常用颜色</span>
      <NovaColorPicker v-model="color" :preset="presetColors" />
      <span class="demo-value">{{ color }}</span>
    </div>

    <div class="demo-group">
      <span class="demo-label">主题色组合</span>
      <NovaColorPicker v-model="accent" :preset="themeColors" />
      <span class="demo-value">{{ accent }}</span>
    </div>
  </div>
</template>

<style scoped>
.demo-preset {
  display: flex;
  flex-wrap: wrap;
  flex-direction: row;
  gap: 12px 48px;
}

.demo-group {
  display: flex;
  flex-wrap: wrap;
  flex-direction: row;
  align-items: center;
  gap: 8px;
}

.demo-label {
  font-size: 13px;
}

.demo-value {
  font-family: ui-monospace, monospace;
  font-size: 13px;
}
</style>

自定义触发器

通过 trigger 插槽替换触发按钮,仍保留下拉定位与焦点管理。

预览

源码
vue
<script setup lang="ts">
import { ref } from 'vue'
import '@jiangshengdev/nova-next/styles/themes.css'
import '@jiangshengdev/nova-next/styles/dropdown.css'
import '@jiangshengdev/nova-next/styles/color-picker.css'
import { NovaColorPicker } from '@jiangshengdev/nova-next'

const highlight = ref('#722ed1')
</script>

<template>
  <div class="demo-trigger">
    <NovaColorPicker v-model="highlight">
      <template #trigger>
        <button type="button" class="demo-trigger-button">
          <span class="demo-trigger-label">选中颜色</span>
          <span class="demo-trigger-value">{{ highlight }}</span>
        </button>
      </template>
    </NovaColorPicker>
  </div>
</template>

<style scoped>
.demo-trigger {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
}

.demo-trigger-button {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 8px 14px;
  border: 1px solid var(--vp-c-divider);
  border-radius: 8px;
  background: transparent;
  cursor: pointer;
  font-size: 14px;
}

.demo-trigger-value {
  font-family: ui-monospace, monospace;
}
</style>

属性

名称说明类型默认值
modelValue受控值,配合 v-model 使用,优先级高于 valuestringnull
value非受控初始值,未传入 modelValue 时生效。string'#ff0000'
alpha是否展示 Alpha 滑条与输入,关闭时会自动丢弃透明度。booleanfalse
format决定 v-model 输出格式。'hex' | 'rgb' | 'hsl''hex'
preset预设色列表,传入十六进制或 CSS 颜色字符串即可渲染拾色块。string[]null
disabled禁用状态,继承自 NovaDropdown,会阻止触发与键盘交互。booleanfalse
theme覆盖环境主题,内部同时写入 data-nova-themestringnull
placement下拉面板定位,同 NovaDropdown,支持 bottomLeft 等多个预设位置。Placement'bottomLeft'
teleportToBody是否将面板 Teleport 到 document.body,便于脱离溢出容器。booleantrue
panelClass作用于下拉面板的额外类名,可自定义尺寸与圆角。unknownnull
panelStyle作用于下拉面板的内联样式。StyleValuenull
panelProps添加到下拉面板根节点的原生属性,如 data-*Record<string, unknown>null

插槽

名称说明
trigger自定义触发器内容,保持焦点自动管理。作用域提供 colordisabledColorPickerTriggerScoped 数据。
preset自定义预设区域,可根据 preset 数组与 setColorAndPosition 方法自行渲染色卡。

事件

名称说明
updateJSX 专用更新事件,返回最新颜色字符串。
update:modelValuev-model 所需的同步事件。

NovaColorPicker 不额外派发打开/关闭事件,相关需求可通过外层 NovaDropdown 处理。

基于 MIT 许可发布