创建自己的功能时出现未知错误

时间:2017-08-02 15:49:55

标签: javascript jquery

我编写了自己的函数,用于为伪元素分配属性,并注意到一个未知错误。通过向styleSheet添加行来分配属性。

当我在第三种情况下调用一个函数时,为什么第一个元素用蓝色绘制,尽管我没有为它设置color

(function() {
  var setPseudoElement = function(parameters) {
    for (var element of parameters.elements.get()) {
      if (!element.pseudoElements) element.pseudoElements = {
        styleSheet: null,
        before: {
          index: null,
          properties: null
        },
        after: {
          index: null,
          properties: null
        }
      };

      var selector = (function() {
        if (element.id) {
          return '#' + element.id + '::' + parameters.pseudoElement;
        } else {
          var parentsList = $(element).parents().map(function() {
            return this.tagName.toLowerCase();
          }).get().reverse().join(' > ') + ' > ' + element.tagName.toLowerCase();

          var elementClass = element.classList.length ? '.' + $(element.classList).get().join('.') : '';

          var elementAttributes = element.hasAttributes() ? $(element.attributes).get().map(function(className) {
            return className.nodeName !== 'class' ? className.nodeValue ? '[' + className.nodeName + '="' + className.nodeValue + '"]' : '[' + className.nodeName + '"]' : '';
          }).join('') : '';

          var elementNthChild = ':nth-child(' + ($(element).index() + 1) + ')';

          return parentsList + elementClass + elementAttributes + elementNthChild + '::' + parameters.pseudoElement;
        };
      })();

      if (!element.pseudoElements.styleSheet) {
        if (document.styleSheets[0]) {
          element.pseudoElements.styleSheet = document.styleSheets[0];
        } else {
          var styleSheet = document.createElement('style');

          document.head.appendChild(styleSheet);
          element.pseudoElements.styleSheet = styleSheet.sheet;
        };
      };

      if (element.pseudoElements[parameters.pseudoElement].properties !== null && element.pseudoElements[parameters.pseudoElement].index !== null) {
        element.pseudoElements.styleSheet.deleteRule(element.pseudoElements[parameters.pseudoElement].index);
      };

      if (typeof parameters.argument === 'object') {
        if (!element.pseudoElements[parameters.pseudoElement].properties && !element.pseudoElements[parameters.pseudoElement].index) {
          var newIndex = element.pseudoElements.styleSheet.rules.length || element.pseudoElements.styleSheet.cssRules.length || element.pseudoElements.styleSheet.length;

          element.pseudoElements[parameters.pseudoElement].index = newIndex;
          element.pseudoElements[parameters.pseudoElement].properties = parameters.argument;
        };

        var properties = '';

        for (var property in parameters.argument) {
          element.pseudoElements[parameters.pseudoElement].properties[property] = parameters.argument[property];
        };

        for (var property in element.pseudoElements[parameters.pseudoElement].properties) {
          properties += property + ': ' + element.pseudoElements[parameters.pseudoElement].properties[property] + ' !important; ';
        };

        element.pseudoElements.styleSheet.addRule(selector, properties, element.pseudoElements[parameters.pseudoElement].index);
      } else if (parameters.argument !== undefined && parameters.property !== undefined) {

      } else if (parameters.argument !== undefined && parameters.property === undefined) {

      } else {
        console.error('Invalid values!');
        return false;
      };
    };
  };

  $.fn.cssBefore = function(argument, property) {
    setPseudoElement({
      elements: this,
      pseudoElement: 'before',
      argument: argument,
      property: property
    });
  };
})();

$(function() {
  // Case 1
  $('.el0').cssBefore({
    'content': '"New \'before\'"',
    'color': 'green'
  });
  // Case 2
  $('.el1').cssBefore({
    'content': '"New \'before\' №2"',
    'color': 'blue'
  });
  // Case 3
  $('.el0').cssBefore({
    'content': '"New \'before\' №3"'
  });
});
.element {
  width: 480px;
  margin: 0 auto;
  border: 2px solid red;
}

