JavaScript DOM高级程序设计 5动态修改样式和层叠样式表2--我要坚持到底!

时间:2021-04-11 10:55:59

把样式置于DOM脚本之外

  • style属性

我们可以这样设置前景色之类的属性:

element.style.color='red';

也可以使用下面的代码设置背景颜色:

element.style.backgroundColor='red';

将background-color转换为驼峰形式大小写形式的backgroundColor(删除连接字符串并将后续单词的首字母变成大写)是必须的,DOM2样式规范为CSSStyleDeclaration对象定义了相应的方法,比如setProperty()就使用固有的带连字符的CSS属性名称和值(但是ie不支持):

element.style.setProperty('background-color','red');

为了不针对环境,将setStyleById(),setStyleByClassName(),setStylsByTagName()方法添加到ADS库中。

/**
*通过ID修改单个元素的样式
*/
function setStyleById(element, styles) {
//取得对象的引用
if(!(element = $(element))) return false;
//循环遍历styles对象并应用每个属性
for (property in styles) {
if(!styles.hasOwnProperty(property)) continue; if(element.style.setProperty) {
//DOM2样式规范方法
element.style.setProperty(
uncamelize(property,'-'),styles[property],null);
} else {
//备用方法
element.style[camelize(property)] = styles[property];
}
}
return true;
}
window['ADS']['setStyle'] = setStyleById;
window['ADS']['setStyleById'] = setStyleById; /**
* 通过类名修改多个元素的 样式
*/
function setStylesByClassName(parent, tag, className, styles) {
if(!(parent = $(parent))) return false;
var elements = getElementsByClassName(className, tag, parent);
for (var e = 0 ; e < elements.length ; e++) {
setStyleById(elements[e], styles);
}
return true;
}
window['ADS']['setStylesByClassName'] = setStylesByClassName; /**
* 通过标签名修改多个元素的样式
*/
function setStylesByTagName(tagname, styles, parent) {
parent = $(parent) || document;
var elements = parent.getElementsByTagName(tagname);
for (var e = 0 ; e < elements.length ; e++) {
setStyleById(elements[e], styles);
}
}
window['ADS']['setStylesByTagName'] = setStylesByTagName;
/**实例
ADS.setStylesByClassName(
'findclass',
'*',
document,
{'background-color':'red'}
)
或者 ADS.setStylesByTagName('a',{'text-decoration':'underline'});
*/

基于className切换样式

对于中小范围的表现变化,例如只影响少数元素的颜色、边框、背景和字体,可以通过切换className来避免在代码中苦苦寻找样式属性。

使用className切换方法可以维护适当的分离,并且为CSS设计者打开了使用样式表设计网站表现的大门。下面将操纵classname的方法添加到ADS库中

/*取得包含元素类名的数组*/
function getClassNames(element) {
if(!(element = $(element))) return false;
//用一个空格替换多个空格,然后给予空格分割类名
return element.className.replace(/\s+/,' ').split(' ');
};
window['ADS']['getClassNames'] = getClassNames; /*检查元素是否存在某个类*/
function hasClassName(element, className) {
if(!(element = $(element))) return false;
var classes = getClassNames(element);
for (var i = 0; i < classes.length; i++) {
//检测className是否匹配,如果是则返回true
if (classes[i] === className) { return true; }
}
return false;
};
window['ADS']['hasClassName'] = hasClassName; /*为元素添加类*/
function addClassName(element, className) {
if(!(element = $(element))) return false;
//将类名添加到当前className的末尾,如果没有className,则不包含空格
element.className += (element.className ? ' ' : '') + className;
return true;
};
window['ADS']['addClassName'] = addClassName; /*从元素中删除类*/
function removeClassName(element, className) {
if(!(element = $(element))) return false;
var classes = getClassNames(element);
var length = classes.length
//循环遍历数组删除匹配的项
//因为从数组中删除项会使数组变短,所以要反响循环
for (var i = length-1; i >= 0; i--) {
if (classes[i] === className) { delete(classes[i]); }
}
element.className = classes.join(' ');
return (length == classes.length ? false : true);
};
window['ADS']['removeClassName'] = removeClassName; /*
方便的取得与一个元素关联的所有累
var element=document.getElementById('example');
var classes=ADS.getClassName(element);
var class;
for (var i = 0;class=class[i];i++)
{
//对每个类进行操作
} 或者在向元素添加类名之前检查是否存在该雷鸣,以便实现切换效果
function toggleClassName(element,className)
{
if(!)ADS.hasClassName(element,className)
{
ADS.addClassName(element,className);
}
else
{
ADS.removeClassName(element,className);
}
}
ADS.addEvent('toggleButton','click',function(){
toggleClassName(this,'active')
}); 甚至还能通过使用适当的事件侦听器和hover类生成翻转效果
var element=document.getElementById('example');
ADS.addEvent(element,'mouseover',function(){ADS.addClassName(this,'hover');});
ADS.addEvent(element,'mouseout',function(){ADS.removeClassName(this,'hover')});
*/
  • 切换样式表
  1. 可以使用<link>元素的rel属性定义备用的样式表,并在他们之间进行切换。
  2. 可以为body标签应用一个类,并根据这个类修改CSS选择符--实际上是以body标签做为跟元素的className切换
  3. 可以动态添加或移除样式表
  • 使用备用样式表

