原生JS实现vue / vue-loader中的scoped原理

scoped原理就是穿透组件,为组件下的标签绑定data-v-hash来实现

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
    <title></title>
    <style>
        #app {
            color: white;
        }

        .childB {
            background-color: #07c160;
        }

        .childCCC {
            background-color: #ff9e55;
        }
    </style>
</head>
<body>
<div id="app" style="background: #2C93FF">
    <div>
        子组件A
    </div>
    <div class="childB">
        子组件B
        <p>孙子组件BB</p>
    </div>
    <div>
        子组件C
        <div>孙子组件CC
            <div class="childCCC">从孙组件CCC</div>
        </div>
    </div>
</div>
<script>
    function createHash(hashLength) {
        if (!hashLength || typeof (Number(hashLength)) != 'number') {
            return;
        }
        const ar = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'];
        const hs = [];
        const hl = Number(hashLength);
        const al = ar.length;
        for (let i = 0; i < hl; i++) {
            hs.push(ar[Math.floor(Math.random() * al)]);
        }

        return hs.join('');
    }
    /**
     * 递归整个DOM树,添加上data-v-hash的属性
     */
    function recursive(el) {
        if (el.children && el.children.length > 0) {
            for (let i = 0; i < el.children.length; i++) {
                const childrenNode = el.children[i]
                setHashAttribute(childrenNode)
                recursive(childrenNode)
            }
        }
    }

    function setHashAttribute(el) {
        el.setAttribute('data-v-' + hash, "");
    }

    /**
     * 将data-v-hash属性添加到css
     * @param cssForElment cssSheet中的每个CSS项目
     * @param hash
     */
    function _SetCSSStyleValue(cssForElment, hash) {
        if (cssForElment.selectorText) {
            cssForElment.selectorText = cssForElment.selectorText + `[data-v-${hash}]`
        }
    }

    const el = document.getElementById('app')
    const hash = createHash(7);
    //拿到style表,找到里面选择器的style项目 重置他们的选择器 这样就是针对.类名 [data-v-hash]的形式
    for (let j = 0; j < document.styleSheets.length; j++) {
        let cSSStyleList = []
        if (document.styleSheets[j].cssRules)
            cSSStyleList = document.styleSheets[j].cssRules
        else cSSStyleList = document.styleSheets[j].rules;
        for (let k = 0; k < cSSStyleList.length; k++) {
            _SetCSSStyleValue(cSSStyleList[k], hash)
        }
    }
    recursive(el)
    setHashAttribute(el)
</script>
</body>
</html>

效果图

 

原生JS实现vue / vue-loader中的scoped原理

原生JS实现vue / vue-loader中的scoped原理

 

上一篇:Vue——ElementUI 如何修改this.$message消息提示框样式及内容样式


下一篇:《风尚坐火箭学习vue》-- 第十九章:在Vue脚手架中用组件