【问题标题】:How can I bind two classes on two distinct conditions in Vue.js?如何在 Vue.js 中在两个不同的条件下绑定两个类?
【发布时间】:2021-08-10 00:35:02
【问题描述】:

我正在使用 Vue (v 2.x.x) 开发一个小型结帐步进器。

当前项目的类名应为“active”,而所有之前的项目的类名应为“completed”,如下图所示:

* {
  margin: 0;
  padding: 0;
  font-family: "Poppins", sans-serif;
}

.progressbar {
  display: flex;
  list-style-type: none;
  counter-reset: steps;
  padding-top: 50px;
  justify-content: space-between;
}

.progressbar li {
  font-size: 13px;
  text-align: center;
  position: relative;
  flex-grow: 1;
  flex-basis: 0;
  color: rgba(0, 0, 0, 0.5);
  font-weight: 600;
}

.progressbar li.completed {
  color: #ccc;
}

.progressbar li.active {
  color: #4caf50;
}

.progressbar li::after {
  counter-increment: steps;
  content: counter(steps, decimal);
  display: block;
  width: 30px;
  height: 30px;
  line-height: 30px;
  border: 2px solid rgba(0, 0, 0, 0.5);
  background: #fff;
  border-radius: 50%;
  position: absolute;
  left: 50%;
  margin-left: -15px;
  margin-top: -60px;
}

.progressbar li.active::after,
.progressbar li.completed::after {
  background: #4caf50;
  border-color: rgba(0, 0, 0, 0.15);
  color: #fff;
}

.progressbar li.completed::after {
  content: '\2713';
}

.progressbar li::before {
  content: "";
  position: absolute;
  top: -26px;
  left: -50%;
  width: 100%;
  height: 2px;
  background: rgba(0, 0, 0, 0.5);
  z-index: -1;
}

.progressbar li.active::before,
.progressbar li.completed::before,
.progressbar li.active+li::before {
  background: #4caf50;
}

