javascript - Vue.js:从 jQueryUI slider 、搜索关键字和流派中过滤一组包含 2 个浮点值之间的值的数据

标签 javascript jquery jquery-ui vue.js

我用 Vue.js 和 Axios 组合了这个电影列表应用

该应用程序显示来自 themoviedb.org 的电影列表。

与按流派过滤器不同,可以在工具栏中看到的 UI slider 不起作用。它应该按评级过滤电影

var app = new Vue({
  el: '#app',
  data: {
    movies: [],
    genres: [],
    genreSelected: "all",
    filteredMovies: [],
    loading: true,
    errored: false,
    url: "https://api.themoviedb.org/3/movie/now_playing?api_key=10a6546780c9082d52c54eb9c07f5d67&language=en-US&page=1",
    genreUrl: "https://api.themoviedb.org/3/genre/movie/list?api_key=10a6546780c9082d52c54eb9c07f5d67&language=en-US",
    search: '',
    page: 1,
    perPage: 12,
    pages: [],
  },
  methods: {
    getGenres() {
      axios.get(this.genreUrl)
        .then(response => {
          this.genres = response.data.genres;
        })
        .catch(error => {
          console.log(error)
        });
    },
    getMovies() {
      axios
        .get(this.url)
        .then(response => {
          $("#rating_slider").slider({
            range: true,
            step: 0.5,
            min: 1,
            max: 10,
            values: [3, 10],
            animate: "slow",
            orientation: "horizontal",
            slide: function(event, ui) {
              $(this).find('.ui-state-focus').append($(this).find('#amount').show().text(ui.value));
            }
          });
          this.movies = response.data.results;
          this.filteredMovies = response.data.results;
        })
        .catch(error => {
          console.log(error)
          this.errored = true
        })
        .finally(() => this.loading = false)
    },
    setPages(movies) {
      this.pages.length = 0;
      var numberOfPages = Math.ceil(movies.length / this.perPage);
      for (var index = 1; index <= numberOfPages; index++) {
        this.pages.push(index);
      }
    },
    paginate(movies) {
      var page = this.page;
      var perPage = this.perPage;
      var from = (page * perPage) - perPage;
      var to = (page * perPage);
      return movies.slice(from, to);
    },
    scrollToTop() {
      $("html, body").animate({
        scrollTop: 0
      }, 250);
      return false;
    },
    getMoviesByGenre() { // To filter movies by selected genre
      this.page = 1; // Show filtered results stating at page one
      if (this.genreSelected !== "all") {
        this.filteredMovies = this.movies.filter(movie => {
          return movie.genre_ids.indexOf(this.genreSelected) > -1;
        });
        this.setPages(this.filteredMovies);
        this.filteredMovies = this.paginate(this.filteredMovies);
        return;
      }
      this.setPages(this.movies);
      this.filteredMovies = this.paginate(this.movies);
    }
  },
  created() {
    this.getGenres();
    this.getMovies();
  },
  watch: {
    displayedMovies() {
      this.setPages(this.searchResults);
    }
  },
  computed: {
    displayedMovies() {
      return this.paginate(this.searchResults);
    },
    searchResults() {
      this.page = 1;
      return this.movies.filter((movie) => {
        return movie.title.toLowerCase().match(this.search.toLowerCase());
      });
    }
  },
  filters: {
    lowercase(value) {
      return value.toLowerCase();
    },
    capitalize(value) {
      return value.charAt(0).toUpperCase() + value.slice(1);
    },
    titlecase(value) {
      return value.toLowerCase().replace(/(?:^|[\s-/])\w/g, function(match) {
        return match.toUpperCase();
      })
    }
  }
});
.input-group {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  align-items: stretch;
  width: 100%;
}

.input-group .form-control {
  position: relative;
  flex: 1 1 auto;
  width: 1%;
  margin-bottom: 0;
  padding: .375rem .75rem;
  border-radius: .25rem;
}

.input-group-append {
  margin-left: -1px;
  display: flex;
}

.site-wrapper {
  min-height: 100%;
  display: flex;
  flex-direction: column;
}

.topbar {
  box-shadow: 0 3px 7px 0 rgba(21, 30, 38, 0.3);
  display: flex;
  flex-direction: column;
  padding-bottom: 10px;
}

