Practice a project to remove the jQuery

Why jQuery removed from the project

Early projects compatible browser in order to reduce the cost of using jQuery, during use project, are gradually exposed some problems. Since we are sdk project, it needs to be integrated into other sectors of the company's products, so the fit and compatibility requirements are relatively high. In the application process, issues with mobile end-party libraries zepto variable $ conflict occurs. To solve this problem at the time, we created a new variable to provide jQuery to avoid conflicts. Late With plenty of time, then consider writing a base class used in place of jQuery, while reducing network requests once, why not do it.

I put this base class named called BaseElement, due to the dom node actually used in the project is not a lot, do not need to consider the performance of rendering consumption, so only a few nodes to achieve the necessary operating method.

With a base class to encapsulate dom node, there must be a different node types and different styles, the text sometimes, so give the constructor added several parameters:

    constructor (tag, className, text) {
        this._element = null;
        if (typeof tag === 'string') {
            this._element = document.createElement(tag);

        } else if (tag instanceof HTMLElement) {
            this._element = tag;
        }

        if (this._element) {
            if (typeof className === 'string' && className !== '') {
                this._element.className = className;
            }
            if (typeof text === 'string' && text !== '') {
                this._element.innerText = text;
            }
        }
    }
    
    get element () {
        return this._element;
    }
复制代码

This BaseElementbase class will use _elementthis variable holds a dom node, the following methods are associated with a series of dom nodes.

The first is the show and hide methods, and joined the variable _visibledisplay state record for the current node, the node displayed by default:

    constructor () {
        this._visible = true;
    }
    
    show () {
        this._element.style.display = '';
        this._visible = true;
        return this;
    }
    
    hide () {
        this._element.style.display = 'none';
        this._visible = false;
        return this;
    }
    
    get visible () {
        return this._visible;
    }
复制代码

Both methods return the current node base class, to facilitate a variety of functions with the external line of code calling, for example:

let element = new BaseElement('div');
element.show().hide();
复制代码

Base class light show and hide methods have not enough, also need to be added to the node node in the tree can really show out here and jQuery to achieve the same method name appendand preAppendmethod:

    append (child) {
        if (this._element instanceof HTMLElement) {
            if (child instanceof BaseElement) {
                this._element.appendChild(child.element);
            } else if (child instanceof HTMLElement) {
                this._element.appendChild(child);
            }
            return this;
        }
        return null;
    }
    
    preAppend (child) {
        if (this._element instanceof HTMLElement) {
            if (child instanceof BaseElement) {
                this._element.prepend(child.element);
            } else if (child instanceof HTMLElement) {
                this._element.prepend(child);
            }
            return child;
        }
        return null;
    }
复制代码

A method of removing again:

    remove (child) {
        if (this._element instanceof HTMLElement)
            if (child instanceof BaseElement) {
                this._element.removeChild(child.element);
            } else if (child instanceof HTMLElement) {
                this._element.removeChild(child);
            }
            return this;
        }
        return null;
    }
复制代码

And then implement a child node to remove all its own way:

    empty () {
        if (this._element instanceof HTMLElement) {
            let children = this._element.children;
            while (children.length) {
                this._element.removeChild(children[0]);
            }
        }
    }
复制代码

After implementing these methods, the base class nodes already free to add and remove nodes, then we need to deal with inter-node of the content and style of the line.

Line content between nodes can be easily achieved with two access control:

    set text (value) {
        if (typeof value === 'string' && this._element instanceof HTMLElement) {
            this._element.innerText = value;
        }
    }
    
    get text () {
        if (this._element instanceof HTMLElement) {
            return this._element.innerText;
        }
        return '';
    }
    
    set html (value) {
        if (typeof value === 'string' && this._element instanceof HTMLElement) {
            this._element.innerHTML = value;
        }
    }
    
    get html () {
        if (this._element instanceof HTMLElement) {
            return this._element.innerHTML;
        }
        return '';
    }
复制代码

