计数器
功能需求
- 左右两端分别是"-"和"+", 红色
- 中间数值默认是"1",最大值是99,最小值是1
- 大于等于99后,右边变为灰色,左边是红色,小于等于1后,相反
效果图:
默认状态:
99之后:
1以下:
中间:
分析:
- 这个demo包括左右两边按钮和中间文本框三个部分
- 文本框要考虑输入非数值的情况
- 文本框数值达到上下限,要考虑左右两边的按钮的停止点击和继续点击,继而优化性能。
下面附上代码
html页面引入js文件,实例化组件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script type="module">
import StepNumber from "./js/StepNumber.js";
let step=new StepNumber();
step.appendTo("body");
</script>
</body>
</html>
StepNumber.js 文件封装组件
import Utils from "./Utils.js";
export default class StepNumber extends EventTarget{
leftBn;
rightBn;
input;
step=1; //初始值
ids; //节流
constructor(){
super();
this.elem=this.createElem();
}
createElem(){
if(this.elem) return this.elem;
let div=Utils.ce("div",{
width:"80px",
height:"22px",
position:"relative"
});
this.leftBn=Utils.ce("a",{
width:"15px",
height:"20px",
border:"1px solid #cccccc",
display:"block",
textDecoration: "none",
color:"#ff0000",
textAlign:"center",
lineHeight:"20px",
float:"left",
})
this.leftBn.href="javascript:void(0)";
this.leftBn.textContent="-";
this.input=Utils.ce("input",{
border:"none",
borderTop:"1px solid #cccccc",
borderBottom:"1px solid #cccccc",
textAlign:"center",
outline:"none",
float:"left",
width:'42px',
height:"18px"
})
this.input.value="1";
this.rightBn=this.leftBn.cloneNode(false);
this.rightBn.textContent="+";
div.appendChild(this.leftBn);
div.appendChild(this.input);
div.appendChild(this.rightBn);
this.input.addEventListener("input",e=>this.inputHandler(e));
this.leftBn.addEventListener("click",e=>this.clickHandler(e));
this.rightBn.addEventListener("click",e=>this.clickHandler(e));
return div;
}
appendTo(parent){
if (typeof parent === "string") parent = document.querySelector(parent);
parent.appendChild(this.elem);
}
inputHandler(e){
if(this.ids!==undefined) return //input事件添加节流
this.ids=setTimeout(()=>{
clearTimeout(this.ids);
this.ids=undefined;
this.setStep(this.input.value);
},500)
}
clickHandler(e){
var bn=e.currentTarget;
if(bn.bool)return; //防止浪费内存
if(bn===this.leftBn){
this.step--;
}else{
this.step++;
}
this.setStep(this.step);
}
setStep(_step){
if(typeof _step==="string"){
_step=Number(_step.replace(/\D/g,""));
}
if(_step>=99){
_step=99;
this.rightBn.style.color="#CCCCCC";
this.rightBn.bool=true;
this.leftBn.bool=false;
this.leftBn.style.color="#ff0000"
}else if(_step<=1){
this.leftBn.style.color="#CCCCCC";
this.leftBn.bool=true;
this.rightBn.bool=false;
this.rightBn.style.color="#ff0000"
_step=1;
} //中间数值不用设置,对应bool值为undefined,可以执行点击事件
this.step=_step;
this.input.value=this.step;
}
}
Utils.js是一个工具包 ,只展示需要的部分了
export default class Utils{
static time=0;
static ids=0;
static timeManage={};
//代码执行时间
static timeStart(){
if(Utils.time) return;
Utils.time=new Date().getTime();
}
static timeEnd(){
var t=new Date().getTime()-Utils.time;
Utils.time=0;
return t;
}
static ts(){
Utils.ids++;
Utils.timeManage[Utils.ids]=new Date().getTime();
return ids;
}
static te(id){
if(!Utils.timeManage[Utils.id]) return 0;
var t=new Date().getTime()-Utils.timeManage[Utils.id];
delete Utils.timeManage[Utils.id];
return t;
}
//随机颜色
static randomColor(){
var col="#";
for(var i=0;i<6;i++){
col+=Math.floor(Math.random()*16).toString(16);
}
return col;
}
//随机数值
static random(min,max){
return Math.floor(Math.random()*(max-min)+min);
}
//创建元素 设置样式 插入父级元素
static ce(type,style,parent){
var elem=document.createElement(type);
if(style){
for(var prop in style){
elem.style[prop]=style[prop];
}
}
if(typeof parent==="string") parent=document.querySelector(parent);
if(parent) parent.appendChild(elem);
return elem;
}
//读取css样式
static setStyle(styles){
var style=document.createElement("style");
document.head.appendChild(style);
var styleSheet=document.styleSheets[document.styleSheets.length-1];
for(var prop in styles){
Utils.addCss(styleSheet,prop,styles[prop]);
}
}
//添加css样式
static addCss(styleSheet,selector,style){
var str=selector+" {";
for(var prop in style){
var value=style[prop]
prop=prop.replace(/([A-Z])/g,function($1){
return "-"+$1.toLowerCase();
})
str+=prop+":"+value+";"
}
str+=" }";
styleSheet.insertRule(str,styleSheet.cssRules.length);
}
//css样式转化为js内样式
static CSStoString(str){
return str.replace(/(?<=:)(.*?)(?=;)|-[a-z](?=.+:)|;/g,function(item){
if(item===";") return ","
if(item[0]==="-") return item[1].toUpperCase();
return "'"+item.trim()+"'";
});
}
//字符串css转换为js内样式
static CSStoObject(str){
str=Utils.CSStoString(str);
return str.split(",").reduce((value,item)=>{
item=item.replace(/\n/g,"");
var arr=item.split(":");
arr[0]=arr[0].replace(/\s/g,"");
if(arr[1]===undefined) return value;
arr[1]=arr[1].replace(/'/g,"");
value[arr[0]]=arr[1];
return value;
},{})
}
}