.branding {
  display: flex;
  height: 52px;
  align-items: center;
  margin-right: auto;
  padding: 0 5px;
  color: #fff;
  font-size: 24px;
}

#search-bar {
  order: 3;
}

#group-search {
  padding: 0 5px;
}

#group-search input,
#group-search button {
  background: #343a40;
  border: 1px solid rgba(255, 255, 255, .05);
  color: #e2e2e2;
}

#group-search input {
  border-right: none;
  border-top-right-radius: 0;
  border-bottom-right-radius: 0;
  outline: none !important;
}

#group-search button {
  padding: 0.375rem 1rem;
  border-left: none;
}

.container {
  width: 100%;
  max-width: 1280px;
  margin: 0 auto;
}

.toolbar {
  padding: 10px 15px;
  background: #efefef;
  border: 1px solid #ddd;
  margin: 0 10px 10px 10px;
}

#slider-container {
  position: relative;
}

#rating_slider {
  width: 200px;
  background: #fff;
}

#amount {
  position: absolute;
  left: 50%;
  bottom: -24px;
  transform: translateX(-50%);
  display: none;
  line-height: 16px;
  width: 36px;
  border: 1px solid #e2e2e2;
  background-color: #fff;
  border-radius: 2px;
  color: #777;
  font-size: 11px;
  text-align: center;
}

#amount:after,
#amount:before {
  z-index: 3;
  position: absolute;
  border-style: solid;
  border-width: 0 4px 4px;
  content: "";
  height: 0;
  width: 0;
  right: auto;
}

#amount:before {
  top: -5px;
  left: 14px;
  border-color: transparent transparent #e2e2e2;
}

#amount:after {
  top: -4px;
  left: 14px;
  border-width: 0 4px 4px;
  border-color: transparent transparent #fff;
}

.ui-state-focus,
#amount {
  outline: none !important;
}

.grid {
  display: flex;
  flex-wrap: wrap;
  padding-top: 15px;
}

.grid .grid-item {
  padding: 0 10px;
  width: 100%;
  display: flex;
  flex-direction: column;
  margin-bottom: 25px;
}

.grid .video-box {
  position: relative;
  flex-grow: 1;
  display: flex;
  flex-direction: column;
  padding-bottom: 10px;
  border-radius: 2px;
  background: #fff;
  transition: all 0.3s ease-in-out;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.11);
}

.video-box .photo img {
  max-width: 100%;
  height: auto;
  border-radius: 2px 2px 0 0;
}

.video-box .info {
  padding: 11px 8px;
  position: relative;
}

.video-box h2 {
  margin: 0;
  font-size: 1.25rem;
}

.video-box .meta {
  margin: 0;
  line-height: 1.1;
  padding: 5px 10px;
  position: absolute;
  left: -5px;
  top: -16px;
  background: #b42d3a;
  display: inline-block;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
  color: #fff;
}

.video-box .meta::before {
  content: '';
  display: block;
  width: 0;
  height: 0;
  position: absolute;
  left: 0;
  bottom: -10px;
  z-index: -1;
  border: 5px solid;
  border-color: #6e0000 transparent transparent transparent;
}

.video-box .more {
  margin: auto 8px 0 8px;
  text-decoration: none;
  text-align: center;
  padding: 7px 10px;
  border-radius: 2px;
  color: #fff;
  background: #1B192F;
}

.video-box .more:hover {
  background: #252438;
}

.video-box .rating {
  position: absolute;
  top: -30px;
  right: 5px;
  padding: 2px 5px;
  background: rgba(255, 255, 255, .85);
  border-radius: 2px;
  color: #3f51b5;
  font-size: 12px;
  font-weight: bold;
}


/*Page items*/

.page-item {
  display: inline-block;
}

.site-footer {
  margin-top: auto;
  color: #fff;
}

@media (min-width: 576px) {
  .grid .grid-item {
    flex: 0 0 50%;
    max-width: 50%;
  }
}

