如何在 ipyvuetify 中从浅色主题切换到深色主题?

how to switch from light to dark theme in ipyvuetify?

我在 Jupyter Python 环境中使用 ipyvuetify 为我的最终用户创建交互式仪表板。

我想创建一个交互式 toogle btn,将 vuitify.theme.darkTrue 切换到 False

当我使用以下代码测试此行为时:

import ipyvuetify as v

v.theme.dark = True

#validate the selected data 
v.Container(children=[
    v.Btn(color='primary', children=[
        v.Icon(left=True, children=[
            'mdi-square'
        ]),
        'Click me'
    ])
])

只有 Btn 组件的周围有深色背景,页面的其余部分保持浅色背景。

一个技巧可能是在我的 url 末尾添加 ?voila-theme=dark,但它不再是动态的。

有没有办法同时更改 voilaipyvuetify 主题?或者强制 ipyvuetify 背景占据整个屏幕?

更改 body 背景颜色

使用 Voilà(默认)实验室模板,ipyvuetify 应用程序周围的背景似乎是 HTML body 背景,因此解决方法是将 ipyvuetify 主题的背景颜色应用到body 背景。 Ipyvuetify-v.1.6.2 背景色在浅色主题中为 #fff,在深色主题中为 #121212(来自 vuetify.min.css-v2.2.26)。

可以通过在 HTML <style> 元素中添加内部 CSS 来修改背景颜色:

dark_bg = '.jp-Notebook {background-color: #121212}'
light_bg = '.jp-Notebook {background-color: #fff}'

def bg_switch(widget, event, data):
    v.theme.dark = not v.theme.dark
    css.children = [dark_bg] if v.theme.dark==True else [light_bg]

btn = v.Btn(children=[v.Icon(children=['mdi-theme-light-dark'])])
btn.on_event('click',bg_switch)

css = v.Html(tag='style', children=[dark_bg] if v.theme.dark==True else [light_bg])

v.Container(children=[css,btn])

另一种解决方案是通过设置 HTML DOM 样式 backgroundColor 属性 of body:

添加内联 CSS
class BtnTheme(v.VuetifyTemplate):
    dark = traitlets.Bool(v.theme.dark).tag(sync=True)
    template = traitlets.Unicode('''
    <v-btn icon @click="switchTheme">
      <v-icon>mdi-theme-light-dark</v-icon>
    </v-btn>
    <script> {created() {this.updateBackground()},
      methods: {
        switchTheme() {
          this.dark = !this.dark;
          this.updateBackground()
          },
        updateBackground() {
          document.body.style.backgroundColor = this.dark ? '#121212' : '#fff'
        }
      }}
    </script>''').tag(sync=True)
    
btn = BtnTheme()
ipywidgets.jslink((btn, 'dark'), (v.theme, 'dark'))

v.Container(children=[btn])

在上述解决方案中,主题按钮使用 v.theme.dark 的值初始化,即 False 除非在应用程序代码中早些时候设置为 True。另外,主题按钮可以初始化为Voilà(实验室模板)主题:

  1. 通过检查查询参数:
v.theme.dark = (os.environ.get('QUERY_STRING', '').find('dark') != -1)
  1. 或者通过在 created() 函数的开头检查 theme-darkbody 类:
  2. 中的存在
if (document.body.classList.contains('theme-dark')) {this.dark = true}

在背景颜色未知的情况下,可以通过两个虚拟元素检测这两种颜色,每个虚拟元素都使用以下两个主题之一设置样式:

class BtnTheme(v.VuetifyTemplate):
    dark = traitlets.Bool(v.theme.dark).tag(sync=True)
    v_dark_bg = traitlets.Unicode('').tag(sync=True)
    v_light_bg = traitlets.Unicode('').tag(sync=True)
    template = traitlets.Unicode('''
    <v-btn icon @click="switchTheme">
      <v-icon>mdi-theme-light-dark</v-icon>
      <div class="v-application theme--dark" id="v-dark-style"></div>
      <div class="v-application theme--light" id="v-light-style"></div>
    </v-btn>
    <script> {
      mounted() {
        this.v_dark_bg = getComputedStyle(document.getElementById("v-dark-style")).backgroundColor
        this.v_light_bg = getComputedStyle(document.getElementById("v-light-style")).backgroundColor
        if (document.body.classList.contains('theme-dark')) {this.dark = true}
        this.updateBackground()
        },
      methods: {
        switchTheme() {
          this.dark = !this.dark
          this.updateBackground()
          },
        updateBackground() {
          document.body.style.backgroundColor = this.dark ? this.v_dark_bg : this.v_light_bg
        }
      }
    }
    </script>''').tag(sync=True)

一个技巧是添加一个不透明的 Overlay 组件作为背景(z-index=-1)并在切换 ipyvuetify 主题时改变它的颜色:

import ipyvuetify as v

dark_bg = '#121212'
light_bg = '#fff'

bg = v.Overlay(
    color=dark_bg if v.theme.dark==True else light_bg, 
    opacity=1, 
    style_='transition:unset', 
    z_index=-1
)

def bg_switch(widget, event, data):
    v.theme.dark = not v.theme.dark
    bg.color = dark_bg if v.theme.dark==True else light_bg

btn = v.Btn(children=[v.Icon(children=['mdi-theme-light-dark'])])
btn.on_event('click', bg_switch)

v.Container(children=[bg, btn])

不需要 JS 代码。颜色定义来自 vuetify.min.css(ipyvuetify 1.6.2 使用的 v2.2.26):#fff 浅色主题和 #121212 深色主题。