【问题标题】:Modify an element on-the-fly so it matches a given selector即时修改元素,使其匹配给定的选择器
【发布时间】:2015-06-08 11:53:51
【问题描述】:

假设我有这样的元素:

<div class="some-class"></div>

和选择器类似:

#mydiv.super.another-class[some-attribute="true"]

我想让我的 div 匹配这个选择器。这需要

  • 添加 id mydiv
  • 添加类superanother-class
  • 添加属性some-attribute 和值true

所以最终的 div 看起来像

<div class="some-class super another-class" id="mydiv" some-attribute="true"></div>

有没有办法做类似的事情

$(".some-class").makeMatch('#mydiv.super.another-class[some-attribute="true"]');

这将解析选择器并为任何有效选择器执行上面列出的步骤?

我知道我可以做一些函数来解析选择器并做到这一点,但是选择器可能非常复杂,并且相同的选择器可能以多种不同的方式组成,因此我决定尝试找到一些可靠的现有解决方案。

你知道类似的事情吗,或者有什么本地方法吗?


编辑:根据 cmets,我将尝试以不同的方式解释我的问题。

问题的重点是:

是否可以使用 javascript 解析任何有效的选择器以知道它指向什么 id、什么类和什么属性?

所以我们会喜欢

var selectorData = parseSelector('#my-id.class-one.class-two[attr-one="value-one"]');
selectorData.id //my-id
selectorData.classes //class-one class-two
selectorData.attributes["attr-one"] //value

因为有了关于选择器的这些数据,所以很容易让任何元素匹配它。

【问题讨论】:

  • 这是一个非常有趣的用例,虽然有点晦涩难懂。选择器确实很复杂,但是您尝试做的事情的性质会产生一些有趣的限制,可以通过这些限制来缩小潜在解决方案的范围。例如,只有特征选择器(类型、ID、类和属性)和可能的结构伪类可以被接受。尽管可能必须编写一个成熟的解析器,但精确的实现可能有点宽泛,即使解析器仅限于处理仅由特征选择器组成的单个复合选择器。

标签: javascript jquery css jquery-selectors css-selectors


【解决方案1】:

我已经为你写了一个小的 jquery 函数

$.fn.makeMatch = function(ids, classes, attr) {
    this.attr('id', ids).addClass(classes).attr(attr);
    return this;
}

你现在只需要:

$('div').makeMatch('firstComesOneId', 'then classes seperated by space', {'data-arrayKey1' : 'value1', 'data-arrayKey2' : 'value2'})

会输出:

<div id="firstComesOneId" class="then classes seperated by space" data-arrayKey1="value1" data-arrayKey2="value2">

希望这就是你所需要的。


在操作人员告诉我这不是他需要的方式之后(尽管它有效),我希望这是他需要的所需功能:

    $.fn.stringToObject = function(values) {

    var selectorData = [];

    var start_posID = values.indexOf('#') + 1;
    var end_posID = values.indexOf('.',start_posID);
    selectorData['id'] = values.substring(start_posID,end_posID);


    var classSplit = values.split('.');
    var classLength = classSplit.length -1;
    var attrSplit = values.match(/\[/g);
    var attrLength = attrSplit.length;


    var start_posClass = end_posID;
    var end_posClass = values.indexOf('[',start_posClass);
    var stringClass = values.substring(start_posClass, end_posClass);
    selectorData['classes'] = stringClass.replace(/\./g, " ");

    for (var i = 0; i <= attrLength; i++) {
        if (i == 0) {
            var start = values.indexOf('[') + 1;
        } else if(i == attrLength) {
            start = nextstart -1;
        } else {
            start = nextstart +2;
        }


        var end                 = values.indexOf(']',start);
        var newstring           = values.substring(start, end);
        var nextstart           = end;

        var newstringLength     = newstring.length;
        var firstPartOffset     = newstring.indexOf('=');
        var firstPart           = newstring.substring(0, firstPartOffset);
        var secondPart          = newstring.substring(firstPartOffset +1, newstringLength);

        selectorData[firstPart] = secondPart;


    };

    return selectorData;
}

这是你如何使用它:

var valueArray = $( "div" ).stringToObject('#mydiv.super.another-class[some-attribute1="true"][some-attribute2="truesdsda"][some-attribute3="trueasd"][some-attribute4="true"][some-attribute5="truedfg"]');

console.log(valueArray); // gives you everything
console.log(valueArray.id); // = gives you the id
console.log(valueArray.classes); // = gives you the classes
console.log(valueArray['some-attribute5']); // = gives you the value from some-attribute5

花了我一些时间,我真的希望对你有帮助:)

你好,提米

【讨论】:

  • 所以如果元素有一个数据属性或一个你想得到的ID?
  • 我也没有得到你想要的东西......例如,你有一个 div 和一些 attr 和类。你现在想从 jquery 的那个 div 中获取所有的类和属性?对吗?
【解决方案2】:

一种可能的方法是:

