【问题标题】:change stylesheet by button click for specific element only仅通过单击特定元素的按钮更改样式表
【发布时间】:2020-06-01 13:00:31
【问题描述】:

所以,这个问题是基于我目前正在做的一项家庭作业。我得到了一个 HTML 文档和两个样式表。 HTML 文档真的很简单:

<html>
<head>
   <title>DOM-scripting: change style</title>
   <link rel="stylesheet" href="style/style1.css" id="stylesheet"/>
</head>
<body>
    <nav class="chooseStyle">
        <input type="button" id="style1Button" value="Style 1"/>
        <input type="button" id="style2Button" value="Style 2"/>
    </nav>
    <article>
        <h1>Style change using DOM-scripting</h1>
        <p> sample text </p>
        <p> sample text </p>
        <p> sample text </p>
    </article>
    <nav class="links">
        <ul>
            <li><a href="link">school name</a></li>
            <li><a href="link">school name</a></li>
       </nav>

    <script src="scriptToUse.js"></script>
</body>
</html>

style1.css 包含以下内容:

body {
    background-color: #676632;
}

input[type="button"] {
    color: #F5F265;
    background-color: #9B9302;
}

article {
    margin-left: 150px;
    margin-right: 150px;
    text-indent: 20px;
    color: #C9C892;
}

h1 {
    color: #EEF1BA;
    text-align: center;
}

a {
    color: #A1FA56;
    text-decoration: none;
    font-weight: bold;
}

ul {
    padding: 0;
}

li {
    list-style-type: none;
}

Style2.css 包含以下内容:

body {
    color: #EEEEAA;
}

input[type="button"] {
    color: #9B9302;
    background-color: #F5F265;
}

article {
    margin-left: auto;
    margin-right: auto;
    text-align: justify;

    color: #A3A163;
}

h1 {
    color: #AAAA66;
    text-align: left;
}

a {
    color: #CDCF9B;
}

ul {
    padding: 0;
}

li {
    list-style-type: none;
}

练习的第一部分说明我需要创建一个 javascript 文件,该文件允许网页的样式表根据单击的按钮进行更改。第一个按钮引用第一个样式表,第二个按钮引用第二个样式表。我发现这很容易,一切正常。

但是,练习的第二部分陈述如下:“现在编辑 javascript 文件,以便在单击按钮时只更改文章的样式。不要编辑 CSS 文件。”这意味着样式表的 href 仍应更改,就像第一部分一样,但现在它可能只影响文章元素的样式,而不是整个页面的样式。

过去一个小时我一直在寻找相关问题,但似乎没有什么能真正提供解决方案。我已经阅读了一些问题,指出不可能仅将样式表应用于特定元素而不更改样式表本身的任何内容。请记住,我才刚上大学一年级,才刚刚开始学习 javascript,这意味着解决方案不应该那么难找到。我猜?

到目前为止我写的 Javascript 代码:

'use strict';

const handleLoad = () => {
    let style1 = document.getElementById('style1Button');
    let style2 = document.getElementById('style2Button');
    style1.addEventListener('click', handleClick);
    style2.addEventListener('click', handleClick);
};

const handleClick = (event) => {
    if(event.target.value === "Style 1") {
        document.getElementById("stylesheet").href = "style/style1.css";
        // should only change article style 
        // currently still referring to the whole document
    } else {
        document.getElementById("stylesheet").href = "style/style2.css";
        // should also only change article style
        // also still referring to the whole document
    }
};

window.addEventListener('load', handleLoad);

有什么方法可以阻止除文章元素之外的所有元素的 CSS 规则吗?或者可能更改不应该受到影响的元素的类或 ID?

提前非常感谢:)


这就是最终解决它的方法。 (代码可能不像它应该的那样紧凑和正确,但它可以工作,所以我非常高兴:D):

'use strict';

const handleLoad = () => {
    let style1 = document.getElementById('style1Button');
    let style2 = document.getElementById('style2Button');
    style1.addEventListener('click', handleClick);
    style2.addEventListener('click', handleClick);
    makeShadow();
};

const handleClick = (event) => {
    let article = document.querySelector('article');
    let shadow = article.shadowRoot;

    let style = event.target.value === "Style 1" ? "style/style2.css" : "style/style1.css";

    for(let node of shadow.childNodes) {
        if(node.hasAttribute('href')){
            node.href = style;
        }
    }
};

