自制单选多选日历文本框文本域控件

/*
ZZSWidget.js 版本号2021.06.29
目前共有单选、多选、日历、文本框、文本域、按钮 6个控件

2021.06.29增加了单选、多选和日历控件的options的widgetParentNode属性,可以自由设置每一个的widgetParentNode了,这样就可在多个滚动条的地方不响应其他滚动条的事件

2021.06.28 增加ZZSWidget.setWidgetParentNode()方法,现在可以设置非document.body作为单选多选日历控件的parentNode了,这样可以使一些跟随滚动条滚动的情况不会出现panel飞出特定的元素视窗,起到美观的作用
目前该方法可以传入id或直接传入dom对象。注意,该对象会被附上position:relative属性,如果有滚动条则会自动跟随滚动。请不要随意使用该方法。一般该方法用于绑定存在滚动条的那一个非body对象。
2021.06.28 解决单选多选不满最大高度时上置偏移的问题

2021.06.27 增加按钮控件
2021.06.27 为小三角增加双事件,点击第二次会自动关闭,增加控件对滚动条(高度)的自动判断功能。如果滚动条有变化,会自动跟踪其变化重新适应
2021.06.25 将滚动事件绑定到外部的每一层符合要求的元素上,而不是只绑定一个,并且设置控件自动判断滚动条高度和自动控制出现位置
2021.06.25 增加自动判断控件绑定的外部元素高度的功能,如果为空,则赋予默认值
2021.06.25 增加ZZSWidget.getValue(id,value)方法

2021.06.24 给所有控件统一增加onlytips和placeholder、offsetHeight属性
2021.06.24 增加Widget.getResult(id,t)方法

2021.06.23 增加文本框、文本域控件
2021.06.23 给文本框控件添加正则校验功能

2021.06.22 增加日历控件到达屏幕下方显示不全自动上置的功能

2021.06.21 增加日历控件

2021.06.19 增加多选控件

2021.06.18 开始制作,初步完成单选控件

增加各种控件随滚动条自由移动的功能

Option(单选)控件:
ZZSOption(id,[1,2,3],offsetHeight:20,placeholder:"123",onlytips:true});
offsetHeight是高度向下偏移量
placeholder是默认值
onlytips表示placeholder的内容是否是可用的实际值,还是只是一个提示语,默认true,只是一个提示语,当为false时则是一个默认值,用Widget.getResult()的时候是会返回该值的

MultipleOption(多选)控件:
ZZSMultipleOption(id,[1,2,3],{offsetHeight:20,placeholder:"123",onlytips:true});
offsetHeight是高度向下偏移量
placeholder是默认值
onlytips表示placeholder的内容是否是可用的实际值,还是只是一个提示语,默认true,只是一个提示语,当为false时则是一个默认值,用Widget.getResult()的时候是会返回该值的

Calendar(日历)控件:
ZZSCalendar(id,{offsetHeight:20,placeholder:"__today__"});
第一个参数是目标id
第二个参数是一个对象,目前支持offsetHeight和placeholder两个属性
offsetHeight是偏移y绝对值
placeholder是默认显示的数值,以灰色字体显示,当为“__today__”时显示今天的时间

INPUT(文本框)控件:
ZZSInput(id,{minusHeight:0,minusWidth:4,placeholder:"请输入数字",onlyinput:"number"})
minusHeight和minusWidth属性可以缩小input控件相对于外部标签的大小,如果外部标签高度为0,则自动变成高度20px。
placeholder属性不再赘述
onlytips如果为false则placeholder会变成默认文本值,默认为true
onlyinput属性表示设置只能输入某些值,当设为num或number时只能输入阿拉伯数字、加减号和小数点;
当设为chn或chinese时只能输入中文
当设为letter时只能输入英文

TEXTAREA(文本域)控件:
与INPUT控件完全一致,只是将input变成textarea
如果外部标签没有高度则默认高度为40px

Button(按钮)控件:
ZZSButton(id,function(){alert(1)},{text:"按钮上面的字",width:100,height:100,borderRadius:10})
这里的function是点击事件
width height borderRadius属性为可选项,不需要带上"px"或"pt"等单位字眼

Widget.getResult(id,t)方法:
该方法用于获取绑定控件的对象上面的值
如果placeholder设为onlytips则返回的值为空字符串
如果t为空则放回一个对象{value:"某个value",type:"某个type"}
如果t为value就直接返回value
如果t为type就直接返回type,type有五种,分别是Option MultipleOption Calendar Input Textarea 

Widget.setValue(id,v)方法:
该方法用于对已经绑定控件的目标元素设置一个值,目标对象是否设置onlytips为true没有影响

 */
window.ZZSWidget = function(){}
ZZSWidget.widgetParentNode = document.body;
ZZSWidget.isDOM = (typeof HTMLElement === 'object') ? function(obj){return obj instanceof HTMLElement;} :
  function(obj){return obj && typeof obj === 'object' && (obj.nodeType === 1 || obj.nodeType === 9) && typeof obj.nodeName === 'string';}
