美文网首页
数据动态过滤技巧在 Vue 项目中的实践

数据动态过滤技巧在 Vue 项目中的实践

作者: IT修真院 | 来源:发表于2020-03-23 19:39 被阅读0次

作者简介:
钱昱
多年前端工作经验 《JavaScript 设计模式精讲》 作者,主要分享前端方面技术博客
公众号:前端下午茶

这个问题是在下在做一个 Vue 项目中遇到的实际场景,这里记录一下我遇到问题之后的思考和最后怎么解决的(老年程序员记性不好 -。-),过程中会涉及到一些Vue源码的概念比如 $mount、 render watcher等,如果不太了解的话可以瞅瞅 Vue源码阅读系列文章 ~

问题是这样的:页面从后台拿到的数据是由 0、 1之类的key,而这个key代表的value比如 0-女、 1-男的对应关系是要从另外一个数据字典接口拿到的;类似于这样的Api:

{

"SEX_TYPE"
:

[

{

"paramValue"
:

0
,

"paramDesc"
:

"女"

},

{

"paramValue"
:

1
,

"paramDesc"
:

"男"

}

]

}

那么如果view拿到的是 0,就要从字典中找到它的描述 女并且显示出来;下面故事开始了~

  1. 思考
    有人说,这不是过滤器 filter 要做的事么,直接 Vue.filter 不就行了,然而问题是这个filter 是要等待异步的数据字典接口返回之后才能拿到,如果在 $mount 的时候这个filter没有找到,那么就会导致错误影响之后的渲染(白屏并报 undefined错);

我想到的解决方法有两个:

把接口变为同步,在 beforeCreate或 created钩子中同步地获取数据字典接口,保证在 $mount的时候可以拿到注册好的filter,保证时序,但是这样会阻塞挂载,延长白屏时间,因此不推介;

把filter的注册变为异步,在获取filter之后通知 render watcher 更新自己,这样可以利用vue自己的响应式化更新视图,不会阻塞渲染,因此在下初步采用了这个方法。

  1. 实现
    因为filter属于 assettypes ,关于在Vue实例中assettypes的访问链有以下几个结论;具体代码实践可以参考:Codepen - filter test

asset_types包括 filters、 components、 directives,以下所有的 asset_types都自行替换成前面几项

子组件中的 asset_types访问不到父组件中的 asset_types,但是可以访问到全局注册的挂载在 root.options.asset_types.proto上的 asset_types,这里对应源码 src/core/util/options.js

全局注册方法Vue.assettypes,比如Vue.filters注册的assettypes会挂载到根实例(其他实例的 root)的options.asset_types.proto上,并被以后所有创建的Vue实例继承,也就是说,以后所有创建的Vue实例都可以访问到

组件的slot的作用域仅限于它被定义的地方,也就是它被定义的组件中,访问不到父组件的 asset_types,但是可以访问到全局定义的 asset_types

同理,因为main.js中的 newVue()实例是根实例,它中注册的 asset_types会被挂载在 root.options.asset_types上而不是 root.options.asset_types.proto

根据以上几个结论,可以着手coding了~

2.1 使用根组件的filters
因此首先我考虑的是把要注册的filter挂载到根组件上,这样其他组件通过访问 $root可以拿到注册的filter,这里的实现:

<template>

<div>

{{ rootFilters( sexVal )}}

</div>

</template>

<script

type

'text/javascript'

import

Vue
from
'vue'

import

{
registerFilters
}
from
'utils/filters'

export

default

{

data

()

{

return

{

    sexVal

:

1

// 性别

}

},

methods

:

{

/* 根组件上的过滤器 */

  rootFilters

(
val
,
id
=

'SEX_TYPE'
)

{

const
mth
=

this
.
root .options
.
filters
[
id
]

return
mth
&&
mth
(
val
)

||
val

}

},

created

()

{

// 把根组件中的filters响应式化

Vue
.
util
.
defineReactive
(
this
.
root .options
,

'filters'
,

this
.
root .options
.
filters
)

},

mounted

()

{

  registerFilters

.
call
(
this
)

.
then
(
data
=>

// 这里获取到数据字典的data

)

}

}

</script>

注册filter的js

// utils/filters

import

as
Api
from
'api'

/**

  • 获取并注册过滤器

  • 注册在root.options.filters上不是root.options.filters.proto

  • 注意这里的this是vue实例,需要用call或apply调用

  • @returns {Promise}

*/

export

function
registerFilters
()

{

return

Api
.
sysParams
()

// 获取数据字典的Api,返回的是promise

.
then
(({
data
})

=>

{

Object
.
keys
(
data
).
forEach
(
T
=>

this
.
set ( this .root
.
$options
.
filters
,
T
,
val
=>

{

const
tar
=
data
[
T
].
find
(
item
=>
item
[
'paramValue'
]

===
val
)

return
tar
[
'paramDesc'
]

||

''

})

)

return
data

})

.
catch
(
err
=>
console
.
error
(
err
,

' in utils/filters.js'
))

}

这样把根组件上的filters变为响应式化的,并且在渲染的时候因为在 rootFilters方法中访问了已经在created中被响应式化的 root.options.filters,所以当异步获取的数据被赋给 root.options.filters的时候,会触发这个组件render watcher的重新渲染,这时候再获取 rootFilters方法的时候就能取到filter了;

那这里为什么不用Vue.filter方法直接注册呢,因为 Object.defineProperty不能监听 proto上数据的变动,而全局Vue.filter是将过滤器注册在了根组件 root.options.asset_types.proto上,因此其变动不能被响应。

