Пытаюсь создать собственный метод с использованием свойства прототипа, но я получаю сообщение «Невозможно прочитать свойство заменить» неопределенного значения. - PullRequest
0 голосов
/ 19 июня 2020

Итак, я возился с JS, пытаясь создать метод, который добавляет стиль CSS к элементам без удаления применяемого в данный момент стиля:

// ==================================================================================================
// this method adds style to an element using CSS inline syntax without removing unaltered CSS styles
// ==================================================================================================
Element.prototype.cssStyle = function (style)
{
    let styleChars = style.split(''); // split each character of the style arg as an item in an array
    let positions = [];
    for(let i=0; i<styleChars.length; i++){
        if(styleChars[i] === '-'){
            positions.push(i+1);
        };
    };
    positions.forEach(function (position){ // for each match
        styleChars.splice(position, 1, style[position].toUpperCase()); // make that character uppercase
    });
    styleChars.splice(0, 0, '[["'); // add a "[[" item on the first position
    styleChars.splice(styleChars.length, 0, '"]]'); //add a "[[" on the last position
    style = styleChars.join('') // join back the array into a string
    style = style.replace(/:/g, "\",\"").replace(/;/g, "\"],[\"").replace(/-/g, ""); // replace some character in order to make the string look like an array
    style = JSON.parse(style); // parse the string into an array
    for(let i=0; i<style.length; i++){ // for each item in the array
        let property = style[i][0].replace(/ */, ""); // remove some characters which might inhibit normal execution
        let value = style[i][1].replace(/;/, "").replace(/ */, ""); //remove some characters which might inhibit normal execution
        this.style[property] = value // change style of the element
    };
    return this.getAttribute('style'); //return all inline CSS styles
}

, поэтому, если я попытаюсь стилизовать такой элемент, как это:

Element.cssStyle('background-color: white; color: #000')

Он работает, как ожидалось, но если я добавлю ; в конец строки параметра, я получу это

Element.cssStyle('background-color: white; color: #000;')
'Uncaught TypeError: Cannot read property 'toUpperCase' of undefined'

Хотя я не Не вижу никаких явных проблем с методом замены, что это может быть?

Замена пробелов в этой строке работает нормально, но при попытке заменить ; я получаю эту ошибку.

Также насколько плохо написан мой код?

Спасибо!

Ответы [ 2 ]

3 голосов
/ 19 июня 2020

Вот пример:

Element.prototype.cssStyle = function(styleStr) {
  let styles = styleStr.split(';')
  styles.forEach(style => {
    if (!style.trim()) return;

    let name = style.split(':')[0].trim();
    let value = style.split(':')[1].trim();
    this.style[name] = value;
  })

  return this.getAttribute('style'); //return all inline CSS styles
}

let testEl = document.getElementById("test")
console.log(testEl.cssStyle("color: white; background-color: black;"))
<p id="test">This is a test paragraph</p>

Несколько замечаний:

  • Это НЕ анализирует все CSS, но я считаю, что это работает для ваших примеров.
  • НЕ рекомендуется изменять прототип объекта, потому что, если вы используете чужой код вместе со своим, вы можете столкнуться с проблемами перезаписи модификаций друг друга.

Код работает, разбивая строку на каждый сегмент стиля, а затем он перебирает те, которые имеют forEach, и меняет стиль элемента, используя this.style

Документация:

Надеюсь, это поможет.

1 голос
/ 19 июня 2020

Вот как бы я это сделал:

Element.prototype.cssStyle = function(str) {
  // Split styles
  const styles = str.split(';');
  // For each of them
  for (let style of styles) {
    // Get the property and value without extra spaces (using trim)
    const [property, value] = style.split(':').map(s => s.trim());
    // If none of them is empty
    if (property.length && value.length) {
      const camelCaseProperty = kebakCaseToCamelCase(property);
      this.style[camelCaseProperty] = value;
    }
  }

  return this.getAttribute('style');
};

function kebakCaseToCamelCase(str) {
  return str.replace(/-(.)/g, (match, capture) => capture.toUpperCase());
}

document.querySelector('span')
  .cssStyle('display: block; background-color: red; color: white;');
<span>Hello world</span>

но, как @anbcodes доказал это в своем ответе, я думаю, вы даже можете пропустить преобразование случая верблюда

...