ZZSWidget.Inside = function(a,b){ //a元素是否是b元素的子对象或孙,孙孙孙……对象
  while(a){
    a = a.parentNode;
    if(a == b) return true
  }
  return false
}
window.ZZSOption = function(targetid,data,options){
  options = (Object.prototype.toString.call(options)==='[object Object]')?options:{};
  var offsetHeight = 'offsetHeight' in options?options['offsetHeight']:0;
  var onlytips = ('onlytips' in options&&options['onlytips']==false)?false:true;
  var placeholder = 'placeholder' in options?options['placeholder']:'';
  if('widgetParentNode' in options){
    if(document.getElementById(options['widgetParentNode'])){
      window.ZZSOption.widgetParentNodes[targetid] = document.getElementById(options['widgetParentNode']);
    }else if(ZZSWidget.isDOM(options['widgetParentNode'])){
      window.ZZSOption.widgetParentNodes[targetid] = options['widgetParentNode'];
    }
    window.ZZSOption.widgetParentNodes[targetid].style.position = 'relative';
  }
  function decorate(arr){
    var str = "["
    for(var i=0;i<arr.length;i++){
      str += (Number.isFinite(arr[i])?arr[i]:"'"+arr[i]+"'") +","
    }
    return str.slice(0,-1)+"]";
  }
  var tar = document.getElementById(targetid);
  if(!tar){
    throw Error("ZZSOption控件无法绑定到id为【"+targetid+"】的元素上");
  }
  tar.innerHTML = '<div style="width:100%;height:100%;margin:0;padding:0;"><span class="ZZSWidgetOutput" ZZSWidgetType="Option" onlytips=\''+onlytips+'\' placeholder=\''+placeholder+'\' style="display:inline-block;height:100%;width:'+ (tar.clientWidth-18) +'px;">'+(placeholder?(onlytips?'<span style="color:gray;">'+placeholder+'</span>':placeholder):'')+'</span>\
  <span onmouseout="this.style.color=\'deepskyblue\'" onmouseover="this.style.color=\'dodgerblue\'" style="cursor:pointer;float:right;color:deepskyblue;font-family:微软雅黑;background-color:#f1f1f1;display:inline-block;" onclick="ZZSOption.panel(this.parentNode,'+decorate(data)+',\''+targetid+'\','+offsetHeight+')" class="ZZSWidgetUnit">▼</span></div>';
}
ZZSOption.widgetParentNodes = {};
ZZSOption.scroller = [];
ZZSOption.panel = function(node,options,targetid,offsetHeight){
  window.ZZSOption.currentTargetId = targetid;
  var myWidgetParentNode = (targetid in window.ZZSOption.widgetParentNodes)?window.ZZSOption.widgetParentNodes[targetid]:window.ZZSWidget.widgetParentNode;
  window.ZZSOption.myWidgetParentNode = myWidgetParentNode;
  if(!window.ZZSOption.lastnode){
  	window.ZZSOption.lastnode = node;
  }
  if(window.ZZSOption.lastnode == node && document.getElementById("ZZSWidget") && document.getElementById("ZZSWidget").getAttribute("ZZSWidgetType")=="Option"){
  	document.getElementById("ZZSWidget").remove();
  	return
  }
  window.ZZSOption.lastnode = node;
  var targetHeight = node.parentNode.offsetHeight?node.parentNode.offsetHeight:20;
  function getAbsolutePosition(node) {
    var position = { left:0, top:0 };
    while(node){
      position.left += node.offsetLeft;
      position.top += node.offsetTop;
      node = node.offsetParent;
    }
    return position;
  }
  var position = getAbsolutePosition(node.parentNode);
  var x = position.left-1;
  var y = position.top + targetHeight;
  var w = node.offsetWidth+2;
  if(myWidgetParentNode!=document.body){
    y -= getAbsolutePosition(myWidgetParentNode).top;
  }
  y += offsetHeight;
  var megaHeight = window.innerHeight;
  window.ZZSOption.scroller = []; //2021.06.29升级,每次都把整个scroller重置,这样可以避免存在多个scroll域时只对一个域绑定scroll事件的情况
  while(node){
    node =node.parentNode;
    if(node && (node.scrollHeight>node.clientHeight || node.offsetHeight>node.clientHeight)){
      window.ZZSOption.scroller.push(node);
    }
  }
  for(var i=0;i<window.ZZSOption.scroller.length;i++){
    var sc = window.ZZSOption.scroller[i];
    if(!sc.ZZSOptionBinded){ //此处会做判断,如果已经绑了就不会绑第二次了
      sc.addEventListener("scroll",function(e){
        if(document.getElementById("ZZSWidget")&&document.getElementById("ZZSWidget").getAttribute("ZZSWidgetType")=="Option"){
          if(!ZZSWidget.Inside(document.getElementById(window.ZZSOption.currentTargetId),e.target)){ return }
          if(window.ZZSOption.myWidgetParentNode!=document.body && (window.ZZSOption.myWidgetParentNode.style.overflowY=="auto"||window.ZZSOption.myWidgetParentNode.style.overflowY=="scroll")){return}
          document.getElementById("ZZSWidget").style.top = (window.ZZSOption.y - (e.target.scrollTop - e.target.currentScrollTop)) + "px";
        }
      })
      sc.ZZSOptionBinded = true
    }
    y -= sc.scrollTop;
    if(sc.scrollHeight-sc.offsetHeight>0 && sc.scrollHeight!=0 && sc.offsetHeight!=0){
      var tmpHeight = sc.scrollHeight + getAbsolutePosition(sc).top;
      if(sc.style.overflowY && sc.style.overflowY=="hidden"){
        tmpHeight = 0;
      }
      //var tmpHeight = window.innerHeight+sc.scrollHeight-sc.offsetHeight;
      megaHeight = tmpHeight>megaHeight?tmpHeight:megaHeight;
    }
  }
  var again = false
  if(position.top + targetHeight + 122 > megaHeight){
    again = true
    y -= (122+offsetHeight*2+targetHeight);
  }
  if(myWidgetParentNode!=document.body && (myWidgetParentNode.style.overflowY=="auto"||myWidgetParentNode.style.overflowY=="scroll")){
    y += myWidgetParentNode.scrollTop;
  }    
  window.ZZSOption.x = x;
  window.ZZSOption.y = y;
  for(var i=0;i<window.ZZSOption.scroller.length;i++){
  	window.ZZSOption.scroller[i].currentScrollTop = window.ZZSOption.scroller[i].scrollTop;
  }
  if(document.getElementById("ZZSWidget")){
    document.getElementById("ZZSWidget").remove();
  }
  var ZZSOptionPanel = '<div id="ZZSWidget" ZZSWidgetType="Option" class="ZZSWidgetUnit" style="overflow-y:auto;border:1px solid #777;width:'+w+'px;max-height:120px;background-color:#eee;position:absolute;left:'+x+'px;top:'+y+'px;">';
  for(var i=0;i<options.length;i++){
    ZZSOptionPanel += '<div onclick="ZZSOption.choose(\''+targetid+'\',this)" class="ZZSWidgetUnit" onmouseout="this.style.backgroundColor=\'#eee\'" onmouseover="this.style.backgroundColor=\'dodgerblue\'" style="border:1px solid white;cursor:pointer;" >'+options[i]+'</div>';
  }
  ZZSOptionPanel += '<div onclick="ZZSOption.choose(\''+targetid+'\',this,1)" class="ZZSWidgetUnit" onmouseout="this.style.backgroundColor=\'#eee\'" onmouseover="this.style.backgroundColor=\'dodgerblue\'" style="border:1px solid white;cursor:pointer;color:gray;">不选</div>'
  ZZSOptionPanel += '</div>';
  myWidgetParentNode.insertAdjacentHTML("beforeend",ZZSOptionPanel);
  var rh = document.getElementById("ZZSWidget").offsetHeight;
  if(again && rh<122){
    y += 122 - rh;
    if(position.top + targetHeight + rh < megaHeight){
      y += rh + targetHeight;
    }
    window.ZZSOption.y = y;
    document.getElementById("ZZSWidget").style.top = y + "px";
  }
}
ZZSOption.choose = function(targetid,t,special){
  document.getElementById('ZZSWidget').remove();
  var o = document.getElementById(targetid).getElementsByClassName('ZZSWidgetOutput')[0];
  if(special){
    if(o.getAttribute('onlytips')=='true'){
      console.log(o.getAttribute('placeholder'));
      o.innerHTML = "<span style='color:gray;'>" + o.getAttribute('placeholder') + "</span>";
    }else{ 
      o.innerHTML = "" 
    } 
  }else{
    o.innerHTML=t.innerHTML;
  }
}
window.ZZSMultipleOption = function(targetid,data,options){
  options = (Object.prototype.toString.call(options)==='[object Object]')?options:{};
  var offsetHeight = 'offsetHeight' in options?options['offsetHeight']:0;
  var onlytips = ('onlytips' in options&&options['onlytips']==false)?false:true;
  var placeholder = 'placeholder' in options?options['placeholder']:'';
  if('widgetParentNode' in options){
    if(document.getElementById(options['widgetParentNode'])){
      window.ZZSMultipleOption.widgetParentNodes[targetid] = document.getElementById(options['widgetParentNode']);
    }else if(ZZSWidget.isDOM(options['widgetParentNode'])){
      window.ZZSMultipleOption.widgetParentNodes[targetid] = options['widgetParentNode'];
    }
    window.ZZSMultipleOption.widgetParentNodes[targetid].style.position = 'relative';
  }
  function decorate(arr){
    var str = "["
    for(var i=0;i<arr.length;i++){
      str += (Number.isFinite(arr[i])?arr[i]:"'"+arr[i]+"'") +","
    }
    return str.slice(0,-1)+"]";
  }
  var tar = document.getElementById(targetid);
  if(!tar){
    throw Error("ZZSMultipleOption控件无法绑定到id为【"+targetid+"】的元素上");
  }
  tar.innerHTML = '<div style="width:100%;height:100%;margin:0;padding:0;"><span class="ZZSWidgetOutput" ZZSWidgetType="MultipleOption" onlytips=\'' + onlytips + '\' placeholder=\'' + placeholder + '\' style="display:inline-block;height:100%;width:'+ (tar.clientWidth-18) +'px;">'+(placeholder?(onlytips?'<span style="color:gray;">'+placeholder+'</span>':placeholder):'')+'</span>\
  <span onmouseout="this.style.color=\'deepskyblue\'" onmouseover="this.style.color=\'dodgerblue\'" style="cursor:pointer;float:right;color:deepskyblue;font-family:微软雅黑;background-color:#f1f1f1;display:inline-block;" onclick="ZZSMultipleOption.panel(this.parentNode,'+decorate(data)+',\''+targetid+'\','+offsetHeight+');" class="ZZSWidgetUnit">▼</span></div>';
}
ZZSMultipleOption.widgetParentNodes = {};
ZZSMultipleOption.scroller = [];
ZZSMultipleOption.panel = function(node,options,targetid,offsetHeight){
  window.ZZSMultipleOption.currentTargetId = targetid;
  var myWidgetParentNode = (targetid in window.ZZSMultipleOption.widgetParentNodes)?window.ZZSMultipleOption.widgetParentNodes[targetid]:window.ZZSWidget.widgetParentNode;
  window.ZZSMultipleOption.myWidgetParentNode = myWidgetParentNode;
  if(!window.ZZSMultipleOption.lastnode){
    window.ZZSMultipleOption.lastnode = node;
  }
  if(window.ZZSMultipleOption.lastnode == node && document.getElementById("ZZSWidget") && document.getElementById("ZZSWidget").getAttribute("ZZSWidgetType")=="MultipleOption"){
    document.getElementById("ZZSWidget").remove();
    return
  }
  window.ZZSMultipleOption.lastnode = node;
  var targetHeight = node.parentNode.offsetHeight?node.parentNode.offsetHeight:20;
  function getAbsolutePosition(node) {
    var position = { left:0, top:0 };
    while(node){
      position.left += node.offsetLeft;
      position.top += node.offsetTop;
      node = node.offsetParent;
    }
    return position;
  }
  var position = getAbsolutePosition(node.parentNode);
  var x = position.left-1;
  var y = position.top + targetHeight;
  var w = node.offsetWidth+2;
  if(myWidgetParentNode!=document.body){
    y -= getAbsolutePosition(myWidgetParentNode).top;
  }
  y += offsetHeight;
  var megaHeight = window.innerHeight;
  window.ZZSMultipleOption.scroller = [];
  while(node){
    node =node.parentNode;
    if(node && (node.scrollHeight>node.clientHeight || node.offsetHeight>node.clientHeight)){
      window.ZZSMultipleOption.scroller.push(node);
    }
  }
  for(var i=0;i<window.ZZSMultipleOption.scroller.length;i++){
    var sc = window.ZZSMultipleOption.scroller[i];
    if(!sc.ZZSMultipleOptionBinded){
      sc.addEventListener("scroll",function(e){
        if(document.getElementById("ZZSWidget")&&document.getElementById("ZZSWidget").getAttribute("ZZSWidgetType")=="MultipleOption"){
          if(!ZZSWidget.Inside(document.getElementById(window.ZZSMultipleOption.currentTargetId),e.target)){ return }
          if(window.ZZSMultipleOption.myWidgetParentNode!=document.body && (window.ZZSMultipleOption.myWidgetParentNode.style.overflowY=="auto"||window.ZZSMultipleOption.myWidgetParentNode.style.overflowY=="scroll")){return}
          document.getElementById("ZZSWidget").style.top = (window.ZZSMultipleOption.y - (e.target.scrollTop - e.target.currentScrollTop)) + "px";
        }
      })
      sc.ZZSMultipleOptionBinded = true
    }
    y -= sc.scrollTop;
    if(sc.scrollHeight-sc.offsetHeight>0 && sc.scrollHeight!=0 && sc.offsetHeight!=0){
      var tmpHeight = sc.scrollHeight + getAbsolutePosition(sc).top;
      if(sc.style.overflowY && sc.style.overflowY=="hidden"){
        tmpHeight = 0;
      }
      //var tmpHeight = window.innerHeight+sc.scrollHeight-sc.offsetHeight;
      megaHeight = tmpHeight>megaHeight?tmpHeight:megaHeight;
    }
  }
  var again = false
  if(position.top + targetHeight + 150 > megaHeight){
    again = true
    y -= (150+offsetHeight*2+targetHeight);
  }
  if(myWidgetParentNode!=document.body && (myWidgetParentNode.style.overflowY=="auto"||myWidgetParentNode.style.overflowY=="scroll")){
    y += myWidgetParentNode.scrollTop;
  }
  window.ZZSMultipleOption.x = x;
  window.ZZSMultipleOption.y = y;
  for(var i=0;i<window.ZZSMultipleOption.scroller.length;i++){
  	window.ZZSMultipleOption.scroller[i].currentScrollTop = window.ZZSMultipleOption.scroller[i].scrollTop;
  }
  if(document.getElementById("ZZSWidget")){
    document.getElementById("ZZSWidget").remove();
  }
  var ZZSMultipleOptionPanel = '<div id="ZZSWidget" ZZSWidgetType="MultipleOption" class="ZZSWidgetUnit" style="width:'+w+'px;position:absolute;left:'+x+'px;top:'+y+'px;"><div style="border:1px solid #777;max-height:120px;overflow-y:auto;background-color:#eee;">';
  for(var i=0;i<options.length;i++){
    ZZSMultipleOptionPanel += '<div onclick="this.childNodes[0].checked = true;" class="ZZSWidgetUnit" onmouseout="this.style.backgroundColor=\'#eee\'" onmouseover="this.style.backgroundColor=\'dodgerblue\'" style="border:1px solid white;cursor:pointer;" ><input type="checkbox" class="ZZSWidgetUnit"/><span class="ZZSWidgetUnit">'+options[i]+'</span></div>';
  }
  ZZSMultipleOptionPanel += '</div><div style="cursor:pointer;background-color:dodgerblue;color:white;font-weight:bold;font-size:15px;line-height:26px;text-align:center;height:26px;border:1px solid #777;" onclick="ZZSMultipleOption.choose(\''+targetid+'\',this)">确定</div></div>';
  myWidgetParentNode.insertAdjacentHTML("beforeend",ZZSMultipleOptionPanel);
  var rh = document.getElementById("ZZSWidget").offsetHeight;
  if(again && rh<150){
    y += 150 - rh;
    if(position.top + targetHeight + rh < megaHeight){
      y += rh + targetHeight;
    }
    window.ZZSMultipleOption.y = y;
    document.getElementById("ZZSWidget").style.top = y + "px";
  }
}
ZZSMultipleOption.choose = function(targetid,t){
  var tars = t.parentNode.getElementsByTagName('input');
  var str = '';
  for(var i=0;i<tars.length;i++){
    if(tars[i].checked){
      str += tars[i].nextSibling.innerHTML + ','
    }; 
  } 
  str=str.slice(0,-1);
  var o = document.getElementById(targetid).getElementsByClassName('ZZSWidgetOutput')[0]
  if(o.getAttribute('onlytips')=='true' && str== ''){ 
    o.innerHTML = '<span style="color:gray;">'+ o.getAttribute('placeholder') + '</span>';
  }
  else if(o.getAttribute('onlytips')!='true' && str==''){
    o.innerHTML = '';
  }
  else{ 
    o.innerHTML = str; 
  }
  document.getElementById('ZZSWidget').remove();
}
window.ZZSCalendar = function(targetid,options){
  options = (Object.prototype.toString.call(options)==='[object Object]')?options:{};
  var offsetHeight = 'offsetHeight' in options?options['offsetHeight']:0;
  var onlytips = ('onlytips' in options&&options['onlytips']==false)?false:true;
  var placeholder = 'placeholder' in options?options['placeholder']:null;
  if('widgetParentNode' in options){
    if(document.getElementById(options['widgetParentNode'])){
      window.ZZSCalendar.widgetParentNodes[targetid] = document.getElementById(options['widgetParentNode']);
    }else if(ZZSWidget.isDOM(options['widgetParentNode'])){
      window.ZZSCalendar.widgetParentNodes[targetid] = options['widgetParentNode'];
    }
    window.ZZSCalendar.widgetParentNodes[targetid].style.position = 'relative';
  }
  if(placeholder=="__today__"){
    var D = new Date();
    var y = D.getFullYear();
    var m = D.getMonth()+1;
    m = m<10?"0"+m:m;
    var d = D.getDate();
    d = d<10?"0"+d:d;
    placeholder = y + "-" + m + "-" + d;
  }
  function decorate(arr){
    var str = "["
    for(var i=0;i<arr.length;i++){
      str += (Number.isFinite(arr[i])?arr[i]:"'"+arr[i]+"'") +","
    }
    return str.slice(0,-1)+"]";
  }
  var tar = document.getElementById(targetid);
  if(!tar){
    throw Error("ZZSCalendar控件无法绑定到id为【"+targetid+"】的元素上");
  }
  tar.innerHTML = '<div style="width:100%;height:100%;margin:0;padding:0;"><span class="ZZSWidgetOutput" ZZSWidgetType="Calendar" onlytips='+onlytips+' placeholder='+placeholder+' style="display:inline-block;height:100%;width:'+ (tar.clientWidth-18) +'px;">'+(placeholder?(onlytips?'<span style="color:gray;">'+placeholder+'</span>':placeholder):'')+'</span>\
  <span onmouseout="this.style.color=\'deepskyblue\'" onmouseover="this.style.color=\'dodgerblue\'" style="cursor:pointer;float:right;color:deepskyblue;font-family:微软雅黑;background-color:#f1f1f1;display:inline-block;" onclick="ZZSCalendar.panel(this.parentNode,\''+targetid+'\','+offsetHeight+')" class="ZZSWidgetUnit">▼</span></div>';
}
ZZSCalendar.setYear = function(plus){
  if(document.getElementById("ZZSCalendar_year")){
    var year = parseInt(document.getElementById("ZZSCalendar_year").innerHTML);
    year += plus;
    document.getElementById("ZZSCalendar_year").innerHTML = year;
    ZZSCalendar.setDay();
  }
}
ZZSCalendar.setMonth = function(plus){
  if(document.getElementById("ZZSCalendar_month")){
    var month = parseInt(document.getElementById("ZZSCalendar_month").innerHTML);
    month += plus;
    if(month>12){
      month = 1;      
      ZZSCalendar.setYear(1);
    }
    else if(month<1){
      month = 12;
      ZZSCalendar.setYear(-1);
    }
    document.getElementById("ZZSCalendar_month").innerHTML = month;
    ZZSCalendar.setDay();
  }
}
ZZSCalendar.setDay = function(){
  var y = parseInt(document.getElementById("ZZSCalendar_year").innerHTML);
  var m = parseInt(document.getElementById("ZZSCalendar_month").innerHTML);

  ZZSCalendar_days = document.getElementsByClassName("ZZSCalendar_day");
  for(var i=0;i<ZZSCalendar_days.length;i++){
    ZZSCalendar_days[i].innerHTML = '';
    ZZSCalendar_days[i].style.backgroundColor = '';
  }
  var D = new Date();
  D.setFullYear(y,m-1,1);
  var row = D.getDay();//从星期几开始,0是日,1是一,以此类推6是六
  var column = 0;
  var dates = 30; //天数
  if(m==1 || m==3 || m==5 || m==7 || m==8 || m==10 || m==12){
    dates = 31;
  }
  else if(m==4 || m==6 || m==9 || m==11){
    dates = 30;
  }
  else if(m==2){
    if((y%100!=0&&y%4==0)||y%400==0){ //闰年
      dates = 29;
    }
    else{
      dates = 28;
    }
  }
  for(var i=1;i<dates+1;i++){
    document.getElementById("ZZSCalendar_day_x"+row+"_y"+column).innerHTML = i;
    if(y == new Date().getFullYear() && m == new Date().getMonth()+1 && i == new Date().getDate()){
      document.getElementById("ZZSCalendar_day_x"+row+"_y"+column).style.backgroundColor = "gold";
    }
    row += 1;
    if(row>6){
      row = 0;
      column += 1;
    }
  }
}
ZZSCalendar.widgetParentNodes = {};
ZZSCalendar.scroller = [];
ZZSCalendar.panel = function(node,targetid,offsetHeight){
  window.ZZSCalendar.currentTargetId = targetid;
  var myWidgetParentNode = (targetid in window.ZZSCalendar.widgetParentNodes)?window.ZZSCalendar.widgetParentNodes[targetid]:window.ZZSWidget.widgetParentNode;
  window.ZZSCalendar.myWidgetParentNode = myWidgetParentNode;
  if(!window.ZZSCalendar.lastnode){
    window.ZZSCalendar.lastnode = node;
  }
  if(window.ZZSCalendar.lastnode == node && document.getElementById("ZZSWidget") && document.getElementById("ZZSWidget").getAttribute("ZZSWidgetType")=="Calendar"){
    document.getElementById("ZZSWidget").remove();
    return
  }
  window.ZZSCalendar.lastnode = node;
  var targetHeight = node.parentNode.offsetHeight?node.parentNode.offsetHeight:20;
  function getAbsolutePosition(node) {
      var position = { left:0, top:0 };
      while(node){
        position.left += node.offsetLeft;
        position.top += node.offsetTop;
        node = node.offsetParent;
      }
      return position;
  }
  var position = getAbsolutePosition(node.parentNode);
  var x = position.left-1;
  var y = position.top + targetHeight;
  var w = node.offsetWidth+2;
  if(myWidgetParentNode!=document.body){
    y -= getAbsolutePosition(myWidgetParentNode).top;
  }
  y += offsetHeight;
  var megaHeight = window.innerHeight;
  window.ZZSCalendar.scroller = [];
  while(node){
    node =node.parentNode;
    if(node && (node.scrollHeight>node.clientHeight || node.offsetHeight>node.clientHeight)){
      window.ZZSCalendar.scroller.push(node);
    }
  }
  if(window.ZZSCalendar.scroller.length){
    for(var i=0;i<window.ZZSCalendar.scroller.length;i++){
      var sc = window.ZZSCalendar.scroller[i];
      if(!sc.ZZSCalendarBinded){
        sc.addEventListener("scroll",function(e){
          if(document.getElementById("ZZSWidget")&&document.getElementById("ZZSWidget").getAttribute("ZZSWidgetType")=="Calendar"){
            if(!ZZSWidget.Inside(document.getElementById(window.ZZSCalendar.currentTargetId),e.target)){ return }
            if(window.ZZSCalendar.myWidgetParentNode!=document.body && (window.ZZSCalendar.myWidgetParentNode.style.overflowY=="auto"||window.ZZSCalendar.myWidgetParentNode.style.overflowY=="scroll")){return}
            document.getElementById("ZZSWidget").style.top = (window.ZZSCalendar.y - (e.target.scrollTop - e.target.currentScrollTop)) + "px";
          }
        })
        sc.ZZSCalendarBinded = true
      }
      y -= sc.scrollTop;
      if(sc.scrollHeight-sc.offsetHeight>0 && sc.scrollHeight!=0 && sc.offsetHeight!=0){
        var tmpHeight = sc.scrollHeight + getAbsolutePosition(sc).top;
        if(sc.style.overflowY && sc.style.overflowY=="hidden"){
          tmpHeight = 0;
        }
        //var tmpHeight = window.innerHeight+sc.scrollHeight-sc.offsetHeight;
        megaHeight = tmpHeight>megaHeight?tmpHeight:megaHeight;
      }
    }
  }
  if(position.top + targetHeight + 201 > megaHeight){
    y -= (201+offsetHeight*2+targetHeight);
  }
  if(myWidgetParentNode!=document.body && (myWidgetParentNode.style.overflowY=="auto"||myWidgetParentNode.style.overflowY=="scroll")){
    y += myWidgetParentNode.scrollTop;
  }
  window.ZZSCalendar.x = x;
  window.ZZSCalendar.y = y;  
  for(var i=0;i<window.ZZSCalendar.scroller.length;i++){
  	window.ZZSCalendar.scroller[i].currentScrollTop = window.ZZSCalendar.scroller[i].scrollTop;
  }
  if(document.getElementById("ZZSWidget")){
    document.getElementById("ZZSWidget").remove();
  }
  var ZZSCalendarPanel = '<div id="ZZSWidget" class="ZZSWidgetUnit" style="overflow-y:auto;border:1px solid #777;background-color:#eee;position:absolute;left:'+x+'px;top:'+y+'px;">\
  <table style="table-collapse:collapse;width:100%;text-align:center;" class="ZZSWidgetUnit">\
  <tr class="ZZSWidgetUnit">\
  <td onclick="ZZSCalendar.setYear(-1)" style="cursor:pointer;width:28px;" class="ZZSWidgetUnit">←</td>\
  <td onclick="ZZSCalendar.setMonth(-1)" style="cursor:pointer;width:28px;" class="ZZSWidgetUnit"><</td>\
  <td colspan="3" style="width:84px;" class="ZZSWidgetUnit"><span class="ZZSWidgetUnit" id="ZZSCalendar_year" style="color:dodgerblue;"></span>年<span id="ZZSCalendar_month" style="color:dodgerblue;" class="ZZSWidgetUnit"></span>月</td>\
  <td onclick="ZZSCalendar.setMonth(1)" style="cursor:pointer;width:28px;" class="ZZSWidgetUnit">></td>\
  <td onclick="ZZSCalendar.setYear(1)" style="cursor:pointer;width:28px;" class="ZZSWidgetUnit">→</td>\
  </tr>\
  <tr class="ZZSWidgetUnit">\
  <td style="width:28px;" class="ZZSWidgetUnit">日</td>\
  <td style="width:28px;" class="ZZSWidgetUnit">一</td>\
  <td style="width:28px;" class="ZZSWidgetUnit">二</td>\
  <td style="width:28px;" class="ZZSWidgetUnit">三</td>\
  <td style="width:28px;" class="ZZSWidgetUnit">四</td>\
  <td style="width:28px;" class="ZZSWidgetUnit">五</td>\
  <td style="width:28px;" class="ZZSWidgetUnit">六</td>\
  </tr>';
  for(var i=0;i<6;i++){
    ZZSCalendarPanel += '<tr>';
    for(var j=0;j<7;j++){
      ZZSCalendarPanel += '<td class="ZZSCalendar_day ZZSWidgetUnit" style="cursor:pointer;width:28px;height:20px;" onmouseout="this.style.backgroundColor=\'\';var d = new Date();if(this.innerHTML == d.getDate() && document.getElementById(\'ZZSCalendar_year\').innerHTML==d.getFullYear() && document.getElementById(\'ZZSCalendar_month\').innerHTML == d.getMonth()+1){this.style.backgroundColor=\'gold\'}" onmouseover="this.style.backgroundColor=\'dodgerblue\';" id="ZZSCalendar_day_x'+(j)+'_y'+(i)+'" onclick="ZZSCalendar.choose(this,\''+targetid+'\');"></td>';
    }
    ZZSCalendarPanel += '</tr>';
  }
  ZZSCalendarPanel += '</table></div>';
  myWidgetParentNode.insertAdjacentHTML("beforeend",ZZSCalendarPanel);
  document.getElementById("ZZSWidget").setAttribute("ZZSWidgetType","Calendar");
  var d = new Date();
  document.getElementById("ZZSCalendar_year").innerHTML = d.getFullYear();
  document.getElementById("ZZSCalendar_month").innerHTML = d.getMonth()+1;
  ZZSCalendar.setDay();
}
ZZSCalendar.choose = function(target,targetid){
  var day = target.innerHTML;
  var final = "";
  if(day!=""){
    day = parseInt(day)<10?("0"+day):day;
    var month = document.getElementById("ZZSCalendar_month").innerHTML;
    month = parseInt(month)<10?("0"+month):month;
    var year = document.getElementById("ZZSCalendar_year").innerHTML;
    final = year + "-" + month + "-" + day;
  } 
  document.getElementById(targetid).getElementsByClassName("ZZSWidgetOutput")[0].innerHTML = final;
  document.getElementById("ZZSWidget").remove();
}
window.ZZSInput = function(targetid,options){
  options = (Object.prototype.toString.call(options)==='[object Object]')?options:{};
  var tar = document.getElementById(targetid);
  var placeholder = 'placeholder' in options?options['placeholder']:"";
  var minusWidth = 'minusWidth' in options?options['minusWidth']:0;
  var minusHeight = 'minusHeight' in options?options['minusHeight']:0;
  var onlyinput = 'onlyinput' in options?options['onlyinput']:"";
  var onlytips = ('onlytips' in options&&options['onlytips']==false)?false:true;
  var type = ('type' in options && options['type']=="textarea")?options['type']:"input";
  if(!tar){
    throw Error((type=="input"?"ZZSInput":"ZZSTextarea")+"控件无法绑定到id为【"+targetid+"】的元素上");
  }
  var w = tar.clientWidth - minusWidth;
  var h = (tar.clientHeight?tar.clientHeight:(type=="input"?20:40)) - minusHeight;
  tar.innerHTML = '<'+type+' ZZSWidgetType="'+(type=="input"?"Input":"Textarea")+'" class="ZZSWidgetOutput" '+(onlytips?'placeholder':'value')+'="'+placeholder+'" type="text" style="width:'+ (w) + 'px;height:'+ (h) + 'px;border:1px solid dodgerblue;margin:auto;padding:0;display:block;"' + (type=="input"?'/>':'>'+(onlytips==false&&type=="textarea"?placeholder:'')+'</textarea>');
  var op = tar.getElementsByClassName('ZZSWidgetOutput')[0];
  var handle = function(e){}
  switch(onlyinput){
    case "number":
    case "num":
    case "数字":
      handle = function(e){e.target.value = e.target.value.replace(/[^\n0-9\.\+\-]*/g,'');}
      break
    case "letter":
    case "字母":
      handle = function(e){e.target.value = e.target.value.replace(/[^\\\|\……\——\.\,\。\,\、\《\》\<\>\?\/\?\、\;\;\:\:\"\'\“\”\‘\’\[\]\{\}\【\】\-\+\_\=\*\/\(\)\(\)\!\!\~\·\@\#\$\%\^\&\n\sa-zA-Z]*/g,'');}
      break
    case "chinese": case "中文": case "Chinese": case "CHINESE": case "chn": case "Chn": case "CHN":
      handle = function(e){
        if(!ZZSInput.inputtingChinese){
          e.target.value = e.target.value.replace(/[^\\\|\……\——\.\,\。\,\、\《\》\<\>\?\/\?\、\;\;\:\:\"\'\“\”\‘\’\[\]\{\}\【\】\-\+\_\=\*\/\(\)\(\)\!\!\~\·\@\#\$\%\^\&\n\s\u4e00-\u9fa5]*/g,'');
        }
      }
      op.addEventListener("compositionstart",function(e){
        ZZSInput.inputtingChinese = true
      },false)
      op.addEventListener("compositionend",function(e){
        ZZSInput.inputtingChinese = false
        e.target.value = e.target.value.replace(/[^\\\|\……\——\.\,\。\,\、\《\》\<\>\?\/\?\、\;\;\:\:\"\'\“\”\‘\’\[\]\{\}\【\】\-\+\_\=\*\/\(\)\(\)\!\!\~\·\@\#\$\%\^\&\n\s\u4e00-\u9fa5]*/g,'');
      },false)
      break
    default:
      break
  }
  op.addEventListener("change",function(e){handle(e)},false)
  op.addEventListener("input",function(e){handle(e)},false)
}
ZZSInput.inputtingChinese = false;
window.ZZSTextarea = function(targetid,options){
  options = (Object.prototype.toString.call(options)==='[object Object]')?options:{};
  options["type"] = "textarea";
  window.ZZSInput(targetid,options);
}
window.ZZSButton = function(targetid,func,options){
  options = (Object.prototype.toString.call(options)==='[object Object]')?options:{};
  var tar = document.getElementById(targetid);
  if(!tar){
    throw Error("ZZSButton控件无法绑定到id为【"+targetid+"】的元素上");
  }
  var width = 'width' in options?options['width']:0;
  var height = 'height' in options?options['height']:0;
  var borderRadius = 'borderRadius' in options?options['borderRadius']:0;
  var text = 'text' in options?options['text']:'按钮';
  if(!window.ZZSButton.funcs){
    window.ZZSButton.funcs = {}
  }
  window.ZZSButton.funcs[targetid] = func
  tar.innerHTML = '<div style="'+(borderRadius?"border-radius:"+borderRadius+"px;":"")+(width?"width:"+width+"px;":"")+(height?"height:"+height+"px;line-height:"+height+"px;":"")+'text-align:center;cursor:pointer;background-color:deepskyblue;margin:auto;" class="ZZSWidgetOutput" ZZSWidgetType="Button" onmouseout="this.style.backgroundColor=\'deepskyblue\'" onmouseover="this.style.backgroundColor=\'dodgerblue\';" onclick="window.ZZSButton.funcs[\''+targetid+'\']()">'+text+'</div>'
}
ZZSWidget.getResult = function(id,t){
  var result = {"value":"","type":""}
  var tar = document.getElementById(id);
  if(!tar) return result;
  if(tar.getElementsByClassName("ZZSWidgetOutput")){
    tar = tar.getElementsByClassName("ZZSWidgetOutput")[0];
    result["type"] = tar.getAttribute("ZZSWidgetType");
    if(tar.getAttribute("ZZSWidgetType")=="Button"){return null}
    if(tar.tagName=="INPUT" || tar.tagName == "TEXTAREA"){
      result["value"] = tar.value;
    }else{
      result["value"] = tar.innerText;
    }
    var onlytips = tar.getAttribute("onlytips")
    if((onlytips==="true"||onlytips===true) && tar.getAttribute("placeholder")==tar.innerText){
      result["value"] = "";
    }
  }
  if(t=="value"||t=="val") return result["value"];
  if(t=="type") return result["type"];
  return result;
}
ZZSWidget.setValue = function(id,v){
  var tar = document.getElementById(id);
  if(!tar) return;
  if(tar.getElementsByClassName("ZZSWidgetOutput")){
    tar = tar.getElementsByClassName("ZZSWidgetOutput")[0];
    switch(tar.getAttribute("ZZSWidgetType")){
      case "Input":
      case "Textarea":
        tar.value = v;
        break
      case "Option":
      case "MultipleOption":
      case "Calendar":
        tar.innerHTML = v;
        break
      case "Button":
      default:
        break
    }
  }
}
ZZSWidget.setWidgetParentNode = function(id){
  if(ZZSWidget.isDOM(id)){
    ZZSWidget.widgetParentNode = id;
  }
  else if(document.getElementById(id)){
    ZZSWidget.widgetParentNode = document.getElementById(id);
  }else{
    return;
  }
  ZZSWidget.widgetParentNode.style.position = "relative";
}
document.addEventListener("click",function(e){
  if(document.getElementById("ZZSWidget") && e.target.className.indexOf("ZZSWidgetUnit")<0){
    document.getElementById("ZZSWidget").remove();
  }
})

上面是我写的ZZSWidget.js的代码,下面是用法demo

<!DOCTYPE html>
<html>
<head>
	<title></title>
</head>
<body style="width:100%;height:100%;margin:0;padding:0;overflow:hidden;">
<div style="font-weight:bold;width:100%;height:50px;background-color:dodgerblue;text-align:center;line-height:50px;color:white;">ZZSWidget控件demo</div>
<div style="overflow-y:scroll;color:black;" id="demo">
	<div id="s" style="background-color:#eee;height:300px;">这个将绑定按钮</div>
	<button onclick='ZZSButton("s",function(){alert(1)},{text:"按钮",width:40,height:40,borderRadius:6})'>点击绑定按钮控件到上方</button>
	<button onclick='alert(ZZSWidget.getResult("f","value"))'>点击获取输入框控件的值</button>
	<br/><br/><br/><br/><br/><br/>
	<div id="a" style="background-color:#eee;">这个将绑定单选</div>
	<button onclick='ZZSOption("a",[1,2,3,4,5],{offsetHeight:20,placeholder:"这是提示,请选择单选值",onlytips:true})'>点击绑定单选控件到上方</button>
	<button onclick='alert(ZZSWidget.getResult("a","value"))'>点击获取单选控件的值</button>
	<br/><br/><br/><br/><br/><br/>
	<div id="b" style="background-color:#eee;">这个将绑定多选</div>
	<button onclick='ZZSMultipleOption("b",[1,2,3,4,5],{offsetHeight:20,placeholder:"这是提示,请选择多选值",onlytips:true})'>点击绑定多选控件到上方</button>
	<div id="c" style="background-color:#eee;">这个将绑定日历</div>
	<button onclick='alert(ZZSWidget.getResult("b","value"))'>点击获取多选控件的值</button>
	<br/><br/><br/><br/><br/><br/>
	<button onclick='ZZSCalendar("c",{offsetHeight:20,placeholder:"__today__",onlytips:false})'>点击绑定日历控件到上方</button>
	<button onclick='alert(ZZSWidget.getResult("c","value"))'>点击获取日历控件的值</button>
	<br/><br/><br/><br/><br/><br/>
	<div id="d" style="background-color:#eee;">这个将绑定日历</div>
	<button onclick='ZZSCalendar("d",{offsetHeight:20,placeholder:"请选择日期",onlytips:true})'>点击绑定日历控件到上方</button>
	<button onclick='alert(ZZSWidget.getResult("d","value"))'>点击获取日历控件的值</button>
	<br/><br/><br/><br/><br/><br/>
	<div id="e" style="background-color:#eee;">这个将绑定中文文本框</div>
	<button onclick='ZZSTextarea("e",{placeholder:"请输入中文",minusWidth:4,minusHeight:-20,onlyinput:"Chinese"})'>点击绑定文本域控件到上方</button>
	<button onclick='alert(ZZSWidget.getResult("e","value"))'>点击获取文本域控件的值</button>
	<br/><br/><br/><br/><br/><br/>
	<div id="f" style="background-color:#eee;">这个将绑定英文输入框</div>
	<button onclick='ZZSInput("f",{placeholder:"请输入英文",minusWidth:4,minusHeight:2,onlyinput:"letter"})'>点击绑定输入框控件到上方</button>
	<button onclick='alert(ZZSWidget.getResult("f","value"))'>点击获取输入框控件的值</button>
	<br/><br/><br/><br/><br/><br/>
</div>
</body>
<script type="text/javascript" src="ZZSWidget.js"></script>
<script type="text/javascript">
document.getElementById("demo").style.height = (window.innerHeight - 50) + "px"
window.addEventListener("resize",function(){
document.getElementById("demo").style.height = (window.innerHeight - 50) + "px"
})


</script>
</html>

该控件库是我在项目中设计的,可以单独使用,不依赖其他库

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值