黑魔法:在CSS文件中内嵌JavaScript

JavaScript guokai 发表于 2 年前最后回复来自 qq2850071112 2 年前

看如下代码示例,一段内联CSS,和一段内联JavaScript,但真正的核心代码却隐藏在CSS文件中。这里用到了CSS的content属性,content属性通常与:before及:after伪元素配合使用,来插入生成内容。这里我们创建了一个隐藏的元素,id为#jhtmls,其content内容是我们base64编码过之后的JavaScript代码:

<!doctype html>
<html>
<head>
    <meta charset="utf-8">
    <style type="text/css">
        #style-code #jhtmls {
            display: none;
            visibility: hidden;
            content: 'dm9pZCBmdW5jdGlvbihlKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gbihlKXtyZXR1cm4gU3RyaW5nKGUpLnJlcGxhY2UoL1siPD4mIF0vZyxmdW5jdGlvbihlKXtyZXR1cm4iJiIrb1tlXSsiOyJ9KX1mdW5jdGlvbiB0KGUpe3ZhciBuPVtdO3JldHVybiBuLnB1c2goIndpdGgodGhpcyl7Iiksbi5wdXNoKGUucmVwbGFjZSgvPChzY3JpcHR8c3R5bGUpW14+XSo+W1xzXFNdKj88XC9cMT4vZyxmdW5jdGlvbihlKXtyZXR1cm5bJyEje3VuZXNjYXBlKCInLGVzY2FwZShlKSwnIil9J10uam9pbigiIil9KS5yZXBsYWNlKC9bXHJcbl0rL2csIlxuIikucmVwbGFjZSgvXlxuK3xccyskL2dtLCIiKS5yZXBsYWNlKC9eKFsgXHdcdF8kXSooW14mXF4/fFxuXHdcLycie31cW1xdK1wtKCk6OyBcdD1cLiRfXXw6XC9cLykuKiR8Xig/IVxzKihlbHNlfGRvfHRyeXxmaW5hbGx5fHZvaWR8dHlwZW9mXHNbXHckX10qKVxzKiQpW14nIjo7e30oKVxufD0mXC9eP10rJClccz8vZ20sZnVuY3Rpb24oZSl7cmV0dXJuIGU9ZS5yZXBsYWNlKC8mbm9uZTsvZywiIikucmVwbGFjZSgvWyInXFxdL2csIlxcJCYiKS5yZXBsYWNlKC9cbi9nLCJcXG4iKS5yZXBsYWNlKC8oIT8jKVx7KC4qPylcfXwoIT9cJCkoW2Etel9dK1x3Kig/OlwuW2Etel9dK1x3KikqKS9nLGZ1bmN0aW9uKGUsbix0LHIsdSl7aWYociYmKG49cix0PXUpLCF0KXJldHVybiIiO3Q9dC5yZXBsYWNlKC9cXG4vZywiXG4iKS5yZXBsYWNlKC9cXChbXFwnIl0pL2csIiQxIik7dmFyIG89L15bYS16JF1bXHcrJF0rJC9pLnRlc3QodCkmJiEvXih0cnVlfGZhbHNlfE5hTnxudWxsfHRoaXMpJC8udGVzdCh0KTtyZXR1cm5bIicsIixvP1sidHlwZW9mICIsdCwiPT09J3VuZGVmaW5lZCc/Jyc6Il0uam9pbigiIik6IiIsIiMiPT09bnx8IiQiPT09bj8iX2VuY29kZV8iOiIiLCIoIix0LCIpLCciXS5qb2luKCIiKX0pLGU9WyInIixlLCInIl0uam9pbigiIikucmVwbGFjZSgvXicnLHwsJyckL2csIiIpLGU/WyJfb3V0cHV0Xy5wdXNoKCIsZSwiKTsiXS5qb2luKCIiKToiIn0pKSxuLnB1c2goIn0iKSxuZXcgRnVuY3Rpb24oIl9vdXRwdXRfIiwiX2VuY29kZV8iLCJoZWxwZXIiLCJqaHRtbHMiLG4uam9pbigiIikpfWZ1bmN0aW9uIHIoZSxyLG8peyJmdW5jdGlvbiI9PXR5cGVvZiBlJiYoZT1TdHJpbmcoZSkucmVwbGFjZSgvXlteXHtdKlx7XHMqXC9cKiE/WyBcZlx0XHZdKlxuP3xbIFxmXHRcdl0qXCpcL1s7fFxzXSpcfSQvZywiIikpO3ZhciBpPXQoZSksYz1mdW5jdGlvbihlLHQpe3ZhciByPVtdO3JldHVybiJ1bmRlZmluZWQiPT10eXBlb2YgdCYmKHQ9ZnVuY3Rpb24oZSl7aS5jYWxsKGUscixuLHQsdSl9KSxpLmNhbGwoZSxyLG4sdCx1KSxyLmpvaW4oIiIpfTtyZXR1cm4gYXJndW1lbnRzLmxlbmd0aDw9MT9jOmMocixvKX12YXIgdT11fHx7fSxvPXsnIic6InF1b3QiLCI8IjoibHQiLCI+IjoiZ3QiLCImIjoiYW1wIiwiICI6Im5ic3AifTt1LnJlbmRlcj1yLCJmdW5jdGlvbiI9PXR5cGVvZiBkZWZpbmU/KGRlZmluZS5hbWR8fGRlZmluZS5jbWQpJiZkZWZpbmUoZnVuY3Rpb24oKXtyZXR1cm4gdX0pOiJ1bmRlZmluZWQiIT10eXBlb2YgbW9kdWxlJiZtb2R1bGUuZXhwb3J0cz9tb2R1bGUuZXhwb3J0cz11OndpbmRvd1tlXT11fSgiamh0bWxzIik7';
        }
    </style>