@media (min-width: 768px) {
  .site-wrapper {
    padding-top: 60px;
  }
  .topbar {
    display: flex;
    position: fixed;
    z-index: 2;
    left: 0;
    right: 0;
    top: 0px;
    height: 52px;
    flex-direction: row;
    padding: 5px 0;
  }
  .branding {
    height: 40px;
  }
  .navigation {
    padding: 0;
    position: static;
    order: 3;
  }
  .navigation li {
    height: 42px;
  }
  #search-bar {
    display: flex;
    align-items: center;
    max-width: 767px;
    flex: 1;
  }
  #group-search {
    padding: 0 20px;
  }
  .grid {
    padding-top: 0;
  }
  .grid .grid-item {
    flex: 0 0 33.333333%;
    max-width: 33.333333%;
  }
}

@media (min-width: 1200px) {
  .grid .grid-item {
    flex: 0 0 25%;
    max-width: 25%;
  }
}

@media (max-width: 479px) {
  .hide-xxs {
    display: none !important;
  }
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet" />
<link href="https://code.jquery.com/ui/1.10.4/themes/ui-lightness/jquery-ui.min.css" rel="stylesheet" />
<div class="site-wrapper" id="app">
  <div class="topbar bg-dark">
    <a href="#" class="branding">Movies</a>
    <div id="search-bar">
      <div id="group-search" class="input-group">
        <input class="form-control form-control-dark" type="text" name="search" v-model="search" placeholder="Search movies..." aria-label="Search">
        <div class="input-group-append">
          <button class="btn" type="submit" disabled="disabled">
          <i class="fa fa-search"></i>
          </button>
        </div>
      </div>
    </div>
  </div>
  <div class="container">
    <div class="toolbar rounded-sm clearfix">
      <div class="d-inline-block">
        <p class="my-0 d-inline-block">Filter by genre:</p>
        <!-- Added model and onchange Event -->
        <select name="genres" id="genre_filter" class="d-inline-block" v-model="genreSelected" v-on:change="getMoviesByGenre()">
          <option value="all">All</option>
          <!-- This will be the default option -->
          <option v-for="genre in genres" v-bind:value="genre.id">{{genre.name}}</option>
        </select>
      </div>
      <div class="d-inline-block pl-4" id="slider-container">
        <p class="my-0 pr-3 d-inline-block">Filter by rating:</p>
        <div id="rating_slider" class="d-inline-block">
          <div id="amount">3</div>
        </div>
      </div>
    </div>
    <div class="grid">
      <!-- Replaced displayedMovies with filteredMovies -->
      <div v-for="(movie, index) in filteredMovies" class="grid-item">
        <div class="video-box">
          <div class="photo text-center">
            <img :src="'https://image.tmdb.org/t/p/w500_and_h282_face/' + movie.poster_path" :alt="movie.title">
          </div>
          <div class="info">
            <h2>{{movie.title}}</h2>
            <p class="meta">{{movie.release_date}}</p>
            <p class="genres mt-0">Genres:
              <span v-for="(id, index) in movie.genre_ids">{{ index > 0 ? ", "  : "" }}{{ genres.filter(genre => genre.id === id)[0].name }}</span>
            </p>
            <p class="rating m-0">
              <i class="fa fa-star" aria-hidden="true"></i> {{movie.vote_average}}
            </p>
          </div>
          <a href="#" class="more">More Info</a>
        </div>
      </div>
      <div class="justify-content-center py-3" v-if="!filteredMovies.length">No movies found</div>
    </div>
    <nav aria-label="Page navigation">
      <ul class="pagination pagination-sm text-center">
        <li class="page-item" @click="scrollToTop">
          <a class="page-link" href="#" @click="page = 1;" aria-label="First">
          <span aria-hidden="true">&laquo;</span>
          </a>
        </li>
        <li class="page-item" @click="scrollToTop">
          <a class="page-link" href="#" v-if="page != 1" @click="page--;" aria-label="Previous">
          <span aria-hidden="true">&lsaquo;</span>
          </a>
        </li>
        <li class="page-item" v-for="pageNumber in pages.slice(page-1, page+2)" :class="{'active': page === pageNumber}" @click="scrollToTop">
          <a class="page-link" href="#" @click="page = pageNumber;">{{pageNumber}}</a>
        </li>
        <li class="page-item" @click="scrollToTop">
          <a class="page-link" href="#" @click="page++" v-if="page < pages.length" aria-label="Next">
          <span aria-hidden="true">&rsaquo;</span>
          </a>
        </li>
        <li class="page-item" @click="scrollToTop">
          <a class="page-link" href="#" @click="page = pages.length;" aria-label="Last">
          <span aria-hidden="true">&raquo;</span>
          </a>
        </li>
      </ul>
    </nav>
  </div>
  <footer class="site-footer bg-dark">
    <p class="text-center">&copy; 2019 MyWebsite.com</p>
  </footer>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://unpkg.com/axios@0.18.0/dist/axios.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.10.4/jquery-ui.min.js"></script>

我一直无法找到一种方法来“捕获” slider 的两个值并将它们用作应用程序的 Vue.js 部分中的过滤器。

最佳答案

您需要使用计算方法生成并返回经过筛选的电影列表,方法是在同一方法中使用所选类型、搜索关键字和评分范围的参数。

目前,你有太多的方法,但你需要做的就是有一个计算方法,它将在模板中迭代,并在每次任何属性(流派、范围、搜索关键字、更新列表、分页)时更新) 改变。

