JavaScript双向选择器的实现

目录

前言

  双向选择器是网站中经常使用的一种组件,适合于要求用户输入固定的一个或多个标签内容的场景,这种格式比普通input输入框的交互方式更加友好,而且可以防止因用户输入的随意性而导致的其他多余工作(比如表单验证)甚至错误。


效果

  在说具体细节之前,可以先看一下效果,下图中就实现了一个最基本的双向选择器。


注意事项

1.以上组件的编写没有基于原生的CSS,而是引入了AmazeUI框架,利用了框架提供的布局等样式,以下html代码中看到的以“am-”为前缀的class均是如此,具体的含义和使用方法可以参考AmazeUI官方文档
2.实际使用中,我们往往需要左侧的待选项可以动态可变,那就不能在页面上写死,应该在双向选择器渲染生成之前向后台请求数据,获取最新的待选项即可。而如下代码中仅作为示例,固定写了几个选项。


HTML结构

  主要文档结构如下:

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
<div class="am-g">
<div class="am-form-group am-u-sm-4 am-margin-left-sm am-margin-right-0 am-padding-right-0">
<label>待选项列表</label><br />
<select multiple id="for-select" style="height: 300px;">
<option>选项1</option>
<option>选项2</option>
<option>选项3</option>
<option>选项4</option>
<option>选项5</option>
</select>
</div>
<div class="am-form-group am-u-sm-1">
<div class="am-text-center am-text-middle">
<br /><br /><br />
<a id="to-right" style="cursor: pointer;"><i class="am-icon-angle-right am-icon-md"></i></a><br /><br />
<a id="to-right-double" style="cursor: pointer;"><i class="am-icon-angle-double-right am-icon-md"></i></a><br /><br />
<a id="to-left" style="cursor: pointer;"><i class="am-icon-angle-left am-icon-md"></i></a><br /><br />
<a id="to-left-double" style="cursor: pointer;"><i class="am-icon-angle-double-left am-icon-md"></i></a>
</div>
</div>
<div class="am-form-group am-u-sm-4 am-u-end am-margin-horizontal-0 am-padding-horizontal-0">
<label>已选项列表</label><br />
<select multiple id="has-selected" style="height: 300px;">
</select>
</div>
</div>

JavaScript控制逻辑

  控制逻辑完整如下,基本的思想就是监听两个列表中每一项的点击事件,当触发点击事件后,遍历另一个列表中的选项,当无重复的情况下,将其从本列表中移除,添加至另一个列表中。

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
$(function(){
var leftSel = $("#" + "for-select");
var rightSel = $("#" + "has-selected");

//逐个向右
$("#" + "to-right").bind("click",function(){
leftSel.find("option:selected").each(function(){
var tmp = $(this).val();
var lthis = $(this);
var right = rightSel.find("option");
var flag = 0;
for(var i=0;i<right.length;i++){
if(tmp !== right[i].label){
flag++;
}
}
if(flag == right.length){
lthis.remove().appendTo(rightSel);
}
});
});

//全部向右
$("#" + "to-right-double").bind("click",function(){
leftSel.find("option").each(function(){
var tmp = $(this).val();
var lthis = $(this);
var right = rightSel.find("option");
var flag = 0;
for(var i=0;i<right.length;i++){
if(tmp !== right[i].label){
flag++;
}
}
if(flag == right.length){
lthis.remove().appendTo(rightSel);
}
});
});

//逐个向左
$("#" + "to-left").bind("click",function(){
rightSel.find("option:selected").each(function(){
var tmp = $(this).val();
var rthis = $(this);
var left = leftSel.find("option");
var flag = 0;
for(var i=0;i<left.length;i++){
if(tmp !== left[i].label){
flag++;
}
}
if(flag == left.length){
rthis.remove().appendTo(leftSel);
}else {
rthis.remove();
}
});
});

//全部向左
$("#" + "to-left-double").bind("click",function(){
rightSel.find("option").each(function(){
var tmp = $(this).val();
var rthis = $(this);
var left = leftSel.find("option");
var flag = 0;
for(var i=0;i<left.length;i++){
if(tmp !== left[i].label){
flag++;
}
}
if(flag == left.length){
rthis.remove().appendTo(leftSel);
}else {
rthis.remove();
}
});
});

//左侧待选记录的双击事件
leftSel.dblclick(function(){
leftSel.find("option:selected").each(function(){
var tmp = $(this).val();
var lthis = $(this);
var right = rightSel.find("option");
var flag = 0;
for(var i=0;i<right.length;i++){
if(tmp !== right[i].label){
flag++;
}
}
if(flag == right.length){
lthis.remove().appendTo(rightSel);
}
});
});

//右侧已选记录的双击事件
rightSel.dblclick(function(){
rightSel.find("option:selected").each(function(){
var tmp = $(this).val();
var rthis = $(this);
var left = leftSel.find("option");
var flag = 0;
for(var i=0;i<left.length;i++){
if(tmp !== left[i].label){
flag++;
}
}
if(flag == left.length){
rthis.remove().appendTo(leftSel);
}else {
rthis.remove();
}
});
});
})