JavaScript object-oriented case -- object-oriented Tab bar switching

Case style:

 

 

Functional requirements:

  1. Click the tab bar to switch the effect
  2. Click the + sign to add tab items and content items
  3. click × Number, you can delete the current tab item and content item
  4. Double click the text of tab item or content item to modify the text content

Extracting objects: Tab objects

  1. The object has the function of switching
  2. This object has the function of adding
  3. The object has deletion function
  4. This object has modification function

Get all elements:

var that;
class Tab {
    constructor(id){
        //Get element
        that = this;
        this.main = document.querySelector(id);
        this.add = this.main.querySelector('.tabadd');
        //Parent element of li
        this.ul = this.main.querySelector('.firstnav ul:first-child');
        //Parent element of section
        this.fsection = this.main.querySelector('.tabscon');
        this.init();//init is called through the instance object
    }
    init (){
        this.updateNode();
        // init initializes the operation and lets the related elements bind events
        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;
            }
    }
    //Get all small li and section s 
    updateNode(){
        this.lis = this.main.querySelectorAll('li');
        this.sections = this.main.querySelectorAll('section');
    }

Switching function:

Click different li to switch the tabs

 //1. Switching function
    toggleTab(){
        // console.log(this.index);
        that.clearClass();
        this.className = 'liactive';
        that.sections[this.index].className = 'conactive';
    }
    clearClass (){
        for (var i = 0; i <this.lis.length; i++){
            this.lis[i].className = '';
            this.sections[i].className = '';
        }
    }

Add features:

  1. Click + to add new tabs and contents
  2. Step 1: create a new tab li and a new content section
  3. Step 2: append the two created elements to the corresponding parent element
  4. Previous practice: dynamically create the element createElemnet, but there are many contents in the element. innerHTML assignment is required and appended to the parent element in appendChild
  5. Now advanced approach: using insertAdjacentHTML(), you can directly add string format elements to the parent element
  6. appendChild does not support appending sub elements of strings. insertAdjanceHTML supports appending elements of strings
 //2. Add functions
    addTab(){
        that.clearClass();//Clear all li and section classes
        //(1) Create li element and section element
        var random = Math.random();
        var li = ' <li class="liactive"><span>new tab </span><span class="iconfont icon-guanbi"></span></li>';
        var section = ' <section class="conactive">test'+ random +'</section>';
        //(2) Append these two elements to the corresponding parent element
        that.ul.insertAdjacentHTML('beforeend',li);
        that.fsection.insertAdjacentHTML('beforeend',section);
        that.init();//Solve the problem that the added element has no click event
    }

Delete function

Click × You can delete the current li tab and the current section

× There is no index number, but its father li has an index number. This index number is exactly what we want

So the core idea is: click x to delete the li and section corresponding to the index number

 //3. Delete function
    removeTab(e){
        e.stopPropagation();//Prevent bubbling and trigger switching click events of li
        var index = this.parentNode.index;
        console.log(index);
        //Delete the corresponding li and section remove methods according to the index number to directly delete the specified element
        that.lis[index].remove();
        that.sections[index].remove();
        that.init();
        //When we delete a li that is not in the selected state, the li in the original selected state remains unchanged
        if(document.querySelector('.liactive')) return;
        //When we delete the li in the selected state, we make the previous li in the selected state
        index--;
        //Manually call the click event without mouse triggering
        that.lis[index] && that.lis[index].click();
    }

Edit operation

  1. Double click the text in the tab li or section to realize the modification function
  2. The double click event is: ondbllick
  3. If you double-click the text, the text will be selected by default. At this time, you need to double-click to prohibit the selection of text
  4. window.getSelection?window.getSelection().removeAllRanges():document.selection.empty();
  5. Core idea: when you double-click the text, a text box is generated inside. When you lose focus or press enter, and then give the value entered in the text box to the original element.
 //4. Modify function
    editTab(){
        var str = this.innerHTML;
        //Double click to suppress the selected text
        window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty();
        this.innerHTML = '<input type="text" />';
        var input = this.children[0];
        input.value = str;
        input.select();//Make the text in input in the selected state
        input.onblur = function(){
            this.parentNode.innerHTML = this.value;
            //Press enter to return the value in the text box to span
            input.onkeyup = function(e){
                if (e.keyCode === 13){
                    //Manually calling the event that the form loses focus does not require the mouse to leave the operation
                    this.blur();
                }
            }
        }
    }

Full code:

HTML part

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="../css/tab.css">
</head>
<body>
    <main>
        <h4>JS Object oriented dynamic adding tabs</h4>
        <div class="tabsbox" id="tab">
            <!-- tab label -->
            <nav class="firstnav">
                <ul>
                    <li class="liactive"><span>Test 1</span><span class="icon-cross"></span></span></li>
                    <li><span>Test 2</span><span class="icon-cross"></span></span></li>
                    <li><span>Test 3</span><span class="icon-cross"></span></span></li>
                </ul>
                <div class="tabadd">
                    <span>+</span>
                </div>
            </nav>

            <!-- tab content -->
            <div class="tabscon">
                <section class="conactive">Test 1</section>
                <section>Test 2</section>
                <section>Test 3</section>
            </div>
        </div>
    </main>
    <script src="../js/tab.js"></script>
</body>
</html>

CSS part

