关于javascript:如何使用多个组件来过滤数据

How to use multiple component to filter data

我想要发生的是,当您单击左侧的单选按钮时,它会过滤右侧的内容以仅显示相同的位置。

当有人单击单选按钮时,我不知道如何发出事件。

我在这个 vue 代码中使用了 x-template。

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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
const locations = {
    options: [
        {
            title: 'A',
            value: 'a'
        },
        {
            title: 'B',
            value: 'b'
        },
        {
            title: 'C',
            value: 'c'
        }]
};
const team = {
    options: [
        {
            name: 'Team A',
            location: 'a'
        },
        {
            name: 'Team B',
            location: 'b'
        },
        {
            name: 'Team C',
            location: 'c'
        }]
};

Vue.component('location-filter', {
    template: '#location-filter',
    props: {
        location: {
            type: Array,
            required: true
        }
    }

});


new Vue({
    el: '#location-finder',
    data: {
        location: locations.options,
        teams: team.options
    }
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
.page {
    padding:5px;
    border:1px solid #cccccc;
    display:flex;
    flex-flow:row;
}

.sidebar {
    flex-grow:0.6;
    border: 1px solid red;
    padding:10px;
}

.body {
    padding:10px;
    border:1px solid blue;
    flex-grow:1;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js">

   
   
    <location-filter :location="location"></location-filter>
   
   
   
    {{ team.name }}




<script type="text/x-template" id="location-filter">
   
   
    <label>
<input type="radio" name="place" value="place.value">{{ place.title }}
</label>

希望我的解释和代码足以让您了解我正在努力实现的目标。


您可以从组件内部发出自定义事件,例如当用户单击单选标签时,如下所示:

1
<label @click="$emit('location', place.value)">

我将事件命名为 location。现在您可以在父模板 (locationFinder) 中监听名为 location 的事件,如下所示:

1
<location-filter :location="location" @location="changeLocation">

现在,locationFinder 将尝试在每次发出 location 事件时调用名为 changeLocation 的实例中的方法。下面是这个方法的样子:

1
2
3
changeLocation(location) {
    this.selected = location;
}

您可以看到它为所选位置设置了一个名为 selected 的数据属性。因此,现在您将需要 teams 循环来检查 selected 位置,并且仅在其位置与所选位置匹配时才显示团队。最好的方法是创建一个 computed 属性,该属性将始终包含团队列表的过滤版本。如果没有选中的队伍,则返回所有队伍:

1
2
3
4
5
6
7
filtered() {
    if (this.selected) {
        return this.teams.filter(team => team.location == this.selected);
    } else {
        return this.teams;
    }
}

最后,更新模板以循环遍历这个 filtered 团队列表而不是未过滤的列表:

1
 

我包含了一个更新的片段。

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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
const locations = {
    options: [
        {
            title: 'A',
            value: 'a'
        },
        {
            title: 'B',
            value: 'b'
        },
        {
            title: 'C',
            value: 'c'
        }]
};
const team = {
    options: [
        {
            name: 'Team A',
            location: 'a'
        },
        {
            name: 'Team B',
            location: 'b'
        },
        {
            name: 'Team C',
            location: 'c'
        }]
};

Vue.component('location-filter', {
    template: '#location-filter',
    props: {
        location: {
            type: Array,
            required: true
        }
    }

});


new Vue({
    el: '#location-finder',
    data: {
        location: locations.options,
        teams: team.options,
        selected: null
    },
    computed: {
        filtered() {
            if (this.selected) {
                return this.teams.filter(team => team.location == this.selected);
            } else {
                return this.teams;
            }
        }
    },
    methods: {
        changeLocation(location) {
            this.selected = location;
        }
    }
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
.page {
    padding:5px;
    border:1px solid #cccccc;
    display:flex;
    flex-flow:row;
}

.sidebar {
    flex-grow:0.6;
    border: 1px solid red;
    padding:10px;
}

.body {
    padding:10px;
    border:1px solid blue;
    flex-grow:1;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js">

   
   
    <location-filter :location="location" @location="changeLocation"></location-filter>
   
   
   
    {{ team.name }}




<script type="text/x-template" id="location-filter">
   
   
    <label @click="$emit('location', place.value)">
<input type="radio" name="place" value="place.value">{{ place.title }}
</label>