【问题标题】:Trying to create a custom method using prototype property but i get Cannot read property 'replace' of undefined尝试使用原型属性创建自定义方法,但我得到无法读取未定义的属性“替换”
【发布时间】:2020-06-19 01:26:45
【问题描述】:

所以我在搞乱 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'

即使我没有发现 replace 方法有任何明显问题,但可能是什么?

在该行替换空格可以正常工作,但尝试替换 ; 我得到了那个错误。

我的代码写得有多糟糕?

谢谢!

【问题讨论】:

  • 哇...我认为您的“与 JS 混在一起”介绍在这里非常准确 :) 您想多了,过于复杂了。您永远不应该尝试自己构建 JSON 字符串。永远不会有任何借口。您无缘无故地给自己(以及您未来的自己,作为需要在 5 年内维护此代码的人)带来困难
  • 感谢您的评论。以我对 JavaScript 的有限了解,这就是我所能想到的 :(。对此的任何建议或替代解决方案将不胜感激。
  • 当然,我正试图弄清楚这是做什么的(因为这确实使事情更难阅读)。我只是想让你明白这一点并在未来记住它。我过去是通过艰难的方式学会它的,作为初学者,我很想早点得到这个建议。我可能会在几分钟内发布答案

标签: javascript regex methods replace prototype


【解决方案1】:

这是一个例子:

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;"))
&lt;p id="test"&gt;This is a test paragraph&lt;/p&gt;

需要注意的几点:

  • 这不会解析所有 CSS,但我相信它适用于您的示例。
  • 不建议修改对象的原型,因为如果您将其他人的代码与您的代码一起使用,您可能会遇到覆盖彼此修改的问题。

代码的工作原理是将字符串拆分为每个样式段,然后循环使用 forEach 并使用 this.style 更改元素的样式

文档:

希望这会有所帮助。

【讨论】:

  • 天哪,这证明了我仍然对 JS 有多么的烂透了。谢谢,它简单,简洁,绝对不会像我的那样过于复杂。谢谢!如果你这么好心,它不会解析哪个 CSS?
  • @neophoriac 它无法解析 selectors 或任何其他更复杂的 css 功能。
【解决方案2】:

我会这样做:

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;');
&lt;span&gt;Hello world&lt;/span&gt;

但正如@anbcodes 在他的回答中证明的那样,我认为您甚至可以跳过驼峰式转换

【讨论】:

  • 感谢您抽出宝贵时间。我不知道您可以像这样使用拆分,也不知道修剪。我肯定对自己感觉不好。虽然我会给 anbcodes 最好的答案,让它看起来如此简单,并完全绕过大小写转换。像我这样的新手仍然不知道 map() 。你也使用解构吗?我还是不知道 :( 无论如何再次感谢
  • 别难过!我们都在学习。看到了吗?你已经知道我在这里使用的是解构,即使我没有提到它!现在您需要做的就是在 Google 和 SO 上查找它以了解更多关于它的信息,如果您想使用它
猜你喜欢
  • 2020-05-13
  • 2015-07-01
  • 2021-08-01
  • 2021-10-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-29
相关资源
最近更新 更多