栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > Web开发 > Vue.js

手把手教你用Vue造轮子(3):开发可排序的表格组件

Vue.js 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

手把手教你用Vue造轮子(3):开发可排序的表格组件

前言

最近闰土大叔跟Vue干上了,没办法,公司业务驱动,不用Vue没招啊,leader尝到了前后端分离带来的好处,除非你离职,哈哈哈,当然,那是不可能的,对于我这种要攒钱买房子的人来说。那还说什么呢,干就完了。今天,大叔将带你们手把手地造个轮子——开发一个可以对表格某一列数据进行排序的表格组件。

接下来,正文从这开始~

俗话说的好,写个功能组件还不让看展示效果的,都是耍流氓。直接上图:

看到动图是不是更形象生动了呢,之前一直羡慕别人文章里的效果动图,如今大叔也学会如何生成gif动态图了,想取经的童鞋可以私聊我。

先来简单的介绍下,一个标准的表格是由

、、、、里面,可以指定某一列是否需要排序;data是每一行的数据,由columns决定每一行里各列的顺序。

按照惯例,先初始化文件。

    
    


为了让排序后的columns和data不影响原始数据,我们需要给v-table组件的data选项添加两个对应的数据。

Vue.component('vTable',{
    // ...
    data:function(){
 return {
     currentColumns:[],
     currentdata:[]
 }
    }
}    

columns的每一项都是一个对象,对象中有三个字段,分别是title、key、sortable。其中title和key字段是必填的,title用来标识这列的表头标题,key是对应的data中列内容的字段名。sortable是选填字段,如果值为true,说明该列需要排序。

var app = new Vue({
el:'#app',
data:{
    columns:[
 {
     title:'姓名',
     key:'name'
 },
 {
     title:'年龄',
     key:'age',
     sortable:true
 },
 {
     title:'出生日期',
     key:'birthday',
     sortable:true
 },
 {
     title:'地址',
     key:'address'
 }
    ],
    data:[
 {
     name:'司徒正美',
     age:26,
     birthday:'1999-02-21',
     address:'北京市朝阳区芍药居'
 },
 {
     name:'吕大豹',
     age:30,
     birthday:'1992-01-23',
     address:'北京市海淀区西二旗'
 },
 {
     name:'阮一峰',
     age:25,
     birthday:'1987-11-10',
     address:'上海市浦东新区世纪大道'
 },
 {
     name:'张鑫旭',
     age:18,
     birthday:'1991-10-10',
     address:'深圳市南山区深南大道'
 }
    ]
}
})

然后在html结构里,把数据传递给组件v-table:

v-table组件目前的prop:columns和data的数据已经从父级获取到,但是v-table不直接操作它们,而是使用data选项的currentColumns和currentData。所以在v-table初始化时,需要把columns和data赋值给currentColumns和currentData,并且在mounted钩子函数内调用:

Vue.component('vTable',{
  // ...
    methods:function(){
 return {
     makeColumns:function(){
  this.currentColumns = this.columns.map(function(col, index){
      // 添加一个字段标识当前列排序的状态
      col._sortType = 'normal';
      // 添加一个字段标识当前列在数组中的索引
      col._index = index;
      return col;
  })
     },
     makedata:function(){
  this.currentData = this.data.map(function(row, index){
      // 添加一个字段标识当前行在数组中的索引
      row._index = index;
      return row;
  })
     }
 }
    },
    mounted(){
     // v-table初始化时调用
     this.makeColumns();
     this.makeData();
    }
}

在上面的业务代码中,我们用到了map()方法,这是javascript数组中的一个方法,根据传入的函数重新构造一个新数组。排序分为升序(asc)和降序(desc)两种,而且同时只能对一列数据进行排序。为了标识当前列的排序状态,在map列添加数据时,默认给每列都添加一个_sortType字段,赋值为normal,表示默认的排序,也就是不排序。在排序后,currentData每项的顺序都有可能发生变化,所以给currentColumns和currentData的每个数据都添加_index字段,代表当前数据在原始数据中的索引。

到这儿,数据整理阶段便告一段落,接下来就可以用render函数来构造虚拟DOM了。

Vue.component('vTable',{
  // ...
    render:function(h){
 var _this = this;
 var ths = [];
 this.currentColumns.forEach(function(col, index){
     // console.log(col.title);
     if(col.sortable){
  ths.push(h('th',[
      h('span',col.title),
      //升序
      h('a',{
   class:{
on:col._sortType === 'asc'
   },
   on:{
click:function(){
    _this.handleSortByAsc(index)
}
   }
      },''),
      //降序
      h('a',{
   class:{
on:col._sortType === 'desc'
   },
   on:{
click:function(){
    _this.handleSortByDesc(index)
}
   }
      },'')
  ]));
     }else{
  ths.push(h('th',col.title));
     }
 });
 var trs = [];
 this.currentData.forEach(function(row){
     var tds = [];
     _this.currentColumns.forEach(function(cell){
  tds.push(h('td',row[cell.key]));
     });
     trs.push(h('tr',tds));
 });
 return h('table',[
     h('thead',[
  h('tr',ths)
     ]),
     h('tbody',trs)
 ]);
    }
}

上面的h就是createElement,只是换了一个别名而已。表格主体trs是一个二维数组,数据由currentColumns和currentData 组成,然后先遍历所有的行,在每一行内再遍历各列,最终组合出主体内容节点trs。表头的节点ths要相对复杂点,因为加了排序的功能。

如果col.sortable没有定义 ,或者值为false,就直接把col.title渲染出来,否则除了渲染title,还加了两个元素来实现升序和降序的操作。接下来,我们在v-table的methods选项里再添加两个方法(升序 / 降序)

Vue.component('vTable',{
// ...
methods:{
    handleSortByAsc:function(index){
 var key = this.currentColumns[index].key;
 this.currentColumns.forEach(function(col){
     col._sortType = 'normal';
 });
 this.currentColumns[index]._sortType = 'asc';
 this.currentData.sort(function(a,b){
     return a[key] > b[key] ? 1 : -1;
 })
    },
    handleSortByDesc:function(index){
 var key = this.currentColumns[index].key;
 this.currentColumns.forEach(function(col){
     col._sortType = 'normal';
 });
 this.currentColumns[index]._sortType = 'desc';
 this.currentData.sort(function(a,b){
     return a[key] < b[key] ? 1 : -1;
 })
    }
}

}

不管是升序还是降序,目的都是改变currentColumns数组每项的顺序。排序用的是Javascript数组的sort()方法,这里之所以返回1和-1,而不是直接返回a[key]

当渲染完表格后,如果我们点击添加数据按钮(这里也可以设置为删除),使得父级修改了data数据,v-table的currentData也应该得到更新,如果某一列已经排序过,更新后应该监听处理一次排序。

Vue.component('vTable',{
// ...
watch:{
    data:function(){
     this.makeData();
     var sortedColumn = this.currentColumns.filter(function(col){
  return col._sortType !== 'normal';
     });
     if(sortedColumn.length > 0){
  if(sortedColumn[0]._sortType === 'asc'){
      this.handleSortByAsc(sortedColumn[0]._index);
  }else{
      this.handleSortByDesc(sortedColumn[0]._index);
  }
     }
 }
    }

}

通过遍历currentColumns来找出是否按某一列进行过排序,如果有的话,就按照当前排序状态对更新后的数据做一次排序操作。

后记

最近忙碌于公司项目无法抽身,在公众号留言提问的小伙伴们,大叔建议你们可以去我的前端圈里交流讨论,公众号下面的菜单里有加入的方式。另外,你问我问题,我可能不会,就算我会,可能我也没时间。所以,欢迎大家多多关注我的公众号吧!

转载请注明:文章转载自 www.mshxw.com
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号

等元素组成的。搁平常table布局早已经被我们前端仔摒弃了,没有语义化的东西。但当你想用来展示大量结构化的数据时,table却是最好的选择。

接下来,进入正题。

表格组件的所有内容(表头和行数据)由两个prop构成:columns 和data。两者都是数组,columns用来描述每列的信息,并渲染在表头