var app = new Vue({
    el: '#app',
    data: {
        movies: [],
        genres: [],
        genreSelected: "all",
        //filteredMovies: [], //this one should be computed
        loading: true,
        errored: false,
        url: "https://api.themoviedb.org/3/movie/now_playing?api_key=10a6546780c9082d52c54eb9c07f5d67&language=en-US&page=1",
        genreUrl: "https://api.themoviedb.org/3/genre/movie/list?api_key=10a6546780c9082d52c54eb9c07f5d67&language=en-US",
        search: '',
        page: 1,
        perPage: 6, //I have reduced it to lower number due to console outputs in snippet run
        pages: [],
        votesFrom : 1,
        votesTo : 10,
    },
    methods: {
        getGenres() {
            axios.get(this.genreUrl)
                .then(response => {
                    this.genres = response.data.genres;
                })
                .catch(error => {
                    console.log(error)
                });
        },
        getMovies() {
            let self = this;
            axios
                .get(this.url)
                .then(response => {
                    $("#rating_slider").slider({
                        range: true,
                        step: 0.5,
                        min: 1,
                        max: 10,
                        values: [3, 10],
                        animate: "slow",
                        orientation: "horizontal",
                        slide: function(event, ui) {
                            $(this).find('.ui-state-focus').append($(this).find('#amount').show().text(ui.value));
                            self.votesFrom = ui.values[0];
                            self.votesTo = ui.values[1];
                            
                            self.resetPages();

                        }
                    });
                    this.movies = response.data.results;
                    this.setPages(this.nonPaginatedMovies);
                  //  this.filteredMovies = response.data.results;
                })
                .catch(error => {
                    console.log(error)
                    this.errored = true
                })
                .finally(() => this.loading = false)
        },
        setPages(movies) {
            this.pages.length = 0;
            console.log('total movies',movies.length);
           // var numberOfPages = Math.ceil(movies.length / this.perPage);
            this.pages = Math.ceil(movies.length / this.perPage);
          /*  for (var index = 1; index <= numberOfPages; index++) {
                this.pages.push(index);
            }*/
        },
        resetPages(){
            this.page = 1;
            this.setPages(this.nonPaginatedMovies);
        },
        paginate(movies) {
            var page = this.page;
            var perPage = this.perPage;
            var from = (page * perPage) - perPage;
            var to = (page * perPage);
            return movies.slice(from, to);
        },
        scrollToTop() {
            $("html, body").animate({
                scrollTop: 0
            }, 250);
            return false;
        },
        /*   getMoviesByGenre() { // To filter movies by selected genre
         this.page = 1; // Show filtered results stating at page one
            if (this.genreSelected !== "all") {
                this.filteredMovies = this.movies.filter(movie => {
                    return movie.genre_ids.indexOf(this.genreSelected) > -1;
                });
                this.setPages(this.filteredMovies);
                this.filteredMovies = this.paginate(this.filteredMovies);
                return;
            }
            this.setPages(this.movies);
            this.filteredMovies = this.paginate(this.movies);
        } */
    },
    created() {
        this.getGenres();
        this.getMovies();
    },
    ready(){

    },
    watch: {
       /* displayedMovies() {
            this.setPages(this.searchResults);
        },*/
        search(){ //watching on change, we reset pagination
           this.resetPages()
        },
        genreSelected(){ //on changing genre we reset pagination
            this.resetPages()
        },
        page(){

        },
    },
    computed: {
  /*      displayedMovies() {
            return this.paginate(this.searchResults);
        },*/
       /* searchResults() {
            //this.page = 1;
            return this.movies.filter((movie) => {
                return movie.title.toLowerCase().match(this.search.toLowerCase());
            });
        },*/
        nonPaginatedMovies(){ //need total movies for pagination
            return this.movies.filter((movie) => {
                let matchesSearch = true;
                let withinRatingRange = true;
                let belongsToGenre = true;


                if(this.search !== ''){
                    matchesSearch = movie.title.toLowerCase().match(this.search.toLowerCase());

                }

                withinRatingRange = (movie.vote_average >= this.votesFrom && movie.vote_average <= this.votesTo);

                if (this.genreSelected !== "all") {
                    belongsToGenre = movie.genre_ids.indexOf(this.genreSelected) > -1;
                }

                return (matchesSearch && withinRatingRange === true && belongsToGenre === true);

            })
        },
        filteredMovies(){
           return this.paginate(this.nonPaginatedMovies);
        }
    },
    filters: {
        lowercase(value) {
            return value.toLowerCase();
        },
        capitalize(value) {
            return value.charAt(0).toUpperCase() + value.slice(1);
        },
        titlecase(value) {
            return value.toLowerCase().replace(/(?:^|[\s-/])\w/g, function(match) {
                return match.toUpperCase();
            })
        }
    }
});
.input-group {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  align-items: stretch;
  width: 100%;
}