.element:before {
  content: "Old 'before'";
  color: orange;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>

<div class="element el0" name="MyName"></div>
<div class="element el0 el1" id="elem"></div>
<div>
  <div class="element el1"></div>
</div>

为什么在第三种情况下第一个元素涂成蓝色?如何解决?

UPDATA:

如果在每次分配后在控制台中显示元素的值,则会出现非常奇怪的值:

(function () {
    var i = 1;

    var setPseudoElement = function (parameters) {
        for (var element of parameters.elements.get()) {
            if (!element.pseudoElements) element.pseudoElements = {styleSheet: null, before: {index: null, properties: null}, after: {index: null, properties: null}};
            
            var selector = (function () {
                if (element.id) {
                    return '#' + element.id + '::' + parameters.pseudoElement;
                } else {
                    var parentsList = $(element).parents().map(function () {
                        return this.tagName.toLowerCase();
                    }).get().reverse().join(' > ') + ' > ' + element.tagName.toLowerCase();

                    var elementClass = element.classList.length ? '.' + $(element.classList).get().join('.') : '';

                    var elementAttributes = element.hasAttributes() ? $(element.attributes).get().map(function (className) {
                        return className.nodeName !== 'class' ? className.nodeValue ? '[' + className.nodeName + '="' + className.nodeValue + '"]' : '[' + className.nodeName + '"]' : '';
                    }).join('') : '';

                    var elementNthChild = ':nth-child(' + ($(element).index() + 1) + ')';

                    return parentsList + elementClass + elementAttributes + elementNthChild + '::' + parameters.pseudoElement;
                };
            })();

            if (!element.pseudoElements.styleSheet) {
                if (document.styleSheets[0]) {
                    element.pseudoElements.styleSheet = document.styleSheets[0];
                } else {
                    var styleSheet = document.createElement('style');

                    document.head.appendChild(styleSheet);
                    element.pseudoElements.styleSheet = styleSheet.sheet;
                };
            };

            if (element.pseudoElements[parameters.pseudoElement].properties !== null && element.pseudoElements[parameters.pseudoElement].index !== null) {
                element.pseudoElements.styleSheet.deleteRule(element.pseudoElements[parameters.pseudoElement].index);
            };

            if (typeof parameters.argument === 'object') {
                if (!element.pseudoElements[parameters.pseudoElement].properties && !element.pseudoElements[parameters.pseudoElement].index) {
                    var newIndex = element.pseudoElements.styleSheet.rules.length || element.pseudoElements.styleSheet.cssRules.length ||  element.pseudoElements.styleSheet.length;

                    element.pseudoElements[parameters.pseudoElement].index = newIndex;
                    element.pseudoElements[parameters.pseudoElement].properties = parameters.argument;
                };

                var properties = '';

                for (var property in parameters.argument) {
                    element.pseudoElements[parameters.pseudoElement].properties[property] = parameters.argument[property];
                };

                for (var property in element.pseudoElements[parameters.pseudoElement].properties) {
                    properties += property + ': ' + element.pseudoElements[parameters.pseudoElement].properties[property] + ' !important; ';
                };

                element.pseudoElements.styleSheet.addRule(selector, properties, element.pseudoElements[parameters.pseudoElement].index);
            
                console.log('Launch number: ' + Math.round(i / 2) + '; Assignment number to element: ' + i);
                console.log({
                    'Element 1': $('.el0:not(.el1)').get(0).pseudoElements,
                    'Element 2': $('.el0.el1').get(0).pseudoElements,
                    'Element 3': $('.el1:not(.el0)').get(0).pseudoElements
                });
                i++;
            } else if (parameters.argument !== undefined && parameters.property !== undefined) {

            } else if (parameters.argument !== undefined && parameters.property === undefined) {

            } else {
                console.error('Invalid values!');
                return false;
            };
        };
    };

    $.fn.cssBefore = function (argument, property) {
        setPseudoElement ({
            elements: this, 
            pseudoElement: 'before', 
            argument: argument, 
            property: property
        });
    };
})();

$(function() {
  // Case 1
  $('.el0').cssBefore({
    'content': '"New \'before\'"',
    'color': 'green'
  });
  // Case 2
  $('.el1').cssBefore({
    'content': '"New \'before\' №2"',
    'color': 'blue'
  });
  // Case 3
  $('.el0').cssBefore({
    'content': '"New \'before\' №3"'
  });
});
.element {
  width: 480px;
  margin: 0 auto;
  border: 2px solid red;
}

.element:before {
  content: "Old 'before'";
  color: orange;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>

<div class="element el0" name="MyName"></div>
<div class="element el0 el1" id="elem"></div>
<div>
  <div class="element el1"></div>
</div>

如果你看一下控制台,第一次调用该函数时出于某种原因的第一个元素是蓝色,内容编号为3

2 个答案:

答案 0 :(得分:1)

问题出在这里

element.pseudoElements[parameters.pseudoElement].properties = parameters.argument;

第一个和第二个元素共享相同的parameters.argument对象,当你为第二个元素(第二次运行)更改它时,它将被更改为第一个元素。

你可以用

来避免它
element.pseudoElements[parameters.pseudoElement].properties = {};

element.pseudoElements[parameters.pseudoElement].properties = Object.assign({}, parameters.argument);

答案 1 :(得分:0)

你在代码中有一点错误,并且对cols el0 el1和el2的错误引用,我的意思是,el2不存在,但你可以创建它并给它一个你想要的颜色。 / p>

但如果您没有指定任何颜色,则会使用您使用的最后一种颜色

&#13;
&#13;
(function() {
  var f_cssPseudoElement = function(o_parameters) {
    o_parameters.element.each(function() {
      var $_target = $(this);

      var s_selector = $_target.parents().map(function() {
        return this.tagName.toLowerCase();
      }).get().reverse().join(' > ') + ' > ' + $_target.get(0).tagName.toLowerCase() + ':nth-child(' + ($_target.index() + 1) + ')::' + o_parameters.pseudoElement;

      if (!$_target.data('__pseudoElements__')) $_target.data('__pseudoElements__', {
        StyleSheet: null,
        after: {
          index: null,
          properties: null
        },
        before: {
          index: null,
          properties: null
        }
      });

      var o_pseudoElements = $_target.data('__pseudoElements__');

      // I create a body to save styles
      if (!o_pseudoElements.StyleSheet) {
        if (document.styleSheets[0]) {
          o_pseudoElements.StyleSheet = document.styleSheets[0];
        } else {
          var e_StyleSheet = document.createElement('style');

          document.head.appendChild(e_StyleSheet);

          o_pseudoElements.StyleSheet = e_StyleSheet.sheet;
        };

        $_target.data('__pseudoElements__', o_pseudoElements);
      };

      if (typeof o_parameters.undefinedArgument === 'object') {
        /* === Function start ===*/
        if (o_pseudoElements[o_parameters.pseudoElement].properties === null && o_pseudoElements[o_parameters.pseudoElement].index === null) {
          var index = o_pseudoElements.StyleSheet.rules.length || o_pseudoElements.StyleSheet.length;

          o_pseudoElements[o_parameters.pseudoElement].index = index;
          o_pseudoElements[o_parameters.pseudoElement].properties = o_parameters.undefinedArgument;
        } else {
          o_pseudoElements.StyleSheet.deleteRule(o_pseudoElements[o_parameters.pseudoElement].index);
        };

        var rule = '';

        // I add new properties
        for (var property in o_parameters.undefinedArgument) {
          o_pseudoElements[o_parameters.pseudoElement].properties[property] = o_parameters.undefinedArgument[property];
        };

        // Create a new CSS
        for (var property in o_pseudoElements[o_parameters.pseudoElement].properties) {
          rule += property + ': ' + o_pseudoElements[o_parameters.pseudoElement].properties[property] + ' !important; ';
        };

        o_pseudoElements.StyleSheet.addRule(s_selector, rule, o_pseudoElements[o_parameters.pseudoElement].index);

        $_target.data('__pseudoElements__', o_pseudoElements);

        return o_parameters.element;
        /* === End of function ===*/
      } else if (o_parameters.undefinedArgument !== undefined && o_parameters.property !== undefined) {
        // Unreported part
      } else if (o_parameters.undefinedArgument !== undefined && o_parameters.property === undefined) {
        // Unreported part
      } else {
        console.error('Invalid values!');
        return false;
      };
    });
  };

  $.fn.cssBefore = function(s$o_argument, s_property) {
    f_cssPseudoElement({
      element: $(this),
      pseudoElement: 'before',
      undefinedArgument: s$o_argument,
      property: s_property
    });

    return false;
  };
  $.fn.cssAfter = function(s$o_argument, s_property) {
    f_cssPseudoElement({
      element: $(this),
      pseudoElement: 'after',
      undefinedArgument: s$o_argument,
      property: s_property
    });

    return false;
  };
})();

$(function() {
  // Case 1
  $('.el0').cssBefore({
    'content': '"New \'before\'"',
    'color': 'red'
  });
  // Case 2
  $('.el1').cssBefore({
    'content': '"New \'before\' №2"',
    'color': 'orange'
  });
  // Case 3
  $('.el2').cssBefore({
    'content': '"New \'before\'"',
    'color': 'blue'
  });
});
&#13;
.element {
  width: 480px;
  margin: 0 auto;
  border: 2px solid red;
}

.element:before {
  content: "Old 'before'";
  color: orange;
}
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>

<div class="element el0"></div>
<div class="element el1"></div>
<div class="element el2"></div>
&#13;
&#13;
&#13;