【问题标题】:How to filter date range using vue js?如何使用 vue js 过滤日期范围?
【发布时间】:2021-02-14 07:35:02
【问题描述】:

我正在学习 vue.js,并且正在尝试使用范围日期的过滤功能。场景是:首先按类型过滤,然后按日期范围过滤(有开始日期和结束日期)。选择结束日期后将显示结果。我创建了第一个过滤器,它是类型,它可以工作。我已经搜索了日期范围的各种方法,但仍然找不到合适的方法。如何使用computedmethods 过滤日期范围?如果有人知道,请您一步一步告诉我吗?

new Vue({
  el: '#app',
  data: {
    selectedType: '',
    startDate:null,
    endDate:null,
    items: [
      {
        name: 'Nolan',
        type: 'mercedes',
        year: '2020',
        country: 'england',
        date: '08/01/2020'
      },
      {
        name: 'Edgar',
        type: 'bmw',
        year: '2020',
        country:'belgium',
        date: '08/11/2020'
      },
      {
        name: 'John',
        type: 'bmw',
        year: '2019',
        country: 'england',
        date: '08/21/2020'
      },
      {
        name: 'Axel',
        type: 'mercedes',
        year: '2020',
        country: 'england',
        date: '08/01/2020'
      }
    ]
  },
  computed: {
    filterItem: function () {
      
      let filterType = this.selectedType
      if (!filterType) return this.items;  // when filterType not selected

      let startDate = this.startDate && new Date(this.startDate);
      let endDate = this.endDate && new Date(this.endDate);
      
      return this.items.filter(item => {
        return item.type == filterType;
      }).filter(item => {
        const itemDate = new Date(item.date)
        if (startDate && endDate) {
          return startDate <= itemDate && itemDate <= endDate;
        }
        if (startDate && !endDate) {
          return startDate <= itemDate;
        }
        if (!startDate && endDate) {
          return itemDate <= endDate;
        }
        return true;  // when neither startDate nor endDate selected
      })
      
    }
  }
})
.list-item {
  margin-top: 50px;
}

#app {
  position: relative;
  padding-bottom: 200px;
}

span {
  margin: 0 15px;
  cursor: pointer;
}

.filter-box {
  margin-top: 15px;
}

.card {
  box-shadow: 0px 10px 16px rgba(0, 0, 0, 0.16);
  width: 400px;
  padding: 20px 30px;
  margin-bottom: 30px;
}

button {
  background-color: #1cf478;
  border: none;
  padding: 10px 25px;
  font-weight: bold;
  border-radius: 15px;
}

