三级联动控件在日常开发中经常会用到,比如选择省市区,年月日等情况,而原生的html并没有这样的一个控件,闲暇之余,写了这么一个控件,预览效果如下:
废话不多说,直接贴代码:
jquery.dropmenu.css
.dropmenu {
width: auto;
height: auto;
}
.dropmenu > .top {
position: relative;
width: 100%;
height: 30px;
border: 1px #cccccc solid;
font-size: 0;
overflow:hidden;
}
.dropmenu > .top >.data {
float: left;
padding: 0 5px;
width: 100%;
height: 30px;
line-height: 30px;
font-size: 16px;
border-right: 1px #cccccc solid;
background: #dddddd;
}
.dropmenu > .top > .data > p {
padding: 0 30px 0 0;
margin: 0;
white-space:nowrap;
word-break:break-all;
text-overflow:ellipsis;
overflow:hidden;
}
.dropmenu > .top > .btn {
position: absolute;
right: 0;
width: 30px;
height: 30px;
line-height: 30px;
font-size: 16px;
text-align: center;
cursor: pointer;
z-index: 1;
background: #ffffff;
}
.dropmenu > .drop {
position: absolute;
margin-top: -1px;
height: auto;
width: auto;
z-index: 999;
background: #fff;
font-size: 0;
}
.dropmenu > .drop > .options {
display: inline-block;
vertical-align: top;
height: auto;
width: auto;
border-left: 1px #cccccc solid;
border-right: 1px #cccccc solid;
border-top: 1px #cccccc solid;
}
.dropmenu > .drop > .options > ul {
margin: 0;
padding:0;
list-style-type: none;
}
.dropmenu > .drop > .options > ul > li {
padding:0 5px;
height: 30px;
line-height: 30px;
border-bottom: 1px #cccccc solid;
cursor: pointer;
font-size: 14px;
}
.dropmenu > .drop > .options > ul > li:hover {
background: #cccccc
}
jquery.dropmenu.js
if (jQuery === undefined)
throw new Error("本控件基于jQuery,请先引入jQuery相关文件!")
$.fn.dropmenu = function(config) {
return DropMenu.call(this,config)
}
var DropMenu = function(config) {
this.top = null//顶部部分
this.drop = null//下拉部分
this.width = null//top的宽度
this.optionsWidth = null//options区域宽度
this.last = false//是否允许选择非末级
this.cache = {}//缓存解析的数据
this.options = [] //下拉数据
this.data = {}//被选中的数据
this.interface = null//如果需要从网络请求数据
this.listener = {}//事件监听
$.extend(this,DropMenu.prototype,config)
this.init()
this.bind()
this.adjust()
return this
}
/**
* 初始化控件视图
*/
DropMenu.prototype.init = function() {
this.top = $("<div class='top'>")
this.top.append("<div class='data'><p></p></div>")
this.top.append("<div class='btn'>▼</div>")
this.drop = $("<div class='drop'>")
this.drop.hide()
if (this.width !== null)
this.top.css("width",this.width)
this.append(this.top)
this.append(this.drop)
}
/**
* 绑定事件
*/
DropMenu.prototype.bind = function () {
this.top.on("click.api.dropmenu.display",".btn",this,DropMenu.prototype.display)
this.drop.on("click.api.dropmenu.click",".options > ul > li",this,DropMenu.prototype.click)
this.drop.on("mouseleave.api.dropmenu.leave",".options",this,DropMenu.prototype.leave)
this.drop.on("mouseover.api.dropmenu.slide",".options > ul > li",this,DropMenu.prototype.slide)
}
/**
* 调整和绑定数据
* @param level 需要加载的数据的级别(1,2,3),默认为1
* @param offsetTop 偏移
* @param parent 父级关键字
*/
DropMenu.prototype.adjust = function(level,offsetTop,parent) {
if (level === undefined || isNaN(level))
level = "1"
var data = this.parse(level,parent)
if (data === undefined || data.length === 0)
return;
var options = $("<div class='options' data-level='"+level+"'>")
var ul = $("<ul>")
for (var i=0 ; i < data.length ; i++) {
ul.append("<li data-key='"+data[i].key+"'>"+data[i].value+"</li>")
}
options.append(ul)
if (offsetTop !== undefined && !isNaN(offsetTop))
options.css("margin-top",offsetTop+"px")
if (this.optionsWidth !== null)
options.css("width",this.optionsWidth)
this.drop.append(options)
}
/**
* 解析options,并将解析过的直接存入缓存,方便直接使用
*/
DropMenu.prototype.parse = function(level,parent){
if (this.options === undefined || this.options.length === 0)
return
if (level === undefined)
level = "1"
if (parent !== undefined && this.cache[parent] !== undefined)
return this.cache[parent]
var result = new Array
for (var i=0;i<this.options.length;i++) {
if (level === this.options[i].level && parent === this.options[i].parent) {
result.push(this.options[i])
}
}
if (parent === undefined)
this.cache["top"] = result
else
this.cache[parent] = result
return result
}
/**
* btn点击事件
* @param event
*/
DropMenu.prototype.display = function(event) {
var plugin = event.data
plugin.drop.fadeToggle()
}
/**
* 下拉列表中选项的鼠标移动事件
* @param event
*/
DropMenu.prototype.slide = function(event) {
var plugin = event.data
var level = $(this.closest(".options")).attr("data-level")
var nextLevel = "1"
if (level === "1") {
plugin.drop.find(".options:gt(0)").remove()
nextLevel = "2"
}else if (level === "2") {
plugin.drop.find(".options:gt(1)").remove()
nextLevel = "3"
}else if (level === "3") {
return
}
var offsetTop = this.offsetTop - 1
var parent = $(this).attr("data-key")
plugin.adjust(nextLevel,offsetTop,parent)
}
/**
* item点击事件
* @param event
*/
DropMenu.prototype.click = function (event) {
var plugin = event.data
var level = $(this).closest(".options").attr("data-level")
var parent = $(this).attr("data-key")
var key = $(this).attr("data-key")
var value = $(this).text()
var p = plugin.top.find(".data > p")
var children = null
if (!plugin.last && level === "1" ) {
children = plugin.parse("2",parent)
}else if (!plugin.last && level === "2") {
children = plugin.parse("3",parent)
}
if (children === null || children.length === 0) {
p.text(value)
p.attr("key",key)
plugin.drop.hide()
plugin.data["key"]=key
plugin.data["value"]=value
if (plugin.listener.select !== undefined)
plugin.listener.select(plugin.data,this,plugin)
}
}
/**
* 鼠标离开options区域事件
* @param event
*/
DropMenu.prototype.leave = function (event) {
var plugin = event.data
var to = event.toElement
if (to.closest(".options") == null) {
plugin.drop.hide()
plugin.drop.find(".options:gt(0)").remove()
}
}
DropMenu.prototype.request = function() {
}
DropMenu.prototype.getData = function () {
return this.data
}
index.html
<!DOCTYPE html>
<html>
<head>
<title>测试</title>
<meta charset="UTF-8">
<script src='https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js'></script>
<link rel="stylesheet" type="text/css" href="jquery.dropmenu.css">
<script type="text/javascript" src="jquery.dropmenu.js"></script>
</head>
<body>
<div class="dropmenu"></div>
<script type="text/javascript">
$(function(){
var obj=$(".dropmenu").dropmenu({
"width":"210px",
"optionsWidth" : "210px",
"options":[
{"key":"1","value":"湖南省","level":"1"},
{"key":"2","value":"湖北省","level":"1"},
{"key":"3","value":"河北省","level":"1"},
{"key":"4","value":"河南省","level":"1"},
{"key":"5","value":"广东省","level":"1"},
{"key":"6","value":"广西省","level":"1"},
{"key":"7","value":"福建省","level":"1"},
{"key":"8","value":"安徽省","level":"1"},
{"key":"21","value":"长沙市","level":"2","parent":"1"},
{"key":"22","value":"株洲市","level":"2","parent":"1"},
{"key":"23","value":"衡阳市","level":"2","parent":"1"},
{"key":"24","value":"邵阳市","level":"2","parent":"1"},
{"key":"21","value":"武汉市","level":"2","parent":"2"},
{"key":"22","value":"黄石市","level":"2","parent":"2"},
{"key":"23","value":"十堰市","level":"2","parent":"2"},
{"key":"24","value":"宜昌市","level":"2","parent":"2"},
{"key":"25","value":"襄阳市","level":"2","parent":"2"},
{"key":"26","value":"鄂州市","level":"2","parent":"2"},
{"key":"27","value":"荆门市","level":"2","parent":"2"},
{"key":"28","value":"孝感市","level":"2","parent":"2"},
{"key":"21","value":"石家庄市","level":"2","parent":"3"},
{"key":"22","value":"唐山市","level":"2","parent":"3"},
{"key":"23","value":"秦皇岛市","level":"2","parent":"3"},
{"key":"24","value":"邯郸市","level":"2","parent":"3"},
{"key":"21","value":"邢台市","level":"2","parent":"3"},
{"key":"41","value":"开封市","level":"2","parent":"4"},
{"key":"42","value":"洛阳市","level":"2","parent":"4"},
{"key":"43","value":"安阳市","level":"2","parent":"4"},
{"key":"231","value":"茅箭区","level":"3","parent":"23"},
{"key":"232","value":"张湾区","level":"3","parent":"23"},
{"key":"233","value":"十堰经济技术开发区","level":"3","parent":"23"},
{"key":"234","value":"郧阳区","level":"3","parent":"23"},
{"key":"235","value":"郧西县","level":"3","parent":"23"},
{"key":"236","value":"竹山县","level":"3","parent":"23"},
{"key":"237","value":"竹溪县","level":"3","parent":"23"},
{"key":"238","value":"房县","level":"3","parent":"23"}
]
});
})
</script>
</body>
</html>
本控件仅供学习使用,可能存在一定的BUG,欢迎大家指正。