我是靠谱客的博主 鲤鱼早晨,这篇文章主要介绍vue商城中商品“筛选器”功能的实现代码,现在分享给大家,希望可以做个参考。

   在使用vue搭建商城项目的时候,要实现一个商品筛选器的功能,在完成之后,再一次被vue的数据驱动的强大感到震撼!

       首先,我们来看一下具体的需求吧。你可以先看下面的这两张图,然后再看文字描述,可能会更容易理解。

没有触发时的状态

触发后的状态

       我们需求有下面几点:
       1、默认情况下,只显示一级菜单,二级菜单不显
       2、存在二级菜单的情况下,在二级菜单没有显示的情况下,点击一级菜单,一级菜单的样式发生改变,二级菜单不显示
       3、存在二级菜单的情况下,一级菜单已经点击过之后,再点击一级菜单,会显示二级菜单
       我们举例子说明一下,当前的一级菜单有默认、有货优先、直营优先,只有默认是含有二级菜单的,比如现在焦点在有货优先上面,那么我们点击默认的时候,不会弹出默认下面的二级菜单,只会改变一级菜单默认的样式(字体和三角形的颜色),当再次点击一级菜单默认的时候,其下面的二级菜单就显示出来了。
       需求分析完成后,我们开始编写代码吧。

一、创建筛选器数据结构

       跟以前的开发方式不同,我们首先要创建数据结构,而不是编写模版代码。

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
// 数据源 optionsDatas: [ { id: '1', name: '默认', subs: [ { id: '1', name: '默认', }, { id: '1-2', name: '价格由高到低', }, { id: '1-3', name: '销量由高到低', }, ] }, { id: '2', name: '有货优先', subs: [] }, { id: '3', name: '直营优先', subs: [] } ]

       这个数据结构设计得是非常出彩的,此处您可能还看不到,在下面具体的应用中你就能感觉到它的优美呢。

2、设置二级菜单(选中项subs)的数据结构

复制代码
1
2
3
4
5
6
7
8
9
10
// 选中的筛选项 selectOption: {}, // 是否展开子筛选项 sShowSubContent: false 当然,我们要在created钩子函数中对selecOption进行赋值操作,保证其具有初始值。 created: function () { // 设置初始选中项 this.selectOption = this.optionsDatas[0]; }

二、设置模版代码

       下面是完整模版代码,内容相对比较多,我们按照功能逐块进行讲解吧。

复制代码
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
<div class="goods-options z-index-2"> <ul class="goods-options-list"> <li class="goods-options-item" v-for="(item, index) in optionsDatas" :key="index"> <a class="goods-options-item-content" @click="onOptionsItemClick(item, index)"> <span class="goods-options-item-content-name" :class="{'goods-options-item-content-name-active' : selectOption.id === item.id}">{{item.name}}</span> <span class="goods-options-item-content-caret caret" v-if="item.subs.length > 0" :class="[isShowSubContent && selectOption.id === item.id ? 'goods-options-item-content-caret-open' : 'goods-options-item-content-caret-close']" ></span> </a> </li> </ul> <transition name="fold-height"> <div class="options-sub-content z-index-2" v-show="isShowSubContent"> <ul class="options-sub-content-list"> <li class="options-sub-content-list-item" v-for="(item, index) in selectOption.subs" :key="index" @click="onSubOptionsItemClick(item, index)"> <a class="options-sub-content-list-item-content"> <span class="options-sub-content-list-item-content-name" :class="{'options-sub-content-list-item-content-name-active' : selectOption.id === item.id}">{{item.name}}</span> <img class="options-sub-content-list-item-content-select" v-show="selectOption.id === item.id" src="@img/options-select.svg" alt="" srcset=""> </a> </li> </ul> </div> </transition> <div class="cover" v-show="isShowSubContent" @click="isShowSubContent = false"></div> </div> 1、渲染一级菜单 <ul class="goods-options-list"> <li class="goods-options-item" v-for="(item, index) in optionsDatas" :key="index"> <a class="goods-options-item-content" @click="onOptionsItemClick(item, index)"> <span class="goods-options-item-content-name" :class="{'goods-options-item-content-name-active' : selectOption.id === item.id}">{{item.name}}</span> <span class="goods-options-item-content-caret caret" v-if="item.subs.length > 0" :class="[isShowSubContent && selectOption.id === item.id ? 'goods-options-item-content-caret-open' : 'goods-options-item-content-caret-close']" ></span> </a> </li> </ul>

1.1、一级菜单的样式变化

       一级菜单的文字颜色的变化需要满足下面的规则,也就是selectOption.id === item.id。也就是说在当选中是一级菜单是默认的时候,我们就要其文字颜色改编成红色。

:class="{'goods-options-item-content-name-active' : selectOption.id === item.id}"

       相应地,三角形的颜色和箭头的朝向也需要进行更改。更改的逻辑如下。当然,如果一级菜单没有对应的二级菜单时,三角形就不应该显示。