select,input {
  border: none;
  padding: 10px 15px;
  background-color: #c1c1c1;
  border-radius: 10px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div id="app">
  <label for="">Type</label>
  <select v-model="selectedType">
    <option value="" disabled selected hidden>Type</option>
    <option value="mercedes">Mercedes</option>
    <option value="bmw">BMW</option>
  </select>
  
  <label for="">From</label>
  <input type="date" v-model="startDate">
  
  <label for="">To</label>
  <input type="date" v-model="endDate">
  
  <div class="list-item" v-for="item in filterItem">
    <div class="card">
      <p>Name: {{ item.name }}</p>
      <p>Car: {{ item.type }}</p>
      <p>Date: {{ item.date }}</p>
      <p>Country: {{ item.country }}</p>
    </div>
  </div>
</div>

【问题讨论】:

  • 您是如何尝试实现数据过滤器的?

标签: javascript vue.js vuejs2


【解决方案1】:

以下是您可以解决的方法:

  1. startDateendDate 创建为Dates。但是请注意,日期选择器使用 ISO 字符串格式 (yyyy-mm-dd),即 UTC。数据包含特定于区域设置的日期 (mm/dd/yyyy),因此 Date 使用本地时区解析字符串。我们需要标准化日期,以便我们比较具有相同时区偏移量的日期(本地首选):

    methods: {
      localizeDate(date) {
        if (!date || !date.includes('-')) return date
        const [yyyy, mm, dd] = date.split('-')
        return new Date(`${mm}/${dd}/${yyyy}`)
      }
    }
    
    let startDate = this.localizeDate(this.startDate);
    let endDate = this.localizeDate(this.endDate);
    
  2. if-else 中的日期比较显式检查 null,但它们的值不会是 null,因为您正在实例化 Date 对象。通过第 1 步中的更新,日期值为 Datefalse,因此您可以更新比较以检查虚假值而不是 null

    if (startDate && endDate) {/*...*/}
    if (startDate && !endDate) {/*...*/}
    if (!startDate && endDate) {/*...*/}
    
  3. selectedType 永远不会是null,但你可以检查它是否是虚假的,以确定类型是否未指定。在这种情况下,您可以只返回原始数组以避免对Array.prototype.filter 的不必要调用:

    const itemsByType = filterType ? this.items.filter(item => item.type === filterType) : this.items
    
  4. 由于您想将日期显示为MMM dd, yyyy,您可以在组件方法中使用Intl.DateTimeFormat“长”日期样式,并从模板中调用它:

    methods: {
      formatDate(date) {
        return new Intl.DateTimeFormat('en-US', { dateStyle: 'long' }).format(new Date(date))
      }
    }
    
    <p>Date: {{ formatDate(item.date) }}</p>
    

new Vue({
  el: '#app',
  data: {
    selectedType: '',
    startDate:null,
    endDate:null,
    items: [
      {
        name: 'Nolan',
        type: 'mercedes',
        year: '2020',
        country: 'england',
        date: '08/01/2020'
      },
      {
        name: 'Edgar',
        type: 'bmw',
        year: '2020',
        country:'belgium',
        date: '08/11/2020'
      },
      {
        name: 'John',
        type: 'bmw',
        year: '2019',
        country: 'england',
        date: '08/21/2020'
      },
      {
        name: 'Axel',
        type: 'mercedes',
        year: '2020',
        country: 'england',
        date: '08/01/2020'
      }
    ]
  },
  computed: {
    filterItem() {
      let filterType = this.selectedType;
      let startDate = this.localizeDate(this.startDate);
      let endDate = this.localizeDate(this.endDate);
      
      const itemsByType = filterType ? this.items.filter(item => item.type === filterType) : this.items
      return itemsByType
        .filter(item => {
          const itemDate = new Date(item.date)
          if (startDate && endDate) {
            return startDate <= itemDate && itemDate <= endDate;
          }
          if (startDate && !endDate) {
            return startDate <= itemDate;
          }
          if (!startDate && endDate) {
            return itemDate <= endDate;
          }
          return true;
        })
    }
  },
  methods: {
    localizeDate(date) {
      // Date picker uses ISO format (yyyy-mm-dd), which is UTC. The data
      // contains locale specific date strings (mm/dd/yyyy), which `Date`
      // parses with local time-zone offset instead of UTC. Normalize the
      // ISO date so we're comparing local times.
      if (!date || !date.includes('-')) return date
      const [yyyy, mm, dd] = date.split('-')
      return new Date(`${mm}/${dd}/${yyyy}`)
    },
    formatDate(date) {
      return new Intl.DateTimeFormat('en-US', { dateStyle: 'long' }).format(new Date(date))
    }
  }
})
.list-item {
  margin-top: 50px;
}

.card {
  box-shadow: 0px 10px 16px rgba(0, 0, 0, 0.16);
  width: 400px;
  padding: 20px 30px;
  margin-bottom: 30px;
}

select,input {
  border: none;
  padding: 10px 15px;
  background-color: #c1c1c1;
  border-radius: 10px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

<div id="app">
  <label for="">Type</label>
  <select v-model="selectedType">
    <option value="" disabled selected hidden>Type</option>
    <option value="mercedes">Mercedes</option>
    <option value="bmw">BMW</option>
  </select>
  
  <label for="">From</label>
  <input type="date" v-model="startDate">
  
  <label for="">To</label>
  <input type="date" v-model="endDate">
  
  <div class="list-item" v-for="item in filterItem">
    <div class="card">
      <p>Name: {{ item.name }}</p>
      <p>Car: {{ item.type }}</p>
      <p>Date: {{ formatDate(item.date) }}</p>
      <p>Country: {{ item.country }}</p>
    </div>
  </div>
</div>

【讨论】:

    【解决方案2】:

    这个问题更多的是关于js,而不是vuejs。对日期数据使用日期类型,而不是字符串类型。是可比的,比如new Date('2020-01-01') &lt; new Date('2020-01-02')就是true

      computed: {
        filterItem: function () {
          const filterType = this.selectedType  // string or null
          const startDate = this.startDate;    // Date or null
          const endDate = this.endDate;  // Date or null
          
          return this.items.filter(item => {
            if (filterType === null) return true;  // when filterType not selected
            return item.type == filterType;
          }).filter(item => {
            const itemDate = new Date(item.date)
            if (startDate !== null && endDate !== null)) {
              return startDate <= itemDate && itemDate <= endDate;
            }
            if (startDate !== null && endDate === null) {
              return startDate <= itemDate;
            }
            if (startDate === null && endDate !== null) {
              return                          itemDate <= endDate;
            }
            return true;  // when neither startDate nor endDate selected
          })
        }
    

    【讨论】:

    • 我已经编辑了我的帖子,并在那里添加了您的代码。但它不起作用
    • 控制台是否出错?我猜 startDate 和 endDate 将是字符串,而不是日期。您可能需要投射。
    猜你喜欢
    • 2018-06-19
    • 1970-01-01
    • 2014-12-30
    • 2020-02-26
    • 2013-03-26
    • 1970-01-01
    • 1970-01-01
    • 2016-12-07
    • 1970-01-01
    相关资源
    最近更新 更多