4. 面向对象案例
- 第一步
class Tab {
constructor(id) {
//获取元素
this.main = document.querySelector(id); //最大的Tab盒子
this.lis = this.main.querySelectorAll(\'li\'); //大盒子里面的li
this.sections = this.main.querySelectorAll(\'section\');
this.init();//new的时候自动调用 用于测试代码console.log(this.index);是否可以打印正确的索引号
}
//初始化模块 让相关的元素绑定事件
init() {
for (var i = 0; i < this.lis.length; i++) {
this.lis[i].index = i;
this.lis[i].onclick = function() {
console.log(this.index);
}
}
}
//1. 切换功能
toggleTab() {}
//2. 添加功能
addTab() {}
//3. 删除功能
removeTab() {}
//4. 修改功能
editTab() {}
}
//页面中可能会有很多Tab都需要使用这个功能,那就可以实例化不同的对象。
var tab = new Tab(\'#tab\');
- 第二步
class Tab {
constructor(id) {
//获取元素
this.main = document.querySelector(id); //最大的Tab盒子
this.lis = this.main.querySelectorAll(\'li\'); //大盒子里面的li
this.sections = this.main.querySelectorAll(\'section\');
this.init();
}
//初始化模块 让相关的元素绑定事件
init() {
for (var i = 0; i < this.lis.length; i++) {
this.lis[i].index = i;
this.lis[i].onclick = this.toggleTab; //点击之后调用函数toggleTab(),函数前面的this就是函数的调用者。this.toggleTab的this就是被点击的li
}
}
//1. 切换功能
toggleTab() {
//函数里面的this都指向函数的调用者
console.log(this.index); //这个this指向当前的li,每个li都有一个index属性
}
//2. 添加功能
addTab() {}
//3. 删除功能
removeTab() {}
//4. 修改功能
editTab() {}
}
//页面中可能会有很多Tab都需要使用这个功能,那就可以实例化不同的对象。
var tab = new Tab(\'#tab\');
- 第三步:切换功能的实现
var that;
class Tab {
constructor(id) {
that = this;
//获取元素
this.main = document.querySelector(id); //最大的Tab盒子
this.lis = this.main.querySelectorAll(\'li\'); //大盒子里面的li
this.sections = this.main.querySelectorAll(\'section\');
this.init();
}
//初始化模块 让相关的元素绑定事件
init() {
for (var i = 0; i < this.lis.length; i++) {
this.lis[i].index = i;
this.lis[i].onclick = this.toggleTab; //点击之后调用函数toggleTab()
}
}
//1. 切换功能
toggleTab() {
// console.log(this.index); //这个this指向当前的li,每个li都有一个index属性
that.clearClass(); //必须要实例对象来调用这个函数
this.className = "liactive";
that.sections[this.index].className = "conactive"; //that指向实例化的对象(大盒子)
}
//清除其他"类"的函数
clearClass() { //由于这里是实例对象that来调用该函数,所以该函数里的this依然指向的是调用者:实例对象Tab
for (var i = 0; i < this.lis.length; i++) {
this.lis[i].className = \'\';
this.sections[i].className = \'\';
}
}
//2. 添加功能
addTab() {}
//3. 删除功能
removeTab() {}
//4. 修改功能
editTab() {}
}
//页面中可能会有很多Tab都需要使用这个功能,那就可以实例化不同的对象。
var tab = new Tab(\'#tab\');
对于insertAdjacenthtml():https://developer.mozilla.org/zh-CN/docs/Web/API/Element/insertAdjacentHTML
若用appendChild,那么还要经过createElement创建。。。
- 第四步
var that;
class Tab {
constructor(id) {
that = this;
//获取元素
this.main = document.querySelector(id); //最大的Tab盒子
this.lis = this.main.querySelectorAll(\'li\'); //大盒子里面的li
this.sections = this.main.querySelectorAll(\'section\');
this.add = this.main.querySelector(\'.tabadd\');
//li的父元素
this.ul = this.main.querySelector(\'.fisrstnav ul:first-child\');
//section父元素
this.fsection = this.main.querySelector(\'.tabscon\');
this.init(); //这里的this是实例对象,说明实例对象来调用的init(),那么init()里面的this都指向实例对象
}
//初始化模块 让相关的元素绑定事件
init() {
this.add.onclick = this.addTab;
for (var i = 0; i < this.lis.length; i++) {
this.lis[i].index = i;
this.lis[i].onclick = this.toggleTab; //点击之后调用函数toggleTab()
}
}
//1. 切换功能
toggleTab() {
// console.log(this.index); //这个this指向当前的li,每个li都有一个index属性
that.clearClass(); //必须要实例对象来调用这个函数
this.className = "liactive";
that.sections[this.index].className = "conactive"; //that指向实例化的对象(大盒子)
}
//清除其他"类"的函数
clearClass() { //由于这里是实例对象that来调用该函数,所以该函数里的this依然指向的是调用者:实例对象Tab
for (var i = 0; i < this.lis.length; i++) {
this.lis[i].className = \'\';
this.sections[i].className = \'\';
}
}
//2. 添加功能
addTab() {
that.clearClass();
//创建li和section
var li = \'<li class="liactive"><span>新选项卡</span><span class="iconfont icon-guanbi"></span></li>\';
var section = \'<section class="conactive">测试1</section>\';
//将li和section追加到父元素里
that.ul.insertAdjacentHTML(\'beforeend\', li);
that.fsection.insertAdjacentHTML(\'beforeend\', section);
}
//3. 删除功能
removeTab() {}
//4. 修改功能
editTab() {}
}
//页面中可能会有很多Tab都需要使用这个功能,那就可以实例化不同的对象。
var tab = new Tab(\'#tab\');
bug1:那些新增的li没有切换功能
解决思路:由于一部分li是后来才添加的,所以要求,当点击加号后,需要重新获取所有的小li和所有的section
var that;
class Tab {
constructor(id) {
that = this;
//获取元素
this.main = document.querySelector(id); //最大的Tab盒子
this.add = this.main.querySelector(\'.tabadd\');
//li的父元素
this.ul = this.main.querySelector(\'.fisrstnav ul:first-child\');
//section父元素
this.fsection = this.main.querySelector(\'.tabscon\');
this.init(); //这里的this是实例对象,说明实例对象来调用的init(),那么init()里面的this都指向实例对象
}
//获取所有的li和section
updateNode() { //解决bug1
this.lis = this.main.querySelectorAll(\'li\'); //大盒子里面的li
this.sections = this.main.querySelectorAll(\'section\');
}
//初始化模块 让相关的元素绑定事件
init() {
this.updateNode(); //解决bug1
this.add.onclick = this.addTab;
for (var i = 0; i < this.lis.length; i++) {
this.lis[i].index = i;
this.lis[i].onclick = this.toggleTab; //点击之后调用函数toggleTab()
}
}
//1. 切换功能
toggleTab() {
// console.log(this.index); //这个this指向当前的li,每个li都有一个index属性
that.clearClass(); //必须要实例对象来调用这个函数
this.className = "liactive";
that.sections[this.index].className = "conactive"; //that指向实例化的对象(大盒子)
}
//清除其他"类"的函数
clearClass() { //由于这里是实例对象that来调用该函数,所以该函数里的this依然指向的是调用者:实例对象Tab
for (var i = 0; i < this.lis.length; i++) {
this.lis[i].className = \'\';
this.sections[i].className = \'\';
}
}
//2. 添加功能
addTab() {
that.clearClass();
//创建li和section
var random = Math.random();
var li = \'<li class="liactive"><span>新选项卡</span><span class="iconfont icon-guanbi"></span></li>\';
var section = \'<section class="conactive">测试\' + random + \'</section>\';
//将li和section追加到父元素里
that.ul.insertAdjacentHTML(\'beforeend\', li);
that.fsection.insertAdjacentHTML(\'beforeend\', section);
that.init(); //解决bug1 重新绑定事件
}
//3. 删除功能
removeTab() {}
//4. 修改功能
editTab() {}
}
//页面中可能会有很多Tab都需要使用这个功能,那就可以实例化不同的对象。
var tab = new Tab(\'#tab\');
var that;
class Tab {
constructor(id) {
that = this;
//获取元素
this.main = document.querySelector(id); //最大的Tab盒子
this.add = this.main.querySelector(\'.tabadd\');
//li的父元素
this.ul = this.main.querySelector(\'.fisrstnav ul:first-child\');
//section父元素
this.fsection = this.main.querySelector(\'.tabscon\');
this.init(); //这里的this是实例对象,说明实例对象来调用的init(),那么init()里面的this都指向实例对象
}
//获取所有的li和section和❌
updateNode() { //解决bug1
this.lis = this.main.querySelectorAll(\'li\'); //大盒子里面的li
this.sections = this.main.querySelectorAll(\'section\');
//获取❌
this.remove = this.main.querySelectorAll(\'.icon-guanbi\');
}
//初始化模块 让相关的元素绑定事件
init() {
this.updateNode(); //解决bug1
this.add.onclick = this.addTab;
for (var i = 0; i < this.lis.length; i++) {
this.lis[i].index = i;
this.lis[i].onclick = this.toggleTab; //点击之后调用函数toggleTab()
this.remove[i].onclick = this.removeTab;
}
}
//1. 切换功能
toggleTab() {
// console.log(this.index); //这个this指向当前的li,每个li都有一个index属性
that.clearClass(); //必须要实例对象来调用这个函数
this.className = "liactive";
that.sections[this.index].className = "conactive"; //that指向实例化的对象(大盒子)
}
//清除其他"类"的函数
clearClass() { //由于这里是实例对象that来调用该函数,所以该函数里的this依然指向的是调用者:实例对象Tab
for (var i = 0; i < this.lis.length; i++) {
this.lis[i].className = \'\';
this.sections[i].className = \'\';
}
}
//2. 添加功能
addTab() {
that.clearClass();
//创建li和section
var random = Math.random();
var li = \'<li class="liactive"><span>新选项卡</span><span class="iconfont icon-guanbi"></span></li>\';
var section = \'<section class="conactive">测试\' + random + \'</section>\';
//将li和section追加到父元素里
that.ul.insertAdjacentHTML(\'beforeend\', li);
that.fsection.insertAdjacentHTML(\'beforeend\', section);
that.init(); //解决bug1
}
//3. 删除功能
removeTab(e) {
e.stopPropagation(); //阻止点击事件冒泡,❌有点击事件,li也有点击事件(导致li切换)。若不阻止冒泡,点击❌的时候会导致li切换toggleTab()
var index = this.parentNode.index; //也就是得到 所在li的索引号
console.log(index);
//根据索引号删除对应的li和section remove()可以直接删除指定的元素
that.lis[index].remove();
that.sections[index].remove();
//删除之后也要重新获取一下当前的元素
that.init();
}
//4. 修改功能
editTab() {}
}
//页面中可能会有很多Tab都需要使用这个功能,那就可以实例化不同的对象。
var tab = new Tab(\'#tab\');
现在进一步优化删除操作:希望将选中的li删除之后,程序自动将其前一个li看作选中的li,否则会出现没有选中li的情况,如下:
//3. 删除功能
removeTab(e) {
e.stopPropagation(); //阻止点击事件冒泡,❌有点击事件,li也有点击事件(导致li切换)。若不阻止冒泡,点击❌的时候会导致li切换toggleTab()
var index = this.parentNode.index; //也就是得到 所在li的索引号
console.log(index);
//根据索引号删除对应的li和section remove()可以直接删除指定的元素
that.lis[index].remove();
that.sections[index].remove();
//删除之后也要重新获取一下当前的元素
that.init();
//当我们删除了选中状态这个li的时候,让它的前一个li处于选中状态
index--;
that.lis[index].click(); //让前一个小li自动做一个点击动作
}
进一步优化:若当前是第一个li,那么点击删除之后,index==-1,程序就会报错,解决办法如下:
//3. 删除功能
removeTab(e) {
e.stopPropagation(); //阻止点击事件冒泡,❌有点击事件,li也有点击事件(导致li切换)。若不阻止冒泡,点击❌的时候会导致li切换toggleTab()
var index = this.parentNode.index; //也就是得到 所在li的索引号
console.log(index);
//根据索引号删除对应的li和section remove()可以直接删除指定的元素
that.lis[index].remove();
that.sections[index].remove();
//删除之后也要重新获取一下当前的元素
that.init();
//当我们删除了选中状态这个li的时候,让它的前一个li处于选中状态
index--;
that.lis[index] && that.lis[index].click(); //如果有这个li(即索引号大于等于0),就让前一个小li自动做一个点击动作
}
有出现一个问题:若选中的li是第4个,要删除的li是第2个,那么在删除2之后,选中的li自动更换为第1个,我们希望的是选中的li不会更换,这样更友好。
//3. 删除功能
removeTab(e) {
e.stopPropagation(); //阻止点击事件冒泡,❌有点击事件,li也有点击事件(导致li切换)。若不阻止冒泡,点击❌的时候会导致li切换toggleTab()
var index = this.parentNode.index; //也就是得到 所在li的索引号
console.log(index);
//根据索引号删除对应的li和section remove()可以直接删除指定的元素
that.lis[index].remove();
that.sections[index].remove();
//删除之后也要重新获取一下当前的元素
that.init();
//当我们删除了不是选中状态这个li的时候,原来选中状态的li保持不变
if (document.querySelector(".liactive")) return; //如果当前还有选中状态的li,就不执行以下代码( 若只有一个if可以不加{})
//当我们删除了选中状态这个li的时候,让它的前一个li处于选中状态
index--;
that.lis[index] && that.lis[index].click(); //如果有这个li(即索引号大于等于0),就让前一个小li自动做一个点击动作
}
window.getSelection?window.getSelection().removeAllRanges():document.section.empty();
上述代码可以禁止双击时选中文字
var that;
class Tab {
constructor(id) {
that = this;
//获取元素
this.main = document.querySelector(id); //最大的Tab盒子
this.add = this.main.querySelector(\'.tabadd\');
//li的父元素
this.ul = this.main.querySelector(\'.fisrstnav ul:first-child\');
//section父元素
this.fsection = this.main.querySelector(\'.tabscon\');
this.init(); //这里的this是实例对象,说明实例对象来调用的init(),那么init()里面的this都指向实例对象
}
//获取所有的li和section和❌
updateNode() { //解决bug1
this.lis = this.main.querySelectorAll(\'li\'); //大盒子里面的li
this.sections = this.main.querySelectorAll(\'section\');
//获取❌
this.remove = this.main.querySelectorAll(\'.icon-guanbi\');
//获取span
this.spans = this.main.querySelectorAll(\'.fisrstnav li span:first-child\');
}
//初始化模块 让相关的元素绑定事件
init() {
this.updateNode(); //解决bug1
this.add.onclick = this.addTab;
for (var i = 0; i < this.lis.length; i++) {
this.lis[i].index = i;
this.lis[i].onclick = this.toggleTab; //点击之后调用函数toggleTab()
this.remove[i].onclick = this.removeTab;
this.spans[i].ondblclick = this.editTab;
}
}
//1. 切换功能
toggleTab() {
// console.log(this.index); //这个this指向当前的li,每个li都有一个index属性
that.clearClass(); //必须要实例对象来调用这个函数
this.className = "liactive";
that.sections[this.index].className = "conactive"; //that指向实例化的对象(大盒子)
}
//清除其他"类"的函数
clearClass() { //由于这里是实例对象that来调用该函数,所以该函数里的this依然指向的是调用者:实例对象Tab
for (var i = 0; i < this.lis.length; i++) {
this.lis[i].className = \'\';
this.sections[i].className = \'\';
}
}
//2. 添加功能
addTab() {
that.clearClass();
//创建li和section
var random = Math.random();
var li = \'<li class="liactive"><span>新选项卡</span><span class="iconfont icon-guanbi"></span></li>\';
var section = \'<section class="conactive">测试\' + random + \'</section>\';
//将li和section追加到父元素里
that.ul.insertAdjacentHTML(\'beforeend\', li);
that.fsection.insertAdjacentHTML(\'beforeend\', section);
that.init(); //解决bug1
}
//3. 删除功能
removeTab(e) {
e.stopPropagation(); //阻止点击事件冒泡,❌有点击事件,li也有点击事件(导致li切换)。若不阻止冒泡,点击❌的时候会导致li切换toggleTab()
var index = this.parentNode.index; //也就是得到 所在li的索引号
console.log(index);
//根据索引号删除对应的li和section remove()可以直接删除指定的元素
that.lis[index].remove();
that.sections[index].remove();
//删除之后也要重新获取一下当前的元素
that.init();
//当我们删除了不是选中状态这个li的时候,原来选中状态的li保持不变
if (document.querySelector(".liactive")) return; //如果当前还有选中状态的li,就不执行以下代码( 若只有一个if可以不加{})
//当我们删除了选中状态这个li的时候,让它的前一个li处于选中状态
index--;
that.lis[index] && that.lis[index].click(); //如果有这个li(即索引号大于等于0),就让前一个小li自动做一个点击动作
}
//4. 修改功能
editTab() {
//双击禁止选定文字
window.getSelection ? window.getSelection().removeAllRanges() : document.section.empty();
//双击生成文本框
this.innerHTML = \'<input type="text" />\'; //这个this指向当前被点击的span
}
}
//页面中可能会有很多Tab都需要使用这个功能,那就可以实例化不同的对象。
var tab = new Tab(\'#tab\');
完善
//4. 修改功能
editTab() {
//这里的this指向当前被点击的span
//先获取span中原先的文字
var str = this.innerHTML;
//双击禁止选定文字
window.getSelection ? window.getSelection().removeAllRanges() : document.section.empty();
//双击生成文本框
this.innerHTML = \'<input type="text" />\';
//获取文本框
var input = this.children[0];
//将原先span中的内容赋值给文本框
input.value = str;
//让文本框里的默认文字处于选定状态,这样用户可以直接删除或修改原先的内容,不需要一个字一个字地删
input.select();
//当文本框失去焦点,就将文本框里的值给span
input.onblur = function() {
//这里的this指向input
this.parentNode.innerHTML = this.value; //this.parentNode即input的父亲即span
}
}
继续优化:希望按下回车键,也可以将input内容给span
//4. 修改功能
editTab() {
//这里的this指向当前被点击的span
//先获取span中原先的文字
var str = this.innerHTML;
//双击禁止选定文字
window.getSelection ? window.getSelection().removeAllRanges() : document.section.empty();
//双击生成文本框
this.innerHTML = \'<input type="text" />\';
//获取文本框
var input = this.children[0];
//将原先span中的内容赋值给文本框
input.value = str;
//让文本框里的默认文字处于选定状态,这样用户可以直接删除或修改原先的内容,不需要一个字一个字地删
input.select();
//当文本框失去焦点,就将文本框里的值给span
input.onblur = function() {
//这里的this指向input
this.parentNode.innerHTML = this.value; //this.parentNode即input的父亲即span
}
// 按下回车键,也可以将input内容给span
input.onkeyup = function(e) {
//这里的this指向input
if (e.keyCode === 13) { //回车键的ASCII是13
this.blur(); //手动调用失去焦点事件 不用加on
}
}
}
下面继续写对section修改内容
//初始化模块 让相关的元素绑定事件
init() {
this.updateNode(); //解决bug1
this.add.onclick = this.addTab;
for (var i = 0; i < this.lis.length; i++) {
this.lis[i].index = i;
this.lis[i].onclick = this.toggleTab; //点击之后调用函数toggleTab()
this.remove[i].onclick = this.removeTab;
this.spans[i].ondblclick = this.editTab;
this.sections[i].ondblclick = this.editTab;
}
}