这里有新鲜出炉的 vue.js 教程,程序狗速度看过来!
Vue.js 是构建 web 界面的 JavaScript 库,提供数据驱动的组件,还有简单灵活的 API,使得 MVVM 更简单。
这篇文章主要为大家详细介绍了 Vue.js 仿 Metronic 高级表格的数据渲染,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
上篇使用 Vue.js 制作仿 Metronic 高级表格(一)静态设计介绍了需求、原型设计以及静态页面实现,这篇讲解如何使用 Vue 渲染数据,实现动态展示。
表格数据
先定义一个数组来保存所有数据:
- var vm = new Vue({
- el: '#content',
- data: {
- book_list: [{
- id: 1,
- name: "标准日本语",
- type: "文化",
- price: 19.00,
- time: 1492502043
- },
- {
- id: 2,
- name: "微观经济学",
- type: "经济",
- price: 29.00,
- time: 1492502143
- },
- {
- id: 3,
- name: "大数据时代",
- type: "经济",
- price: 39.00,
- time: 1492502243
- },
- {
- id: 4,
- name: "TCP/IP协议详解",
- type: "科技",
- price: 49.00,
- time: 1492502343
- },
- {
- id: 5,
- name: "大学英语",
- type: "文化",
- price: 59.00,
- time: 1492502443
- },
- ]
- }
- });
使用 v-for 指令来渲染,将 tr 标签改写成:
- <tr v-for="(book, key) in book_list">
- <td v-text="key + 1">
- </td>
- <td v-text="book.name">
- </td>
- <td v-text="book.type">
- </td>
- <td v-text="book.price">
- </td>
- <td v-text="book.time">
- </td>
- <td>
- <button class="btn btn-info btn-xs">
- <i class="fa fa-pencil">
- </i>
- 修改
- </button>
- <button class="btn btn-danger btn-xs">
- <i class="fa fa-trash">
- </i>
- 删除
- </button>
- </td>
- </tr>
其指令含义为:遍历 book_list 对象,将元素赋值给 book,索引赋值给 key,并且使用元素渲染该 tr 标签 值得注意的是: ① 应该使用 v-text 来设置文本值,这样不会出现闪烁问题。 ② Vue2.0 中,不支持隐式的 $index,需要显式声明,例如上述代码中 "(book, key) in book_list",key 可以看做 $index 数据渲染完了,但是看效果会知道,价格、更新时间需要做一些格式调整。 Vue1.0 中对于价格的调整可以使用
{{book.price | currency}}
也就是过滤器,但在 Vue2.0 中,已废弃默认过滤器了,这意味着我们需要自定义过滤器,并且注册到 Vue 对象中去。 不难写出 currency 和 date 过滤器为:
- Vue.filter('date', function (timestamp) {
- let date = new Date(timestamp*1000);
- let y = date.getFullYear();
- let month = date.getMonth()+1;
- let d = date.getDate();
- let h = date.getHours();
- let m = date.getMinutes();
- let s = date.getSeconds();
- return y + '年'+
- (month < 10 ? '0':'') + month + '月' +
- (d < 10 ? '0':'') + d + '日' +
- (h < 10 ? '0':'') + h + ':' +
- (m < 10 ? '0':'') + m + ':' +
- (s < 10 ? '0':'') + s;
- });
- Vue.filter('currency', function(money, unit, fixed){
- if (isNaN(money)) {return "";}
- if (typeof fixed == 'undefined' || isNaN(fixed)) {
- fixed = 2
- }
- if (typeof unit =='undefined') {
- unit = '¥ ';
- }
- let num = parseFloat(money);
- return unit + num.toFixed(fixed);
- });
再次修改 tr 模板为:
- <td>
- {{book.price | currency}}
- </td>
- <td>
- {{book.time | date}}
- </td>
值得注意的是:过滤器不能和 v-text 指令配合使用,下述代码无法生效:
- <td v-text="book.price | currency">
- </td>
- <td v-text="book.time | date">
- </td>
修改后的表格效果如下:
分页展示
分页其实就是只显示原始数据中,索引值在某一个范围内的数据,可以理解为是一种数据的过滤处理. 如果知道了页容量,当前页码,原始数据集,就能计算出当前页要显示哪些数据。 页码从 1 开始,那么第 N 页的数据,他的索引 (从 0 开始) 范围应该是:(N - 1)*SIZE ~ N*SIZE - 1 由于 "分页" 这一动作具有普遍性,我们现在 methods 中定义一个 pageData 方法:
- methods: {
- pageData: function(data, page_size, page_num) {
- if (! (data instanceof Array)) {
- return [];
- }
- let start = (page_num - 1) * page_size;
- return data.slice(start, start + page_size);
- }
- }
值得注意的是:slice 方法返回的是数组的原始元素,而不是数组的备份(copy)。 "当前页的数据" 我们使用计算属性来完成,而不是方法:
- computed : {
- page_book_list: function() {
- return this.pageData(this.book_list, this.page_size, this.page_num);
- }
- }
值得注意的是:这里没什么值得好注意的。page_size、page_num 是在 data 中定义的。 此时表格的数据集就得换成 page_book_list 了
页码
要渲染页码列表,必须先得到总页数,因为后期可能会增加关键字过滤,所以我们使用计算属性来得到总页数: 不足一页也要当一页来显示
- computed : {
- total_page: function () {
- let len = this.book_list.length;
- let ret = parseInt(len/this.page_size);
- if ((len % this.page_size) != 0) {
- ret++;
- }
- return ret < 1 ? 1 : ret;;
- }
- }
页码列表的渲染使用 v-for 即可,参照 bootstrap 的页码 html,不难写出:
- <ul class="pagination">
- <li :class="{disabled:page_num<=1}" @click="prePage()">
- <a href="javascript:;" rel="external nofollow" rel="external nofollow"
- rel="external nofollow">
- <i>
- «
- </i>
- </a>
- </li>
- <li v-for="n in total_page" :class="{active:page_num==n}">
- <a href="javascript:;" rel="external nofollow" rel="external nofollow"
- rel="external nofollow" v-text="n" @click="page_num=n">
- </a>
- </li>
- <li :class="{disabled:page_num >= total_page}" @click="nextPage()">
- <a href="javascript:;" rel="external nofollow" rel="external nofollow"
- rel="external nofollow">
- <i>
- »
- </i>
- </a>
- </li>
- </ul>
值得注意的是:
① @click 是绑定 click 事件,可以是函数执行,也可是是 js 代码执行 ② :class 是绑定 class 属性,格式是 "样式名称: 条件",当条件为 true 时,才设置这个样式。 此处为何不用 v-show?因为效果太难看了
自定义页容量
这就很简单了,将页码下拉框改造一下即可,不难写出:
- <select class="form-control" v-model="page_size">
- <option
- v-for = "size in [5,10,15,20]"
- :value = "size"
- v-text = "size+'条'">
- </option>
- </select>
① :value 是绑定 value 的值 ② v-model 会使得 select 的 value 与 page_size 绑定,这个绑定双向的
这里会出现一个小 bug,即在切换页容量的时候,会导致总页数变化,有可能总页数会小于当前页。 于是在获取总页数的时候需要对当前页做一些变动:
- total_page: function () {
- let len = this.book_list.length;
- let ret = parseInt(len/this.page_size);
- if ((len % this.page_size) != 0) {
- ret++;
- }
- if (this.page_num > ret) {
- this.page_num = ret;
- } else if (this.page_num < 1) {
- this.page_num = 1;
- }
- return ret < 1 ? 1 : ret;;
- }
本次效果图:
来源: http://www.phperz.com/article/17/0610/333977.html