js修改伪元素的属性、styleSheets获取样式表,Failed to read the 'cssRules' property from 'CSSStyleSheet' Cannot acces

登录验证中的判断逻辑

1.提示输入用户,输入8 - 16位密码2.检验输入用户名和密码是否正确

  • 用户名不允许空格,任何字符数字都行,不允许为空

  • 密码8-16位,不允许空格 ,小于8位给出提示

  • 密码必须包含字母,数字,符号两种

  • 手机号码,11位,只允许数字

效果类似于

效果1,无法跳转看qq注册页面

无法打开,看QQ注册页面效果

效果3

想要达成的目的

实现提示时,用的span的伪元素加载背景图片,实现icon变化的效果。通过动态控制伪元素的属性和杨思,达到效果。

 

<body>
    <form action="post" id="register-form">
        <input type="text" name="" id="register-input-uname" placeholder="昵称" maxlength="8">
        <span id="register-hint-uname"></span>
​
        <!-- 提示的这段出问题,实现困难 -->
        <input type="password" name="" id="register-input-psw" placeholder="密码" maxlength="16">
        <span id="register-hint-psw-space"></span>
        <span id="register-hint-psw-length"></span>
        <span id="register-hint-psw"></span>
        <!-- 实现困难代码块结束 -->
        
        <div class="register-wrapper-tel">
            <select id="registr-select-country" aria-placeholder="+86">
            </select>
            <input type="number" name="" id="register-input-tel" οninput="if(value.length>11)value=value.slice(0,11)">
        </div>
        <button type="submit" id="register-btn-confirm">立即注册        </button>
    </form>
</body>

问题:

伪元素本身不是DOM元素,它不存在于文档中。所以Js无法获取它。伪元素有六个,分别是::after、::before、::first-line、::first-letter、::selection、::backdrop。

解决方案:

想得到伪元素,用js控制

方案一:控制伪元素的content动态显示,动态改变。

通过css的函数attr()和Html5的自定义data-*属性。

attr()方法,就是返回当前元素获得的属性值,比如当前元素<a herf="http://www.test.com">

attr(herf)获得的就是http://www.test.com

而herf是自带的属性,我们可以通过Html5来自定义一个属性,选定这个属性,去修改content的值。

data-*就是去自定义一个属性

但data-*创建属性是附加在伪元素的父类身上,也就是这种方法不是去操作伪元素,而是去操作伪元素的父类,达到目的。

/* 自定义属性data-after,操作data-after里面的属性值,来修改content的值 */
<span id="register-hint-psw-length"></span>
#register-hint-length ::before {
    content: attr(data-after);
    }
 var PswInputHint = document.getElementById("register-hint-psw-length");
 PswInputHint.setAttribute("data-after", "长度为8-16个字符");

看代码就知道,并非选中了伪元素,我们要实现的功能是小于8个字符的密码框,会弹出提示长度为8-16个字符,并非将伪元素控制的背景icon变为红色警示icon,字体颜色变为红色。

用div套div的实现会简单很多,但试试js控制伪元素。

工作中就不较真了,做个考量采取最优计划,但学习过程中就探究下为什么不能解决问题,为什么出现这些毛病。

解决方案一中遇到的问题

百度几篇文章,提到如下方法获得伪元素去控制

var myIdElement = document.getElementById("myId");
var beforeStyle = window.getComputedStyle(myIdElement, ":before");
console.log(beforeStyle); // [CSSStyleDeclaration Object]
console.log(beforeStyle.width); // 100px
console.log(beforeStyle.getPropertyValue("width")); // 100px
console.log(beforeStyle.content);

Window.getComputedStyle()

语法

/**
* @param  {获取到的一个元素} element
* @param  {里面的伪元素} [pseudoElt]
* @return {返回的style是一个实时的 CSSStyleDeclaration 对象,当元素的样式更改时,它会自动更新本身。}
*/
let style = window.getComputedStyle(element, [pseudoElt]);