</head>
<body>
<div></div>
<script>
    (function() {
        var map = document.createElement('map');
        map.setAttribute('id', 'style-code');
        map.innerHTML = '<area id="jhtmls"></area>';
        document.body.appendChild(map);
        String(getComputedStyle(map.querySelector('#jhtmls'), false).content).replace(/[\w+=\/]+/, function(all) {
            eval(atob(all));
        });

        document.body.removeChild(map);
    })();

    (function() {
        document.querySelector('div').innerHTML = jhtmls.render(function() {
            /*!
                for(var i = 0; i < 10; i++) {
                    <h1>#{this} - #{i}</h1>
                }
            */
        }, 'hello world!');
    })();
</script>
</body>
</html>

如何对JavaScript代码进行base64编码?

var encodedData = window.btoa("Hello, world"); //encode
var decodedData = window.atob(encodedData); //decode

目前除了Internet Explorer之外的现代浏览器都支持该方法(兼容性列表:http://caniuse.com/#search=atob,备注:感谢Zack__lin提出的指正,在iOS5中不支持atob和btoa)。如下代码即为我们通过atob解码之后的真实JavaScript代码:

void
function(e) {
    "use strict";

    function n(e) {
        return String(e).replace(/["<>& ]/g, function(e) {
            return "&" + o[e] + ";"
        })
    }

    function t(e) {
        var n = [];
        return n.push("with(this){"), n.push(e.replace(/<(script|style)[^>]*>[\s\S]*?<\/\1>/g, function(e) {
            return ['!#{unescape("', escape(e), '")}'].join("")
        }).replace(/[\r\n]+/g, "\n").replace(/^\n+|\s+$/gm, "").replace(/^([ \w\t_$]*([^&\^?|\n\w\/'"{}\[\]+\-():; \t=\.$_]|:\/\/).*$|^(?!\s*(else|do|try|finally|void|typeof\s[\w$_]*)\s*$)[^'":;{}()\n|=&\/^?]+$)\s?/gm, function(e) {
            return e = e.replace(/&none;/g, "").replace(/["'\]/g, "\$&").replace(/\n/g, "\n").replace(/(!?#)\{(.*?)\}|(!?\$)([a-z_]+\w*(?:\.[a-z_]+\w*)*)/g, function(e, n, t, r, u) {
                if (r && (n = r, t = u), !t) return "";
                t = t.replace(/\n/g, "\n").replace(/\([\'"])/g, "$1");
                var o = /^[a-z$][\w+$]+$/i.test(t) && !/^(true|false|NaN|null|this)$/.test(t);
                return ["',", o ? ["typeof ", t, "==='undefined'?'':"].join("") : "", "#" === n || "$" === n ? "_encode_" : "", "(", t, "),'"].join("")
            }), e = ["'", e, "'"].join("").replace(/^'',|,''$/g, ""), e ? ["_output_.push(", e, ");"].join("") : ""
        })), n.push("}"), new Function("_output_", "_encode_", "helper", "jhtmls", n.join(""))
    }

    function r(e, r, o) {
        "function" == typeof e && (e = String(e).replace(/^[^\{]*\{\s*\/\*!?[ \f\t\v]*\n?|[ \f\t\v]*\*\/[;|\s]*\}$/g, ""));
        var i = t(e),
            c = function(e, t) {
                var r = [];
                return "undefined" == typeof t && (t = function(e) {
                    i.call(e, r, n, t, u)
                }), i.call(e, r, n, t, u), r.join("")
            };
        return arguments.length <= 1 ? c : c(r, o)
    }
    var u = u || {},
        o = {
            '"': "quot",
            "<": "lt",
            ">": "gt",
            "&": "amp",
            " ": "nbsp"
        };
    u.render = r, "function" == typeof define ? (define.amd || define.cmd) && define(function() {
        return u
    }) : "undefined" != typeof module && module.exports ? module.exports = u : window[e] = u
}("jhtmls");

可以看到其实就是一个mini的模板引擎,实现有render方法,render方法会对传入的函数进行toString并解析其内容,然后执行渲染返回结果。

所以经过以上这番折腾,我们就能够看到页面循环10次输出"hello world!"和循环的索引。

共收到5条回复
merb20080511 2 年前 #1

表示已无力呻吟

myljs 2 年前 #2

酷炫吊炸。

oOose 2 年前 #3

为啥要写成这样?

Zander 2 年前 #4

能否说明一下在CSS中嵌入JS有啥作用?

bob_aren 2 年前 #5

吓倒...

登录后即可参与回复