动态改变 <link> 标签的 href 属性并不能让 CSS 即时生效,要动态改变外联 CSS 的路径,需要用到一些小技巧,有了这些技巧,就可以为 HTMLayout 增加“动态换肤”的功能了。

link[rel=”stylesheet”] 的 disabled 状态可以控制其样式表的有效性:将其设置为 true(禁用),所有由该 产生的样式会被移除;将其设置为 false(启用),则重新加载这些样式。(来源于:http://terrainformatica.com/forums/topic.php?id=964)

下面是一个例子,为了让大家更方便地测试,我处理了 HLN_LOAD_DATA 响应通知以模拟外联 CSS,真正的项目中不需要这么写。

代码示例:

import win.ui;
/*DSG{{*/
var winform = ..win.form(text="动态改变外联 CSS 路径";right=654;bottom=422)
winform.add()
/*}}*/

import console;

import web.layout;
var wbLayout = web.layout(winform);

var cssData = {
["/skins/1.css"] = /**
html { background: #800; color: #fff }
**/;
["/skins/2.css"] = /**
html { background: #008 }
button[type=checkbox] {
padding: 4px 20px 4px 4px;
background-position: 100% 50%;
}
**/;
}

wbLayout.callback = function (message, wParam, lParam, vParam, notifyCode) {
if (notifyCode === 0xB01/*_HLN_LOAD_DATA*/) {
var nmld = web.layout.NMHL_LOAD_DATA();
raw.convert(lParam, nmld);
var uri = string.fromUnicode(nmld.uri, 0, true);
if (cssData[uri]) {
var data = string.fromto(cssData[uri], 0, 65001);
web.layout.DataReady(winform.hwnd, uri, data, #data);
}
return 0/*_LOAD_OK*/;
}
}

namespace web.layout.behavior {
class alterCss {
ctor (ltEle, layout) {

}

onButtonClick = function (ltTarget, ltEle, reason, behaviorParams) {
with (layout.getEle("stylesheet")) {
state.disabled = true;
href = ltEle.state.checked ? "skins/2.css" : "skins/1.css";
state.disabled = false;
}
}
}
}

wbLayout.html = /**
<head>
<link #stylesheet rel="stylesheet" href="skins/1.css" />
</head>
<body>
<button type="checkbox" style="behavior: ~alter-css;">Alter external CSS</button>
</body>
**/

winform.show();
win.loopMessage();

另外,用 activate 函数也可以实现该效果:

Changing HTMLayout skins in run time
namespace web.layout.behavior.alterCss {
onButtonStateChanged = function (ltTarget, ltEle, reason, behaviorParams) {
var ltSytle = ltEle.documentElement.querySelector("#stylesheet")
ltSytle.href = ltEle.state.checked ? "skins/2.css" : "skins/1.css";
ltSytle.xcall("activate")
}
}