Vue.js应用程序错误:对搜索结果进行分页失败

时间:2018-12-21 19:09:39

标签: javascript vue.js

我正在研究一个小型应用程序,该应用程序在HTML5表中显示“用户” JSON。为此,我使用Bootstrap 3,Axios和Vue.js 2。

显示的项目是分页的。以下是所有代码:

var app = new Vue({
  el: '#app',
  data: {
    users: [],
    loading: true,
    errored: false,
    url: "https://randomuser.me/api/?&results=100&inc=name,location,email,cell,picture",
    page: 1,
    perPage: 10,
    pages: [],

  },
  methods: {
    getUsers() {
      axios
        .get(this.url)
        .then(response => {
          this.users = response.data.results
        })
        .catch(error => {
          console.log(error)
          this.errored = true
        })
        .finally(() => this.loading = false)
    },
    setPages() {
      var numberOfPages = Math.ceil(this.users.length / this.perPage);
      for (var index = 1; index <= numberOfPages; index++) {
        this.pages.push(index);
      }
    },
    paginate(users) {
      var page = this.page;
      var perPage = this.perPage;
      var from = (page * perPage) - perPage;
      var to = (page * perPage);
      return users.slice(from, to);
    }
  },
  created() {
    this.getUsers();
  },
  watch: {
    users() {
      this.setPages();
    }
  },
  computed: {
    displayedUsers() {
      return this.paginate(this.users);
    }
  },
  filters: {
    lowercase(value) {
      return value.toLowerCase();
    },
    capitalize(value) {
      return value.charAt(0).toUpperCase() + value.slice(1);
    }
  }
});
.table-container {
  margin: 10px;
}

.table-container .panel-heading {
  font-weight: bold;
}

.table-container .panel-body {
  padding: 0;
}

.table-container table {
  margin-bottom: 0;
  border: none;
}

.table-container table tr:last-child td {
  border-bottom: none;
}

.table-container table tr th {
  font-weight: bold;
}

.table-container table tr th:first-child,
.table-container table tr td:first-child {
  border-left: none;
}

.table-container table tr th:last-child,
.table-container table tr td:last-child {
  border-right: none;
}

.table-container table tr td {
  padding: 2px 8px !important;
  vertical-align: middle;
}

.table-container table tr td .picture {
  padding-right: 10px;
}

.table-container table tr td img {
  max-height: 30px;
  width: auto;
  border: 1px solid #c7c7c7;
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>

<div id="app" class="container">
  <div class="panel panel-default table-container">
    <div class="panel-heading">Users</div>
    <div class="panel-body">
      <div class="table-responsive">
        <table class="table table-striped table-bordered" id="dataTable">
          <thead>
            <tr>
              <th class="text-right">#</th>
              <th>Name</th>
              <th>Email</th>
              <th>City</th>
            </tr>
          </thead>
          <tbody>
            <tr v-for="(user, index) in displayedUsers">
              <td class="text-right">{{perPage * (page - 1) + index + 1}}</td>
              <td>
                <span class="picture">
                  <img :src="user.picture.thumbnail" :alt="user.name.first + ' ' + user.name.last" class="img-circle">
                </span>
                <span>{{user.name.first | capitalize}} {{user.name.last | capitalize}}</span>
              </td>
              <td><a :href="'mailto:' + user.email | lowercase">{{user.email | lowercase}}</a></td>
              <td>{{user.location.city | capitalize}}</td>
            </tr>
          </tbody>
        </table>
      </div>
    </div>
  </div>
  <nav class="text-center" aria-label="Page navigation">
    <ul class="pagination pagination-sm">
      <li>
        <a href="#" @click="page = 1" aria-label="First">
          <span aria-hidden="true">&laquo;</span>
        </a>
      </li>
      <li>
        <a href="#" v-if="page != 1" @click="page--" aria-label="Previous">
          <span aria-hidden="true">&lsaquo;</span>
        </a>
      </li>
      <li v-for="pageNumber in pages.slice(page-1, page+4)" :class="{'active': page === pageNumber}"><a href="#" @click="page = pageNumber">{{pageNumber}}</a></li>
      <li>
        <a href="#" @click="page++" v-if="page < pages.length" aria-label="Next">
          <span aria-hidden="true">&rsaquo;</span>
        </a>
      </li>
      <li>
        <a href="#" @click="page = pages.length" aria-label="Last">
          <span aria-hidden="true">&raquo;</span>
        </a>
      </li>
    </ul>
  </nav>
</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>

在向他的应用程序添加搜索/过滤器功能后,我遇到了问题。我已将其添加到模板/视图:

<div class="panel-heading clearfix">
  <h2 class="pull-left">Users</h2>
  <div class="searchbox">
    <input type="text" v-model="search" class="form-control" placeholder="Search...">
  </div>
</div>

,并将<tr v-for="(user, index) in displayedUsers">替换为<tr v-for="(user, index) in searchResults">

然后,在脚本的computed部分中,我添加了脚本:

searchResults() {
   return this.users.filter((user) => {
    return user.name.first.match(this.search);
   });
 }

搜索(通过 names )有效,但是无法对整个JSON和搜索结果进行分页。

我未能让他们一起工作 。可以 HERE 看到损坏的应用程序。

缺少什么?

1 个答案:

答案 0 :(得分:0)

为了使分页与过滤一起工作,您需要将pagination逻辑与searchResults中的displayedUsers组合起来

displayedUsers() {
    return this.paginate(this.searchResults);
},

然后,您将需要在所有对合并结果感兴趣的地方使用displayedUsers,因此请在模板中使用:

<tr v-for="(user, index) in displayedUsers">

您的代码中还有另一件事需要解决:当前总使用原始用户数的页面数,必须对其进行更新以使用“当前”用户数:

setPages(users) {
    this.pages.length = 0; //we need to clear the previously set pages
    var numberOfPages = Math.ceil(users.length / this.perPage);
    for (var index = 1; index <= numberOfPages; index++) {
       this.pages.push(index);
    }
},

并在更改dispayedUsers时更新页面:

watch: {
    displayedUsers() {
        this.setPages(this.searchResults);
    }
},

如果您还想在搜索时重置页面,则只需在page中设置searchResults

searchResults() {
    this.page = 1;
    return this.users.filter((user) => {
        return user.name.first.match(this.search);
      });
}

工作JSFiddle