:class="[isShowSubContent && selectOption.id === item.id ? 'goods-options-item-content-caret-open' : 'goods-options-item-content-caret-close']"
v-if="item.subs.length > 0"

1.2、一级菜单的点击事件onOptionsItemClick(item, index)实现的主要功能是改变一次菜单的样式和二级菜单的显示/隐藏。具体的功能如下分析所示:
       1、如果子选项视图处于展开状态,则关闭掉子选项视图
       2、展示子选项视图
              2.1、选中项包含子选项
              2.2、当前筛选项处于选中状态
       3、设置选中项为用户点击的选项

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
onOptionsItemClick: function (item, index) { // 如果子选项视图处于展开状态,则关闭掉子选项视图 if (this.isShowSubContent) { this.isShowSubContent = false; return; } // 1、选中项包含子选项 // 2、当前筛选项处于选中状态 // 展示子选项视图 if (item.subs.length > 0 && this.selectOption.id === item.id) { this.isShowSubContent = true; } // 设置选中项为用户点击的选项 this.selectOption = item; }

2、渲染二级菜单

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
<transition name="fold-height"> <div class="options-sub-content z-index-2" v-show="isShowSubContent"> <ul class="options-sub-content-list"> <li class="options-sub-content-list-item" v-for="(item, index) in selectOption.subs" :key="index" @click="onSubOptionsItemClick(item, index)"> <a class="options-sub-content-list-item-content"> <span class="options-sub-content-list-item-content-name" :class="{'options-sub-content-list-item-content-name-active' : selectOption.id === item.id}">{{item.name}}</span> <img class="options-sub-content-list-item-content-select" v-show="selectOption.id === item.id" src="@img/options-select.svg" alt="" srcset=""> </a> </li> </ul> </div> </transition>

2.1、二级菜单样式的变化
       二级菜单的样式变化需要满足下面的规则。这个规则基本上跟一级菜单的一致。

:class="{'options-sub-content-list-item-content-name-active' : selectOption.id === item.id}"

       对于右侧的对勾,需要符合下面的逻辑。

v-show="selectOption.id === item.id"

2.2、二级菜单的点击事件onSubOptionsItemClick(item, index),这个事件需要实现功能如下:
       1、设置选中项为用户点击的选项
       2、将选中项置顶
       3、关闭子选项视图

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
onSubOptionsItemClick: function (subItem, index) { // 遍历所有的可选项,将选中项置顶 this.optionsDatas.forEach(options => { options.subs.forEach (subOptions => { if (subOptions.id === subItem.id) { options.id = subOptions.id; options.name = subOptions.name; } }) }); // 关闭子选项视图 this.isShowSubContent = false; }

2.3、二级菜单动画的实现
       二级菜单动画的实现,我们采用了vue的过度动画。其使用到的css动画如下:

复制代码
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
/** 子选项内容区展开动画,当 v-if=“true” 的时候调用 当子选项部分展开时,初始状态max-height为0,结束状态max-height为180 */ .fold-height-enter-active { animation-duration: .3s; animation-name: fold-height-open; } @keyframes fold-height-open { 0% { max-height: 0; } 100% { max-height: px2rem(180); } } /** 子选项内容区关闭动画,当 v-if=false 的时候调用 当子选项部分关闭时,初始状态max-height为180,结束状态max-height为0 */ .fold-height-leave-active { animation-duration: .3s; animation-name: fold-height-close; } @keyframes fold-height-close { 0% { max-height: px2rem(180); } 100% { max-height: 0; } }

2、遮罩的显示/隐藏

       最后就剩下一个遮罩的样式和逻辑了,这个比较简单,其逻辑如下:此处不在进行多余的解释。

复制代码
1
2
<div class="cover" v-show="isShowSubContent" @click="isShowSubContent = false"> </div>

       至此,我们所有的逻辑分析和代码实现都已完成。设计的最巧妙的就是这个数据结构,完全满足了我们业务需求。在下面是完整的代码,希望对您有用。

复制代码
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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
<template> <div class="goods-options z-index-2"> <ul class="goods-options-list"> <li class="goods-options-item" v-for="(item, index) in optionsDatas" :key="index"> <a class="goods-options-item-content" @click="onOptionsItemClick(item, index)"> <span class="goods-options-item-content-name" :class="{'goods-options-item-content-name-active' : selectOption.id === item.id}">{{item.name}}</span> <span class="goods-options-item-content-caret caret" v-if="item.subs.length > 0" :class="[isShowSubContent && selectOption.id === item.id ? 'goods-options-item-content-caret-open' : 'goods-options-item-content-caret-close']" ></span> </a> </li> </ul> <transition name="fold-height"> <div class="options-sub-content z-index-2" v-show="isShowSubContent"> <ul class="options-sub-content-list"> <li class="options-sub-content-list-item" v-for="(item, index) in selectOption.subs" :key="index" @click="onSubOptionsItemClick(item, index)"> <a class="options-sub-content-list-item-content"> <span class="options-sub-content-list-item-content-name" :class="{'options-sub-content-list-item-content-name-active' : selectOption.id === item.id}">{{item.name}}</span> <img class="options-sub-content-list-item-content-select" v-show="selectOption.id === item.id" src="@img/options-select.svg" alt="" srcset=""> </a> </li> </ul> </div> </transition> <div class="cover" v-show="isShowSubContent" @click="isShowSubContent = false"></div> </div> </template> <script> export default { data: function () { return { // 数据源 optionsDatas: [ { id: '1', name: '默认', subs: [ { id: '1', name: '默认', }, { id: '1-2', name: '价格由高到低', }, { id: '1-3', name: '销量由高到低', }, ] }, { id: '2', name: '有货优先', subs: [] },{ id: '3', name: '直营优先', subs: [] } ], // 选中的筛选项 selectOption: {}, // 是否展开子筛选项 isShowSubContent: false } }, created: function () { // 设置初始选中项 this.selectOption = this.optionsDatas[0]; }, methods: { /** * 1、如果子选项视图处于展开状态,则关闭掉子选项视图 * 2、展示子选项视图 * 1、选中项包含子选项 * 2、当前筛选项处于选中状态 * 3、设置选中项为用户点击的选项 */ onOptionsItemClick: function (item, index) { // 如果子选项视图处于展开状态,则关闭掉子选项视图 if (this.isShowSubContent) { this.isShowSubContent = false; return; } // 1、选中项包含子选项 // 2、当前筛选项处于选中状态 // 展示子选项视图 if (item.subs.length > 0 && this.selectOption.id === item.id) { this.isShowSubContent = true; } // 设置选中项为用户点击的选项 this.selectOption = item; }, /** * 1、设置选中项为用户点击的选项 * 2、将选中项置顶 * 3、关闭子选项视图 */ onSubOptionsItemClick: function (subItem, index) { // 设置选中项为用户点击的选项 // this.selectOption = subItem; // 遍历所有的可选项,将选中项置顶 this.optionsDatas.forEach(options => { options.subs.forEach (subOptions => { if (subOptions.id === subItem.id) { options.id = subOptions.id; options.name = subOptions.name; } }) }); // 关闭子选项视图 this.isShowSubContent = false; }, }, watch: { /** * 当选择项发生变化的时候,需要通知父组件 */ selectOption: function (newValue, oldValue) { this.$emit('optionsChange', newValue); } } } </script> <style lang="scss" scoped> @import '@css/style.scss'; .goods-options { width: 100%; border-bottom: 1px solid $lineColor; &-list { display: flex; width: 100%; height: $goodsOptionsHeight; background-color: white; .goods-options-item { flex-grow: 1; &-content { height: 100%; display: flex; justify-content: center; align-items: center; &-name { font-size: $infoSize; margin-right: $marginSize; &-active{ color: $mainColor; } } // 子选项展开时,三角形的动画 &-caret { &-open { transform:rotate(-180deg); transition: all .3s; } &-close { transform:rotate(0deg); transition: all .3s; } } } } } // 子选项内容区 .options-sub-content { // 脱离标准文档流 position: absolute; width: 100%; max-height: px2rem(180); overflow: hidden; overflow-y: auto; background-color: white; &-list { &-item { &-content { display: flex; align-items: center; border-top: 1px solid $lineColor; padding: $marginSize; height: px2rem(44); box-sizing: border-box; &-name { font-size: $infoSize; display: inline-block; flex-grow: 1; &-active{ color: $mainColor; } } &-select { width: px2rem(18); height: px2rem(18); } } } } } /** 子选项内容区展开动画,当 v-if=“true” 的时候调用 当子选项部分展开时,初始状态max-height为0,结束状态max-height为180 */ .fold-height-enter-active { animation-duration: .3s; animation-name: fold-height-open; } @keyframes fold-height-open { 0% { max-height: 0; } 100% { max-height: px2rem(180); } } /** 子选项内容区关闭动画,当 v-if=false 的时候调用 当子选项部分关闭时,初始状态max-height为180,结束状态max-height为0 */ .fold-height-leave-active { animation-duration: .3s; animation-name: fold-height-close; } @keyframes fold-height-close { 0% { max-height: px2rem(180); } 100% { max-height: 0; } } } </style>

总结

到此这篇关于vue商城中商品“筛选器”功能的实现代码的文章就介绍到这了,更多相关vue商品筛选器内容请搜索靠谱客以前的文章或继续浏览下面的相关文章希望大家以后多多支持靠谱客!

最后

以上就是鲤鱼早晨最近收集整理的关于vue商城中商品“筛选器”功能的实现代码的全部内容,更多相关vue商城中商品“筛选器”功能内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(132)

评论列表共有 0 条评论

立即
投稿
返回
顶部