Knockout.jsとPrimefacesの統合ログ2
14673 ワード
もっと読む
統合の第一歩は、クライアントの棚を組み立てることです.
その前に、Knockout.jsを知らない友達は先にKnockoutjs.comに行って、公式のtutorialを遊ぶことを提案します.中国語の資料はネットで検索できます.例えばhttp://yangshen998.iteye.com/blog/1310194 これはよさそうです.
前期の準備
私達の製品はもともとjquery 1.11を導入しました.json 2(IE 7対応のため)とundersscore.js(http://underscorejs.org/これらのライブラリは、フレームコードもこれらのライブラリに依存しています(新しいブラウザだけをサポートするなら、Json 2を導入する必要はありません.ブラウザはAPIを持っています).また、簡単なJavaオブジェクトを監視対象に変換するためには、ko.view modelライブラリを導入する必要があります.http://coderenaissance.github.io/knockout.viewmodel/)
まず、ブラウザconsolieの自動補完機能を日常的に利用しやすくすることと、名前空間を隔離することを考慮して、まずapp名前空間を導入して、後続のフレームコードとView Modelはこれを基にします.
次に私たちはよく使う道具の方法を準備します.(余談ですが、私は内蔵対象のプロトタイプを汚染するのがあまり好きではありませんので、プロトタイプではなくUnderscore.jsを選択する傾向があります.ここでは内蔵対象のプロトタイプを修正する代わりにツールを使う方法を選択します.)
Knockout.jsはView Modelの形式に対して厳格な要求がなく、対象であればいいです.しかし、統一コードのスタイルと拡張しやすいという考えから、やはり全てのコンストラクタを書いてからコンストラクタからインスタンスを作成する方法に統一されています.このように複雑なシーンでは、同じタイプのView Modelに対して複数のインスタンスを作成し、それぞれ異なる領域をバインドすることをサポートすることができる.
検索とデバッグを容易にするために、すべてのView Modelコンストラクタをap.co nstructorsに置いて、実用化されたView Modelオブジェクトをap.vmに置くことになっています.この規定を強制的に推進するために、APP.register Costructor方法を提供して、コンストラクタを作成し、同時に登録します.
このようにして、我々は以下の方法でビューモデルのコンストラクタを定義することができます.
ビューモデルのコンストラクタから表示モデルの例を作成するには、構造方法を直接呼び出すことができます.
しかし、この方法はまだタイピングが多すぎます.また、JSオブジェクトから直接にビューモデルを作成する方法をサポートしたいので、ap.creat VMインターフェースを提供したいです.
次のcreateVM方法は前のコードのTODO部分に入ります.
注2:ko.pureComputedとko.com mputedなどの受容関数の方法は、通常、この関数の内部のthis参照を結合するための第二のパラメータを提供します.
注3:一般的なコールバック方法は、undersscore.jsのbind方法によってthis参照をバインドする必要があります.プログラムが新式のブラウザだけで実行されていることを確認すれば、元のFuntion.bindメソッドを直接使用することができます.
ビューモデルをDOM要素に適用し、最も直接的な方法はKnockoutのappyBindings法を使用することである.
Last Name:
&噫13;
var vm=ap.create VM("MyForm")&菵13;
ko.appyBindings(vm,document.getElemenntById(「25785;MyForm」)&21813;13;
しかし、このような方法は私の需要を完全に満たすことができません.前の節で解決すべき問題の一つは、どうやって問題が発生したDOMノードから逆方向に結合されたJSコードを探し出すかということでしたが、Knockoutの原生バインディング方式はJSからDOMへの一方向参照のみを要求したことを覚えています.DOMからJSへの逆参照を強制的に追加するためには、バインディングされたルート要素上のdata−vm属性を適用する必要があり、バインディングされているビューモデル名の値を持つ.
また、JSFでは頻繁にページをローカルに再レンダリングするので、結合されたルートの接合点はDOMツリーから取り除かれる可能性が高い.新しい接合点を結合する際に、古い接合点をチェックしたいです.DOMツリーから孤立した接合点に移動した場合、メモリ漏れが発生しないようにビューモデルへの参照を遮断します.
今は前のコードの中のbind方法を補完できます.
&噫13;
ap.create VM(MyForm).bind(「芫MyForm」)&21873;13;
(本節で終了)
統合の第一歩は、クライアントの棚を組み立てることです.
その前に、Knockout.jsを知らない友達は先にKnockoutjs.comに行って、公式のtutorialを遊ぶことを提案します.中国語の資料はネットで検索できます.例えばhttp://yangshen998.iteye.com/blog/1310194 これはよさそうです.
前期の準備
私達の製品はもともとjquery 1.11を導入しました.json 2(IE 7対応のため)とundersscore.js(http://underscorejs.org/これらのライブラリは、フレームコードもこれらのライブラリに依存しています(新しいブラウザだけをサポートするなら、Json 2を導入する必要はありません.ブラウザはAPIを持っています).また、簡単なJavaオブジェクトを監視対象に変換するためには、ko.view modelライブラリを導入する必要があります.http://coderenaissance.github.io/knockout.viewmodel/)
まず、ブラウザconsolieの自動補完機能を日常的に利用しやすくすることと、名前空間を隔離することを考慮して、まずapp名前空間を導入して、後続のフレームコードとView Modelはこれを基にします.
;(function($, win, undefined) {
if (!win.app) win.app = {}
/* */
})(jQuery, this)
旧式のブラウザーがconsoneに対する支持がよくないことを考慮して、および生産環境の中でログを遮るのに都合よくて、私達は先にconsolieのAPIを統一します.以下のコードは前のコードのコメントに挿入します.
;(function() {
var unified = win.console || {};
var dummy = {};
_.each([
"assert", "clear", "count", "debug", "dir", "dirxml", "error",
"group", "groupCollapsed", "groupEnd", "info", "log", "time", "timeEnd",
"trace", "warn", "table"
],
function(m) {
if (!unified[m]) unified[m] = _.noop;
dummy[m] = _.noop
});
win.app.enableConsole = function() {
win.app.consoleEnabled = true
win.app.console = unified
}
win.app.disableConsole = function() {
win.app.consoleEnabled = false
win.app.console = dummy
}
win.app.enableConsole()
})()
このように、app.co nsoleでconsoneコマンドを呼び出す時に、ブラウザがこのインターフェースをサポートしていなくても、異常がないことを保証します.さらに、操作台には、ap.enabeleConsone()とap.disable Consone()を介してオンまたは遮蔽出力することができる.次に私たちはよく使う道具の方法を準備します.(余談ですが、私は内蔵対象のプロトタイプを汚染するのがあまり好きではありませんので、プロトタイプではなくUnderscore.jsを選択する傾向があります.ここでは内蔵対象のプロトタイプを修正する代わりにツールを使う方法を選択します.)
win.app.utils = {
/**
* s
*/
stringEndsWith: function(s, suffix) {
return s.indexOf(suffix, s.length - suffix.length) != -1
},
/**
* 。( 《JavaScript 》 )
*/
trimString: function(s) {
s = s.replace(/^\s+/, "")
for (var i = s.length - 1; i >= 0; i--) {
if (/\S/.test(str.charAt(i))) {
s = s.substring(0, i + 1)
break
}
}
return s
}
/**
* JSF id , jQuery , id , jQuery 。
*/
idToSelector : function(id) {
return id.replace(/:/g, "\\:")
},
/**
* ID。
* app.utils.id.next() ID
* app.utils.id.peek() ID,
*/
id: (function() {
var _id = 0;
return {
next: function() {
_id = _id + 1
return _id
},
peek: function() {
return _id
}
}
})()
}
View Modelを定義するKnockout.jsはView Modelの形式に対して厳格な要求がなく、対象であればいいです.しかし、統一コードのスタイルと拡張しやすいという考えから、やはり全てのコンストラクタを書いてからコンストラクタからインスタンスを作成する方法に統一されています.このように複雑なシーンでは、同じタイプのView Modelに対して複数のインスタンスを作成し、それぞれ異なる領域をバインドすることをサポートすることができる.
検索とデバッグを容易にするために、すべてのView Modelコンストラクタをap.co nstructorsに置いて、実用化されたView Modelオブジェクトをap.vmに置くことになっています.この規定を強制的に推進するために、APP.register Costructor方法を提供して、コンストラクタを作成し、同時に登録します.
;(function() {
/*TODO bind */
function bind(elem) {
}
function addVM(vmName, vm) {
/* app.vm , */
if (win.app.vm[vmName]) {
//
var oldVM = win.app.vm[vmName]
/* __destroy__ , */
oldVM.__destory__ && oldVM.__destory__();
_.each(oldVM.__elements__, function(el) {
ko.cleanNode(el)
})
oldVM.__elements__ = null
}
/* __vmName__ , */
vm.__vmName__ = vmName;
/* __elements__ */
vm.__elements__ = []
/* app.vm */
win.app.vm[vmName] = vm;
}
_.extend(win.app, {
constructors: {},
vm: {},
registerConstructor: function(name, func, isStatic) {
/* isStatic true , */
if (isStatic && this.constructors[name]) return;
/* bind */
func.prototype.bind = bind //TODO bind
/* __from__ Ctor- */
func.prototype.__from__ = "Ctor-" + name
var self = this;
/* constructor , ViewModel 。
* , , ,
* 。
* , ,
* 。
*/
self.constructors[name] = function(vmName, options) {
/* */
if (_.isObject(vmName)) {
options = vmName
vmName = undefined
}
/* , */
if (!vmName) vmName = name
/* ViewModel , options */
var vm = new func(options)
addVM(vmName, vm)
return vm;
}
return self.constructors[name];
},
//TODO
createVM: function() {}
});
})()
ここにコンストラクタを登録すると同時に、そのprototypeにbindメソッドを追加します.このように作成されたView Modelはこの方法を持っています.ap.vm.MyView Model.bind()の方式で、ViemodelをDOM要素に適用できます.bind法の実現は後述する.このようにして、我々は以下の方法でビューモデルのコンストラクタを定義することができます.
app.registerConstructor("MyForm", function(opts) {
var self = this
self.firstName = ko.observable(opts.firstName || "")
self.lastName = ko.observable(opts.lastName || "")
self.fullName = ko.pureComputed(function() {
return app.utils.trimString(self.firstName() + " " + self.lastName())
})
})
ビューモデルの例を作成ビューモデルのコンストラクタから表示モデルの例を作成するには、構造方法を直接呼び出すことができます.
app.constructors.MyForm() // MyForm
app.constructors.MyForm("form1") // form1
app.constructors.MyForm({firstName: "Tom"}) // MyForm 。 app.vm MyForm 。
app.constructors.MyForm("form2", {lastName: "Parker"}) // form2
ブラウザコントロールに入力します.
app.vm.
作成した3つのビューモデルの例のリストが表示されます.しかし、この方法はまだタイピングが多すぎます.また、JSオブジェクトから直接にビューモデルを作成する方法をサポートしたいので、ap.creat VMインターフェースを提供したいです.
次のcreateVM方法は前のコードのTODO部分に入ります.
createVM: function() {
var constructor, vmName, options, vm, self = this
/* */
if (_.isObject(arguments[0])) {
vm = arguments[0]
vmName = arguments[1]
} else if (_.isString(arguments[1])) {
constructor = arguments[0]
vmName = arguments[1]
options = arguments[2]
} else if (_.isObject(arguments[1])) {
vmName = constructor = arguments[0]
options = arguments[1]
} else if (_.isUndefined(arguments[1])) {
if (_.isString(arguments[0])) {
vmName = constructor = arguments[0]
}
}
if (constructor) { // VM
if (self.constructors[constructor]) {
vm = self.constructors[constructor](vmName, options)
} else {
self.console.error("Constructor " + constructor + " not defined.")
}
} else if (vm) { // Json VM, ,
if (_.isUndefined(vmName)) {
vmName = "vm_" + win.app.utils.id.next()
}
/* ko.viewmodel Json */
vm = ko.viewmodel.fromModel(vm)
/* bind app.vm */
vm.bind = bind
addVM(vmName, vm)
} else {
self.console.error("Illegal arguments.")
return
}
return vm
}
このようにして、我々は以下の様々な形でビューモデルの実例を作成することができます.
app.createVM("MyForm") // MyForm
app.createVM("MyForm", "form1") // MyForm form1
app.createVM("MyForm", {"lastName": "Parker"}) // MyForm ,
app.createVM("MyForm", "form2", {"firstName": "Tom"}) // MyForm form2 ,
app.createVM({"firstName": "Tom", "lastName": "Parker"}) // , fullName 。 , vm_ 。
app.createVM({"firstName": "Tom", "lastName": "Parker"}, "simpleForm") // simpleForm
もちろん、JSオブジェクトを使って直接にビューモデルを作成する方法も、実は比較的複雑な論理を書くことができます.例えば
app.createVM({
"firstName": "Tom",
"lastName": "Parker",
"fullName": ko.pureComputed(function() {
return this.firstName() + " " + this.lastName() /* 1 */
}, this), /* 2 */
"clear": _.bind(function() {
this.firstName("")
this.lastName("")
}, this) /* 3 */
}, "form3") // JS form3
注1:作成したビューモデルは、ko.view modelプラグインを通じてモニタオブジェクトに変換されますので、関数を使って属性にアクセスする必要があります.注2:ko.pureComputedとko.com mputedなどの受容関数の方法は、通常、この関数の内部のthis参照を結合するための第二のパラメータを提供します.
注3:一般的なコールバック方法は、undersscore.jsのbind方法によってthis参照をバインドする必要があります.プログラムが新式のブラウザだけで実行されていることを確認すれば、元のFuntion.bindメソッドを直接使用することができます.
"clear": function() {
this.firstName("")
this.lastName("")
}.bind(this)
表示モデルをDOM要素に適用ビューモデルをDOM要素に適用し、最も直接的な方法はKnockoutのappyBindings法を使用することである.
ファーストName:Last Name:
&噫13;
var vm=ap.create VM("MyForm")&菵13;
ko.appyBindings(vm,document.getElemenntById(「25785;MyForm」)&21813;13;
しかし、このような方法は私の需要を完全に満たすことができません.前の節で解決すべき問題の一つは、どうやって問題が発生したDOMノードから逆方向に結合されたJSコードを探し出すかということでしたが、Knockoutの原生バインディング方式はJSからDOMへの一方向参照のみを要求したことを覚えています.DOMからJSへの逆参照を強制的に追加するためには、バインディングされたルート要素上のdata−vm属性を適用する必要があり、バインディングされているビューモデル名の値を持つ.
また、JSFでは頻繁にページをローカルに再レンダリングするので、結合されたルートの接合点はDOMツリーから取り除かれる可能性が高い.新しい接合点を結合する際に、古い接合点をチェックしたいです.DOMツリーから孤立した接合点に移動した場合、メモリ漏れが発生しないようにビューモデルへの参照を遮断します.
今は前のコードの中のbind方法を補完できます.
function intervalBind(vm, elem) {
// DOM
ko.applyBindings(vm, elem)
// , DOM
var parts = _.partition(vm.__elements__, function(e) {
if (document.contains) return document.contains(e)
if (document.body.contains) return document.body.contains(e)
while (elem && ko.utils.tagNameLower(elem) != "html") elem = elem.parent
return !!elem
})
vm.__elements__ = parts[0]
// DOM
_.each(parts[1], function(e) {
// , 。
// DOM DOM ,
ko.cleanNode(e)
})
//
vm.__elements__.push(elem)
// __init__
try {
if (vm.__init__) vm.__init__(elem)
} catch (e) {
win.app.console.error(e)
}
}
function bind(elem) {
var selector = elem
elem = $(elem)
var vm = this // ,this
if (elem.size() > 0) {
elem.each(function(idx, el) { // , ,
var vmName = $(this).attr("data-vm")
if (vmName == vm.__vmName__) {
if (_.indexOf(vm.__elements__, el) < 0) {
intervalBind(vm, el)
} else {
win.app.console.log("Element has already been bound to the same VM.")
win.app.console.log(selector)
}
} else {
win.app.console.error("Element must have data-vm attribute refer to " + vm.__vmName__)
win.app.console.error(this)
}
})
} else {
win.app.console.error("Element " + selector + " not found")
}
}
これから,ビューモデル上のbind法を用いて要素バインディングが可能になる.
app.vm.MyForm.bind("#MyForm")
app.createVM("MyForm", "form4").bind("#MyForm4") //
前の例は
…&噫13;
ap.create VM(MyForm).bind(「芫MyForm」)&21873;13;
(本節で終了)