TypeScript绘制菜单的问题
MyNote/JavaScript绘制菜单.md
一、菜单-按钮类型
//有一个对象MenuObj
var MenuObj = {
MenuName: "MenuName",
Btn: [
{ BtnName: "Btn1", func: function () { console.log("Btn1"); } },
{ BtnName: "Btn1", func: function () { console.log("Btn2"); } } //func1,func2与Btn1无关
]
};
如果如下实现
var MenuImple = document.createElement("div");
MenuImple.innerText = MenuObj.MenuName;
for (var i = 0; i < MenuObj.Btn.length; i++) {
var thisBtnImple = document.createElement("div");
thisBtnImple.innerText = MenuObj.Btn[i].BtnName;
var funclick = function () {
MenuObj.Btn[i].func();
};
thisBtnImple.addEventListener("click", funclick);
MenuImple.appendChild(thisBtnImple);
}
document.getElementById("test").appendChild(MenuImple);
这样绘制出的所有按钮的点击后会报错, Unable to get property 'func' of undefined or null reference
原因在于外部对象的作用域无法延伸到函数内部
外部函数的作用域可以进入函数内部。可否用另外一个变量来引用呢?
var MenuImple=document.createElement("div");
MenuImple.innerText=MenuObj.MenuName;
for(var i=0;i<MenuObj.Btn.length;i++)
{
var thisBtnImple=document.createElement("div");
thisBtnImple.innerText=MenuObj.Btn[i].BtnName;
var thisfunc=MenuObj.Btn[i].func;
var funclick=function(){
thisfunc();
}
thisBtnImple.addEventListener("click",funclick);
MenuImple.appendChild(thisBtnImple);
}
document.getElementById("test").appendChild(MenuImple);
这样绘制的所有按钮的点击事件都是最后一按钮的点击事件
原因在于funclick只在点击时才调用,构建过程中是不会调用的,在点击时根据上下文,此时的i为最后一个,funclick就是最后一个按钮的func;
如果加上自执行
var MenuImple=document.createElement("div");
MenuImple.innerText=MenuObj.MenuName;
for(var i=0;i<MenuObj.Btn.length;i++)
{
var thisBtnImple=document.createElement("div");
thisBtnImple.innerText=MenuObj.Btn[i].BtnName;
var thisfunc=MenuObj.Btn[i].func;
var funclick1=function(){
thisfunc();
}();
thisBtnImple.addEventListener("click",funclick1);
MenuImple.appendChild(thisBtnImple);
}
document.getElementById("test").appendChild(MenuImple);
Typescript编译器会报错,强行编译的话,浏览器根本不会为其添加事件函数,这个函数在渲染过程中就直接执行了
可以这样写
var MenuImple=document.createElement("div");
MenuImple.innerText=MenuObj.MenuName;
for(var i=0;i<MenuObj.Btn.length;i++)
{
var thisBtnImple=document.createElement("div");
thisBtnImple.innerText=MenuObj.Btn[i].BtnName;
var thisfunc=MenuObj.Btn[i].func;
thisBtnImple.addEventListener("click",thisfunc);
MenuImple.appendChild(thisBtnImple);
}
document.getElementById("test").appendChild(MenuImple);
也可以这样写
var MenuImple=document.createElement("div");
MenuImple.innerText=MenuObj.MenuName;
for(var i=0;i<MenuObj.Btn.length;i++)
{
var thisBtnImple=document.createElement("div");
thisBtnImple.innerText=MenuObj.Btn[i].BtnName;
thisBtnImple.addEventListener("click",MenuObj.Btn[i].func);
MenuImple.appendChild(thisBtnImple);
}
document.getElementById("test").appendChild(MenuImple);
共同点是不要在循环中定义onclick函数,而是在类的构造中就定义了这个函数
二、折叠菜单类型
在上述菜单加一个折叠开关,折叠开关的计数用闭包实现;
var MenuImple=document.createElement("div");
var MenuImple_Title=document.createElement("div");
var MenuSwitch=document.createElement("span");
MenuSwitch.innerText="Switch";
function funclick1(){
var tc=0;
function funclick2(){
if(tc%2==0){
console.log("open");
MenuImple_List.style.display="flex";
}
else{
console.log("close");
MenuImple_List.style.display="none";
}
tc++;
tc=tc%2;
}
return funclick2;
}
MenuSwitch.addEventListener("click",funclick1);
MenuImple_Title.appendChild(MenuSwitch);
var MenuImple_Title_Text=document.createElement("span");
MenuImple_Title_Text.innerText=MenuObj.MenuName;
MenuImple_Title.appendChild(MenuImple_Title_Text);
MenuImple.appendChild(MenuImple_Title);
var MenuImple_List=document.createElement("div");
MenuImple_List.style.display="none";
for(var i=0;i<MenuObj.Btn.length;i++)
{
var thisBtnImple=document.createElement("div");
thisBtnImple.innerText=MenuObj.Btn[i].BtnName;
thisBtnImple.addEventListener("click",MenuObj.Btn[i].func);
MenuImple_List.appendChild(thisBtnImple);
}
MenuImple.appendChild(MenuImple_List);
document.getElementById("test").appendChild(MenuImple);
点击之后函数并不起作用
可以将addEventListener写到闭包内
如下
var MenuImple=document.createElement("div");
var MenuImple_Title=document.createElement("div");
var MenuSwitch=document.createElement("span");
MenuSwitch.innerText="Switch";
var funclick=function(){
console.log("Switch");
var tc=0;
function funclick2(){
if(tc%2==0){
console.log("open");
MenuImple_List.style.display="flex";
}
else{
console.log("close");
MenuImple_List.style.display="none";
}
tc++;
tc=tc%2;
}
MenuSwitch.addEventListener("click",funclick2);
}();
MenuImple_Title.appendChild(MenuSwitch);
var MenuImple_Title_Text=document.createElement("span");
MenuImple_Title_Text.innerText=MenuObj.MenuName;
MenuImple_Title.appendChild(MenuImple_Title_Text);
MenuImple.appendChild(MenuImple_Title);
var MenuImple_List=document.createElement("div");
MenuImple_List.style.display="none";
for(var i=0;i<MenuObj.Btn.length;i++)
{
var thisBtnImple=document.createElement("div");
thisBtnImple.innerText=MenuObj.Btn[i].BtnName;
thisBtnImple.addEventListener("click",MenuObj.Btn[i].func);
MenuImple_List.appendChild(thisBtnImple);
}
MenuImple.appendChild(MenuImple_List);
document.getElementById("test").appendChild(MenuImple);