【问题标题】:Regex to change a html element class with javascript not working正则表达式用 javascript 更改 html 元素类不起作用
【发布时间】:2015-09-01 15:40:00
【问题描述】:

我有以下 javascript 函数来打开和关闭 onclick 事件的子列表元素:

function ShowHideDtls(itId) {
    var subMen = document.getElementById(itId);
    if (subMen != null) {
        if (subMen.className == "nav nav-second-level collapse in") {
            subMen.className = "nav nav-second-level collapse";
        } else {
            subMen.className += " in";
        }
    }
}

“collapse”是一个 css 类,它使 display=none 隐藏子列表,“in”是一个使 display=block 显示子列表的类,创建一个带有子菜单的菜单。

我在这个问题Change an element's class with JavaScript 在第一个(接受的)答案中发现使用正则表达式来做到这一点。我试过这样:

function ShowHideDtls(itId) {
    var subMen = document.getElementById(itId);
    if (subMen != null) {
        if (subMen.className.match(/(?:^|\s)in(?!\S)/)) {
            subMen.className.replace(/(?:^|\s)in(?!\S)/g, '');
        } else {
            subMen.className += " in";
        }
    }
}

没有正则表达式的代码可以完美运行,但使用正则表达式就不行。我检查了 regex101.com 中的正则表达式,它似乎在那里工作。据我了解,使用正则表达式比使用所有类名的长字符串更合适,而且我还有一个导航三级类,我必须关闭和打开,所以正则表达式似乎是方便和正确的方法做。 怎么了? 谢谢。

