Vue v-bind:class在循环外时

时间:2019-02-05 12:17:19

标签: class vue.js

我有一些文章列表,这些文章列表通过json文件按类别进行了过滤。过滤器全部正常工作,但是在json文件中没有一个存档部分,该部分位于v-for循环之外。我正在寻找一种Vue方式,可以将活动类添加到存档过滤器中,我已经创建了codepen(Vue过滤器json提要),您可以在其中查看我在做什么。

Array.prototype.unique = function() {
  return this.filter(function(value, index, self) {
    return self.indexOf(value) === index;
  });
}

var vm = new Vue({
  el: '#app',
  data: {
    items: [],
    errors: [],
    cats: [],
    allItems: [],
    isActive: false,
    catsCount: [],
    filteredItems: [],
    selectedItem: "Event",
    currentPage: 0,
    pageSize: 6
  },

  created() {
    axios
      .get(`https://codepen.io/struthy/pen/qgXJZJ.js`)
      .then(response => {
        // JSON responses are automatically parsed.
        this.items = response.data;
        this.cats = this.items.map(item => item.itemType).unique();
        // this.catsCount = this.items.map(item => item.itemType).unique();
      })
      .catch(e => {
        this.errors.push(e);
      });
  },

  computed: {
    filteredPage: function() {
      var itemSelectedType = this.selectedItem;

      if (this.selectedItem === "All") {
        return this.items
          .sort(function(a, b) {
            return new Date(a.published) - new Date(b.published)
          })
          .slice(0, (this.currentPage * this.pageSize) + this.pageSize)

      } else {
        return this.items
          .sort(function(a, b) {
            if (this.selectedItem != "event") {
              return new Date(a.published) - new Date(b.published)
            }
            // else{
            //   return new Date(a.endDate) - new Date(b.endDate)
            // }
          })
          .filter(function(item) {
            return item.itemType === itemSelectedType;
          }).slice(0, (this.currentPage * this.pageSize) + this.pageSize);
      }
    }, // end filteredPage

    showMore: function() {
      var itemSelectedType = this.selectedItem;

      if (this.items.filter(function(item) {
          return item.itemType == itemSelectedType
        }).length > (this.pageSize * (this.currentPage + 1))) {
        return true;
      } else if (this.items.length > (this.pageSize * (this.currentPage + 1))) {
        return true; // this is all or unfiltered items
      }
      else {
        return false;
      }
    }, // end showMore
  }, // end computed

methods: {
  // give an active class to the filter items
  activeItem: function(category) {
    if (this.selectedItem === category){
        return "isActive"
    } else {
      return ""
    }
  }, // end activeItem

  /// trying to add an active class to the archive link - not succesful yet
  activeAllItem: function() {
    var allCategory = this.cats
    if (this.selectedItem === !allCategory){
        return isActive == true
    } else {
      return isActive == true
    }
  } // end activeItem

}

});
.grid {
  display: flex;
  flex-wrap: wrap;
  list-style: none;
  margin: 0;
  padding: 0; }
  .grid--space-between {
    justify-content: space-between; }
  .grid--full {
    width: 100%; }
  .grid--third {
    width: calc(100% / 12 * 4); }
  .grid--2third {
    width: calc(100% / 12 * 8); }
    @media only screen and (max-width: 768px) {
      .grid--2third {
        width: 100%; } }
  .grid__container {
    padding-top: 60px;
    padding-bottom: 60px;
    border-top: 1px solid #e3e3e3;
    display: flex;
    flex-wrap: wrap; }
    .grid__container--padding-left-right {
      padding-left: 7.03125%;
      padding-right: 7.03125%; }
    .grid__container--space-between {
      justify-content: space-between; }
  .grid__col {
    width: 32%;
    display: flex;
    min-height: 330px;
    margin-bottom: 20px; }
    @media only screen and (max-width: 1100px) {
      .grid__col {
        width: 49%; } }
    @media only screen and (max-width: 640px) {
      .grid__col {
        width: 100%; } }
    .grid__col--half {
      width: 48%; }
      .grid__col--half h2 {
        padding: 20px 0 0 0; }
      @media only screen and (max-width: 768px) {
        .grid__col--half {
          width: 100%; } }
    .grid__col--border {
      margin-bottom: 60px;
      border-bottom: 4px solid #002A48;
      padding-bottom: 60px; }
    .grid__col--column {
      flex-direction: column; }
  .grid__img {
    align-self: flex-start; }
  .grid__arrow-link {
    font-size: 2rem;
    font-family: 'Poppins', sans-serif;
    font-weight: bold;
    position: relative;
    width: fit-content; }
    .grid__arrow-link:after {
      content: " ";
      position: absolute;
      right: -32px;
      top: 10px;
      width: 28px;
      height: 10px;
      background: url(../assets/img/ream-more-blue.png) center no-repeat; }
  .grid__box {
    background-size: cover;
    background-position: center;
    display: flex;
    height: 100%;
    width: 100%;
    flex-direction: column;
    justify-content: flex-end;
    position: relative;
    overflow: hidden; }
    .grid__box:hover p {
      color: #6CB7E3; }
    .grid__box--variation {
      background-color: #6CB7E3;
      color: #fff;
      justify-content: space-between; }
      .grid__box--variation:hover {
        background-color: #57addf; }
        .grid__box--variation:hover p {
          color: #fff; }
  .grid__bg-img {
    background-size: cover;
    background-position: center -50px;
    display: flex;
    height: 100%;
    width: 100%;
    flex-direction: column;
    justify-content: flex-end;
    transform: scale(1);
    -moz-transition: all 0.3s ease-in-out;
    -webkit-transition: all 0.3s ease-in-out;
    -o-transition: all 0.3s ease-in-out;
    transition: all 0.3s ease-in-out; }
    .grid__bg-img:hover {
      transform: scale(1.1);
      -moz-transition: all 0.3s ease-in-out;
      -webkit-transition: all 0.3s ease-in-out;
      -o-transition: all 0.3s ease-in-out;
      transition: all 0.3s ease-in-out; }
  .grid__head {
    padding: 30px 20px 0; }
    .grid__head h3 {
      color: #fff;
      font-size: 3.8rem;
      margin-bottom: 20px; }
  .grid__caption {
    padding: 20px 20px 0;
    position: absolute;
    bottom: 0;
    left: 0;
    width: 100%; }
    .grid__caption--basic {
      background-color: #e3e3e3; }
    .grid__caption--variation {
      background-color: #6CB7E3; }
    .grid__caption h3 {
      font-size: 2.8rem;
      line-height: 0.7;
      padding-bottom: 0;
      margin-bottom: 10px;
      font-family: 'Poppins', sans-serif; }
  .grid__link {
    font-size: 2rem;
    font-weight: 700;
    position: relative;
    width: fit-content; }
    .grid__link--basic {
      color: #6CB7E3; }
    .grid__link:after {
      content: " ";
      position: absolute;
      right: -32px;
      top: 10px;
      width: 28px;
      height: 10px;
      background: url(../assets/img/ream-more-blue.png) center no-repeat; }
    .grid__link--variation {
      color: #fff; }
      .grid__link--variation:after {
        background: url(../assets/img/ream-more-white.png) center no-repeat; }
  .grid:after {
    content: "";
    width: 32%; }

.fullpage-img {
  background-size: cover;
  background-position: center;
  width: 100%;
  height: 600px;
  display: flex;
  justify-content: center;
  flex-direction: row;
  position: relative; }
  .fullpage-img:before {
    content: " ";
    position: absolute;
    height: 100%;
    width: 100%;
    top: 0;
    left: 0;
    background-color: rgba(0, 42, 72, 0.8); }
  .fullpage-img__text {
    z-index: 99;
    align-self: center;
    color: #fff;
    width: calc(100% / 12 * 8);
    text-align: center; }
    .fullpage-img__text h3 {
      font-size: 4.4rem;
      line-height: 1.363;
      font-family: 'Poppins', sans-serif;
      font-weight: 700;
      color: #fff; }
    .fullpage-img__text a {
      font-weight: 700;
      position: relative;
      font-size: 2rem; }
      .fullpage-img__text a:after {
        content: " ";
        position: absolute;
        right: -32px;
        top: 10px;
        width: 28px;
        height: 10px;
        background: url(../assets/img/ream-more-blue.png) center no-repeat; }

.opportunitiesFilter {
  width: calc(100% / 12 * 3);
  list-style: none;
  margin: 0;
  padding: 0;
  height: 300px; }
  @media only screen and (max-width: 768px) {
    .opportunitiesFilter {
      width: 100%;
      margin-bottom: 30px; } }
  .opportunitiesFilter__filter-head {
    background: #002A48;
    padding: 20px;
    font-size: 2.3rem;
    font-weight: 700;
    color: #fff;
    display: block;
    margin: 0; }
  .opportunitiesFilter__title {
    color: #fff;
    padding: 20px;
    display: inline-block;
    font-family: 'Poppins', sans-serif;
    font-size: 2.2rem;
    font-weight: 700; }
  .opportunitiesFilter__list-item {
    margin: 0;
    padding: 0 20px;
    background: #6CB7E3; }
    .opportunitiesFilter__list-item--title {
      background-color: #002A48; }
    .opportunitiesFilter__list-item:last-of-type .opportunitiesFilter__btn {
      border: 0; }
  .opportunitiesFilter__btn {
    background: transparent;
    border-radius: 0;
    border: 0;
    outline: 0;
    width: 100%;
    margin: 0;
    padding: 20px;
    text-align: left;
    color: #fff;
    font-weight: 700;
    border-bottom: 1px solid #fff; }
  .opportunitiesFilter label {
    display: block;
    position: relative;
    padding: 10px 20px;
    cursor: pointer;
    background-color: #6CB7E3;
    color: #fff;
    position: relative; }
    .opportunitiesFilter label:before {
      content: " ";
      display: block;
      height: 1px;
      width: 85%;
      position: absolute;
      bottom: 0;
      left: 20px;
      background-color: #fff; }
    .opportunitiesFilter label:last-of-type:before {
      display: none; }
  .opportunitiesFilter input[type="radio"] {
    position: absolute;
    opacity: 0;
    cursor: pointer;
    height: 0;
    width: 0; }
  .opportunitiesFilter .isActive {
    font-weight: bold; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app" class="grid__container grid__container--space-between grid__container--padding-left-right">

  <div class="opportunitiesFilter">

  <h3 class="opportunitiesFilter__filter-head">Filter</h3>

    <label v-for="cat in cats">
      <input type="radio" v-model="selectedItem"  :value="cat" ref="itemRef"/>
        <span :class="activeItem(cat)" >{{ cat }}
        (
          {{ items.filter(function(x){
            return x.itemType == cat
          }).length }}
        ) </span>
    </label>

    <label>
      <input type="radio" v-bind:class="{isActive: isActive}" v-model="selectedItem" value="All" />
      Archive ({{ items.length }})
    </label>
  </div>

  <ul class="grid grid--2third grid--space-between">
    <li class="grid__col grid__col--half grid__col--column grid__col--border" v-for="item in filteredPage">
      <img class="grid__img" v-bind:src="item.itemImage">
      <!--<h4>{{ item.itemType }} for testing only</h4>-->
      <h2>{{ item.title }}</h2>
      <p>{{ item.content }}</p>
      <a class="grid__arrow-link" :href="item.link">link</a>
    </li>

    <li v-if="showMore"><button class="btn blue" v-on:click="currentPage++">load more</button></li>
  </ul>

</div>

1 个答案:

答案 0 :(得分:0)

您需要做一些事情,我建议您使用计算机来创建此值,并且需要将值包装在span或其他标签中以应用“ isActive”类。当前,您正在将该类添加到输入中-这不会给您其他字体带来的粗体样式。

computed: {
    isArchiveActive () {
      return this.selectedItem === 'All'
    }
}
<label>
      <input type="radio" v-model="selectedItem" value="All" />
      <span v-bind:class="{'isActive': isArchiveActive}">Archive ({{ items.length }})</span
    </label>

这是分叉的代码笔: https://codepen.io/anon/pen/Ervdrr?editors=1010