手机版

Vue.js实现多条件过滤、搜索、排序、分页表功能

时间:2021-09-05 来源:互联网 编辑:宝哥软件园 浏览:

和前面的实用教程一样,在本文中,我将继续从一个公共函数——表中展示Vue.js中的一些优雅特性。同时,我们将比较过滤函数和计算属性,解释它们的适用场景,并准备在2.0版本中删除一些过滤函数。

需求分析

先从需求入手,思考一下实现这样一个功能应该注意什么,一般流程和应用场景。

表本身是一个非常常见的组件,在显示一些复杂的数据时表现很好。当有大量数据时,我们需要提供一些过滤条件,让用户可以更快地列出自己关心的数据。除了一些预设的过滤条件外,可能还需要一些个性化的输入搜索功能。对于订单关系明显的数据,如排名、价格等。需要排序功能来方便数据的快速反演。如果数据量很大,则需要以页面显示表格。需要注意的是,上述需求实际上与大多数数据库提供的功能非常一致,而且由于数据库有索引等优化方法,服务器性能更好,更适合处理这些需求。但是现在流行的前端分离也希望客户端在合理的范围内更多的分担服务器的压力,所以当找到平衡的时候,在前端处理合适的需求才是正确的选择。

接下来,试着用vue来满足这些要求。

完整表格

因为这样的多功能表在很多项目中都可能用到,所以在设计思路上要尽可能把表的相关内容放在Table.vue组件中,这样可以减少耦合,便于复用。

获取测试数据

为了更好地比较上述需求的前端实现的优缺点,我们需要一个庞大而复杂的测试数据。幸运的是,在我之前的项目中,我设计了一个API来满足这个需求。数据是魔兽世界竞技场的阶梯排名API。目前这个API处于开放状态,界面详细在Myarena。

与前面的教程类似,创建一个新的api文件夹和一个arena.js来管理API接口。然后在App.vue中引入arena.js,获取创建阶段的数据。作为演示,我们只得到区域为CN、laddar为3v3的数据,但只要通过v-model将这两个参数绑定到对应的表单控件上,就可以轻松切换不同区域的数据。

介绍table.vue组件

如前所述,我们希望减少表组件与外部环境之间的耦合,所以我们为Table.vue设置了一个props属性行,以获取App.vue检索到的数据,在App.vue中注册表构建时,需要注意的是,默认表不能用于命名,所以如果注册为vTable,可以引入带有v-table标签的表组件。

到目前为止,我们的App.vue已经完成了所有功能,代码如下:

模板div class=' container ' v-table : rows=' rows '/v-table/div/templatescript import arena from '。/api/arena“从导入vTable”。/components/Table ' export default { components : { vTable },data () { return { region: 'CN ',laddar: '3v3 ',row 3360[]},methods: { getLaddar (region,laddar){ area . getLaddar(region,laddar,(err,val)={ if(!呃){这个。rows=val。row } })}),创建了(){this。getladdar(这个。这个地区。laddar)}}/script还有一个在API中获取上次更新时间的操作,以及实际App.vue中的一些css设置,这里省略。那些对完整代码感兴趣的人可以被转移

基本布局

Table.vue的模板有三个主要部分,分别是用于搜索、过滤和分页的表单控件、用于对表格进行排序的标题和用于显示数据的正文。

首先完成tbody的部分,基本思路是用v-for遍历数据,然后通过模板填写,注意以下要点:

返回的数据可能不完全符合要求。比如我希望按胜率排序,但数据只包含输赢场数,需要先计算一次。2.数据中用来显示玩家职业的数据是classId,但是在实际项目中,我想通过每个职业的图标来显示职业,所以我在utils.js中实现了一个classIdToIcon的工具函数,将classId映射到sprite图中的背景位置。以上两点说明我们最好不要遍历道具获得的行的原始数据。因此,创建了另一个计算属性播放器,并在其中完成了预处理。我把所有的预处理都放在handleBefore了。由于要使用的各种过滤器的操作比较复杂,所以console . log(' handlebefore ')是在handlebefore中进行的,这便于我们验证handle before是在哪个阶段执行的。布局完成后,表中的关键代码如下:

模板t body tr-v-for=' player of players : class=' player .派性Id?部落' : '联盟''第{ { player . ranking } }/第{{ player.rating }}/第span class=' class ' : style=' { background image : ' URL(http://7 xs 8 rx.com 1 . z0 . glb . cloud dn.com/class . png)',background position : player . classion } '/span { { player . name } }/第{{ player.realmName }}/Bar“从导入{ classIdToIcon }./assets/utils ' export default { components : { Bar },prop : { rows 3360 { type : Array,default: ()={ return [] } },computed : { players(){ this . rows=this . handlebefore(this . rows)return this . rows } }, methods : { handleBefore(arr){ console . log(' before handle ')if(this . rows[0]){ arr . foreach((item)={ if(item . weekly wins===0 item . weekly loss===0){ item . weekly late=-1 } else { item . weekly late=item . weekly wins/(item . weekly wins item . weekly loss)} if(item . seasonwins===0 item . seasonloss==0){ item。

一开始我是直接在胜率所在的th标签里做各种操作,但是可以想象,在判断一些边界条件的时候,会出现各种包含player等长命名变量的三元表达式。每周获胜和玩家。每周亏损。最初,这是为了方便,但这使得代码难以维护。因此,创建了一个新的bar组件,并将结果传递到组件中,该组件在bar组件中以更具语义的方式实现。条形码中模板的代码如下:

模板div class='clear-fix' span v-if='!hasGame | | win/total 0 ' : style=' { width : 100 * win/total ' % ' } ' : class=' hasGame '?“无游戏”类=“win-bar“{ hasGame?(100 *赢/总数)。tofixed (1)'%' : '无会话' } }/span v-if=' loss/total 0 ' : style=' { width : 100 * loss/total ' % ' } ' class=' loss 0% ' : ' ' } }/span/div/template更好理解和维护,不是吗?