const makeShadow = () => {
    let article = document.querySelector('article');
    let articleClone = makeClone(article);

    let shadow = article.attachShadow({mode:'open'});

    let link = document.createElement('link');
    link.rel = "stylesheet";
    link.href = 'style/style1.css';

    shadow.appendChild(articleClone);
    shadow.prepend(link);
};

const makeClone = (article) => {
    let clone = article.cloneNode();
    clone.innerHTML = article.innerHTML;
    return clone;
};

window.addEventListener('load', handleLoad);

【问题讨论】:

  • 你能提供你的javascript吗?我们不在这里做你的功课,但如果你卡在脚本的某个部分,我们很乐意提供帮助。
  • @ArnoTenkink 当然!我当然不希望你做我的作业:p,但就像你说的那样,我真的被困在这部分,我只是想知道如何解决它。
  • 那些 css 文件是什么样的?全局添加样式表并希望它只影响某些元素有点困难。如果选择器是命名空间,那么它很容易完成,我们只需要打破除 article 之外的所有内容的命名空间,如果不是,那么你的脚本会变大
  • 我将文件添加到原始问题中。 CSS 文件仅包含对元素标记名称的引用。

标签: javascript html css stylesheet


【解决方案1】:

在这种情况下,我们可以使用shadowRoot 作为样式的封装。

这个想法就像在一个只有article元素的页面中添加一个包含大量样式的css文件,显然其他样式不会有任何效果。

我们可以使用shadowRoot 来做同样的事情,将文章放在它自己的小世界中,并添加一个包含更多样式的文件。

代码被大量注释。如果您有任何问题,请发表评论:)

首先在加载时我们准备阴影元素:

const handleLoad = () => {

    // Old Code for button handlers still needed
    let style1 = document.getElementById('style1Button');
    let style2 = document.getElementById('style2Button');
    style1.addEventListener('click', handleClick);
    style2.addEventListener('click', handleClick);


    // New Code Below

    // Select the article from the page 
    const article = document.querySelector('article');
    // Create an empty div Element to work as a bucket
    const placeholderElement = document.createElement('div');
    // set it's id attribute to select it later
    placeholderElement.setAttribute('id', 'placeholderElementShadowRot')
    // replace the article with our div in the document
    // the article element is not completly lose at this point
    // we still have in the variable article
    article.replaceWith(placeholderElement);
    // attache a shadow to the div element
    const shadow = placeholderElement.attachShadow({ mode: 'open' });
    // sets the shadow's innerHTML equal to article outerHTML
    shadow.innerHTML = article.outerHTML;


    // create a link
    const link = document.createElement('link');
    // set it's href attribute to the first style file
    link.setAttribute("href", 'style1.css');
    // set the rel attribute
    link.setAttribute("rel", "stylesheet");
    // add the link to the shadow
    shadow.appendChild(link)
};

然后点击按钮

const handleClick = (event) => {
    // Select our div we created before using the id
    const placeholderElement = document.querySelector('#placeholderElementShadowRot');
    // since we already attached a shadow 
    // we can use it through the property .shadowRoot
    const shadow = placeholderElement.shadowRoot;

    // based on which button we add the relevant style file
    if (event.target.value === "Style 1") {
        shadow.querySelector('link').setAttribute("href", "style1.css")
    } else {
        shadow.querySelector('link').setAttribute("href", "style2.css")
    }
};

注意:您的 JS 中有错字,处理程序称为 handleclick 小写 click 但您将大写 Click handleClick 添加到 addEventListener

【讨论】:

  • 谢谢你!!!我通过添加在 handleLoad 函数中调用的 makeShadow 函数使其正常工作。然后 makeShadow 将调用一个函数来克隆文章节点并将克隆的 innerHTML 设置为文章的 innerHTML。然后将 shadowRoot 附加到文章,并将 style1 设置为默认值。然后将克隆附加到阴影中。 handleClick 现在只查找阴影中的链接元素,并将 href 设置为事件目标引用的元素。真正有趣的解决方案!我喜欢研究它并学习这个新功能:D
  • 是的,我只是尽可能简单地编写代码,因为你说你是一个初学者,不想用不可读的重构代码压倒你。您可以自己进行重构,这会缩短很多时间,并且您会在此过程中学到更多。