这里的代码可以进一步完善,但是这个方法存在一定的问题,首先这里使用了 Vue.util上不稳定的方法,另外在使用中到处可见 this.root.options这样访问vue实例内部属性的情况,不太文明,读起来也让人困惑。

因此在这个项目做完等待测试的时候我思考了一下,谁说过滤器就一定放在filters里面 -。-,也可以使用mixin来实现嘛

2.2 使用 mixin
使用mixin要注意一点,因为vue中把data里所有以 _、 开头的变量都作为内部保留的变量,并不代理到当前实例上,因此直接 this._xx是无法访问的,需要通过 this.data._xx来访问。

// mixins/sysParamsMixin.js

import

as
Api
from
'api'

export

default

{

data
()

{

return

{

  _filterFunc

:

null
,

// 过滤器函数

  _sysParams

:

null
,

// 获取数据字典

  _sysParamsPromise

:

null

// 获取sysParams之后返回的Promise

}

},

methods
:

{

/* 注册过滤器到_filterFunc中 */

_getSysParamsFunc

()

{

const

{
$data
}

=

this

return
$data
.
_sysParamsPromise
||

(
$data
.
_sysParamsPromise
=

Api
.
sysParams
()

.
then
(({
data
})

=>

{

this
.
$data
.
_sysParams
=
data

this
.
$data
.
_filterFunc
=

{}

Object
.
keys
(
data
).
forEach
(
paramKey
=>

this
.
$data
.
_filterFunc
[
paramKey
]

=
val
=>

{

const
tar
=
data
[
paramKey
].
find
(
item
=>
item
[
'paramValue'
]

===
val
)

return
tar
&&
tar
[
'paramDesc'
]

||

''

})

return
data

})

.
catch
(
err
=>
console
.
error
(
err
,

' in src/mixins/sysParamsMixin.js'
)))

},

/* 按照键值获取单个过滤器 */

_rootFilters

(
val
,
id
=

'SEX_TYPE'
)

{

const
func
=

this
.
$data
.
_filterFunc

const
mth
=
func
&&
func
[
id
]

return
mth
&&
mth
(
val
)

||
val

},

/* 获取数据字典 */

_getSysParams

()

{

return

this
.
$data
.
_sysParams

}

}

}

这里把 Api的 promise 保存下来,如果其他地方还用到的话直接返回已经是 resolved状态的 promise,就不用再次去请求数据了。另外为了在其他实例中也可以方便的访问,这里挂载在根组件上。

那在我们的根组件中怎么使用呢:

// src/main.js

import
sysParamsMixin from
'mixins/sysParamsMixin'

new

Vue
({

el
:

'#app'
,

mixins
:

[
sysParamsMixin
],

render
:
h
=>
h
(
App
),

})

在需要用过滤器的组件中:

<template>

<div>

{{ $root._rootFilters( sexVal )}}

</div>

</template>

<script

type

'text/javascript'

export

default

{

data

()

{

return

{
sexVal
:

1

}

},

mounted

()

{

this
.
$root
.
_getSysParamsFunc
()

.
then
(
data
=>

// 这里获取到数据字典的data

)

}

}

</script>

这里不仅注册了过滤器,而且也暴露了数据字典,以方便某些地方的列表显示,毕竟这是实际项目中常见的场景。

当然如果使用 vuex 更好,不过这里的场景个人觉得没必要用 vuex,如果还有更好的方法欢迎讨论一下下啊~

作者简介:
钱昱
多年前端工作经验 《JavaScript 设计模式精讲》 作者,主要分享前端方面技术博客
公众号:前端下午茶

本文已经获得钱昱老师授权转发,其他人若有兴趣转载,请直接联系作者授权。

相关文章

  • 数据动态过滤技巧在 Vue 项目中的实践

    作者简介:钱昱多年前端工作经验 《JavaScript 设计模式精讲》 作者,主要分享前端方面技术博客公众号:...

  • 数据动态过滤技巧在 Vue 项目中的实战

    这个问题是在下在做一个 Vue 项目中遇到的实际场景,这里记录一下我遇到问题之后的思考和最后怎么解决的(老年程序员...

  • Vue项目数据动态过滤实践

    这个问题是在下在做一个Vue项目中遇到的实际场景,这里记录一下我遇到问题之后的思考和最后怎么解决的(老年程序员记性...

  • Vue 项目数据动态过滤实践

    这个问题是在下在做一个Vue项目中遇到的实际场景,这里记录一下我遇到问题之后的思考和最后怎么解决的(老年程序员记性...

  • VUE 全局设置fliters

    在项目中使用到的经常用到过滤器,比如时间,数据截取等过滤器,如果在每个.vue中都可以复制同一个过滤器,这可以达到...

  • 2019-03-25

    vue v-for通过index动态绑定input输入框的数据 vue项目中经常会遇到各种难题,比如v-for...

  • Vue-04

    过滤器:对显示在页面上的数据进行筛选 全局过滤器 和Vue同级 Vue.filter(“过滤器名称”,func...

  • vue之自定义过滤器(六)

    一、过滤器介绍:1、在Vue中会通过过滤器(Filters)来渲染数据,使视图可读性更加优雅。2、Vue中的过滤器...

  • vue搜索过滤、tab切换高亮显示

    vue项目中常用的方法关键词: vue2.0,搜索过滤,tab切换高亮显示

  • vue-awesome-swiper结合echarts的那些坑~

    前题 vue项目中引用vue-awesome-swiper轮播组件通过动态组件动态加载Echarts绘成的图形,进...

网友评论

      本文标题:数据动态过滤技巧在 Vue 项目中的实践

      本文链接:https://www.haomeiwen.com/subject/rhkgyhtx.html