这半年参与了一个基于的中型应用系统开发
其间经历种种
收获不少
前段时间做了一个基于Web的CSS设计器
虽然技术不算复杂
不过综合了C#/XML/HTC等技术
对于大家应该有一定参考价值
而且该设计器相对于系统比较独立
因此在这里和大家共享
供大家参考
并请多提意见!
设计器的主要功能就是在web界面上设计操作CSS样式表目的是方便用户自定义系统界面
相信做过Web开发的人大多用过Dreamweaver或者做开发也应该用过那么应该熟悉里面的样式(style)设计器这里就是在Web上实现这个设计器
系统流程
下面我们先来了解一下整个系统流程
流程再简单说明一下
·先传入参数包括文件名/样式名/操作方法/可视化样式元素其中可视化样式元素是要在设计器中即时显现供效果预览的同时也是承载样式定义内容的要素(样式就加载在元素的style属性上)
·然后设计器根据传入参数操作根据操作方法新建文件/新建样式/修改样式前两者在初始化时不用读取样式文件最后者需要读取样式进行初始化利用一个设计的C#类来对样式文件和样式类进行操作
·在客户端利用Javascript操作XmlDocument对象读取XML定义的样式文件进行设计器构建
·利用Javascript通过样式元素的cssText属性读取样式值对设计器初始化
·用户操作设计器利用HTC组件操作设计样式
·保存利用C#类操作
CSS设计器之样式表操作类
下面我们来详细察看流程的每个环节
为了操作样式表设计了一个简单的样式表操作类功能主要是解析操作指定样式表文件实现对样式类的添加修改删除保存
机制读取Web服务器上某样式表文件将文本转化为一个ArrayList数组元素为自定义的ClassItem对象包含Name和Text属性(Name即样式名称Text即样式的内容)然后通过对ArrayList操作控制样式最后保存
由于在服务器段我们不作具体样式定义因此该类只操作到样式类级别不涉及样式属性和值
下面提供该类的UML图ClassItem是一个结构体仅包含两个属性
CSS设计器之XML样式属性定义
CSS样式中包含很多属性设置设计器中当然要包含相应的属性那么这些属性信息从哪里来呢?
采用XML定义是一种很自然就会想到的方式
经常使用DW和VSNET所以在交互设计上采用了类似的模式先将样式属性按应用分类再设置详细属性
CSS属性是比较复杂的如果要完全按照DW或VSNET的模式实现会比较复杂为了简化我把值的输入简化为两种形式选择和文本输入对于选择直接在XML文件中定义对于文本输入抽象几种输入类型在设计器生成时根据类型设定不同的HTC组件操作这样就将一些复杂的属性输入封装到HTC组件中整个构架就简洁起来
XML文件描述
首先是属性分类
<CSSDesign>
<Category>
<Name>文字</Name>
<Style>
<Name>字体</Name>
</Style>
<Style>
<Name>样式</Name>
</Style>
</Category>
<Category>
<Name>背景</Name>
<Style>
<Name>颜色</Name>
</Style>
</Category>
</CSSDesign>
系统分为文字背景文本位置布局方框边框和其他每种类型有一个Name子元素和若干Style子元素
每个Style子元素表示一个Style属性结构如下
<Style>
<Name>字体</Name>
<CssName>fontfamily</CssName>
<ActionType>select</ActionType>
<SelectItems>
<Item>verdanaarial</Item>
<ItemName=宋体>SimSun</Item>
<ItemName=黑体>SimHei</Item>
</SelectItems>
</Style>
<Style>
<Name>大小</Name>
<CssName>fontsize</CssName>
<ActionType>select</ActionType>
<SelectItems>
<Item>px</Item>
<Item>px</Item>
<Item>px</Item>
</SelectItems>
</Style>
<Style>
<Name>颜色</Name>
<CssName>background</CssName>
<ActionType>input_ColorSelect</ActionType>
</Style>
Name为该属性的描述名称在设计器中为文本描述
CssName为属性名在设计器中即输入字段的ID初始化时也据此赋值
ActionType为属性设置方法在设计器中为输入字段的样式类名该样式中含有Behavior属性制定HTC组件
SelectItems为选择项如果ActionType为Select将会在此列出选择项其子元素Item如果含有Name属性将显示在设计器中否则直接显示该元素的文本内容
框架图
CSS设计器之界面交互
整个操作交互过程除了最后保存文件外其他都是由javascript完成
首先DesignerBuild函数通过XmlDocumnet读取XML样式属性定义文件构建整个设计器界面然后Init函数读取服务器端赋给设计元素的StylecssText属性并把属性作为输入控件ID在设计器中查找并赋值完成初始化
在操作过程中根据输入控件的样式类Class触发绑定的HTC组件做相应的客户端操作
最后再读取设计元素的style属性保存
设计器界面
不同的设计元素
不同输入控件的不同class属性(根据XML中ActionType生成)触发不同HTC组件实现不同输入模式
由于商业原因这里不便提供源代码我将在后面提供部分关键代码供参考
程序代码
这里对前面文章讲的CSS设计器系统关键代码作一些小结如果没有看过前面文章的请先参看开发基于Web的CSS设计器
解析CSS样式文件
这段代码主要作用是把CSS文件分解为多个样式类并按名称/文本属性生成ClassItem对象并保存在一个ArrayList(cssList)中(C#代码)
//读取文件
FileInfotheSource=newFileInfo(@m_filePath);
StreamReaderreader=theSourceOpenText();
//将文件流转化为文本
m_cssText=readerReadToEnd();
readerClose();
//定义CSS文本分割符
char[]delimiters=newchar[]{{}};
intiCheck=;
stringclassName=null;
//将文本转化为ArrayList
foreach(stringsubstringinm_cssTextSplit(delimiters))
{
if(iCheck%==)
//当iCHeck为偶数时字符串为样式属性内容
//将解析的样式名和属性作为ClassItem对象存入cssList
cssListAdd(newClassItem(classNamesubstringTrim()));
else
//当iCHeck为奇数时字符串为样式名暂存
className=substringTrim();
iCheck++;
}
交互界面构建
交互界面由Javascript通过XmlDocument读取Xml文件动态生成
首先要读取XML文件然后遍历整个XML文件先遍历样式分类再对每个分类遍历其下的所有样式属性比较关键的代码是对XML的遍历下面是对样式分类的遍历代码
//LoadXML是XML文件读取函数
vardom=LoadXML(cssxml);
//通过XPath和selectNodes方法返回一个XMLDOMNodeList对象
varoNode=domselectNodes(//Category/Name);
//获取该对象长度即XML文档中该路径节点的数量
varintCategory=oNodeslength;
for(i=;i<intCategory;i++)
{
//获取集合中的节点
oNode=oNodesnextNode;
if(oNode!=null)
{
//样式分类界面构建代码略
……
}
}
样式输入控件构建函数该函数作用是根据XPath路径查询XML定义生成交互控件
functionBuildInput(path)
{
varstr=;
varaNode=null;
varattValue=null;
//通过selectSingleNode返回符合条件的第一个节点
varactNode=domselectSingleNode(path+ActionType);
varnameNode=domselectSingleNode(path+CssName);
//如果属性为选择输入则读取SelectItems并构建select控件
if(actNodetext==select)
{
str+=<selectid=+nameNodetext+name=+nameNodetext+class=eSelect>\n;
//查询该项的所有选择列表项
varitemsNodes=domselectNodes(path+SelectItems/Item);
str+=<optionvalue=>未设置</option>\n;
for(ii=;ii<itemsNodeslength;ii++)
{
aNode=domselectSingleNode(path+SelectItems/Item[+ii+]);
//如果该项含有Name属性则在列表中显示Name属性值
attValue=aNodegetAttribute(Name)
vartxtNode=domselectSingleNode(path+SelectItems/Item[+ii+]);
if(attValue==null)
str+=<optionvalue=+txtNodetext+>+txtNodetext+</option>\n;
else
str+=<optionvalue=+txtNodetext+>+attValue+</option>\n;
}
str+=</select>;
}
else
//如果属性为其他模式则构建input输入设置class属性为ActionType
{
str=<inputname=+nameNodetext+id=+nameNodetext+class=+actNodetext+>\n;
}
return(str);
}
设计器初始化
Js脚本读取解析样式元素的style属性值然后为设计器中构建的控件赋值
//设计器初始化
functionInit()
{
//获得由服务器端赋值的样式属性值
vartxt=documentall(DemoShow)stylecssText;
if(txtlength>)
{
varstrClassName;
//解析字符串
vararyClass=txtsplit(/[:;]/);
for(iinaryClass)
{
varstr=aryClassreplace(/(^\s*)|(\s*$)/g);
if(!(i%==))
{
//当i为奇数时解析的字符串应该为样式属性名称
strClassName=str;
}
else
{
//当i为偶数时获得属性值
//属性名称即控件ID
//判断该属性对应的控件是输入框还是选择列表
if(documentall(strClassName)type==selectone)
{
//如果是选择列表通过setIndexOfValue函数设定选择项
setIndexOfValue(strClassNamestr);
}
else
{
documentall(strClassName)value=str;
}
}
i++;
}
}
}
界面交互
在XML中一共定义了select/input_ColorSelect/input_SizeSelect/input_BorderSelect(后种为颜色/大小/边框输入模式)共种输入模式除select为直接选择外其他在对应控件初始化的时候作为class属性赋值到控件中类似class代码如下
/*颜色输入模式input框的样式类*/
input_ColorSelect{
width:px;
fontfamily:Tahoma;
behavior:url(htc/effColorSelecthtc);
}
通过behavior属性把该输入控件和相应的组件相关联该组件effColorSelecthtc代码如下
<PUBLIC:ATTACHEVENT=onfocusONEVENT=getShow()/>
<PUBLIC:METHODNAME=getChange/>
<SCRIPTLANGUAGE=JScript>
functiongetShow()
{
elementblur();
//记录当前交互控件的ID
effElement=elementid;
//在页面中加载输入控件
ShowControl(SelectColor);
}
functiongetChange()
{
//当值发生变化时对可视化样式元素赋值
SetAttribute(elementidelementvalue);
}
</SCRIPT>
其他
设计器中的值输入模式框只是页面中的几个层通过上面的htc组件触发显示出来输入后再把值传入到样式属性控件中同时也会设置可视化样式元素
另外还需要注意的是XML文档是可以自行扩展或缩减的但是在实际应用中不能完全依据CSS标准来定义因为可视化元素的style属性会自动格式化例如如果你在XML中定义borderbottomwidth属性在将值取出时会自动格式化为borderbottom这样会造成设计器中控件不能匹配我在MSDN没有查到相关文档所以只有经过实际测试来验证
OK比较关键的代码已经差不多了……希望能对大家有所帮助
参考
另外再列出部分技术参考如果大家对其中的技术细节如HTC和XmlDom等有所疑问可以再详细研究一下也欢迎大家来和我交流
MSDN关于JS操作XmlDom的文档
这是英文文档网上没有看到比较详细的中文文档好在不复杂大家将就一下吧:)
(最近MSDN不知道什么毛病经常访问有问题如果无法访问请先登录msdn再输入地址浏览)
蓝色理想的HTC教程
网上也没看见比较全面的讲述这个简单易学基本概念清楚了