JSFiddle - React, Tailwind, and code Playground
HTML
<script src="http://github.com/downloads/SteveSanderson/knockout/knockout-2.1.0.js"></script>
<div class="demo">
<input data-bind="value: NewItemText, accept: AddItem, valueUpdate: 'afterkeydown'" placeholder="アイテムテキスト">
<button data-bind="click: AddItem, enable: AddItemEnable">追加</button>
<button data-bind="click: Add5Items">てきとーに5つ追加</button>
<br>
<div class="listBox">
List-A
<ul class="sortable" data-bind="foreach: ListA, sortable: { connectWith: '.sortable' }">
<li data-bind="text: Text"><span>x</span></li>
</ul>
</div>
</div>
<div class="debugBox">
<h2>デバッグ</h2>
<p>List-A : <span data-bind="text: JsonlistA"></span></p>
</div>
CSS
.demo { clear: both; overflow: hidden; }
.listBox { margin: 20px; width: 200px; float: left; }
.debugBox { margin: 20px; }
.sortable { padding: 20px; list-style-type: none; margin: 0; background: #DDD; }
.sortable li { margin: 0 3px 3px 3px; padding: 0.4em; padding-left: 1.5em; height: 18px; }
.sortable li span.ui-icon { position: absolute; margin-left: -1.3em; }
JavaScript
/**
* @author sukobuto.com
*/
/**
* jQuery UI sortable を適用するカスタムバインディング
*/
ko.bindingHandlers['sortable'] = {
init : function(element, valueAccessor, allBindingsAccessor, viewModel) {
var config = valueAccessor();
if (!config) return;
// オプションイベントハンドラの準備
var dummyFunc = function(){};
var ehs = ko.utils.extend({
itemAdd: dummyFunc,
itemRemove: dummyFunc,
itemSort: dummyFunc,
itemDisposing: dummyFunc,
itemDisposed: dummyFunc
}, config);
var allBindings = allBindingsAccessor();
var array = allBindings.foreach
|| (allBindings.template ? allBindings.template.foreach : false);
var $list = jQuery(element);
if (array) { // foreachでリストがバインドされている場合
$list
.data('ko-sort-array', array)
.sortable(config)
.bind('sortstart', function(event, ui) {
// ドラッグを開始した際に発火するイベントのハンドラ
// 対応するアイテムをDOM要素にタグ付けする
var item = ko.dataFor(ui.item.get(0));
ui.item.data('ko-binded-item', item);
ui.item.data('ko-sort-array', array);
ui.item.data('ko-sort-index', array.indexOf(item));
}).bind('sortupdate', function(event, ui) {
// アイテムのドラッグ&ドロップが完了し、DOM要素の更新が完了した際に発火するイベントのハンドラ
// 自リストへのドロップであれば、バインドされた配列を操作して対応するアイテムを移動する
var $newList = ui.item.parent();
var item = ui.item.data('ko-binded-item');
var oldIndex = ui.item.data('ko-sort-index');
var event = { item: item, array: array, oldIndex: oldIndex };
if ($newList[0] == $list[0]) { //自リストへのドロップであるか
var oldArray = ui.item.data('ko-sort-array');
var newArray = $newList.data('ko-sort-array');
...