.input-group .form-control {
  position: relative;
  flex: 1 1 auto;
  width: 1%;
  margin-bottom: 0;
  padding: .375rem .75rem;
  border-radius: .25rem;
}

.input-group-append {
  margin-left: -1px;
  display: flex;
}

.site-wrapper {
  min-height: 100%;
  display: flex;
  flex-direction: column;
}

.topbar {
  box-shadow: 0 3px 7px 0 rgba(21, 30, 38, 0.3);
  display: flex;
  flex-direction: column;
  padding-bottom: 10px;
}

.branding {
  display: flex;
  height: 52px;
  align-items: center;
  margin-right: auto;
  padding: 0 5px;
  color: #fff;
  font-size: 24px;
}

#search-bar {
  order: 3;
}

#group-search {
  padding: 0 5px;
}

#group-search input,
#group-search button {
  background: #343a40;
  border: 1px solid rgba(255, 255, 255, .05);
  color: #e2e2e2;
}

#group-search input {
  border-right: none;
  border-top-right-radius: 0;
  border-bottom-right-radius: 0;
  outline: none !important;
}

#group-search button {
  padding: 0.375rem 1rem;
  border-left: none;
}

.container {
  width: 100%;
  max-width: 1280px;
  margin: 0 auto;
}

.toolbar {
  padding: 10px 15px;
  background: #efefef;
  border: 1px solid #ddd;
  margin: 0 10px 10px 10px;
}

#slider-container {
  position: relative;
}

#rating_slider {
  width: 200px;
  background: #fff;
}

#amount {
  position: absolute;
  left: 50%;
  bottom: -24px;
  transform: translateX(-50%);
  display: none;
  line-height: 16px;
  width: 36px;
  border: 1px solid #e2e2e2;
  background-color: #fff;
  border-radius: 2px;
  color: #777;
  font-size: 11px;
  text-align: center;
}

#amount:after,
#amount:before {
  z-index: 3;
  position: absolute;
  border-style: solid;
  border-width: 0 4px 4px;
  content: "";
  height: 0;
  width: 0;
  right: auto;
}

#amount:before {
  top: -5px;
  left: 14px;
  border-color: transparent transparent #e2e2e2;
}

#amount:after {
  top: -4px;
  left: 14px;
  border-width: 0 4px 4px;
  border-color: transparent transparent #fff;
}