在使用vue的过程中,需要注意的是,框架中的很多方法实际上在内部以同样的方式结束。

比如我们可以直接对元素中的数据进行一些操作,比如@click='show=!显示。同样,我们可以将方法绑定到事件,并在方法中操作数据,例如@ click=' toggle ',toggle () {this。show=!这个节目.例如,我们可以使用计算属性和观察属性来实现许多相同的功能,然后我们将使用计算来实现与过滤器相同的功能。

vue设计中的灵活性让我们有了更多的可能性,但是在学习的时候,我们应该针对不同场景下不同方式的优缺点进行理解,在实践中选择最好的一种。

使用过滤器实现需求

在示例中,players实际上是一个5000条数据的数组,它将直接渲染5000个TRs,无需任何处理,所以先过滤一下吧!

对于v-for循环,vue提供了三个过滤器过滤器数组,即过滤依据、排序依据和限制依据,其功能对应于搜索/过滤、排序和分页,实现方式为数组。过滤器,阵列。sort()和array。切片()。

这三种过滤器使用起来都非常方便,只要用|将v-for后对应的过滤器分开添加,这三种过滤器的具体参数可以从官方API查看,这里就不赘述了。

需要注意的是,实际的过程是将遍历的数组(示例中的玩家)依次通过过滤器,然后对最后一个过滤器返回的数组执行v-for操作。

因此,放置过滤器的顺序需要根据需求进行调整,由于每个过滤器的内部实现效率不同,所以在需求优先级不明显时,应该优先考虑效率。

注意:在实际测试中发现,无论如何过滤数组,handleBefore方法都没有再次执行,也就是说玩家数组没有改变。

比如在我的例子中,我希望过滤掉名字或服务器包含我输入内容的玩家,并按照一定的方式进行排序,最终的结果只会显示每页20个条目。那么显然切割数组应该永远是最后一步,排序和过滤在需求上没有明显的优先级。但是在大多数情况下,排序的效率要低于过滤,所以我们先过滤减少数组的长度,然后再排序。

有了这个想法,tr对于v-for就变成了:

trv-for=' player of players | filter by在' name ' ' realmName ' | order by sort . key sort . val | limit by 20(page-1)* 20 ' : class=' player .派性Id '?千军万马' :'alliance ' '这里直接动态改变所有变量,然后通过Table.vue中的输入绑定v-model和header thead binding @click事件改变过滤条件,实现了大部分的搜索、过滤、分页功能。

我通过下面的代码实现了表头变化排序排序,可能不是很好,在此列出来:

the and tr th @ click=' sort={ key : ' ranking ',val:-sort.val} ' ranking/th th @ click=' sort={ key : ' rating ',val :-sort . val } ' score/th data/th server/th @ click=' sort={ key : ' weekly rate ',val :-sort . val } '本周记录th @ click=' sort={ key :val} '赛季的战绩/th /tr/thead,我们可以看到我们的大部分功能都可以通过vue的filters功能轻松完成,用的代码非常少这也是很多人在vue2.0的前瞻发布后反应强烈的原因,它提出放弃一些filters功能。然而,正如作者在变更说明中所说,过滤器对于初学者来说很难理解,通过使用计算属性可以更灵活地实现和更好地控制过滤器的功能。此外,在一些复杂的条件下,堆叠过滤器会造成一些额外的复杂性和不便。

那么什么是复杂条件呢?比如我加两个要求,一个是按职业筛选玩家,但是要筛选出一定分数以上的玩家,所以后者用filterBy没有很好的实现。我们需要先过滤分数段再过滤,但注意不要破坏玩家阵列本身。当实际完成时,会发现这个过程还是比较纠结的。

另外,我们会发现页面中最重要的信息——是无法获取的。因为vue没有暴露在一系列过滤管道中产生并最终用于v-for的数组,所以我们无法得到实际循环的数组长度。

当实际黑客攻击这些需求时,发现很容易与过滤器的执行顺序发生冲突,于是决定重新使用计算属性来实现所有功能,而不使用自己的过滤器。

