修改vue第三方组件的内部方法

背景

公司项目需要用到省市区选择器,找了一阵,感觉饿了么团队的region-picker比较美观且好用。然而有一点不太满意,该组件在点击省份/城市时,下拉选择框就会关闭,导致只选择了省份或城市的信息,导致信息选择的不完整,可以查看demo,本来打算在关闭后,再使用事件触发来模拟一个点击事件让选择框重新打开的,但这样用户体验不好,可能会看到选择框闪动,于是便打算修改组件本身。

过程

通过阅读源码,可以发现该组件包含了单选和多选两种组件,这次只考虑修改单选的,于是找到single.vue,从39行开始,可以简单的明白,点击选项时,会调用select方法,因此只要修改select方法就好。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
ul.scroll-option(ref="province")
li(
v-for="province in provinces"
:key="province.adcode"
:class="{ hover: current.province === province }"
@mouseenter="current.province = province; current.city = null"
@click="select(province)"
)
span {{ province.name }}
ul.scroll-option(ref="city")
li(
v-for="city in cities"
:key="city.adcode"
:class="{ hover: current.city === city }"
@mouseenter="current.city = city"
@click="select(city)"
)
span {{ city.name }}
ul.scroll-option(ref="district", v-if="maxLevel > 2")
li(
v-for="district in districts"
:key="district.adcode"
:class="{ hover: current.district === district }"
@mouseenter="current.district = district"
@click="select(district)"
)
span {{ district.name }}

select方法的代码如下。通过console调试可以知道,传给select的place参数是一个具有level的对象,如果传入的是省份,level为1,城市为2,区为3,因此,我们需要让select只接受level为1的参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
select(place) {
this.hidePicker();
this.selected = place;
const map = ['country', 'province', 'city', 'district'];
if (!place.adcode) {
this.current.province = null;
this.current.city = null;
this.current.district = null;
}
const set = (p) => {
const { level } = p;
if (level > 1) {
set(p.parent);
}
this.current[map[p.level]] = p;
};
set(place);
this.clearSearch();
},

首先引入该组件,给该组件加上ref,这里取名为regionPicker。
接着在mounted的钩子上加入一个函数,hackRegionPicker,注意要在mounted的钩子中调用该方法,如果是在created中调用,由于组件尚未加载,通过$refs是获取不到该组件的。

1
2
3
4
5
6
7
8
9
10
11
12
hackRegionPicker() {
// singlePicker 是regionPiker的第一个子组件
let singlePicker = this.$refs.regionPicker.children[0]
// 保存singlePicker的select方法
let select = {...singlePicker}.select
singlePicker.select = place => {
// 只有点击区时才关闭选项
if (place.level ===3) {
select(place)
}
}
}

跳过的坑

原本是直接给select赋值为singlePicker.select的,然而实际上select只是保存了在singlePicker对象中select方法的引用,因此在新的singlePicker.select中调用的select并不是旧的select,而是新的singlePicker.select,实际上这样就成了没有结束条件的递归,导致浏览器卡死。
而使用便利的{…Obj}语法可以成功的保存旧的select函数。

支持作者

如果我的文章对你有帮助,欢迎 关注和 star 本博客 或是关注我的 github,获取更新通知。欢迎发送邮件到hpoenixf@foxmail.com与作者交流