【译】Vue实用笔记(二十七):在Vue组件中通过自定义css属性来自定义主题

作者: Cesar Alberca (@cesalberca), a frontend developer at Autentia that have worked with Vue professionally for 2 years and counting. He’s also done projects in React and Angular and he’s passionate about good practices and testing.

I met Cesar at the last Codemotion Madrid conference and I have to say he’s a really cool guy with lots of potential! Don’t expect too little from this tip 😉.

正文开始


大家好哇!VueDoes的主旨是创建通用灵活稳定的组件。准备好了吗?出发喽!

先看一个简单的button

<template>
  <button><slot/></button>
</template>

<script>
export default {
  name: "AppButton",
};
</script>

<style scoped>
button {
  border: 4px solid #41b883;
  padding: 12px 24px;
  transition: 0.25s ease-in-out all;
}

button:hover {
  color: white;
  background-color: #41b883;
}
</style>

我们希望一个组件越通用越好,这样我们就可以在不同的网站重用它了。但是如何编写一个这样的组件呢?

首先,我们假设不只是需要一段文本内容。如果我们想要不同的内容,例如e <strong></strong> 或者一个icon?最好的解决办法是实用slots

让我们继续刚才的话题,通常,我们的经验是使用 scoped ,在不同的组件中定义CSS。但是,如果我们需要一些全局的配置CSS呢?这样我们就违反了DRY规则。如果我们需要改变主色,我们不得不改变任何一个硬编码的地方。那么解决方案是神马呢?实用custom properties

<style scoped>
:root {
  --primary-color: #41b883;
  --on-primary-color: white;

  --small-spacing: 12px;
  --normal-spacing: calc(var(--small-spacing) * 2);
}

button {
  border: 4px solid var(--primary-color);
  padding: var(--small-spacing) var(--normal-spacing);
  transition: 0.25s ease-in-out all;
}

button:hover {
  color: var(--on-primary-color);
  background-color: var(--primary-color);
}
</style>

我们会在另外一个文件中自定义 :root 选择器,但是为了清楚起见,我们现在当前组件的文件中定义。

颜色和间距在web设计中经常改变的内容,我们需要保证不因他们的改变而改变。

通过改变属性来影响所有的组件从而来达到重用的目的,会使得我们的组件非常灵活。

那么,如果定义一个网站主题呢?我们可以实用免声明的自定义属性。先解释一下:

<style scoped>
button {
  border: 4px solid var(--button-border-color, var(--primary-color));
  padding: var(--small-spacing) var(--normal-spacing);
  transition: 0.25s ease-in-out all;
}

button:hover {
  color: var(--button-hover-text-color, var(--on-primary-color));
  background-color: var(--button-hover-background-color, var(--primary-color));
}
</style>

我们在哪里定义--button-border-color, --button-hover-text-color and --button-hover-background-color这些变量呢?这就是技巧了,我们没有定义。

我们实用了一个为定义的自定义属性但是给它了一个默认值。所以,如果运行时,任何一个属性没有被定义的话,它就会回溯到它的默认值。

这意味着,我们可以从外面定义这些属性。

<template>
  <AppButton class="custom-theme">Hello VueDose!</AppButton>
</template>

<style scoped>
.custom-theme {
  --button-border-color: pink;
  --button-hover-background-color: rgb(206, 161, 195);
}
</style>

这样非常灵活,但可能太灵活了。我们不想暴露太多细节给使用者。这个使用者可能想要自己设定一个主色来代替原来的创建一个新的主题。但是这个Button需要知道,它被设置了什么参数。所以让我们来自定义属性和主题

<template>
  <button :style="getTheme"><slot/></button>
</template>

<script>
export default {
  name: "AppButton6",
  props: {
    theme: String,
    validator: (theme) => ['primary', 'secondary'].includes(theme)
  },
  computed: {
    getTheme() {
      const createButtonTheme = ({
        borderColor,
        hoverTextColor,
        hoverBackgroundColor
      }) => ({
        '--button-border-color': borderColor,
        '--button-hover-text-color': hoverTextColor,
        '--button-hover-background-color': hoverBackgroundColor
      })

      const primary = createButtonTheme({
        borderColor: 'var(--primary-color)',
        hoverTextColor: 'var(--on-primary-color)',
        hoverBackgroundColor: 'var(--primary-color)'
      })

      const secondary = createButtonTheme({
        borderColor: 'var(--secondary-color)',
        hoverTextColor: 'var(--on-secondary-color)',
        hoverBackgroundColor: 'var(--secondary-color)'
      })

      const themes = {
        primary,
        secondary
      }

      return themes[this.theme]
    }
  }
};
</script>

So we can do this easily:

<AppButton theme="secondary">Hello VueDose!</AppButton>

And finally. All the cool kids nowadays are doing dark themes right?

<template>
  <main class="wrapper" :class="mode">
    <AppButton @click.native="toggleTheme" theme="secondary">
      Click me to change to dark mode!
    </AppButton>
  </main>
</template>

<script>
import AppButton from "./components/AppButton";

export default {
  name: "App",
  data: () => ({
    mode: 'light'
  }),
  components: {
    AppButton
  },
  methods: {
    toggleTheme() {
      this.mode = this.mode === 'light' ? 'dark' : 'light'
    }
  }
};
</script>
<style scoped>
.light {
  --background-color: white;
  --on-background-color: #222;
}

.dark {
  --background-color: #222;
  --on-background-color: white;
}

.wrapper {
  transition: 1s ease-in-out background-color;
  background-color: var(--background-color);
  color: var(--on-background-color);
}
</style>

我们可以切换 --background-color--on-background-color这两个来达到创建新主题的目的。
以上就是全部内容了。感谢你读完了全部内容。点击 this CodeSandbox!

Here it goes today’s tip!

Remember you can read this tip online (with copy/pasteable code), and don’t forget to share VueDose with your colleagues, so they also know about these tips as well!

See you soon.

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 8月14日,离中元节还有最后一刻。 此时此刻,在老家 恰巧,一个间接的亲人也刚刚去世。 明天出殡。 在灵魂深处,总...
    艳阳满天阅读 198评论 0 0
  • “十二儿”是一只可爱的金毛,我家的新成员。因为一次巧合的机会,爸爸的朋友转给我们了一只快满一岁的金毛,现在来说...
    马铃薯的妈阅读 229评论 0 0
  • 瑜伽时的你~好美, 心晴伽园~瑜伽时的你,好好美, 美的晃的心晴忘了留影~~ 又要时时留影记录你瑜伽始,瑜伽中,瑜...
    心晴伽园阅读 499评论 0 1
  • 从小到大我们都渴望拥有主角光环 轻轻松松就能够得到一切喜欢的东西 能成为那些大人们口中的“别人家的孩子” 能像《来...
    Sdft阅读 327评论 0 2
  • 在这家台企工作的第四年,子公司的一把手-老大高升了,吃散伙饭那天老大哭了,主管们哭了,小兵喽喽们也哭了,该怎么形容...
    火色石榴花阅读 286评论 0 0

友情链接更多精彩内容