.progressbar li:first-child::before {
  display: none;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.4.1/css/bootstrap.min.css" rel="stylesheet"/>

<div class="container">
  <ul class="progressbar">
    <li class="completed">Shopping cart</li>
    <li class="completed">Shipping</li>
    <li class="active">Payment</li>
    <li>Confirmation</li>
  </ul>
</div>

问题

在 Vue 中,使用 v-bind:class 我能够添加“活动”类。

我可以将“完成”类添加到适当的元素中:

<li v-for="(step, index) in steps" v-bind:class="{completed: step.completed === true}">{{step.text}}</li>

但是因为我还没有找到一种方法来在两个不同的条件下绑定两个类,所以我不能同时做这些事情

var app = new Vue({
  el: "#cart",
  data: {
    stepCounter: 1,
    steps: [
      { step: 1, completed: false, text: "Shopping cart" },
      { step: 2, completed: false, text: "Shipping" },
      { step: 3, completed: false, text: "Payment" },
      { step: 4, completed: false, text: "Confirmation" }
    ]
  },
  mounted() {},
  methods: {
    doPrev: function() {
      if (this.stepCounter > 1) {
        this.stepCounter--;
        this.doCompleted();
      }
    },
    doNext: function() {
      if (this.stepCounter < this.steps.length) {
        this.stepCounter++;
        this.doCompleted();
      }
    },
    doCompleted: function() {
      this.steps.forEach(item => {
        if(item.step < this.stepCounter){
          item.completed = true;
        }
      });
    }  
  }
});
* {
      margin: 0;
      padding: 0;
      font-family: "Poppins", sans-serif;
    }

    .progressbar {
      display: flex;
      list-style-type: none;
      counter-reset: steps;
      padding-top: 50px;
      justify-content: space-between;
    }

    .progressbar li {
      font-size: 13px;
      text-align: center;
      position: relative;
      flex-grow: 1;
      flex-basis: 0;
      color: rgba(0, 0, 0, 0.5);
      font-weight: 600;
    }

    .progressbar li.completed {
      color: #ccc;
    }

    .progressbar li.active {
      color: #4caf50;
    }

    .progressbar li::after {
      counter-increment: steps;
      content: counter(steps, decimal);
      display: block;
      width: 30px;
      height: 30px;
      line-height: 30px;
      border: 2px solid rgba(0, 0, 0, 0.5);
      background: #fff;
      border-radius: 50%;
      position: absolute;
      left: 50%;
      margin-left: -15px;
      margin-top: -60px;
    }

    .progressbar li.active::after,
    .progressbar li.completed::after {
      background: #4caf50;
      border-color: rgba(0, 0, 0, 0.15);
      color: #fff;
    }

    .progressbar li.completed::after {
      content: '\2713';
    }

    .progressbar li::before {
      content: "";
      position: absolute;
      top: -26px;
      left: -50%;
      width: 100%;
      height: 2px;
      background: rgba(0, 0, 0, 0.5);
      z-index: -1;
    }

    .progressbar li.active::before,
    .progressbar li.completed::before,
    .progressbar li.active+li::before {
      background: #4caf50;
    }

    .progressbar li:first-child::before {
      display: none;
    }
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.4.1/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.min.js"></script>

<div id="cart">
  <div class="container">
    <ul class="progressbar">
      <li v-for="(step, index) in steps" v-bind:class="{active: index + 1 === stepCounter}">{{step.text}}</li>
    </ul>
  </div>

  <div class="container mt-5 text-center">
    <div class="btn-group">
      <button type="button" class="btn btn-sm btn-success" @click="doPrev()">Previous</button>
      <button type="button" class="btn btn-sm btn-success" @click="doNext()">Next</button>
    </div>
  </div>
</div>

我该如何解决这个问题?

【问题讨论】:

    标签: javascript vue.js


    【解决方案1】:

    当您绑定类时,它使用一个 javascript 对象,您可以在其中拥有多个属性。

    这意味着您可以分配多个类:

    <li v-for="(step, index) in steps" v-bind:class="{ active: index + 1 === stepCounter, completed : index < stepCounter  }">{{step.text}}</li>
    

    Class binding

    var app = new Vue({
      el: "#cart",
      data: {
        stepCounter: 1,
        steps: [
          { step: 1, completed: false, text: "Shopping cart" },
          { step: 2, completed: false, text: "Shipping" },
          { step: 3, completed: false, text: "Payment" },
          { step: 4, completed: false, text: "Confirmation" }
        ]
      },
      mounted() {},
      methods: {
        doPrev: function() {
          if (this.stepCounter > 1) {
            this.stepCounter--;
          }
        },
        doNext: function() {
          if (this.stepCounter < this.steps.length) {
            this.stepCounter++;
            this.doCompleted();
          }
        },
        doCompleted: function() {
          this.steps.forEach(item => {
            if(item.step < this.stepCounter){
              item.completed = true;
            }
          });
        }  
      }
    });
    * {
          margin: 0;
          padding: 0;
          font-family: "Poppins", sans-serif;
        }
    
        .progressbar {
          display: flex;
          list-style-type: none;
          counter-reset: steps;
          padding-top: 50px;
          justify-content: space-between;
        }
    
        .progressbar li {
          font-size: 13px;
          text-align: center;
          position: relative;
          flex-grow: 1;
          flex-basis: 0;
          color: rgba(0, 0, 0, 0.5);
          font-weight: 600;
        }
    
        .progressbar li.completed {
          color: #ccc;
        }
    
        .progressbar li.active {
          color: #4caf50;
        }
    
        .progressbar li::after {
          counter-increment: steps;
          content: counter(steps, decimal);
          display: block;
          width: 30px;
          height: 30px;
          line-height: 30px;
          border: 2px solid rgba(0, 0, 0, 0.5);
          background: #fff;
          border-radius: 50%;
          position: absolute;
          left: 50%;
          margin-left: -15px;
          margin-top: -60px;
        }
    
        .progressbar li.active::after,
        .progressbar li.completed::after {
          background: #4caf50;
          border-color: rgba(0, 0, 0, 0.15);
          color: #fff;
        }
    
        .progressbar li.completed::after {
          content: '\2713';
        }
    
        .progressbar li::before {
          content: "";
          position: absolute;
          top: -26px;
          left: -50%;
          width: 100%;
          height: 2px;
          background: rgba(0, 0, 0, 0.5);
          z-index: -1;
        }
    
        .progressbar li.active::before,
        .progressbar li.completed::before,
        .progressbar li.active+li::before {
          background: #4caf50;
        }
    
        .progressbar li:first-child::before {
          display: none;
        }
    <link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.4.1/css/bootstrap.min.css" rel="stylesheet"/>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.min.js"></script>
    
    <div id="cart">
      <div class="container">
        <ul class="progressbar">
          <li v-for="(step, index) in steps" v-bind:class="{active: index + 1 === stepCounter, completed : index < stepCounter  }">{{step.text}}</li>
        </ul>
      </div>
    
      <div class="container mt-5 text-center">
        <div class="btn-group">
          <button type="button" class="btn btn-sm btn-success" @click="doPrev()">Previous</button>
          <button type="button" class="btn btn-sm btn-success" @click="doNext()">Next</button>
        </div>
      </div>
    </div>

    【讨论】:

      【解决方案2】:

      您可以通过在绑定上使用数组来为您需要的条件添加更多类,如下所示:

      <li v-for="(step, index) in steps" v-bind:class="[{completed: index < stepCounter-1},{active: index + 1 === stepCounter}]">{{step.text}}</li>
      

      【讨论】:

        【解决方案3】:

        请参阅下面修改的代码,您还可以使用基于参数生成类的方法,这使标记更清晰,并使用中心方法生成正确的类。

        var app = new Vue({
          el: "#cart",
          data: {
            stepCounter: 1,
            steps: [
              { step: 1, completed: false, text: "Shopping cart" },
              { step: 2, completed: false, text: "Shipping" },
              { step: 3, completed: false, text: "Payment" },
              { step: 4, completed: false, text: "Confirmation" }
            ]
          },
          mounted() {},
          methods: {
            doPrev: function() {
              if (this.stepCounter > 1) {
                this.stepCounter--;
              }
            },
            doNext: function() {
              if (this.stepCounter < this.steps.length) {
                this.stepCounter++;
                this.doCompleted();
              }
            },
            doCompleted: function() {
              this.steps.forEach(item => {
                if(item.step < this.stepCounter){
                  item.completed = true;
                }
              });
            },
            getClass: function(index, step) {
              var values = [];
              if (index + 1 === this.stepCounter) values.push('active');
              if (step.completed) values.push('completed');
              return values.join(' ');
            }
          }
        });
        * {
              margin: 0;
              padding: 0;
              font-family: "Poppins", sans-serif;
            }
        
            .progressbar {
              display: flex;
              list-style-type: none;
              counter-reset: steps;
              padding-top: 50px;
              justify-content: space-between;
            }
        
            .progressbar li {
              font-size: 13px;
              text-align: center;
              position: relative;
              flex-grow: 1;
              flex-basis: 0;
              color: rgba(0, 0, 0, 0.5);
              font-weight: 600;
            }
        
            .progressbar li.completed {
              color: #ccc;
            }
        
            .progressbar li.active {
              color: #4caf50;
            }
        
            .progressbar li::after {
              counter-increment: steps;
              content: counter(steps, decimal);
              display: block;
              width: 30px;
              height: 30px;
              line-height: 30px;
              border: 2px solid rgba(0, 0, 0, 0.5);
              background: #fff;
              border-radius: 50%;
              position: absolute;
              left: 50%;
              margin-left: -15px;
              margin-top: -60px;
            }
        
            .progressbar li.active::after,
            .progressbar li.completed::after {
              background: #4caf50;
              border-color: rgba(0, 0, 0, 0.15);
              color: #fff;
            }
        
            .progressbar li.completed::after {
              content: '\2713';
            }
        
            .progressbar li::before {
              content: "";
              position: absolute;
              top: -26px;
              left: -50%;
              width: 100%;
              height: 2px;
              background: rgba(0, 0, 0, 0.5);
              z-index: -1;
            }
        
            .progressbar li.active::before,
            .progressbar li.completed::before,
            .progressbar li.active+li::before {
              background: #4caf50;
            }
        
            .progressbar li:first-child::before {
              display: none;
            }
        <link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.4.1/css/bootstrap.min.css" rel="stylesheet"/>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.min.js"></script>
        
        <div id="cart">
          <div class="container">
            <ul class="progressbar">
              <li v-for="(step, index) in steps" v-bind:class="getClass(index, step)">{{step.text}}</li>
            </ul>
          </div>
        
          <div class="container mt-5 text-center">
            <div class="btn-group">
              <button type="button" class="btn btn-sm btn-success" @click="doPrev()">Previous</button>
              <button type="button" class="btn btn-sm btn-success" @click="doNext()">Next</button>
            </div>
          </div>
        </div>

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-02-06
          • 1970-01-01
          • 1970-01-01
          • 2021-07-05
          • 2019-10-15
          • 2019-04-30
          • 2023-03-30
          • 1970-01-01
          相关资源
          最近更新 更多