【问题标题】:Multiple instances of same component, one with unique style?同一组件的多个实例,一个具有独特风格?
【发布时间】:2022-01-13 19:45:28
【问题描述】:

我正在构建一个包含三个卡片组件的页面。三张牌中的一张(中间一张)的样式与其他两张不同,我无法做到这一点。这是我到目前为止所拥有的......

Card.svelte(下)

<script>
  export let subLevel;
  export let price;
  export let users;
  export let storage;
  export let sendLimit;
  import Button from "./Button.svelte";
</script>

<div class="card">
  <h2>{subLevel}</h2>
  <ul>
    <li class="price"><span class="dollar">$</span>{price}</li>
    <li class="spec">{storage} Storage</li>
    <li class="spec">{users} Users Allowed</li>
    <li class="spec">Send up to {sendLimit} GB</li>
  </ul>
  <Button>Learn more</Button>
</div>

<style>
  .card {
    display: flex;
    flex-flow: column nowrap;
    align-items: center;
    padding-top: 2rem;
    background-color: #fff;
    border-radius: 10px;
    max-width: 350px;
    color: var(--gray-blue);
    padding-inline: 29px;
  }
  .dollar {
    font-size: 2.5rem;
    margin-right: 0.5rem;
  }
  .price {
    display: flex;
    font-size: 4.5rem;
    align-items: center;
    justify-content: center;
    border-top: none;
    color: var(--dark-gray-blue);
  }
  ul {
    width: 100%;
    list-style: none;
    text-align: center;
  }
  li {
    text-decoration: none;
    border-top: 1px solid var(--gray-blue);
    padding-block: 13px;
  }
  li:last-child {
    border-bottom: 1px solid var(--gray-blue);
  }
</style>

Button.svelte(下)

<button><slot /></button>