* {
margin: 0;
padding: 0;
}
@font-face {
    font-family: 'icomoon';
    src:  url('fonts/icomoon.eot?87vq05');
    src:  url('fonts/icomoon.eot?87vq05#iefix') format('embedded-opentype'),
      url('fonts/icomoon.ttf?87vq05') format('truetype'),
      url('fonts/icomoon.woff?87vq05') format('woff'),
      url('fonts/icomoon.svg?87vq05#icomoon') format('svg');
    font-weight: normal;
    font-style: normal;
    font-display: block;
  }
ul li {
list-style: none;
}
main {
width: 960px;
height: 500px;
border-radius: 10px;
margin: 50px auto;
}
main h4 {
height: 100px;
line-height: 100px;
text-align: center;
}
.tabsbox {
width: 900px;
margin: 0 auto;
height: 400px;
border: 1px solid lightsalmon;
position: relative;
}
nav ul {
overflow: hidden;
}
nav ul li {
font-family: 'icomoon';
float: left;
width: 100px;
height: 50px;
line-height: 50px;
text-align: center;
border-right: 1px solid #ccc;
position: relative;
}
nav ul li.liactive {
border-bottom: 2px solid #fff;
z-index: 9;
}
nav ul li:hover {
    background-color: #ccc;
}
main ul li .icon-cross {
    font-family: 'icomoon';
}
#tab input {
width: 80%;
height: 60%;
}
nav ul li span:last-child {
position: absolute;
user-select: none;
font-size: 12px;
top: -18px;
right: 0;
display: inline-block;
height: 20px;
}
.tabadd {
position: absolute;
/* width: 100px; */
top: 0;
right: 0;
}
.tabadd span {
display: block;
width: 20px;
height: 20px;
line-height: 20px;
text-align: center;
border: 1px solid #ccc;
float: right;
margin: 10px;
user-select: none;
}

.tabscon {
width: 100%;
height: 300px;
position: absolute;
padding: 30px;
top: 50px;
left: 0px;
box-sizing: border-box;
border-top: 1px solid #ccc;
}

.tabscon section,
.tabscon section.conactive {
display: none;
width: 100%;
height: 100%;
}

.tabscon section.conactive {
display: block;
}

Note: the font Icon needs to be introduced into the small cross part, and attention should be paid to reference and change when using it.

JavaScript part

var that;
class Tab {
    constructor(id){
        //Get element
        that = this;
        this.main = document.querySelector(id);
        this.add = this.main.querySelector('.tabadd');
        //Parent element of li
        this.ul = this.main.querySelector('.firstnav ul:first-child');
        //Parent element of section
        this.fsection = this.main.querySelector('.tabscon');
        this.init();//init is called through the instance object
    }
    init (){
        this.updateNode();
        // init initializes the operation and lets the related elements bind events
        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;
            this.remove[i].onclick = this.removeTab;
            this.spans[i].ondblclick = this.editTab;
            this.sections[i].ondblclick = this.editTab;
            }
    }
    //Because we add elements dynamically, we need to retrieve the corresponding elements
    updateNode(){
        this.lis = this.main.querySelectorAll('li');
        this.sections = this.main.querySelectorAll('section');
        this.remove = this.main.querySelectorAll('.icon-cross');
        this.spans = this.main.querySelectorAll('.firstnav li span:first-child');
    }
    //1. Switching function
    toggleTab(){
        // console.log(this.index);
        that.clearClass();
        this.className = 'liactive';
        that.sections[this.index].className = 'conactive';
    }
    clearClass (){
        for (var i = 0; i <this.lis.length; i++){
            this.lis[i].className = '';
            this.sections[i].className = '';
        }
    }
    //2. Add functions
    addTab(){
        that.clearClass();//Clear all li and section classes
        //(1) Create li element and section element
        var random = Math.random();
        var li = '  <li class="liactive"><span>New options</span><span class="icon-cross"></span></span></li>';
        var section = ' <section class="conactive">test'+ random +'</section>';
        //(2) Append these two elements to the corresponding parent element
        that.ul.insertAdjacentHTML('beforeend',li);
        that.fsection.insertAdjacentHTML('beforeend',section);
        that.init();//Solve the problem that the added element has no click event
    }
    //3. Delete function
    removeTab(e){
        e.stopPropagation();//Prevent bubbling and trigger switching click events of li
        var index = this.parentNode.index;
        console.log(index);
        //Delete the corresponding li and section remove methods according to the index number to directly delete the specified element
        that.lis[index].remove();
        that.sections[index].remove();
        that.init();
        //When we delete a li that is not in the selected state, the li in the original selected state remains unchanged
        if(document.querySelector('.liactive')) return;
        //When we delete the selected li, the previous li will be selected
        index--;
        //Manually call the click event without mouse triggering
        that.lis[index] && that.lis[index].click();
    }
    //4. Modify function
    editTab(){
        var str = this.innerHTML;
        //Double click to suppress the selected text
        window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty();
        this.innerHTML = '<input type="text" />';
        var input = this.children[0];
        input.value = str;
        input.select();//Make the text in input in the selected state
        input.onblur = function(){
            this.parentNode.innerHTML = this.value;
            //Press enter to return the value in the text box to span
            input.onkeyup = function(e){
                if (e.keyCode === 13){
                    //Manually calling the event that the form loses focus does not require the mouse to leave the operation
                    this.blur();
                }
            }
        }
    }
}
new Tab('#tab');

Keywords: Javascript Front-end

Added by benn600 on Sun, 06 Feb 2022 21:03:03 +0200