Vue 2.0 makes list components to realize pagination, search, batch operation, etc.


This article only explains how to use Vue to create a list component that implements paging, searching, and batch operations, so only the code and instructions for this widget are provided, and no other code or configuration is provided.

github address: https://github.com/jothy1023/vue-component

Technology or framework used

  • Vue.js (2.0) A progressive framework based on MVVM can help us build user interface quickly.
  • semantic UI: A Beautiful UI Framework
  • One of the local storage API s for HTML5 (the other is session Storage), as the name implies, is stored in the memory of the current device and will always exist unless it is actively deleted.

Dead work

  • Install Vue 2.0 (rc.6)
  • Introduce the semantic.js file
  • Create Audit.vue file

Specific process

A simple Vue component consists of three parts: html template, and JavaScript Script and css style. Now let's look at it one by one.
The results are as follows:


Preview Figure 1

Preview Figure 2

Used data structure Is a simple array of user objects in the form of

user {
  id: int
  name: String,
  audit: int
}

Among them, audit is used to mark whether the audit is successful or not. There are four states from 0 to 3: unaudited, under-audited, audited and unaudited.

html template

A pair of < template> </template> tags are used as the only parent tags to wrap the template content, and the template is divided into filter s. (filtering) Container (subject) two parts.

container

The main body of the container is a table table table. The table content tbody uses the v-for instruction of Vue to render the list based on the users array. The main code is as follows

<tr v-for="user in filteredUsers">
  <td class="collapsing">
    <div class="ui toggle slider checkbox" v-if="aKey!==''">
      <input type="checkbox" :value="user" v-model="selectedUsers"> <label></label>
    </div>
  </td>
  <td>{{ user.id }}</td>
  <td>{{ user.name }}</td>
  <td>
    <i class="radio black icon" v-if="user.audit==0"></i>
    <i class="minus blue icon" v-if="user.audit==1"></i>
    <i class="checkmark green icon" v-if="user.audit==2"></i>
    <i class="remove red icon" v-if="user.audit==3"></i>
  </td>
  <td>
    <ui-button css="primary" v-if="user.audit==0" @click="user.audit=1">To examine</ui-button>
    <ui-button css="green" v-if="user.audit==1" @click="user.audit=2">Pass the audit</ui-button>
    <ui-button css="red" v-if="user.audit==1" @click="user.audit=3">Failure to pass audit</ui-button>
    <ui-button css="grey" v-if="user.audit==2 || user.audit==3" @click="user.audit=1">Review again</ui-button>
  </td>
</tr>

Among them, filteredUsers is a getter for computing attribute computed, which is used to separate more complex logic from the template, where filtered logic is returned. users .
Next, there is an input type of checkbox. When filtering according to an audit requirement, it shows that its v-model points to the selected Users array, which is used to save the selected users in batch operation. After that, the array can be operated directly, and the changes will be synchronized to users.

filter

The filter part consists of an input input box and a select box, which can be filtered by user name and audit status respectively. The code is as follows:

<div class="filter">
    <ui-input css="icon">
        <input type="text" v-model="fKey" placeholder="Input Name Search.." />
        <i class="search icon"></i>
    </ui-input>
    <!-- dropdown -->
    <ui-dropdown :setting="{allowAdditions: true}" css="selection">
        <input name="aKey" type="hidden" v-model.lazy="aKey">
        <div class="default text">Select a id</div>
        <i class="dropdown icon"></i>
        <div class="menu">
            <div class="item" data-value="">All</div>
            <div class="item" data-value="0">Not audited</div>
            <div class="item" data-value="1">Under review</div>
            <div class="item" data-value="2">Audited</div>
            <div class="item" data-value="3">Audit failed</div>
        </div>
    </ui-dropdown>
</div>

select uses the dropdown implementation of the semanticUI to set its class to selection. Dropdown contains an input tag with the attribute < input Name= "aKey" type= "hidden" v-model.lazy= "aKey">, where name corresponds to the attribute name of V-model and is responsible for retrieving and passing values from data-value in. item below.
There's a place to be noticed here!! (Knock on the blackboard
Because the input tag here is actually a select component, the default behavior is change rather than input, and there is no input box, so even adding v-model can not trigger. But add @change can be triggered normally, Best Things can not be sister, after thousands of hard journeys, finally found!! There is such a break in the source code of Vue:


Source code

We only focus on the first and last lines, oh... to the effect that lazy attributes (or range in IE environment) are detected, change events are monitored when true, or input events are monitored. The truth is clear, tactfully add a small tail to the v-model. lazy, hot-loader refreshes immediately, and it succeeds! Zamb ()d
P.S: Later, I turned over Vue's course and found that it had been explained in the course, especially in the drawings.


Vue document

And.. 1.0 and 2.0 are slightly different. 1.0 is written directly at the end of the input tag, and 2.0 must follow the v-model.

When the v-model of fKey or aKey is changed, the computed attribute is triggered to recalculate filteredUsers, re-render the users list, and a paginate is paginated.

