# cap4自定義控件-PC端
* * *
cap4表單自定義控件參考開發文檔 (文檔默認是v7.0sp1開始支持,新增內容會備注開始支持版本號,刪除內容會備注頂用版本號)
## 自定義控件介紹
~~~
A. 自定義控件增加了表單的可擴展性。
a. 比如使用者想在頁面中增加一個需求功能,例如在表單中顯示一個統計頁面的板塊。而這樣的需求在表單常規使用中很少會遇見,或者表單沒有這樣的標準控件。就可以通過自定義控件實現。
B. 自定義控件和表單的關系
a. 自定義控件是寄生在表單上的單獨的組件。會自己去渲染,表單不提供渲染。也可以自己通過接口和后端交互數據,不走表單的流程。
b. 表單會給自定義控件一定范圍的基礎數據支持。會提供表單和自定義控件之間的數據交互API
~~~
## 一.開發規范
### 1.1 自定義控件文檔結構
~~~
自定義控件項目前端可按照如下目錄結構組織資源(開發文檔結構沒有強制規范,這只是建議,只要開發中的路徑關系理順就行)。
./ 開發文件夾
├─js js資源
├─css css資源
├─icon 圖標資源
├─index.html html資源
~~~
### 1.2 自定義控件基礎規范
~~~
A.生成一個唯一標識
a 開發者需要在前端代碼中生成一個屬于當前開發自定義控件的唯一標識,用于掛載到全局實現自定義控件命名空間(開發者自己維護)
B.控件代碼里面的所有this指向window[1唯一標識]
C.確保有初始化入口方法(并且要配置到配置文檔去)
D.建議使用閉包進行開發
~~~
### 1.3 自定義控件存在生命周期
~~~
自定義控件由入口方法調用開始加載,表單頁面關閉銷毀。
~~~
## 二. 自定義控件實現和交互規范
~~~
A.表單繪制的時候會根據后端設計器的視圖信息,會在對應的位置生成一個DOM容器,這個容器會附上一個ID(對表單中每一個位置的自定義控件都唯一)
B.會根據自定義控件信息去加載js文件,加載完成后調用配置的入口方法 (js文件路徑和入口方法都來自于配置信息)
C.調用入口方法會傳入一個Object參數(三.3.自定義控件初始傳入的數據解析)
D.開發者需要在入口方法后順序執行的過程中去加載自己的css,js,并且渲染當前控件
E.自定義控件內部的各種事件,操作區域,打開文件等等,都由自定義控件內部開發代碼完成
F.自定義控件需要回填其他標準控件,或者保存自己的數據,可以根據API提供的功能就行回填
~~~
## 三. 3.自定義控件初始傳入的數據解析
### 3.1 入口方法傳入的參數是Object數據類型,里面有5個屬性
(3.1圖)
~~~
數據解析:
A.adaptation : 這個里面有提供的api,方法集合,可實現和表單頁面數據之間的通信.
B.url_prefix : 這個是url前綴,可用于開發者加載css文件和js文件的路徑前綴.
C.privateId : 這個是當前控件的在表單頁面的唯一標識,可用于掛載控件DOM,也是調用部分API操作的必傳參數,用于操作獲取對應的值。
D.getData : 獲取當前控件初始的所有數據
~~~
(D圖,當前控件數據信息)
~~~
a. attachmentInfo : 附件信息 (里面包含附件列表和基礎附件信息)
b. attrs : 視圖里面的簡單控件信息
c. auth: 權限 (‘edit’ : 編輯,’hide’: 隱藏)
d. ctrlType : 視圖里面的控件狀態(這個,自定義控件的是"suiCustomControl")
e. customFieldInfo : 自定義控件的信息,里面包含pc,移動的js信息和入口方法信息,路徑信息。
f. digitNum : 小數位長度
g. display : 控件名
h. enums : 控件的枚舉列表
i. extra :設計器給控件設置的樣式信息
j. fieldLength :控件內字符的限制長度
k. fieldType :字段類型
l. formType : 控件所在的表的類型
m. formatType : 數據格式
n. Formdata : 整個表單的信息
n-1. Alldata :整個表單的所有數據包括視圖信息和用戶信息,主表數據,明細表數據,多視圖信息
n-2. content :表單的基礎信息,包括表單數據ID,表單權限Id等等
n-3. formdata : 表數據
n-4. formmains : 主表數據
n-5. formsons : 明細表數據
n-6. model : 表單中明細表是頁簽還是平鋪(undefined是平鋪,暫時其他是頁簽)
o. id :字段名
p. inputType :控件類型(標準控件判斷)
q. isInCalculate : 是否計算(1為計算)
r. isInCondition : 是否是條件字段
s. isNotNull : 必填校驗(1為必填)
t. isCustomFiled : 是否是自定義控件(1是)
u. placeHolder : 提示語言
v. radioAlignType :
w. relation : 關聯信息(控件公用的基礎信息)
x. relationData : 當前控件的關聯數據
y. showValue : 顯示值
z. value : 計算值
aa. type : 類型
ab. valueId : 值
E. formMessage : 當前控件在表的位置信息
a. tableCategory : 主表還是明細表(formmain = ‘主表’,formson = ’明細表’)
b. tableName : 所在表的表名
~~~
~~~javascript
/**
* 示例:
*
* */
{
tableCategory : '',
tableName : ''
}
~~~
## 四. Api (依賴于(三)傳入的adaptation屬性,具體回填格式和數據請看下面詳解)
| API方法名 | 說明 | 參數 | 參數格式 | 參數說明 | 詳細介紹 |
| --- | --- | --- | --- | --- | --- |
| childrenGetData | 獲取當前控件的數據 | privatedId | String | 當前控件的唯一標識ID | (A) |
| childrenSetData | 更新保存當前控件的數據 | data,privatedId | Object, String | messageObj是獲取的控件數據對象(更新到你維護的最新值),privaredId: 當前控件的唯一標識ID(入口方法傳入) | (B) |
| ObserverEvent | 用于事件發布訂閱 | 屬性方法 | Function | 擴展的屬性方法 | (C) |
| backfillFormControlData | 用于回填控件數據 | data, privatedId | Object/Array, string | payload: 回填的數據, privatedId 當前控件的唯一標識ID(入口方法傳入) | (D) |
| backfillFormAttachment | 用于回填附件數據 | data, privatedId | Object/Array, string | payload: 回填的數據, privatedId 當前控件的唯一標識ID(入口方法傳入) | (E) |
| callTakeFormSave | 調用表單預提交方法 | data, privatedId | Object, string | data 調用方法的參數, privatedId 當前控件的唯一標識ID(入口方法傳入) | (F) |
~~~
(A). childrenGetData (privateId)
~~~
~~~javascript
/**
* 示例:
* 說明:此接口是用于獲取當前的控件的即時數據。
* 參數:privateId->(String)唯一標識
* */
adaptation.childrenGetData(privateId);
~~~
~~~
(B). childrenSetData (data, privateId)
~~~
~~~javascript
/**
* 示例:
* 說明:此接口用于把自定義控件操作當前控件的數據回填到表單維護的當前控件數據中,建議取得數據對象,你就維護此對象,回填的時候傳入此數據。
* 參數:data->(Object)當前控件的數據
* privateId->(String)唯一標識
* */
adaptation.childrenSetData (data, privateId);
~~~
~~~
(C). ObserverEvent
~~~
~~~javascript
/**
* 示例:
* 說明:發布訂閱方法,有多個屬性方法
* 屬性方法:
* one (key, fn) : 處理一次
* remove (key, fn) : 刪除注冊事件
* listen (key , fn) : 組冊事件
* trigger () : 觸發事件,第一個傳入key,后面的傳入需要傳遞的數據
* 參數:
* key->(String) 事件名
* fn->(Function) 回調方法,里面可能有參數,看事件的約定
* */
adaptation.ObserverEvent.one('key', function(params) {});
adaptation.ObserverEvent.remove('key', function() {});
adaptation.ObserverEvent.listen('key', function(params) {});
adaptation.ObserverEvent.trigger('key', params);
~~~
~~~
(D). backfillFormControlData(data, privateId)
~~~
~~~javascript
/**
* 示例:
* 說明:此接口是用于自定義控件回填表單其他控件數據
* 參數:data -> (Object || Array) 組織的回填的數據
* Object格式 :
* {
* tableName : (表名),
* tableCategory : (表類型(formmain || formson)),
* updateData : {
* filedName(表單對應控件名) :{} (回填控件的數據對象)
* },
* updateRecordId : (更新對應的數據行Id,主表控件沒有,明細表控件有)
* }
* Array格式:
* [
* {
* tableName : (表名),
* tableCategory : (表類型(formmain || formson)),
* updateData : {
* filedName(表單對應控件名) :{} (回填控件的數據對象)
* },
* updateRecordId : (更新對應的數據行Id,主表控件沒有,明細表控件有)
* }
* ]
* privateId->(String)唯一標識
* 注意:
* 1.回填是根據后端控件值格式
* 2.回填輸的數據對象里面有三個值很特殊 :從入口方法獲取的前端控件對象里面三個屬性名是showValue, value, valueId.對應的回填對象里面格屬性名是showValue,showValue2, value (非常重要)
* 3. 2里面獲取的前端控件數據對象里面的屬性名和回填控件的數據對象屬性名 showValue = showValue, value = showValue2, valueId = value (非常重要)
* */
adaptation.backfillFormControlData (data, privateId);
~~~
~~~
(E). backfillFormAttachment(data, privateId)
~~~
~~~javascript
/**
* 示例:
* 說明:此接口用于回填表單里面控件的附件
* 參數:data -> (Object || Array) 組織的回填附件數據
* Object格式:
* {
* tableName : (表名),
* tableCategory : (表類型),
* updateRecordId : (更新對應的數據行Id,主表控件沒有,明細表控件有),
* handlerMode : (操作類型值:添加add和刪除delete),
* fieldName : (表單回填的對應控件名),
* addAttchmentData : [{}], // 回填控件的附件信息列表,附件信息對象需要經過后端對應的格式生成
* deleteAttachmentData :[] // 回填控件附件列表中要刪除的對應Id數組
* }
* Array格式:
* [
* {
* tableName : (表名),
* tableCategory : (表類型),
* updateRecordId : (更新對應的數據行Id,主表控件沒有,明細表控件有),
* handlerMode : (操作類型值:添加add和刪除delete),
* fieldName : (表單回填的對應控件名),
* addAttchmentData : [{}], // 回填控件的附件信息列表,附件信息對象需要經過后端對應的格式生成
* deleteAttachmentData :[] // 回填控件附件列表中要刪除的對應Id數組
* }
* ]
* privateId->(String)唯一標識
* 注意:
* 1.handlerMode屬性有兩個值必填其一
* 2.handlerMode屬性為‘add’ => 只會去讀取addAttchmentData屬性列表,所以必填
* 3.handlerMode屬性為‘delete’ => 只會去讀取deleteAttachmentData屬性數組,所以必填
*
*
* */
adaptation.backfillFormAttachment (data, privateId);
~~~
~~~
F. callTakeFormSave(data, privateId)
~~~
~~~javascript
/**
* 示例
* 說明:此接口用于自定義控件調用預提交
* 參數:data -> (Object) 參數對象
* {
* type: 'save', // 必填,值固定
* isPrev: true, // 必填,值固定
* callback :(數據格式為Function), // 回調方法,有一個參數,參數格式為Object
* successFn :(數據格式為Function), // v7.0 sp2-1130版本支持,正確預提交回調方法
* errorFn :(數據格式為Function), // v7.0 sp2-1130版本支持,預提交失敗,或者錯誤回調方法
* }
* privateId->(String)唯一標識
*
* 注意:
* 1.數據格式按規則填寫
* 2.只是預提交表單數據
* 3.只是只支持這些
*
* */
adaptation.callTakeFormSave (data, privateId);
~~~
## 五. 表單觸發的事件(依賴于adaptation.ObserverEvent)
| 監聽事件名 | 說明 | 參數 | 參數格式 | 參數說明 | 詳細介紹 |
| --- | --- | --- | --- | --- | --- |
| Event + 唯一標識 | 用于監聽是否數據更新 | data | Object | 返回的是表單中當前控件最新數據 | (A) |
| Save + 唯一標識 | 通知自定義控件表單要保存了 | 無 | 無 | 無 | (B) |
~~~
(A). Event + 唯一標識:用于告訴對應的自定義控件表單里面當前的數據更新了
~~~
~~~javascript
/**
* 示例:
* 說明: 于告訴對應的自定義控件表單里面當前的數據更新了
* 事件名: 字符串 'Event' + 入口方法傳入的唯一標識privateId
* 參數:data => (Object)
* 當前控件的控件數據對象
*
* */
adaptation.ObserverEvent.listen('Event' + privateId, function(data) {
// 執行你的操作
});
~~~
~~~
(B). Save + 唯一標識:用于告訴對應的自定義控件要保存了 (v7.0 sp2版本支持)
~~~
~~~javascript
/**
* 示例:
* 說明:用于告訴對應的自定義控件當前表單要保存了
* 事件名:字符串 'Save' + 入口方法傳入的唯一標識privateId
* 參數: privateId => (String) 唯一標識
* data => (Object)
* */
adaptation.ObserverEvent.listen('Save' + privateId, function(privateId, data) {
// 執行你的操作
});
~~~
## 六. 前端開發示例
~~~
下面是一個前端自定義控件開發示例 (按鈕自定義控件)
~~~
~~~javascript
/**
* 說明: 是一個按鈕類自定義控件的示例
* */
(function(factory){
var nameSpace = 'field_5902128098173592526';
if(!window[nameSpace]){
var Builder = factory();
window[nameSpace] = {
instance: {}
};
window[nameSpace].init = function (options) {
window[nameSpace].instance[options.privateId] = new Builder(options);
};
window[nameSpace].isNotNull = function (obj) {
return true;
};
}
})(function(){
/**
* 構造函數
* @param options
* @constructor
*/
function App(options) {
var self = this;
//初始化參數
self.initParams(options);
//初始化dom
self.initDom();
//事件
self.events();
}
App.prototype = {
initParams : function (options) {
var self = this;
self.adaptation = options.adaptation;
self.privateId = options.privateId;
self.messageObj = options.getData;
self.preUrl = options.url_prefix;
},
initDom : function () {
var self = this;
dynamicLoading.css(self.preUrl + 'css/formQueryBtn.css');
self.appendChildDom();
},
events : function () {
var self = this;
// 監聽是否數據刷新
self.adaptation.ObserverEvent.listen('Event' + self.privateId, function() {
self.messageObj = self.adaptation.childrenGetData(self.privateId);
self.appendChildDom();
});
},
appendChildDom : function () {
var self = this;
var domStructure = '<section class="customButton_box_content">'+
'<div class="customButton_class_box '+ self.privateId + '" title="' + self.messageObj.display.escapeHTML() + '">'+ self.messageObj.display.escapeHTML() +'</div>'+
'</section>';
document.querySelector('#' + self.privateId).innerHTML = domStructure;
var jumpFun = function() {
// 事件執行
};
document.querySelector('.' + self.privateId).removeEventListener('click',jumpFun);
document.querySelector('.' + self.privateId).addEventListener('click',jumpFun);
//渲染隱藏權限
if (self.messageObj.auth === 'hide') {
document.querySelector('#' + self.privateId).innerHTML = '<div class="cap4-text__browse" style="line-height: 1.8; color: rgb(0, 0, 0) !important;">***</div>';
}
},
dealCdtMapping : function (opt) {
$.ajax({
url: '/seeyon/rest/cap4/formquerybtn/dealCdtMapping?formId=' + opt.formId + '&fieldName=' + opt.fieldName + '&formDataId=' + opt.formDataId + '&formSubDataId=' + opt.formSubDataId + '&designId=' + opt.designId,
success: function (data) {
if(opt.callback && typeof opt.callback === 'function')
opt.callback.apply();
},
error: function (e) {
if(e.message){
top.$.error(e.message);
}else{
top.$.error('處理篩查條件出錯...');
}
}
});
}
};
var dynamicLoading = {
css: function(path) {
if(!path || path.length === 0) {
throw new Error('argument "path" is required !');
}
var head = document.getElementsByTagName('head')[0];
var link = document.createElement('link');
link.href = path;
link.rel = 'stylesheet';
link.type = 'text/css';
head.appendChild(link);
},
js: function(path) {
if(!path || path.length === 0) {
throw new Error('argument "path" is required !');
}
var head = document.getElementsByTagName('head')[0];
var script = document.createElement('script');
script.src = path;
script.type = 'text/javascript';
head.appendChild(script);
}
}
return App;
});
~~~
## 七. 自定義控件調試環境和與表單的交互
~~~
1.協同開發環境.
2.我們會持續維護表單和自定義控件之間的交互api,如有特殊情況可以聯系后討論處理方案
~~~
## 八.常見的錯誤
~~~
1.this的指向問題
2.同一個表單里面可能具有多個相同的自定義控件
1) 需要當前控件防污染處理
3.兼容
1) 因為兼容IE(定義變量使用var (不建議let , const), 不建議ES5以上標準的js書寫代碼)
2) 也可以是最終運行的代碼是編譯成ES5標準的(例如使用:babel-polyfill)
4.事件初始化
1) 初始化方法調用后要對原有注冊的方法進行銷毀處理,并重新注冊
5.數據陳舊
1) 沒有監聽(五-A)的監聽方法,去更新當前控件里面的數據
2) 如果沒有第一步,新操作的時候也沒有去取新的數據
3) 如果沒有第一步,頁面數據變化了自定義控件沒有刷新渲染,出現了運行態和預期不一致
~~~
* * *
*End*
- 概要
- 技術介紹
- 框架與環境
- vue開發
- 開發規范
- 前端開發規范
- 總體原則
- HTML規范
- HTML&css規范
- vue編碼規范
- Javascript規范
- 后端開發規范
- cap4
- 自定義控件
- 前端2.0(PC+移動)
- PC前端
- 后端
- 移動端
- 移動端接口
- 低版本協同升級到V5 8.0適配說明
- 自定義按鈕
- 自定義按鈕(無流程)
- 自定義控件(列表插槽)
- 自定義按鈕(篩選條件)
- 低版本協同升級到V5 8.0適配說明
- 門戶空間
- 門戶與欄目掛載
- 欄目開發及流程說明
- 頁面模板
- 客開通路及插件體系
- 表單設計器擴展配置
- 使用步驟
- 配置說明
- 事件API
- Demo示例
- 運行態客開通路
- 插件使用步驟
- 插件接口
- 事件接口
- 鉤子相關接口
- 表單操作接口
- Demo示例
- 插件機制
- 表單運行態接口(舊)
- 白名單插件
- 版本記錄
- vue組件庫
- 開發指南
- 開發文檔規范
- 業務組件介紹
- 業務組件
- table組件
- 分頁組件
- title組件
- 統計排隊組件
- code組件
- 條件篩選
- 批量導入
- 上傳Excel
- 批量更新
- 批量刷新
- UI組件
- 按鈕組件
- 復選組件
- 取色器組件
- 示例組件
- 水平選擇組件
- 選圖標組件
- 提示組件
- 單選組件
- 搜索組件
- 選擇組件
- 穿梭框組件
- 標簽組件
- 文本組件
- 樹組件
- 驗證組件
- 菜單組件
- iframe組件
- toolbar
- 統計組件
- 餅圖
- 柱狀圖
- 圖標
- 業務關系開發指南
- 自定義觸發
- 自定義關聯
- 后端API
- 更新表單數據緩存
- 發起表單流程
- 取得指定表單PDF或截圖
- 無流程批量添加
- 無流程批量刪除
- 無流程批量更新
- 無流程批量導出
- 客開培訓文檔
- Vue基礎培訓
- Vue實戰培訓
- Vue進階培訓
- VueCLI3培訓
- cap3
- 自定義控件
- 后端
- 移動端
- 前端編譯
- 表單運行態接口
- 協同云