.ui-state-focus,
#amount {
  outline: none !important;
}

.grid {
  display: flex;
  flex-wrap: wrap;
  padding-top: 15px;
}

.grid .grid-item {
  padding: 0 10px;
  width: 100%;
  display: flex;
  flex-direction: column;
  margin-bottom: 25px;
}

.grid .video-box {
  position: relative;
  flex-grow: 1;
  display: flex;
  flex-direction: column;
  padding-bottom: 10px;
  border-radius: 2px;
  background: #fff;
  transition: all 0.3s ease-in-out;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.11);
}

.video-box .photo img {
  max-width: 100%;
  height: auto;
  border-radius: 2px 2px 0 0;
}

.video-box .info {
  padding: 11px 8px;
  position: relative;
}

.video-box h2 {
  margin: 0;
  font-size: 1.25rem;
}

.video-box .meta {
  margin: 0;
  line-height: 1.1;
  padding: 5px 10px;
  position: absolute;
  left: -5px;
  top: -16px;
  background: #b42d3a;
  display: inline-block;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
  color: #fff;
}

.video-box .meta::before {
  content: '';
  display: block;
  width: 0;
  height: 0;
  position: absolute;
  left: 0;
  bottom: -10px;
  z-index: -1;
  border: 5px solid;
  border-color: #6e0000 transparent transparent transparent;
}

.video-box .more {
  margin: auto 8px 0 8px;
  text-decoration: none;
  text-align: center;
  padding: 7px 10px;
  border-radius: 2px;
  color: #fff;
  background: #1B192F;
}

.video-box .more:hover {
  background: #252438;
}

.video-box .rating {
  position: absolute;
  top: -30px;
  right: 5px;
  padding: 2px 5px;
  background: rgba(255, 255, 255, .85);
  border-radius: 2px;
  color: #3f51b5;
  font-size: 12px;
  font-weight: bold;
}


/*Page items*/

.page-item {
  display: inline-block;
}

.site-footer {
  margin-top: auto;
  color: #fff;
}

@media (min-width: 576px) {
  .grid .grid-item {
    flex: 0 0 50%;
    max-width: 50%;
  }
}

@media (min-width: 768px) {
  .site-wrapper {
    padding-top: 60px;
  }
  .topbar {
    display: flex;
    position: fixed;
    z-index: 2;
    left: 0;
    right: 0;
    top: 0px;
    height: 52px;
    flex-direction: row;
    padding: 5px 0;
  }
  .branding {
    height: 40px;
  }
  .navigation {
    padding: 0;
    position: static;
    order: 3;
  }
  .navigation li {
    height: 42px;
  }
  #search-bar {
    display: flex;
    align-items: center;
    max-width: 767px;
    flex: 1;
  }
  #group-search {
    padding: 0 20px;
  }
  .grid {
    padding-top: 0;
  }
  .grid .grid-item {
    flex: 0 0 33.333333%;
    max-width: 33.333333%;
  }
}

@media (min-width: 1200px) {
  .grid .grid-item {
    flex: 0 0 25%;
    max-width: 25%;
  }
}

