You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Jupyter Notebook中实现带颜色预览的自定义下拉选择组件?

如何在Jupyter Notebook中实现带颜色预览的自定义下拉选择组件?

我的问题

我已经折腾好几个小时了,想在Jupyter Notebook里用组件实现一个带颜色预览的自定义下拉选择器——就是下拉列表里每个选项能显示颜色方块+颜色名称的那种。

我知道纯HTML的select只能显示文本,所以先试了ipywidgets做基础逻辑,后来转到ipyvuetify(从1.10.0换到3.0.0.a2),想靠它的自定义能力实现效果。我试过v-select的v_slots、children,最后甚至用了v.VuetifyTemplate,直接参考Vuetify的文档来写,但还是没搞定。

现在我写了这样的代码:

import ipyvuetify as v
import traitlets
from typing import Annotated
import enum

class ColorSelector(v.VuetifyTemplate):
    items = traitlets.List(traitlets.Dict(traitlets.Unicode()), default_value=[{"name": "test", "value": "test"}]).tag(sync=True)
    selected = traitlets.Unicode(default_value=None, allow_none=True).tag(sync=True)
    label = traitlets.Unicode(default_value="Color", allow_none=True).tag(sync=True)
    
    @traitlets.default("template")
    def _template(self):
        return '''
        <template>
            <v-select 
                :items="items" 
                item-title="name" 
                item-value="value" 
                v-model="selected" 
                label="'''+self.label+'''"
                class="mx-3">
                
                <template v-slot:item="{ props, item }">
                  <v-list-item v-bind="props" :key="item.value" @click="item_click(item.value)">
                    <div>
                      <v-icon left small :color="item.value"></v-icon>
                      <span>{{ item.value }}</span>
                    </div>
                  </v-list-item>
                </template>
            </v-select>
        </template>
        '''
    
    def vue_item_click(self, value):
      print(repr(value))
      self.selected = value

# 测试用的颜色枚举
class TestColor(str, enum.Enum):
    PALEVIOLETRED: Annotated[str, "#DB7093"] = "PaleVioletRed"
    YELLOWGREEN: Annotated[str, "#9ACD32"] = "YellowGreen"
    LIGHTCORAL: Annotated[str, "#F08080"] = "LightCoral"
    THISTLE: Annotated[str, "#D8BFD8"] = "Thistle"

wid_favorite_color = ColorSelector(
    items = [
            {
                "name": c.name,
                "value": c.value
            }
            for c in TestColor
    ],
    label = "Favorite Color"
)

display(wid_favorite_color)

但现在的问题是:自定义的颜色预览根本不显示,选择功能也不正常——选完之后下拉框里显示[object Object]或者空,菜单也不会自动关闭,完全不是我想要的效果。

我查了Vuetify的select item slot文档,没说要自己处理点击事件;后来参考ipyvuetify的菜单示例加了@click和:key,但还是不对。我肯定是哪里没搞明白,求帮忙!我就想要个带颜色预览的下拉而已😭


解决方案

兄弟我懂你这种卡壳的痛苦!其实你离成功只差几个小细节的调整,咱们一步步来改:

问题根源分析

  1. 你的item数据里缺少颜色的十六进制值,没法生成真实的颜色方块
  2. 自定义的@click覆盖了Vuetify默认的选择逻辑,导致菜单不关闭、值同步异常
  3. 用v-icon显示颜色不是最优解,而且模板里的label绑定方式不支持响应式更新

修改后的完整代码

import ipyvuetify as v
import traitlets
from typing import Annotated
import enum

class ColorSelector(v.VuetifyTemplate):
    items = traitlets.List(traitlets.Dict(traitlets.Unicode()), 
                           default_value=[{"name": "test", "value": "test", "hex": "#000000"}]).tag(sync=True)
    selected = traitlets.Unicode(default_value=None, allow_none=True).tag(sync=True)
    label = traitlets.Unicode(default_value="Color", allow_none=True).tag(sync=True)
    
    @traitlets.default("template")
    def _template(self):
        return '''
        <template>
            <v-select 
                :items="items" 
                :label="label"  <!-- 用Vue响应式绑定,支持动态更新 -->
                v-model="selected" 
                class="mx-3"
                return-object  <!-- 让v-model绑定整个item对象,方便后续显示 -->
            >
                <!-- 自定义下拉选项的显示样式 -->
                <template v-slot:item="{ props, item }">
                  <!-- 继承默认的选中、点击逻辑,不用自己写@click -->
                  <v-list-item v-bind="props">
                    <v-list-item-avatar style="min-width: 24px; width: 24px; height: 24px; border-radius: 2px;">
                      <!-- 用div生成纯色方块,直接绑定hex值 -->
                      <div :style="{ background: item.hex, width: '100%', height: '100%' }"></div>
                    </v-list-item-avatar>
                    <v-list-item-title>{{ item.name }}</v-list-item-title>
                  </v-list-item>
                </template>
                
                <!-- 自定义选中后下拉框的显示内容 -->
                <template v-slot:selection="{ item }">
                  <div style="display: flex; align-items: center; gap: 8px;">
                    <div :style="{ background: item.hex, width: 16px, height: 16px, border-radius: 2px }"></div>
                    <span>{{ item.name }}</span>
                  </div>
                </template>
            </v-select>
        </template>
        '''

# 测试用的颜色枚举,保留Annotated的hex值
class TestColor(str, enum.Enum):
    PALEVIOLETRED: Annotated[str, "#DB7093"] = "PaleVioletRed"
    YELLOWGREEN: Annotated[str, "#9ACD32"] = "YellowGreen"
    LIGHTCORAL: Annotated[str, "#F08080"] = "LightCoral"
    THISTLE: Annotated[str, "#D8BFD8"] = "Thistle"

# 从枚举的Annotated注解中提取颜色十六进制值
def get_color_hex(color_enum):
    for annotation in color_enum.__annotations__.values():
        if hasattr(annotation, '__metadata__'):
            return annotation.__metadata__[0]
    return "#000000"

# 初始化颜色选择器
wid_favorite_color = ColorSelector(
    items = [
            {
                "name": c.name,
                "value": c.value,
                "hex": get_color_hex(c)
            }
            for c in TestColor
    ],
    label = "Favorite Color"
)

display(wid_favorite_color)

关键调整点说明

  1. 完善item数据结构:给每个选项新增hex字段,存储颜色的十六进制值,这是生成颜色方块的核心数据
  2. 恢复默认选择逻辑:删掉自定义的@click,通过v-bind="props"继承Vuetify原生的点击、选中行为,解决菜单不关闭、值同步异常的问题
  3. 优化颜色显示方式:用普通div生成纯色块代替v-icon,样式更灵活,直接通过:style绑定item.hex实现颜色预览
  4. 添加selection slot:自定义选中后下拉框的显示内容,让选中状态也能看到颜色方块+名称,体验更统一
  5. 响应式label绑定:把模板里的字符串拼接改成:label="label",支持后续动态修改label属性
  6. 正确提取枚举颜色值:新增get_color_hex函数,从Annotated注解中提取预设的颜色十六进制值,让数据更完整

这样改完之后,你就能得到一个完美的带颜色预览的下拉选择器啦!如果想调整色块样式(比如改成圆形),只要修改div的border-radius为50%就行~


备注:内容来源于stack exchange,提问作者Tehoor Marjan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.14 15:28:04