はじめに
Vue.js いいですよ、Vue.js。
シンプルでパワフルです。
Angular(JS)と較べて、学習コストが半端なく低い。
直感的にDOM操作を行えます。
同じくMVVMを基盤にするKnockoutJSよりもシンプルに
書けます。
日本語の情報が充実しているので、今以上に
ブレイクする可能性があると思っています。
公式サイトのガイド・APIリファレンスが有志の方のおかげで
日本語にも対応しているので、クライアントJSにあかるい方が
いれば、即採用可能な状況になっています。
コンポーネント(View Model)へのJSライブラリ組込み
v3.x
-
JSライブラリをディレクティブとしてラップし、
JSライブラリを適用する要素にディレクティブを独自属性と
して追加する -
JSライブラリをディレクティブとしてラップし、
JSライブラリを適用する要素にディレクティブを独自属性と
して追加した上で、デイレクティブを適用した要素の親要素を
コンポーネントとしてラップし、コンポーネントを独自タグとして利用する -
JSライブラリを適用する要素をコンポーネント
としてラップし、JSライブラリを適用する要素のかわりに
コンポーネントを独自タグとして利用する。場合によっては、更に
独自タグの親要素をコンポーネント化する
のどれかで、View ModelにスマートにJSライブラリを統合できます。
v2.xと同じ手法です。
Vue.js の vDOM 実装が書き直され、ディレクティブから
View Model (VM) へのアクセスのしかたが変わっています。
vnode.context
ではなくbinding.instance
で VM にアクセスします。
v3.xは、v2.x とはディレクティブetcの挙動が多少、異なりますので、
注意が必要です。
v2.x
-
JSライブラリをディレクティブとしてラップし、
JSライブラリを適用する要素にディレクティブを独自属性と
して追加する -
JSライブラリをディレクティブとしてラップし、
JSライブラリを適用する要素にディレクティブを独自属性と
して追加した上で、デイレクティブを適用した要素の親要素を
コンポーネントとしてラップし、コンポーネントを独自タグとして利用する -
JSライブラリを適用する要素をコンポーネント
としてラップし、JSライブラリを適用する要素のかわりに
コンポーネントを独自タグとして利用する。場合によっては、更に
独自タグの親要素をコンポーネント化する
のどれかで、View ModelにスマートにJSライブラリを統合できます。
v1.xでの DOM に直接アクセスする実装から、v2.xでは、vDOMを介して、DOM に
アクセスする実装に変更されたため、v2.x はv 1.x とはディレクティブetcの
挙動が異なりますので、注意が必要です。
Vue.js 2.0でtwoWayなカスタムディレクティブを実装する方法
v1.0.x
JSライブラリをディレクティブとしてラップし、
JSライブラリを適用する要素にディレクティブを独自属性と
して追加することでView ModelにスマートにJSライブラリ
を統合できます。
1.0.xでも、ディレクティブではなくコンポーネントとしてラップする
ことは可能です。
※注意
上記手法を取らず、View Modelの外側から直接
JSライブラリを適用することも可能ですが、
その場合、v-for (旧v-repeat) 等で動的に追加したDOMノード等に
対してJSライブラリを適用できません。
組込み例
jQueryプラグイン bootstrap-tokenfield (Vue1.0まで)、
tagEditor (Vue2.0以降)を上記の手法でView Modelに
組み込んでいます。
bootstrap-tokenfield
tagEdtior
1. コンポーネント(View Model)への単純な組込み
v3.x
[directive / composition api]
[directive / options api]
v2.x
[directive]
v1.0
<div id="form">
<input id="text-content" v-tokenfield="content3" type="text">
<p>
<button id="btn-change" v-on:click="on_click">Change Content by JS</button>
</p>
<p>
<button id="btn-log" v-on:click="on_click2">Check VM.content</button>
</p>
<p>{{content2}}</p>
</div>
v0.10, 0.11
<div id="form">
<input id="text-content" v-tokenfield="content3" type="text">
<p>
<button id="btn-change" v-on="click: on_click()">Change Content by JS</button>
</p>
<p>
<button id="btn-log" v-on="click: on_click2()">Check VM.content</button>
</p>
<p>{{content2}}</p>
</div>
v1.0, v0.11
$(function(){
Vue.directive('tokenfield',{
twoWay: true,
bind: function(value){
var self = this;
$(this.el).tokenfield();
$(this.el).on('tokenfield:editedtoken',function (e) {
self.set($(this).tokenfield("getTokensList", ','));
}).on('tokenfield:createdtoken', function(e){
self.set($(this).tokenfield("getTokensList", ','));
}).on('tokenfield:removedtoken', function(e){
self.set($(this).tokenfield("getTokensList", ','));
});
},
update: function(value){
$(this.el).tokenfield('setTokens',value);
}
});
var vm = new Vue({
el: '#form',
data: {
content2: '',
content3: ''
},
methods: {
on_click: function () {
this.content3 = 'hi';
},
on_click2: function () {
this.content2 = this.content3;
}
}
});
});
v1.0:
v0.11:
v0.10
$(function(){
Vue.directive('tokenfield',{
bind: function(value){
var self = this;
$(this.el).tokenfield();
$(this.el).on('tokenfield:editedtoken',function (e) {
self.vm.$set(self.key,$(this).tokenfield("getTokensList", ','));
}).on('tokenfield:createdtoken', function(e){
self.vm.$set(self.key,$(this).tokenfield("getTokensList", ','));
}).on('tokenfield:removedtoken', function(e){
self.vm.$set(self.key,$(this).tokenfield("getTokensList", ','));
});
},
update: function(value){
$(this.el).tokenfield('setTokens',value);
}
});
var vm = new Vue({
el: '#form',
data: {
content2: '',
content3: ''
},
methods: {
on_click: function () {
this.content3 = 'hi';
},
on_click2: function () {
this.content2 = this.content3;
}
}
});
});
2. v-for (旧v-repeat) のある コンポーネント(View Model)への組込み
v3.x
[directive+component / composition api]
[directive+component / options api]
v2.x
[directive+component]
v1.0
<div id="form">
<div v-for="row in contents">
<input type="text" class="tag-editor" v-tokenfield="row.content3" >
<p>
<button id="btn-log" v-on:click="on_click2(row)">Check VM.content</button>
</p>
<p>{{row.content2}}</p>
</div>
<p>
<button id="btn-change" v-on:click="on_click">Add Content by JS</button>
</p>
</div>
</div>
v1.0, v0.11
$(function(){
Vue.directive('tokenfield',{
twoWay: true,
bind: function(value){
var self = this;
$(this.el).tokenfield();
$(this.el).on('tokenfield:editedtoken',function (e) {
self.set($(this).tokenfield("getTokensList", ','));
}).on('tokenfield:createdtoken', function(e){
self.set($(this).tokenfield("getTokensList", ','));
}).on('tokenfield:removedtoken', function(e){
self.set($(this).tokenfield("getTokensList", ','));
});
},
update: function(value){
$(this.el).tokenfield('setTokens',value);
}
});
var vm = new Vue({
el: '#form',
data: {
contents: [
{
content2: '',
content3: 'wi'
},
{
content2: '',
content3: 'fi'
}
]
},
methods: {
on_click: function () {
vm.contents.push({
content2:'',
content3:''
});
},
on_click2: function(row){
row.content2 = row.content3;
}
}
});
});
v1.0:
v0.11:
$(function(){
Vue.directive('tokenfield',{
bind: function(value){
var self = this;
$(this.el).tokenfield();
$(this.el).on('tokenfield:editedtoken',function (e) {
self.vm.$set(self.key,$(this).tokenfield("getTokensList", ','))
}).on('tokenfield:createdtoken', function(e){
self.vm.$set(self.key,$(this).tokenfield("getTokensList", ','))
}).on('tokenfield:removedtoken', function(e){
self.vm.$set(self.key,$(this).tokenfield("getTokensList", ','))
});
},
update: function(value){
$(this.el).tokenfield('setTokens',value);
}
});
var vm = new Vue({
el: '#form',
data: {
contents: [
{
content2: '',
content3: 'wi'
},
{
content2: '',
content3: 'fi'
}
]
},
methods: {
on_click: function () {
vm.contents.push({
content2:'',
content3:''
});
},
on_click2: function (row) {
row.content2 = row.content3;
}
}
});
});
##最後に
組込み例の詳しい解説は書きません。
簡単なので、頑張って?理解してください。
レッツ・トライ、Vue.js。