如果你始终遵守表现与标记分离原则,那你一定熟悉<link>元素:<link type="text/css" href="style.css" media="screen"/>

<link>元素包含一下属性:(和我们本章开始介绍的CSSStyleSheets类似)

  • type:text/css
  • href:指定样式的位置
  • media:限制样式设备类型

这些是常用的,另外还有

  • ref:表示样式与文档之间的关系
  • disable:表示样式是否起作用
  • title:表示与样式表关联的标题

下面讲一个说一个实例,源代码在上一节的chapter5中,switcher/example.html中,在这个例子中公共CSS问津没有设置title属性,而friends of ED和Apress样式都有一个相应的样式表文件,标记中空列表元素:

  <ul id="styleSwitcher"></ul>

是由styleSwitcher.js文件通过load事件处理程序,在备用的样式表文件及其title属性的基础上动态生成的:(其实这个例子看起来听神奇的。)

ADS.addEvent(window,'load',function(){
//取得所有link元素
var list=ADS.$('styleSwitcher');
var links=document.getElementsByTagName('link');
var titles=[]; for(var i=0;i<links.length;i++)
{
//跳过不带title属性的<link>元素
if (links[i].getAttribute("rel").indexOf("style")!=-1
&&links[i].getAttribute("title"))
{
//如果该样式表还未添加则想列表中添加一个新项
var title=links[i].getAttributes("title");
if (!titles[title])
{
var a = document.createElement('a');
a.appendChild(document.createTextNode(title));
a.setAttribute('href'.'#');
a.setAttribute('title','Activate'+title);
a.setAttribute('rel',title);
ADS.addEvent(a,'click',function(){
//单击激活链接是激活锚的rel属性中的标题所表示的样式
setActiveStyleSheet(this.getAttribute('rel'));
ADS.preventDefault(W3CEvent);
}); var li = document.createElement('Li');
li.appendChild(a);
list.appendChild(li); //将title数组中的这个标题项设置为true。一边在多样式使用相同的标题跳过
title[title]=true;
}
}
}
});
  • 切换body元素的className

这种方法的知道思想和上面类似,只不过是body标签的className

/*公共样式*/

body{}
#container{}
/*AdvancED DOM Scripting 样式*/
body.ads{}
body.ads h1{}
body.ads h2{} /*friends of ED 样式*/
body.foed{}
body.foed h1{}
body.foed h2{} /*其他样式*/
/*Apress样式*/
body.apress{}
body.apress h1{}
body.apress h2{}

然后用本章前面的ADS库,你可以动态的勤换body标签的类名,而CSS规则会在相应的修改页面表现:

ADS.addEvent('ads-anchor','click',function(){
ADS.addClassName(document.body,'asd');
});
ADS.addEvent('foed-anchor','click',function(){
ADS.addClassName(document.body,'foed');
});
ADS.addEvent('apress-anchor','click',function(){
ADS.addClassName(document.body,'apress');
});
  • 动态载入和移除样式

相当直观,使用这种技术索要做的就是通过document.createElement()及适当的属性<link>

/*添加新样式表*/
function addStyleSheet(url,media)
{
media=media||'screen';
var link=document.creatElement('LINK');
link.settAttribute('rel','stylesheet');
link.settAttribute('tyle','text/css');
link.settAttribute('href','url');
link.settAttribute('media','media');
document.getElementsByTagName('head')[0].appendChild(link);
}
window['ADS']['addStyleSheet']=addStyleSheet
/*移除样式表*/
function removeStyleSheet(url,media)
{
var styles=getStyleSheets(url,media);
for (var i = 0;i<style.length ;i++ )
{
var node=styles[i].ownerNode||styles[i].owningElement;
//禁用样式
styles[i].disabled=ture;
//移除节点
node.parentNode.removeChild(node);
}
} window['ADS']['removeStyleSheet']=removeStyleSheet
/**实例
ADS.addStyleSheet('/path/style.css','screen');
ADS.removeStyleSheet('/path/style.css','screen');
*/
  • 修改CSS规则

在ADS库中添加方法,他能帮助你从document.styleSheets列表中查找带有适当的href和media属性的样式表:

/*通过URL取得包含所有样式表的数组*/
function getStyleSheets(url,media) {
var sheets = [];
for(var i = 0 ; i < document.styleSheets.length ; i++) {
if (url && document.styleSheets[i].href.indexOf(url) == -1) { continue; }
if(media) {
//规范化media字符串
media = media.replace(/,\s*/,',');
var sheetMedia; if(document.styleSheets[i].media.mediaText) {
//DOM方法
sheetMedia = document.styleSheets[i].media.mediaText.replace(/,\s*/,',');
//Safari会添加额外的都和和空格
sheetMedia = sheetMedia.replace(/,\s*$/,'');
} else {
// MSIE
sheetMedia = document.styleSheets[i].media.replace(/,\s*/,',');
}
// 如果media不匹配则跳过
if (media != sheetMedia) { continue; }
}
sheets.push(document.styleSheets[i]);
}
return sheets;
}
window['ADS']['getStyleSheets'] = getStyleSheets;

现在找到目标样式表了,但是还需要想库中添加ADS.editCSSRule()和ADS.addCSSRule()方法才能修改其中的样式规则:

/**
* 编辑一条样式表规则
*/
function editCSSRule(selector,styles,url,media) {
var styleSheets = (typeof url == 'array' ? url : getStyleSheets(url,media)); for ( i = 0; i < styleSheets.length; i++ ) { //取得规则表
// DOM2样式规范方法是 styleSheets[i].cssRules
// MSIE规范方法是styleSheets[i].rules
var rules = styleSheets[i].cssRules || styleSheets[i].rules;
if (!rules) { continue; } // 由于MSIE默认使用大小写故转换为大写形式
// 如果你使用的是区分大小写的id,则可能导致冲突
selector = selector.toUpperCase(); for(var j = 0; j < rules.length; j++) {
// 检查是否匹配
if(rules[j].selectorText.toUpperCase() == selector) {
for (property in styles) {
if(!styles.hasOwnProperty(property)) { continue; }
// 设置新的样式属性
rules[j].style[camelize(property)] = styles[property];
}
}
}
}
}
window['ADS']['editCSSRule'] = editCSSRule;
/*ADS.editCSSRule('a',{'background-color':'yellow'});*/ /**
* 增加一条CSS样式
*/
function addCSSRule(selector, styles, index, url, media) {
var declaration = ''; // 根据style参数构建声明字符串
for (property in styles) {
if(!styles.hasOwnProperty(property)) { continue; }
declaration += property + ':' + styles[property] + '; ';
} var styleSheets = (typeof url == 'array' ? url : getStyleSheets(url,media));
var newIndex;
for(var i = 0 ; i < styleSheets.length ; i++) {
// 添加规则
if(styleSheets[i].insertRule) {
// DOM2样式规范的方法
// index = length 是列表的结尾
newIndex = (index >= 0 ? index : styleSheets[i].cssRules.length);
styleSheets[i].insertRule(selector + ' { ' + declaration + ' } ',
newIndex);
} else if(styleSheets[i].addRule) {
// MS的方法
// index = -1 是列表的结尾
newIndex = (index >= 0 ? index : -1);
styleSheets[i].addRule(selector, declaration, newIndex);
}
}
}
window['ADS']['addCSSRule'] = addCSSRule;
/**
ADS.addCSSRule('a[href]:after',{
'content':'"("attr(href)")"';
'font-size':'40%',
'color':'#16009b'
});
*/
  • 访问计算样式

DOM2样式规范在document.defaultView中包含了一个名叫getComputedStyle()的方法,就是为了访问计算样式而设计的。该方法返回一个制度的CSSStyleDeclaration对象。

在取得给定元素的计算样式之后,可以通过与操作元素的style属性一样的方式来取得信息

var element=ADS.$('example');
var styles=document.defaultView.getComputedStyle(element);

取得background-color值需要下面这样简单:

var color=styles.getProperty('background-color');

我们在库中添加如下代码:

/*取得一个元素的计算样式*/
function getStyle(element,property)
{
if (!element=$(element)||!property) return false; //检测元素style属性的的值
var value=element.style[camelize(property)];
if(!value)
{
//计算取得样式的值
if (document.defaultView&&document.defaultView.getComputedStyle)
{
//DOM
var css=document.defaultView.getComputedStyle(element,null);
value=css?css.getPropertyValue(property):null;
}
else if (element.currentStyle)
{
MSIE的方法
value=element.currentStyle[camelize(property)];
}
} //返回空字符串而不是auto这样就不必检查auto值了
return value=='auto'?'':value;
}
window['ADS']['getStyle']=getStyle;
window['ADS']['getStyleById']=getStyle;