【问题讨论】:

    标签: javascript html css regex


    【解决方案1】:

    这里不需要regex。你可以使用classList

    使用 classList 是通过 element.className 以空格分隔的字符串形式访问元素的类列表的便捷替代方法。

    function ShowHideDtls(itId) {
        var subMen = document.getElementById(itId);
        if (subMen != null) {
            subMen.classList.toggle('in');
        }
    }
    

    toggle() 将切换元素的类。如果元素已经有类,它将删除它,如果没有,则切换会将类添加到元素。

    检查Browser Compatibility

    您可以在 IE9 中使用 MDN 中的 SHIM

    /* 
     * classList.js: Cross-browser full element.classList implementation.
     * 2014-07-23
     *
     * By Eli Grey, http://eligrey.com
     * Public Domain.
     * NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
     */
    
    /*global self, document, DOMException */
    
    /*! @source http://purl.eligrey.com/github/classList.js/blob/master/classList.js*/
    
    if ("document" in self) {
    
        // Full polyfill for browsers with no classList support
        if (!("classList" in document.createElement("_"))) {
    
            (function (view) {
    
                "use strict";
    
                if (!('Element' in view)) return;
    
                var
                    classListProp = "classList",
                    protoProp = "prototype",
                    elemCtrProto = view.Element[protoProp],
                    objCtr = Object,
                    strTrim = String[protoProp].trim || function () {
                        return this.replace(/^\s+|\s+$/g, "");
                    },
                    arrIndexOf = Array[protoProp].indexOf || function (item) {
                        var
                            i = 0,
                            len = this.length;
                        for (; i < len; i++) {
                            if (i in this && this[i] === item) {
                                return i;
                            }
                        }
                        return -1;
                    }
                    // Vendors: please allow content code to instantiate DOMExceptions
                    ,
                    DOMEx = function (type, message) {
                        this.name = type;
                        this.code = DOMException[type];
                        this.message = message;
                    },
                    checkTokenAndGetIndex = function (classList, token) {
                        if (token === "") {
                            throw new DOMEx(
                                "SYNTAX_ERR", "An invalid or illegal string was specified"
                            );
                        }
                        if (/\s/.test(token)) {
                            throw new DOMEx(
                                "INVALID_CHARACTER_ERR", "String contains an invalid character"
                            );
                        }
                        return arrIndexOf.call(classList, token);
                    },
                    ClassList = function (elem) {
                        var
                            trimmedClasses = strTrim.call(elem.getAttribute("class") || ""),
                            classes = trimmedClasses ? trimmedClasses.split(/\s+/) : [],
                            i = 0,
                            len = classes.length;
                        for (; i < len; i++) {
                            this.push(classes[i]);
                        }
                        this._updateClassName = function () {
                            elem.setAttribute("class", this.toString());
                        };
                    },
                    classListProto = ClassList[protoProp] = [],
                    classListGetter = function () {
                        return new ClassList(this);
                    };
                // Most DOMException implementations don't allow calling DOMException's toString()
                // on non-DOMExceptions. Error's toString() is sufficient here.
                DOMEx[protoProp] = Error[protoProp];
                classListProto.item = function (i) {
                    return this[i] || null;
                };
                classListProto.contains = function (token) {
                    token += "";
                    return checkTokenAndGetIndex(this, token) !== -1;
                };
                classListProto.add = function () {
                    var
                        tokens = arguments,
                        i = 0,
                        l = tokens.length,
                        token, updated = false;
                    do {
                        token = tokens[i] + "";
                        if (checkTokenAndGetIndex(this, token) === -1) {
                            this.push(token);
                            updated = true;
                        }
                    }
                    while (++i < l);
    
                    if (updated) {
                        this._updateClassName();
                    }
                };
                classListProto.remove = function () {
                    var
                        tokens = arguments,
                        i = 0,
                        l = tokens.length,
                        token, updated = false,
                        index;
                    do {
                        token = tokens[i] + "";
                        index = checkTokenAndGetIndex(this, token);
                        while (index !== -1) {
                            this.splice(index, 1);
                            updated = true;
                            index = checkTokenAndGetIndex(this, token);
                        }
                    }
                    while (++i < l);
    
                    if (updated) {
                        this._updateClassName();
                    }
                };
                classListProto.toggle = function (token, force) {
                    token += "";
    
                    var
                        result = this.contains(token),
                        method = result ?
                        force !== true && "remove" :
                        force !== false && "add";
    
                    if (method) {
                        this[method](token);
                    }
    
                    if (force === true || force === false) {
                        return force;
                    } else {
                        return !result;
                    }
                };
                classListProto.toString = function () {
                    return this.join(" ");
                };
    
                if (objCtr.defineProperty) {
                    var classListPropDesc = {
                        get: classListGetter,
                        enumerable: true,
                        configurable: true
                    };
                    try {
                        objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc);
                    } catch (ex) { // IE 8 doesn't support enumerable:true
                        if (ex.number === -0x7FF5EC54) {
                            classListPropDesc.enumerable = false;
                            objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc);
                        }
                    }
                } else if (objCtr[protoProp].__defineGetter__) {
                    elemCtrProto.__defineGetter__(classListProp, classListGetter);
                }
    
            }(self));
    
        } else {
            // There is full or partial native classList support, so just check if we need
            // to normalize the add/remove and toggle APIs.
    
            (function () {
                "use strict";
    
                var testElement = document.createElement("_");
    
                testElement.classList.add("c1", "c2");
    
                // Polyfill for IE 10/11 and Firefox <26, where classList.add and
                // classList.remove exist but support only one argument at a time.
                if (!testElement.classList.contains("c2")) {
                    var createMethod = function (method) {
                        var original = DOMTokenList.prototype[method];
    
                        DOMTokenList.prototype[method] = function (token) {
                            var i, len = arguments.length;
    
                            for (i = 0; i < len; i++) {
                                token = arguments[i];
                                original.call(this, token);
                            }
                        };
                    };
                    createMethod('add');
                    createMethod('remove');
                }
    
                testElement.classList.toggle("c3", false);
    
                // Polyfill for IE 10 and Firefox <24, where classList.toggle does not
                // support the second argument.
                if (testElement.classList.contains("c3")) {
                    var _toggle = DOMTokenList.prototype.toggle;
    
                    DOMTokenList.prototype.toggle = function (token, force) {
                        if (1 in arguments && !this.contains(token) === !force) {
                            return force;
                        } else {
                            return _toggle.call(this, token);
                        }
                    };
    
                }
    
                testElement = null;
            }());
    
        }
    
    }
    

    如果你使用的是jQuery,你可以使用toggleClass():

    function ShowHideDtls(itId) {
        $('#' + itId).toggleClass('in');
    }
    

    编辑

    如果你还想使用regex

    if (/\bin\b/.test(subMen.className))
        subMen.className.replace(/\bin\b/, '');
    } else {
        subMen.className += " in";
    }
    

    您也可以使用split()indexOf 来检查元素上是否存在类。

    var classes = className.split(/\s+/),
        classIndex = classes.indexOf('in');
    if (classIndex > -1) {
        classes.splice(classIndex, 1);
        subMen.className = classes.join(' ');
    } else {
        subMen.className += " in";
    }
    

    【讨论】:

    • 谢谢图沙尔。我在问题中提到的链接上看到了使用类列表的选项。然而,那里也声明它在 IE10 之前不受 IE 支持,所以我宁愿不使用它。
    • @DovMiller 您可以检查答案中的最后一个代码 sn-p。它使用数组和字符串方法来添加/删除类
    • 有趣。你能添加一个解释。拼接和连接有什么作用?它们的参数是什么?这适用于所有浏览器吗?谢谢
    【解决方案2】:

    replace函数返回结果值,它不间接赋值。

    请按照以下步骤操作:

    function ShowHideDtls(itId) {
            var subMen = document.getElementById(itId);
            if (subMen != null) {
                if (subMen.className.match(/(?:^|\s)in(?!\S)/)) {
                    subMen.className = subMen.className.replace(/(?:^|\s)in(?!\S)/g, '');
                }
                else {
                    subMen.className += " in";
                }
            }
        }
    

    【讨论】:

      猜你喜欢
      • 2018-02-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-18
      • 2014-09-12
      • 2015-07-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多