filteredUsers () {
  let fUsers = this.queryFilter('name', this.fKey, this.users)
  fUsers = this.queryFilter('audit', this.aKey, fUsers)
  return this.paginate(fUsers)
}

javascript script

Initial data

This paper defines the initial Users array, stores several user objects, defines the user Storage object, stores fetch and save methods, and calls the getItem and setItem methods of the local Storage to obtain and store data from the local Storage.

var userStorage

function init() {
  var STORAGE_KEY = 'users';

  userStorage = {
    fetch: function () {
      return JSON.parse(localStorage.getItem(STORAGE_KEY)) || initialUsers
    },
    save: function (users) {
      localStorage.setItem(STORAGE_KEY, JSON.stringify(users))
    }
  };
}

init(window);

Next is the attribute methods of the Vue instance.

data () {
  return {
    users: userStorage.fetch(), // users data
    selectedUsers: [], // Save the selected users array
    fKey: '', // Filter name keywords
    name: '', // The last filtered name keyword, initialized to''
    aKey: '', // select audit keyword
    audit: '', // The last filtered audit keyword, initialized to''
    limit: 10, // Number of rows per page
    totalPage: 0, // PageCount
    currentPage: 0, // Current page
    jPage: 1 // Jump to a page
  }
}

The name and audit here seem redundant, but in fact they are very important. They are used to save the keys of the last filter against the keys of this one.

Filtering method queryFilter
queryFilter (prop, key, arr) {
  // none query string, return arr
  if (!key) {
    return arr
  }
  // filtering
  arr = arr.filter((user) => {
    if (user[prop].toString().indexOf(key) !== -1) {
      return true 
    }
  })
  // if it's a new filter query, refilter and turn to page one
  if (key !== this[prop]) {
    this.currentPage = 0
    // save last filter query
    this[prop] = key
  }
  return arr
}

This setting application scenario is: when the variable is not set, if the user flips the page after a search, assuming that it stays on page n, then re-search, the page will stay on page n of the search results, which is very inconvenient. Therefore, if the search is re-searched, the current Page property is recharged to record the new key.

Paging method paginate
paginate (arr) {
  this.totalPage = Math.ceil(arr.length / this.limit)
  let page = this.currentPage
  let curLimit = this.limit
  // Returns an array of specified bars
  arr = arr.slice(curLimit * page, curLimit * (page + 1))
  return arr
}

The slice method of the array is used here for shallow replication.

Page turning method

Accept an array, 1 to flip backwards and - 1 to flip forward.

  • HTML
<div class="jtp">
  <span>Jump to No. </span>
  <ui-input css="icon">
    <input type="text" v-model="jPage" @keyup.enter="jumpToPage">
  </ui-input><span> page</span>
</div>
  • Javascript
turnPage (num) {
  if (num === 1) {
    if (this.currentPage === this.totalPage - 1) {
      return
    } else {
      this.currentPage++
    }
  } else {
    if (this.currentPage === 0) {
      return
    } else {
      this.currentPage--          
    }
  }
}
Single operation modification audit

Add the @click event to the button for a separate operation and modify it directly

Batch operation method

Since the selectedUsers array holds the data of the selected users, you can simply call the setAuditId method, pass in the selectedUsers and the audit to be set, and traverse the selectedUsers to set it. Examples of the code are as follows:

  • HTML
<ui-button css="green" v-if="aKey==='1'" @click="pass">Pass the audit</ui-button>
<ui-button css="red" v-if="aKey==='1'" @click="reject">Failure to pass audit</ui-button>
<ui-button css="small" v-if="aKey==='0'" @click="approveSel">To examine</ui-button>
<ui-button css="small" v-if="aKey==='0'" @click="approveAll">Full audit</ui-button>
<ui-button css="small" v-if="aKey==='2' || aKey==='3'" @click="approveSel">Review again</ui-button>
<ui-button css="small" v-if="aKey==='2' || aKey==='3'" @click="approveAll">All re-audits</ui-button>
  • Javascript
approveSel () {
  this.setAuditId(this.selectedUsers, 1)
},

approveAll () {
  this.setAuditId(this.filteredUsers, 1)
},

pass () {
  this.setAuditId(this.selectedUsers, 2)
},

reject () {
  this.setAuditId(this.selectedUsers, 3)
},

setAuditId (users, aId) {
  users.forEach((user) => {
    user.audit = aId
  })
}

In addition, watch is added to detect users, and new users are stored in the local Storage whenever they change (e.g., audit is modified).

// watch
watch: {
  users: {
    handler () {
      userStorage.save(this.users)
    },
    deep: true
  }
}
CSS

There's nothing to say about this part. Basically, it uses the css of the semanticUI, and only resets the size of the input at the last jump page number input box.

So far, the whole component has completed ~scattering,:()/$:.
First try Vue, the use of some APIs may be inaccurate, there are poor writing areas welcome correction.

Keywords: Vue Attribute Javascript github

Added by pingu on Mon, 15 Jul 2019 02:06:44 +0300