【譯】Vue實(shí)用筆記(二十七):在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的主旨是創(chuàng)建通用, 靈活,穩(wěn)定的組件。準(zhǔn)備好了嗎?出發(fā)嘍!

先看一個(gè)簡單的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>

我們希望一個(gè)組件越通用越好,這樣我們就可以在不同的網(wǎng)站重用它了。但是如何編寫一個(gè)這樣的組件呢?

首先,我們假設(shè)不只是需要一段文本內(nèi)容。如果我們想要不同的內(nèi)容,例如e <strong></strong> 或者一個(gè)icon?最好的解決辦法是實(shí)用slots

讓我們繼續(xù)剛才的話題,通常,我們的經(jīng)驗(yàn)是使用 scoped ,在不同的組件中定義CSS。但是,如果我們需要一些全局的配置CSS呢?這樣我們就違反了DRY規(guī)則。如果我們需要改變主色,我們不得不改變?nèi)魏我粋€(gè)硬編碼的地方。那么解決方案是神馬呢?實(shí)用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>

我們會(huì)在另外一個(gè)文件中自定義 :root 選擇器,但是為了清楚起見,我們現(xiàn)在當(dāng)前組件的文件中定義。

顏色和間距在web設(shè)計(jì)中經(jīng)常改變的內(nèi)容,我們需要保證不因他們的改變而改變。

通過改變屬性來影響所有的組件從而來達(dá)到重用的目的,會(huì)使得我們的組件非常靈活。

那么,如果定義一個(gè)網(wǎng)站主題呢?我們可以實(shí)用免聲明的自定義屬性。先解釋一下:

<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這些變量呢?這就是技巧了,我們沒有定義。

我們實(shí)用了一個(gè)為定義的自定義屬性但是給它了一個(gè)默認(rèn)值。所以,如果運(yùn)行時(shí),任何一個(gè)屬性沒有被定義的話,它就會(huì)回溯到它的默認(rèn)值。

這意味著,我們可以從外面定義這些屬性。

<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>

這樣非常靈活,但可能太靈活了。我們不想暴露太多細(xì)節(jié)給使用者。這個(gè)使用者可能想要自己設(shè)定一個(gè)主色來代替原來的創(chuàng)建一個(gè)新的主題。但是這個(gè)Button需要知道,它被設(shè)置了什么參數(shù)。所以讓我們來自定義屬性和主題。

<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這兩個(gè)來達(dá)到創(chuàng)建新主題的目的。
以上就是全部內(nèi)容了。感謝你讀完了全部內(nèi)容。點(diǎn)擊 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.

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 8月14日,離中元節(jié)還有最后一刻。 此時(shí)此刻,在老家 恰巧,一個(gè)間接的親人也剛剛?cè)ナ馈?明天出殯。 在靈魂深處,總...
    艷陽滿天閱讀 189評論 0 0
  • “十二兒”是一只可愛的金毛,我家的新成員。因?yàn)橐淮吻珊系臋C(jī)會(huì),爸爸的朋友轉(zhuǎn)給我們了一只快滿一歲的金毛,現(xiàn)在來說...
    馬鈴薯的媽閱讀 213評論 0 0
  • 瑜伽時(shí)的你~好美, 心晴伽園~瑜伽時(shí)的你,好好美, 美的晃的心晴忘了留影~~ 又要時(shí)時(shí)留影記錄你瑜伽始,瑜伽中,瑜...
    心晴伽園閱讀 488評論 0 1
  • 從小到大我們都渴望擁有主角光環(huán) 輕輕松松就能夠得到一切喜歡的東西 能成為那些大人們口中的“別人家的孩子” 能像《來...
    Sdft閱讀 325評論 0 2
  • 在這家臺(tái)企工作的第四年,子公司的一把手-老大高升了,吃散伙飯那天老大哭了,主管們哭了,小兵嘍嘍們也哭了,該怎么形容...
    火色石榴花閱讀 281評論 0 0

友情鏈接更多精彩內(nèi)容