1.Button组件案例(有对应的运行时组件)
所在目录:/UI2/system/components/justep/button
1.1 创建组件目录
在运行时组件目录/UI2/system/ components/justep/button下创建designer目录,该目录放置设计时组件的相关代码和资源,如下图:
1.2 创建组件配置文件
在designer目录下创建button.xml配置文件,这个文件的名称要与运行时组件目录名相同,详细描述如下 :
<!-- 创建根元素,可以同时定义多个element -->
<elements>
<!-- 定义组件配置,这里的名称通常定义为运行时组件的名称
tag-name 节点的标签名名称
icon 组件显示在工具箱上面的图标, 默认存放在designer/img下
text 组件文本描述信息
binding-component 跟运行时组件绑定
component-type 组件类型,可自定义, 详细可参见设计时组件开发文档 -->
<element name="$UI/system/components/justep/button/button"
tag-name="a" icon="button.gif" binding-component="$UI/system/components/justep/button/button"
component-type="formControl" design-view="web-designer">
<!-- 定义要可视化编辑的属性 -->
<properties>
<!-- 定义xid属性,所有组件都有这个属性 -->
<property name="xid" text="编号" required="true" />
<!-- 定义class样式属性,默认情况下会继承公共配置中的定义的 class公共属性,
继承后公共属性上定义的配置直接体现到当前属性上,比如这里没有editor-ref,
但会继承了公共属性中的editor-ref,该属性就自动默认带有class属性编辑器 -->
<property name="class" text="class" editor-ref="classSelector">
<editor-parameter><![CDATA[ {
"0base": {
label: "基础样式",
value: "btn"
},
"1color":{
label: "颜色样式",
value: "btn-default|btn-primary|btn-success "
},
"2size": {
label: "尺寸样式",
value: "btn-lg|btn-sm|btn-xs",
require: false
},
"3icon": {
label: "图标位置",
value: "btn-icon-left|btn-icon-top|btn-icon-right|btn-icon-bottom",
require: false
}
}
]]></editor-parameter>
</property>
......
<!-- 包含数据绑定属性 ,$UI/system/components/designerCommon/commonConfig.xml
为为目标文件路径#号后面的//common-properties/group[@name='bind']为标准的xpath表达式 -->
<include
path="$UI/system/components/designerCommon/commonConfig.xml#//common-properties/group[@name='bind']" />
</properties>
<!-- 定义当前组件的事件 -->
<events>
<event name="onClick" type="event" text="点击事件" />
<!-- 包含公共事件 -->
<include
path="$UI/system/components/designerCommon/commonConfig.xml#//html-evens/*" />
</events>
<!-- 定义模板 -->
<templates>
<!-- 默认模板,创建当前组件时会生成模板中的节点代码 -->
<template name="default"><![CDATA[
<a component="$UI/system/components/justep/button/button" class="btn btn-default"
label="button">
<i/><span></span>
</a> ]]></template>
</templates>
</element>
</elements>
补充说明:1)classSelector 编辑器传入的参数讲解
编辑器的参数值放到editor-parameter节点中,是一个json格式的数据,json数据的第一层列出了class的的分类,每个分类下面都有一个或多个class,如:
"1color":{
label: "颜色样式",
value: "btn-default|btn-primary|btn-success”,
require: false
}
label表示分组的名称
value 枚举了可选的class列表,多个用 | 号分隔
require 表示该组的class是不是必须要选一个,默认为false
1.3 创建组件js类
Js类主要负责绘制组件的展现,大多数情况下直接继承运行时的组件,在继承的类里加上设计时的相关的一些设置,以及去掉影响设计时设计的一些功能。设计时组件的的代码结构与运行时组件的一样,但在返回组件类的时候有区别,设计时允许返回多个组件类,这样方便多个设计时组件可以写到一个js文件里面,下面是button组件的js类的说明。
在designer目录下创建button.js文件,代码为:
define(function(require) {
var $ = require("jquery");
var Util = require("$UI/system/components/justep/common/designer/common");
/*引入设计时w页面 模型操作服务类*/
var xuiService = require("$UI/system/components/designerCommon/js/xuiService");
var xuiDoc = xuiService.getXuiDoc();
/*引入运行时的相关组件类*/
var Button = require("../button");
var ButtonGroup = require("../buttonGroup");
var Radio = require("../radio");
var Checkbox = require("../checkbox");
var Toggle = require("../toggle");
/*引入css样式*/
require('css!./css/button').load();
/*创建类*/
var _Button = Button.extend({
/*重载运行时的init方法,主要做一些设计时需要的额外处理*/
init : function(value, bindingContext) {
/*获取到当前组件的dom节点*/
var $domNode = $(this.domNode);
/*调用父的init方法*/
this.callParent(value, bindingContext);
var cfg = Util.attr2js($domNode, [ 'label', 'icon', 'image' ]);
if (cfg)
this.set(cfg);
var onclick = $domNode.attr('onClick');
if (onclick && 0 < onclick.indexOf('operation')) {
// 操作感知
this.on('onClick', onclick);
}
$domNode.removeAttr('onclick').off('click');
this._d_inited_ = true;
/*对dom节点加上各种控制属性,这些控制属性可以参考《设计时组件开发文档》*/
this._getLabelNode().attr('d_selectable', false).attr("d_canRemove", false).attr("d_canAddChild", false);
this._getIconNode().attr('d_selectable', false).attr("d_canRemove", false).attr("d_canAddChild", false);
this._getImgNode().attr('d_selectable', false).attr("d_canRemove", false).attr("d_canAddChild", false);
},
/*在事件编辑里绑定操作后调用的方法,主要是感知操作里的文字和图片*/
bindOperation : function(data) {
if (data && data.eventName)
this.on(data.eventName, data.value);
},
/*重载运行时的属性改变后的处理方法,主要是做一些属性修改后动态更新界面的操作*/
propertyChangedHandler : function(key, oldVal, value) {
switch (key) {
case "label":
this.callParent(key, oldVal, value);
if (this._d_inited_)
xuiDoc.updateText(this._getLabelNode());
break;
case "icon":
if (oldVal != value) {
}
break;
default:
this.callParent(key, oldVal, value);
}
}
});
/*定义按钮组类*/
var _ButtonGroup = ButtonGroup.extend({
init : function(value, bindingContext) {
var $domNode = $(this.domNode);
var cfg = Util.attr2js($domNode, [ 'selected' ]);
this.callParent(value, bindingContext);
if (cfg)
this.set(cfg);
this.$domNode.off('click');
},
/*右键菜单上的操作,添加按钮组件*/
addButton : function() {
xuiDoc.createComponent('$UI/system/components/justep/button/button', this, {
paintComponent : true
});
}
});
/*定义单选按钮类*/
var _Radio = Radio.extend({
init : function(value, bindingContext) {
createRadioButton(this, 'radio');
this.callParent(value, bindingContext);
this._getInput().off('click');
}
});
/*定义多选按钮类*/
var _Checkbox = Checkbox.extend({
init : function(value, bindingContext) {
createRadioButton(this, 'checkbox');
this.callParent(value, bindingContext);
this._getInput().off('click');
}
});
/*返回多个组件类,这里与运行时组件有区别,组件类的key值对应注册文件里面的name属性*/
return {
'$UI/system/components/justep/button/button' : _Button,
'$UI/system/components/justep/button/buttonGroup' : _ButtonGroup,
'$UI/system/components/justep/button/radio' : _Radio,
'$UI/system/components/justep/button/checkbox' : _Checkbox
};
});
补充说明:以上代码只摘取了实际类中的主体内容,具体的可以直接到组件目录下查看
2.listGroup组件案例(没有对应的运行时组件)
所在目录:/UI2/system/components/bootstrap/listGroup
该组件不存在运行期的组件,只是以html标签的形式展现
2.1 创建组件目录
/UI2/system/components/bootstrap/listGroup/designer
2.2 创建组件配置文件
配置文件与上面案例的格式基本上是一样的,因为这里没有对应运行时组件,所以通过加额外的鉴别条件来识别该组件:discriminate-condition=“hasClass(‘list-group’)”
意思就是当有list-group这个class的节点时,该节点就会被识别成listGroup组件。
<elements>
<element name="$UI/system/components/bootstrap/listGroup/listGroup(bootstrap)" tag-name="div" icon="element.gif" text="列表组"
discriminate-condition="hasClass('list-group')" resizable="false"
component-type="layout-container" design-view="web-designer" >
<!-- 右键菜单到工具栏的配置,addItem对应这js类中的方法 -->
<toolbar>
<item text="添加条目" method="addItem"/>
</toolbar>
…..
</element>
</elements>
2.3创建js类
因为没有对应的运行时组件类,所以直接继承了一个组件基类,如:
define(function(require) {
require("$UI/system/components/justep/common/res");
var xuiService = require("$UI/system/components/designerCommon/js/xuiService");
var xuiDoc = xuiService.getXuiDoc();
/*引入组件基类*/
var ViewComponent = require("$UI/system/lib/base/viewComponent");
/*创建组件类*/
var ListGroup = ViewComponent.extend({
/*重载基类的init方法*/
init : function() {
var $domNode = $(this.domNode);
$(">*", $domNode).attr("d_resizable", "false");
},
/*右键菜单的操作,添加一个子项*/
addItem : function(){
xuiDoc.createComponent("$UI/system/components/bootstrap/listGroup/listGroup(bootstrap)#gruopItem", this, {
paintComponent : true
});
}
});
/*返回组件类*/
return {
'$UI/system/components/bootstrap/listGroup/listGroup(bootstrap)' : ListGroup
};
});
3.特定功能点案例
3.1 右键菜单弹出编辑页面
以$UI/system/components/justep/data/data 组件的右键菜单“编辑列”为例
执行效果图
代码片断:
var editColumn = function(data, config) {
/*打开列编辑页面,页面 会以对话框的形式 打开 */
xuiService.openPage("$UI/system/components/justep/data/designer/editColumn.w",
{
title : "data列编辑", //对话框的标题
width:800, //对话框的宽度
height:600,//对话框的高度
xml : config.nodeXml //当前节点的xml,改参数会传入到编辑页面中
},
function(result) {//点确定后的回掉方法
//用返回来的节点替换到当前节点的子节点
xuiDoc.replaceChild(data, result.def.join(""), {
paintComponent : false, //是否要在设计区立即绘制这些新加的子节点,true 或者 false
xpathCondition : "*[local-name()='column']"//目标子节点的查询条件
});
//设置idColumn属性值
xuiDoc.set(data, {
idColumn : result.idColumn
});
});
};
3.2 批量创建子组件
以$UI/system/components/justep/grid/grid 组件添加列为例
appendColumn: function(config) {
var self = this;
//获取data的did
var dataID = this.get('data');
var data = this.getModel().comp(dataID);
if(!data){
alert('请先设置Grid的data属性');
return;
}
var data_did = data.$domNode.attr('d_id');
// 获取data列信息
var cols = xuiDoc.getEditorDataSource("RuleRelationDatasource.getDatasource",null,data_did);
//打开编辑器
xuiService.openPage("$UI/system/components/justep/dataTables/designer/appendColumn.w", {
xml : config.nodeXml,
cols : cols
}, function(result) {
var cols = result.cols;
if($.isArray(cols)){
var configs = [];
//构建要创建的列列表
for(var i=0;i<cols.length;i++){
configs.push({
componentName : "$UI/system/components/justep/grid/grid#column",//注册的列组件名
parentElementId : self.columns_dId,//父的xid
templateContent : '<column width="100" name="'+cols[i]+'"/>'//模板内容
});
}
//批量创建列
xuiDoc.batchCreateComponent(configs, function() {
self.repaintGrid();//重新绘制grid
});
}
});
}
3.3 节点同步删除
当右键删除一个组件的同时还想同时在删除其他地方的节点时,可以参考以下例子来进行处理。
以$UI/system/components/bootstrap/tabs/tabs(bootstrap) 组件右键删除页签为例,删除页签头时,同时删除页签的内容。
接管TabItem的onRemove 方法,如:
//删除时调用的方法
onRemove : function(event) {
if ($("li", this.domNode.parentNode.parentNode).length == 1) {
event.cancel = true;
} else {
//取消默认的删除动作
event.cancel = true;
var $domNode = $(this.domNode);
//找到内容节点
var content = $domNode.attr("content");
var contentDId = $(">.tab-content>*[xid='" + content + "']",
$domNode.parent().parent().parent()).attr("d_id");
//删除内容节点和当前节点
xuiDoc.deleteComponent([ contentDId,
$domNode.parent().attr("d_id") ]);
}
}
结束语:以上是比较典型的案例开发讲解,设计时的组件有些更细的方面这里没有面面俱到,需要更深入了解的话可以去研究更多的组件代码[/fusion_text]
评一波