@media (max-width: 479px) {
  .hide-xxs {
    display: none !important;
  }
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet" />
<link href="https://code.jquery.com/ui/1.10.4/themes/ui-lightness/jquery-ui.min.css" rel="stylesheet" />
<div class="site-wrapper" id="app">
    <div class="topbar bg-dark">
        <a href="#" class="branding">Movies</a>
        <div id="search-bar">
            <div id="group-search" class="input-group">
                <input class="form-control form-control-dark" type="text" name="search" v-model="search" placeholder="Search movies..." aria-label="Search">
                <div class="input-group-append">
                    <button class="btn" type="submit" disabled="disabled">
                        <i class="fa fa-search"></i>
                    </button>
                </div>
            </div>
        </div>
    </div>
    <div class="container">
        <div class="toolbar rounded-sm clearfix">
            <div class="d-inline-block">
                <p class="my-0 d-inline-block">Filter by genre:</p>
                <!-- Added model and onchange Event -->
                <select name="genres" id="genre_filter" class="d-inline-block" v-model="genreSelected">
                    <option value="all">All</option>
                    <!-- This will be the default option -->
                    <option v-for="genre in genres" v-bind:value="genre.id">{{genre.name}}</option>
                </select>
            </div>
            <div class="d-inline-block pl-4" id="slider-container">
                <p class="my-0 pr-3 d-inline-block">Filter by rating:</p>
                <div id="rating_slider" class="d-inline-block">
                    <div id="amount">3</div>
                </div>
            </div>
        </div>
        <div class="grid">
            <!-- Replaced displayedMovies with filteredMovies -->
            <div v-for="(movie, index) in filteredMovies" class="grid-item">
                <div class="video-box">
                    <div class="photo text-center">
                        <img :src="'https://image.tmdb.org/t/p/w500_and_h282_face/' + movie.poster_path" :alt="movie.title">
                    </div>
                    <div class="info">
                        <h2>{{movie.title}}</h2>
                        <p class="meta">{{movie.release_date}}</p>
                        <p class="genres mt-0">Genres:
                            <span v-for="(id, index) in movie.genre_ids">{{ index > 0 ? ", "  : "" }}{{ genres.filter(genre => genre.id === id)[0].name }}</span>
                        </p>
                        <p class="rating m-0">
                            <i class="fa fa-star" aria-hidden="true"></i> {{movie.vote_average}}
                        </p>
                    </div>
                    <a href="#" class="more">More Info</a>
                </div>
            </div>
            <div class="justify-content-center py-3" v-if="!filteredMovies.length">No movies found</div>
        </div>
        <nav aria-label="Page navigation">
            <ul class="pagination pagination-sm text-center">
                <li class="page-item" @click="scrollToTop">
                    <a class="page-link" href="#" @click="page = 1;" aria-label="First">
                        <span aria-hidden="true">&laquo;</span>
                    </a>
                </li>
                <li class="page-item" @click="scrollToTop">
                    <a class="page-link" href="#" v-if="page != 1" @click="page--;" aria-label="Previous">
                        <span aria-hidden="true">&lsaquo;</span>
                    </a>
                </li>
                <li class="page-item" v-for="pageNumber in pages" :class="{'active': page === pageNumber}" @click="scrollToTop">
                    <a class="page-link" href="#" @click="page = pageNumber;">{{pageNumber}}</a>
                </li>
                <li class="page-item" @click="scrollToTop">
                    <a class="page-link" href="#" @click="page++" v-if="page < pages.length" aria-label="Next">
                        <span aria-hidden="true">&rsaquo;</span>
                    </a>
                </li>
                <li class="page-item" @click="scrollToTop">
                    <a class="page-link" href="#" @click="page = pages.length;" aria-label="Last">
                        <span aria-hidden="true">&raquo;</span>
                    </a>
                </li>
            </ul>
        </nav>
    </div>
    <footer class="site-footer bg-dark">
        <p class="text-center">&copy; 2019 MyWebsite.com</p>
    </footer>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://unpkg.com/axios@0.18.0/dist/axios.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.10.4/jquery-ui.min.js"></script>

您会注意到我已经注释掉了一些方法,并且也不需要 :on-change,因为您可以watch 模型更改。 只有两个计算属性,一个用于创建分页,另一个用于分页过滤列表。 此外,不需要为 this.pages 形成一个数组,VueJS 对数字以及数组和对象进行适当的迭代。

关于javascript - Vue.js:从 jQueryUI slider 、搜索关键字和流派中过滤一组包含 2 个浮点值之间的值的数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55017861/

相关文章:

jquery - 如何延迟显示/隐藏 Bootstrap 工具提示?

javascript - 限制 jqueryui 可排序项目可以放置的区域

javascript - 从 child 到 parent 的跨站点 iframe postMessage

javascript - 手动加载JQuery而不触发内容安全策略

javascript - 以编程方式添加过渡样式而不删除现有样式

jQuery Accordion - 事件部分的不同图像

html - jQuery UI 按钮改变焦点颜色

jQuery:链接无法在启用 jQuery 的情况下工作

javascript - Django-autocomplete-light如何从html获取数据?

php - 确认弹出窗口并将 php 值传递给 js,输入图像作为提交