// create a jQuery plug-in, 'makeMatch()' and pass a selector
// string as an argument:
(function ($) {
    $.fn.makeMatch = function (selector) {
        // finding a string of one or more alphanumeric characters,
        // underscores and hyphens that starts with the '#' character,
        // using String.prototype.match() with a regular expression:
        var id = selector.match(/#[\w-]+/),
            // similar to the above, though this string starts with a
            // period (escaped with a back-slash because the period
            // is a special character in regular expressions), using
            // the 'g' (global) flag to retrieve all matching
            // sequences:
            classes = selector.match(/\.[\w-]+/g),
            // this string looks for strings starting with a '['
            // (again escaped because it's a special character) and
            // continuing until it matches a character that is *not*
            // ']':
            attributeValuePairs = selector.match(/\[[^\]]+/g);
        // if we have an 'id' sequence:
        if (id) {
            // assigning the found id sequence to the id variable
            // (preventing us from accessing a property of a null
            // object) after replacing the leading '#' character
            // with an empty string:
            id = id[0].replace(/^#/,'');
        }

        // iterating over the passed-in jQuery object, 'this' (here)
        // is the collection of nodes:
        return this.each(function () {
            // caching the current node found in the collection:
            var self = this;

            // if we have an id (it's not null):
            if (id) {
                // setting the id to that matched-id:
                self.id = id;
            }
            // if we have an array of classes:
            if (classes) {
                // adding the classes from the array, by joining
                // each class-string together with spaces and replacing
                // the period characters (though we could simply do:
                // classes.replace(/\./g,' ') instead):
                $(self).addClass(classes.join(' ').replace(/\./g, ''));
            }
            if (attributeValuePairs) {
                // creating a variable to avoid re-initialising a
                // variable within the forEach():
                var av;
                attributeValuePairs.forEach(function(avp) {
                    // replacing the initial '[' character from
                    // each element of the array with an empty string
                    // and splitting that string on the '=' character
                    // to form a two-part array (if a '=' character
                    // is found):
                    av = avp.replace(/^\[/, '').split('=');
                    // if we do have a two-part array:
                    if (av.length === 2) {
                      // setting the attribute held in 'av[0]' with
                      // the value held in 'av[1]' (after replacing
                      // any quotes held in that string):
                      self.setAttribute(av[0], av[1].replace(/"|'/g, ''));
                    }
                });
            }
        });
    };
})(jQuery);

(function($) {
  $.fn.makeMatch = function(selector) {
    var id = selector.match(/#[\w-]+/),
      classes = selector.match(/\.[\w-]+/g),
      attributeValuePairs = selector.match(/\[[^\]]+/g);
    if (id) {
      id = id[0].replace(/^#/,'');
    }
    return this.each(function() {
      var self = this;
      if (id) {
        self.id = id;
      }
      if (classes) {
        $(self).addClass(classes.join(' ').replace(/\./g, ''));
      }
      if (attributeValuePairs) {
        var av;
        attributeValuePairs.forEach(function(avp) {
          av = avp.replace(/^\[/, '').split('=');
          if (av.length === 2) {
            self.setAttribute(av[0], av[1].replace(/"|'/g, ''));
          }
        });
      }
    });
  };
})(jQuery);


$(".some-class").makeMatch('#mydiv.super.another-class[some-attribute="true"]');
div {
  border: 1px solid #000;
  width: 200px;
  height: 200px;
}

#mydiv.super.another-class[some-attribute="true"] {
  border: 2px solid red;
  background: transparent url(http://lorempixel.com/200/200/nightlife) 50% 50% no-repeat;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="some-class"></div>

但值得注意的是,我没有解决布尔属性/属性(例如checkedselected 等)或添加没有值的属性的能力的问题。这是可以做到的,只是我还没有时间来解释此类功能可能暗示的所有极端情况。

参考资料:

【讨论】:

  • 您需要使用新选择器创建一个 CSS 规则 - 可能与 .some-class 选择器结合使用 - 以显示该元素现在将匹配此选择器。
  • 我理解重点和意图,但我真的不想这样做...... ;)
  • 在这种情况下,拥有一个可运行的 sn-p 似乎是多余的 :)
  • @BoltClock:是的,出于某种原因,我的印象是您的意思是在 sn-p 插件中应该添加选择器(不,我不知道我为什么这么认为)。已编辑并添加。
【解决方案3】:

希望它会起作用。

$(".some-class").addClass('super');
$(".some-class").addClass('another-class');
$(".some-class").attr('id','myDiv');
$(".some-class").attr('some-attribute',true);

【讨论】:

  • 你误解了我的问题。它确实会使元素匹配选择器,但你所做的是 - 你已经用你的大脑将选择器解析为重要元素,在你的脑海中你知道需要什么 id、类和属性,并且你已经编写了反映这一点的代码。我要电脑来做。所以我只会告诉选择器和元素,剩下的交给 javascript。
猜你喜欢
  • 2011-03-19
  • 1970-01-01
  • 2023-03-06
  • 1970-01-01
  • 2020-03-06
  • 1970-01-01
  • 1970-01-01
  • 2011-05-23
  • 2016-06-09
相关资源
最近更新 更多