使用者回饋
@消失的鍵盤 在論壇回饋了一個問題, 在 AppBoxMvc 中的 Title 模型中, 如果將 Name 屬性改名為小寫的 name 屬性, 就會報錯:
因為這是一個 ASP.NET MVC 的專案, 而這個屬性是通過 TextBoxFor 渲染到頁面上的, 因此 name 會生成為 DOM 節點的 id 屬性:
F.SimpleForm .ID("SimpleForm1") .ShowBorder(false) .ShowHeader(false) .BodyPadding(10) .Items( F.TextBoxFor(m => m.name), F.TextAreaFor(m => m.Remark) )按道理說這也沒什麼, 雖然有點彆扭, 但是也沒有規定說name字串不能作為id屬性的值。
並且從另一個方面講, name 也不是 JavaScript 的關鍵字, 不可能衝突阿。
分析問題
還是從代碼入手, 經過簡單的調試, 發現 id=name 的這個文本輸入框物件居然找不到, 而這個物件是保存在 F.ui 上面的。
首先我們看下 F.ui 的定義:
F.ui = function(item) { var itemType = F.getType(item.type || 'component'); return new itemType(item); };為了方便用戶書寫代碼, FineUIMvc中 F.ui 其實有兩個用途:
1. 用作函數:創建控制項, 可以在JS中通過 F.ui 來創建一個控制項:
F.ui({ type: 'button', renderTo: document.body, text: '按鈕', id:'button1', listeners: { click: function (event) { F.alert('你點擊了按鈕'); } } });2. 用作對象:保存控制項, 可以在JS中通過 F.ui 來引用一個控制項(比如上面創建的按鈕):
這樣一分析問題就來了, 因為本身JS函數是有屬性的, 這裡由於 F.ui 是個匿名函數, 所以 F.ui.name == '' (這個函數的 name 屬性為空字串)
對於一個普通的函數, 這個name屬性就是函數名稱, 如下所示:
function test1 { } console.log(test1.name) // "test1"其實JavaScript 函數不僅有 name 屬性, 還是 length , caller, arguments, toString .... 等很多屬性, 在Chrome的調試工具中可以方便的查看:
所以, 當我們試圖將名為 name 的文本輸入框物件保存到 F.ui 上時, 其實是不成功的, 此時 F.ui.name 依然為空字串。
解決問題
由於 F.ui 的兩個作用已經被網友所熟知, 並且已經應用到很多項目中了, 不能因為幾個特殊屬性的衝突就廢棄這種做法。 那麼怎麼規避這個問題呢?
我們使用了一個內部變數來保存頁面上的控制項實例:
F._fjs_objects = {};同時為了相容之前的代碼, F.ui 函數仍然用來保存控制項實例, 只不過在保存之前要先進行判斷, 如果傳入的名稱是函數屬性名的話, 就不要保存:
function nameIsPropertyOfFunction(name) { return $.inArray(name, ['arguments', 'caller', 'length', 'name']) >=0 || $.isFunction(F.ui[name]); } F._fjs_addToFObjects = function(objId, obj) { F._fjs_objects[objId] = obj; if(!nameIsPropertyOfFunction(objId)) { F.ui[objId] = obj; } };優化後, 之前的所有代碼都不用改動, 你仍然可以通過兩種方式獲取控制項實例:
1. F('controlid')2. F.ui.controlid
而對於非常特殊的情況, 控制項ID為 name, length, toString (當然我們極力不推薦你用這樣的名稱來命名控制項ID!!)時,