当然,在这一段的前半部分,我们明显感受到了滤镜带来的便利。如果过滤器可以满足需求,那么在1.x版本中使用过滤器是明智的!

用计算属性完成需求

在Github仓库中,我将上一段过滤器实现的代码存储在Table.vue.bak文件中,便于与我们下一段的实现进行比较。

首先,理清使用计算属性的思路:

首先要实现filter by、order by、limit by的函数,它们的内部实现在上一篇文章中已经提到过,所以分别用Array.filter、Array.sort、Array.slice重写并不复杂。说是计算属性的实现,其实只有计算属性玩家,里面只执行所有过滤动作。我们实际上把各种过滤器的逻辑放在各种方法中。不建议把每一个过滤器方法写得太抽象,因为有些特殊的需求因为内置过滤器的高度抽象而无法实现,所以我们不妨用最有针对性的方式:一个方法对应一个过滤器。在执行每一种过滤方法的时候,还是会出现最初提到的顺序带来的效率问题。由于vue具有整体移动的特性,当任何滤波条件发生变化时,所有滤波方法都会执行一次,因此尽快用高效的滤波器缩短阵列长度更为重要。我试图通过watch属性最小化方法调用,但是我做不到。同时,我也认为前端处理大量数据的情况并不多见,用第4点的数据进行优化后执行效率也不会太低,在这方面不需要做太多纠缠。当出现性能瓶颈时,更容易从服务器端找到解决方案。注意:实现各种过滤方式时,建议在vue中阅读filter by、order by、limit by的源代码,对数组运算有一定的优化,值得学习。在一些特殊情况下,比如数组中有大量相等的值时,过于简单的排序函数会导致执行步骤数急剧增加,vue中的一些处理就被避免了。

根据需求,我设置了以下方法(顺序为执行顺序):

ClassFilter:过滤玩家职业,按项目判断. classId===this.class,绑定一个select控件。QueryFilter:匹配玩家姓名中的字段,通过item.name.indexOf(this.query)判断,this.query绑定了一个输入控件。RatingFilter:过滤玩家分数段,按项目判断,rating=this.rating,与range类型的输入控件绑定,范围由computed属性计算。SortTable:因为Array.sort的步骤比较多,所以应该在用上面三种方法处理完数组之后再执行。分页:所有过滤操作完成后,可以开始分页。在使用Array.slice()之前,将数组的长度转换为this.total,并将其存储起来,以便计算分页后的总页数。除了上面的过滤方法,当然还有一个handleBefore方法来预处理数组。但是由于玩家每次都会重新计算,为了停止handleBefore的重复执行,需要添加一定的判断条件,比如handleBefore添加的属性是否已经存在等等。同时,一些过滤前不需要执行的动作,可以从handleBefore中取出,比如示例中的classId可以转换为Icon,过滤后就可以执行最终要显示的数据,减少了步骤。因此,handleAfter方法被设置为在分页完成后执行后续操作。当然,也可以在handleAfter中重复。因此,如果执行的操作消耗很大,建议增加判断,避免重复执行。在示例代码中,我计算了每个方法中执行的步骤数。实际结果表明,设置合理的过滤顺序可以避免一些性能问题。结果如下:

可以看出,初始化时,排序的步数较高,无需任何过滤。一旦增加一些过滤条件,低阶过滤和排序的步骤就会大大减少。

演示地址

由于工作繁忙,没有计划重建开头显示的MyArena项目,但我可以想象,这将是一个用vue制作单页应用程序的好例子,它可能会在后续教程中作为一个例子。

本教程中的示例侧重于展示多功能桌子本身

DEMO地址指向我的Github仓库

写作计划

上周是第一篇关于Vue.js开发实践的文章,也是第一次在SF社区个人专栏发表文章,希望分享一些平时遇到的问题和解决方法,自己整理一下。

这一系列的开发实践会用一些小例子来展示一些思路,实现一些有用的、可复用的常用功能。计划中会有两个系列的文章:Vue.js实用系列和Sails.js实用系列。前者从一个比较完整的项目入手,分析了技术选择、vue-router和vuex的使用、多终端共享代码、后期维护等方面的一些考虑。后者是用Sails.js框架搭建企业级Node.js后端的一些尝试和经验,包括框架的优缺点、横向比较和细节探索。目前我们也在关注阿里开源项目Weex的内部测试进展。理想的状态是使用Weex在移动终端App上实现项目的开发,真正完成JS全栈。不过Weex还没有正式开放源码,还有待观察,所以只是后期想法,暂时没有计划。

文章目前只在SF专栏发表,如有意见或建议,请在文章下方留言。同时,因为我负责上面提到的所有工作,文章的更新可能快也可能慢,争取做到一周一篇。

以上就是本文的全部内容。希望对大家的学习有帮助,支持我们。

版权声明:Vue.js实现多条件过滤、搜索、排序、分页表功能是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。