Window.getComputedStyle()方法返回一个对象,该对象在应用活动样式表并解析这些值可能包含的任何基本计算后报告元素的所有CSS属性的值。 私有的CSS属性值可以通过对象提供的API或通过简单地使用CSS属性名称进行索引来访问。

描述

返回的对象与从元素的 style  属性返回的对象具有相同的类型;然而,两个对象具有不同的目的。从getComputedStyle返回的对象是只读的,可以用于检查元素的样式(包括由一个<style>元素或一个外部样式表设置的那些样式)。elt.style对象应用于在特定元素上设置样式。

只读类型,无法赋值,不论是通过

beforeStyle.setProperty('content', 'abcdefg'); 
​
beforeStyle.content = "长度为8-16个字符"; 
​
beforeStyle.style.content= "red"; 
​

都没有办法。

报如下错误

register.js:33 Uncaught TypeError: Cannot set property 'color' of undefined at HTMLInputElement.fn

HTMLInputElement.fn相当于HTMLInputElement.prototype,这个意思是我们获取到反而是HTMLInputElement的原型,是为什么呢?现在还弄懂。

留着。

现在需要控制伪元素里的图片,替换为另外一张,相当于不只是控制content的值,还要控制样式。

引出第二种解决方式

方案二:styleSheets.insertRule

其实也不是控制伪元素,而是直接暴力地插入CSS规则,由于就近原则,插入规则尽量在末尾,customStyle.cssRules.length为自动获取规则,不需要减1,这里也有很多问题。

<link rel="stylesheet" href="link.css">
    <style>
        #top {
            width: 1000px;
            background: rebeccapurple;
        }
        
        #super {
            background: yellowgreen;
        }
        
        #childNode {
            background: pink;
        }
        
        #top::before {
            display: block;
            content: "测试看看";
            color: red;
        }
    </style>
<body>
    <div id="top">嵌套树
        <div id="super">父亲节点
            <div id="childNode">孩子节点
            </div>
        </div>
    </div>
    <div id="bottom">底部</div>
</body>
var customStyle = document.styleSheets[0];//获取的是内联样式表
    customStyle.insertRule('#top::before {color:green}', customStyle.cssRules.length);
    var linkStyle = document.styleSheets[1];//获取的是外联样式表

解决方案二中遇到的问题

首先了解下 document.styleSheets,这是获取样式表,按照浏览器加载的顺序排成一个styleSheets数组,内外联都在里面。插入是没问题的,用customStyle.cssRules.length动态添加。

全部样式表

外联样式表

 

styleListp[0]是内联样式表,styleListp[1]是外联样式表

但控制台打印样式表过程中出现,无法获取外联样式表,如下图,抛出了异常。

用trycatch捕捉到异常。

    try {
        var cssrules = styleList[1].cssRules || styleListp[1].rules;
    } catch (e) {
        console.warn("warning" + e);
    }

warningSecurityError: Failed to read the 'cssRules' property from 'CSSStyleSheet': Cannot access rules(anonymous) @ test-stylesheet.html:60

这个问题好像是64位的Chrome和IE9存在安全性的问题,无法获取外部文件,解决方法是

https://github.com/code-dot-org/code-dot-org/pull/21082

能够获取外联样式表

还有个问题,customStyle.cssRules.length是计算的插入样式表之后的数组长度,这个的逻辑。

她应该计算当前渲染页面后的css规则,从0开始计算,当没有规则的时候,便插入为0,当有三个规则的时候,插入下标为3,但实际上是插在从0计算的前三个后面。

 

总结

  • 在js里控制样式的代码,太多,没有达到样式与逻辑的分离,最好不用

  • 可以直接通过写错误提示的样式,正确提示的样式,默认样式,再改变选定元素的classname,来重新渲染样式。

  • 参考:

    用js控制伪元素的方式

https://blog.csdn.net/xiaoya_syt/article/details/60577553

无法读取cssRules的解释

https://stackoverflow.com/questions/49161159/uncaught-domexception-failed-to-read-the-rules-property-from-cssstylesheet

CSSOM

https://www.w3.org/TR/cssom-1/#the-stylesheet-interface

 

 

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值