【解决方案2】:

对你来说非常简单的例子。你说它是 Javascript 中的新功能。这就是为什么我给你一个很容易理解的例子。事实上,更合乎逻辑的解决方案可以通过围绕按钮循环,找出它们在哪个按钮上,根据它定义需要更改的元素,但这是现阶段最简单的示例。你必须自己调查和学习。祝你好运!

const style1Button = document.getElementById("style1Button");
style1Button.addEventListener("click", styleArticle);

function styleArticle(e) {
  let article = document.getElementById("article"); // full article
  // with querySelector, you can access the elements in the main element in this way.
  article.querySelector(".article-title").style.color = "red";
  article.querySelector(".text1").style.color = "blue";
  article.querySelector(".text2").style.color = "orange";
  article.querySelector(".text3").style.color = "gray";
}
<nav class="chooseStyle">
  <input type="button" id="style1Button" value="Style 1" />
  <input type="button" id="style2Button" value="Style 2" />
</nav>
<article id="article">. 
  <!-- you can add a class or id to each of them to get specific with javascript. -->

  <h1 class="article-title">Style change using DOM-scripting</h1> 
  <p class="text1"> sample text </p>
  <p class="text2"> sample text </p>
  <p class="text3"> sample text </p>
</article>
<nav class="links">
  <ul>
    <li><a href="link">school name</a></li>
    <li><a href="link">school name</a></li>
</nav>

更新答案:

我认为你只是犯了一个字母错误。

 const handleLoad = () => {
      let style1 = document.getElementById('style1Button');
      let style2 = document.getElementById('style2Button');
      style1.addEventListener('click', handleClick);
      style2.addEventListener('click', handleClick);
    }

    //handleclick to --- handleClick
    const handleClick = (event) => { 
      if (event.target.value === "Style 1") {
        document.getElementById("styleSheet").href = "style/style.css";
        // should only change article style 
        // currently still referring to the whole document
      } else {
        document.getElementById("styleSheet").href = "style/style2.css";
        // should also only change article style
        // also still referring to the whole document
      }
    };

    window.addEventListener('load', handleLoad);

【讨论】:

  • 谢谢:)。起初我确实考虑过尝试以这种方式解决它,但有人告诉我应该通过在任务中包含的样式表之间进行真正的交替来完成。老实说,我仍然觉得这也是最好的方法,但它不符合任务:(
  • "但有人告诉我应该通过在作业中包含的样式表之间进行真正的交替来完成。"我不太明白你的意思?跨度>
  • 作业包括我的问题中所述的 HTML 文件,以及两个 CSS 文件。作业的第一部分说我应该根据单击的按钮更改样式表,因此第一个按钮应该将文档头中的链接 href 更改为“style/style1.css”,第二个按钮应该将其更改为“风格/风格2”。作业的第二部分要求我们做同样的事情,但现在它可能只影响页面的文章元素。所以我还是应该改变链接href,但在某种程度上,它现在应该只影响文章元素的样式。
  • 我认为你想要类似暗光模式的东西,你可以通过在页面上包含样式文件来做到这一点。好的。
【解决方案3】:

您可以使用 javascript 选择元素并为其设置样式,而无需更改样式表。

有不同的方法可以做到这一点,但如果你不能改变这个 HTML 文件,这应该可以改变文章元素内的文本颜色:

document.querySelector('article').style.color = 'red';

除了颜色之外,您还可以设置其他样式,也可以使用 querySelector 选择文章中的 H1 或段落元素,但我会让您弄清楚 ;)

【讨论】:

  • 谢谢 :),起初我确实考虑过尝试以这种方式解决它,但有人告诉我应该通过在作业中包含的样式表之间进行真正的交替来完成。老实说,我仍然觉得这也是最好的方法,但它不符合任务:(
  • 我不确定是否可以将特定工作表分配给特定元素。也许您可以通过javascript更改css文件? var sheet = document.styleSheets; sheet[0].insertRule("文章 {color: red;}")
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-16
  • 2016-09-11
  • 2013-04-17
相关资源
最近更新 更多