As for the style, but also it provides different methods to manipulate:

    css (key, value) {
        if (value !== null && this._element instanceof HTMLElement) {
            this._element.style[key] = value;
        }
        return this;
    }
    
    addClass (className) {
        if (this._element instanceof HTMLElement) {
            let tmpClassName = this._element.className;
            if (className !== '' && !tmpClassName.split(' ').includes(className)) {
                tmpClassName += ' ' + className;
                this._element.className = tmpClassName;
            }
            return this;
        }
        return null;
    }
    
    removeClass (className) {
        if (this._element instanceof HTMLElement) {
            let tmpClassName = this._element.className;
            if (className !== '') {
                this._element.className = tmpClassName.split(' ').filter((value) => {
                    return value !== className && value !== '';
                }).join(' ');
            }
            return this;
        }
        return null;
    }
    
    hasClass (className) {
        if (this._element instanceof HTMLElement) {
            if(className !== '') {
                return this._element.className.indexOf(className) >= 0;
            }
        }
        return false;
    }
复制代码

The method can directly set an css style node, for example:

let element = new BaseElement('div');
element.css('width', '100%');
复制代码

And addClassa method to directly set a node class, the corresponding need to write css to fit.

Sometimes we also need to get the node leftwith the topcorresponding calculated values, and then provide a _offsetway to obtain these values, _offsetthe method by calling the cycle offsetParentto get the offset of the current node with the upper-left corner of the page, about offsetParentdetails please see here :

    _offset (direction) {
        if (this._element instanceof HTMLElement) {
            let offsetDir: string = 'offset' + direction[0].toUpperCase() + direction.substring(1);

            let realNum: number = this._element[offsetDir];
            var positionParent: Element = (this._element as HTMLElement).offsetParent;

            while(positionParent !== null) {
                realNum += positionParent[offsetDir];
                positionParent = (positionParent as HTMLElement).offsetParent;
            }
            return realNum;
        }
        return 0;
    }
    
    get left () {
        return this._offset('left');
    }
    
    get top () {
        return this._offset('top');
    }
复制代码

In jQuery, the animation is calculated in accordance with the timer node attributes required to implement a certain amount of code, and the project application environments are also modern browsers, so you use css3 animation to achieve. Here's a little trick, if you need to achieve animation repetitive, such as popup effect, you can write two css, such as animate_0and animate_1, coupled with this code, no problem:

this._animateIndex = 0;

applyAnimate () {
    let animateName = `animate_${this._animateIndex}`;
    this._element.removeClass(animateName);
    this._animateIndex = 1 - this._animateIndex;
    this._element.addClasss(animateName);
}
复制代码

Finally, we need to add a node to a number of event listeners, after all, purely demonstrative project few, the vast majority of projects need to generate interaction with the user, as follows:

    on (type, callback) {
        if (this._element instanceof HTMLElement) {
            if (this._element.addEventListener) {
                this._element.addEventListener(type, callback);
            } else if (this._element['attachEvent']) {
                this._element['attachEvent']('on' + type, callback);
            } else {
                this._element['on' + type] = callback;
            }
        }
    }
复制代码

There is also a loved interaction hovermethods:

    hover (inCallback, outCallback) {
        // mouseover和mouseout在进入子节点时也会触发,这里使用mouseenter和mouseleave
        this.on('mouseenter', inCallback);
        this.on('mouseleave', outCallback);
    }
复制代码

Node base class to be here to support project development usually enough, if there is some special node types, such as video and the like, and then you can expand on their own.

to sum up

With the project BaseElementbuild dom node, since the methods used are packaged, it is also possible to operate all the nodes have relatively uniform dom inlet, which in itself uphold object-oriented thinking.

Perhaps the applicability of this base class is not very wide, but as long as they play a valuable role, that is a very good result.

Reproduced in: https: //juejin.im/post/5d0b53f751882554d6312f1a

Guess you like

Origin blog.csdn.net/weixin_34367845/article/details/93177351