<style>
  button {
    text-transform: uppercase;
    width: 100%;
    background: linear-gradient(135deg, #a2a7f0, #696edd);
    color: #fff;
    font-size: 0.8125rem;
    letter-spacing: 1.39px;
    padding-block: 0.875rem;
    border: none;
    border-radius: 6px;
    cursor: pointer;
    margin-block: 2rem;
  }
</style>

App.svelte(下)

<script>
  import Card from "./components/Card.svelte";
  import Footer from "./components/Footer.svelte";

  // Card details
  const basicMonthly = {
    subLevel: "Basic",
    price: 19.99,
    storage: "500 GB",
    users: 2,
    sendLimit: 3,
  };
  const proMonthly = {
    subLevel: "Professional",
    price: 24.99,
    storage: "1 TB",
    users: 5,
    sendLimit: 10,
  };
  const masterMonthly = {
    subLevel: "Master",
    price: 39.99,
    storage: "2 TB",
    users: 10,
    sendLimit: 20,
  };
</script>

<main class="site-content">
  <Card {...basicMonthly} />
  <Card {...proMonthly} />
  <Card {...masterMonthly} />
</main>
<Footer />

<style>
</style>

我的问题是:如何为第二个 Card 组件添加独特的样式?它应该具有以下样式:

中间组件的样式(下)

<style>
  .card {
    display: flex;
    flex-flow: column nowrap;
    align-items: center;
    padding-top: 2rem;
    background-color: linear-gradient(135deg, #a2a7f0, #696edd);
    border-radius: 10px;
    max-width: 350px;
    color: #fff;
    padding-inline: 29px;
  }
  .dollar {
    font-size: 2.5rem;
    margin-right: 0.5rem;
  }
  .price {
    display: flex;
    font-size: 4.5rem;
    align-items: center;
    justify-content: center;
    border-top: none;
    color: #fff;
  }
  ul {
    width: 100%;
    list-style: none;
    text-align: center;
  }
  li {
    text-decoration: none;
    border-top: 1px solid #fff;
    padding-block: 13px;
  }
  li:last-child {
    border-bottom: 1px solid #fff;
  }
</style>

... 和 Button.svelte 也必须在该中间组件上进行更改。它的样式应该如下:

<style>
  button {
    text-transform: uppercase;
    width: 100%;
    background: #fff;
    color: #6d72de;
    font-size: 0.8125rem;
    letter-spacing: 1.39px;
    padding-block: 0.875rem;
    border: none;
    border-radius: 6px;
    cursor: pointer;
    margin-block: 2rem;
  }
</style>

我是 Svelte 的新手,完全被这个难住了。我尝试过使用$$restProps 和动态样式,但我似乎无法深入了解我需要的按钮和嵌套在卡片div 中的各种元素。

这可以通过 Svelte 实现吗,还是我应该简单地构建另一个组件来满足我的需要?当然还有另一种(更干燥的)方法可以做到这一点?非常感谢任何帮助!

【问题讨论】:

    标签: svelte svelte-component


    【解决方案1】:

    有很多不同的方法可以解决这个问题,但我会做以下事情:

    1. 在 Card 和 Button 组件中引入一个名为“secondary”的布尔属性。这将默认为 false,但对于中间卡将设置为 true。控制我们是否应用替代样式。 Card 会将其传递给 Button 组件,因此如果 secondary = true 为 Card ,它也将等于 true 。

      export let secondary = false;
      
      <!-- App.svelte -->
      <main class="site-content">
        <Card {...basicMonthly} />
        <Card secondary {...proMonthly} />
        <Card {...masterMonthly} />
      </main>
      
      <!-- Card.svelte -->
      <!-- ... rest of template -->
      <Button {secondary}>Learn more</Button>
      

      如果您最终有多个不同的变体,则将其设为字符串可能是有意义的,例如variant="secondary"variant="tertiary"

    2. 根据secondary prop 是否为真,将类“secondary”添加到Card 和Button。 Svelte 的class directive 让这一切变得简单。

      <!-- Card.svelte -->
      <div class="card" class:secondary>
      
      <!-- Button.svelte -->
      <button class:secondary><slot /></button>
      
    3. 应用以下样式。虽然您为第二张卡片粘贴了许多不同的样式,但唯一改变的是背景和文本颜色。我将这些值移动到CSS custom properties。应用 secondary 类时,自定义属性会更新,其他所有内容都会使用新颜色。

      <!-- Card.svelte styles -->
      <style>
        .card {
          --background: #fff;
          --text-color: var(--gray-blue);
      
          display: flex;
          flex-flow: column nowrap;
          align-items: center;
          padding-top: 2rem;
          background: var(--background);
          border-radius: 10px;
          max-width: 350px;
          color: var(--text-color);
          padding-inline: 29px;
        }
      
        .card.secondary {
          --background: linear-gradient(135deg, #a2a7f0, #696edd);
          --text-color: #fff;
        }
      
        .dollar {
          font-size: 2.5rem;
          margin-right: 0.5rem;
        }
      
        .price {
          display: flex;
          font-size: 4.5rem;
          align-items: center;
          justify-content: center;
          border-top: none;
          color: var(--text-color);
        }
      
        ul {
          width: 100%;
          list-style: none;
          text-align: center;
        }
      
        li {
          text-decoration: none;
          border-top: 1px solid var(--text-color);
          padding-block: 13px;
        }
      
        li:last-child {
          border-bottom: 1px solid var(--text-color);
        }
      </style>
      
      <!-- Button.svelte styles -->
      <style>
        button {
          --background: linear-gradient(135deg, #a2a7f0, #696edd);
          --text-color: #fff;
      
          text-transform: uppercase;
          width: 100%;
          background: var(--background);
          color: var(--text-color);
          font-size: 0.8125rem;
          letter-spacing: 1.39px;
          padding-block: 0.875rem;
          border: none;
          border-radius: 6px;
          cursor: pointer;
          margin-block: 2rem;
        }
      
        button.secondary {
          --background: #fff;
          --text-color: #6d72de;
        }
      </style>
      

    有了这些更新,没有重复,您也不必创建单独的组件。您可以在 Svelte REPL 中看到最终演示。

    【讨论】:

    • 太好了——谢谢!我通过在第二个 Card 组件周围添加 div 并使用 :global... 设置样式来“暂时”解决了这个问题,但它非常不整洁,并且引入了比严格需要的更多的标记。我怀疑必须有一种更惯用的方法。这完全符合要求。
    猜你喜欢
    • 1970-01-01
    • 2018-11-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-24
    • 2023-03-23
    • 1970-01-01
    • 2022-10-26
    相关资源
    最近更新 更多