2年前の記事、「【Monaca】ons-list-itemをドラッグ&ドロップで並び替える」および「【Monaca】ons-list-itemをドラッグ&ドロップで並び替える・その2」で紹介した方法は、Onsen UI V1とjQueryを使用したが、今回はjQueryを使用せず、Onsen UI V2と「Sortable」を一部改造して実現してみた。
MonacaクラウドIDEで、新しいプロジェクト「Onsen UI V2 Angular 1 Minimum」を作成し、各コードを準備する。
SortableはY軸のほかにX軸の移動もできてしまうため、ons-list-itemのドラッグ&ドロップには都合が悪い。
そこで、オプションにverticalプロパティを新たに追加し、X軸のドラッグを制限するように下記コードのハイライト箇所の行を追加・変更する。
Sortable.js
260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 |
// Default options var defaults = { group: null, sort: true, disabled: false, store: null, handle: null, scroll: true, scrollSensitivity: 30, scrollSpeed: 10, draggable: /[uo]l/i.test(el.nodeName) ? 'li' : '>*', ghostClass: 'sortable-ghost', chosenClass: 'sortable-chosen', dragClass: 'sortable-drag', ignore: 'a, img', filter: null, preventOnFilter: true, animation: 0, setData: function (dataTransfer, dragEl) { dataTransfer.setData('Text', dragEl.textContent); }, dropBubble: false, dragoverBubble: false, dataIdAttr: 'data-id', delay: 0, touchStartThreshold: parseInt(window.devicePixelRatio, 10) || 1, forceFallback: false, fallbackClass: 'sortable-fallback', fallbackOnBody: false, fallbackTolerance: 0, fallbackOffset: {x: 0, y: 0}, supportPointer: Sortable.supportPointer !== false, vertical: true }; |
598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 |
_onTouchMove: function (/**TouchEvent*/evt) { if (tapEvt) { var options = this.options, fallbackTolerance = options.fallbackTolerance, fallbackOffset = options.fallbackOffset, touch = evt.touches ? evt.touches[0] : evt, dx = options.vertical ? 0 : (touch.clientX - tapEvt.clientX) + fallbackOffset.x, dy = (touch.clientY - tapEvt.clientY) + fallbackOffset.y, translate3d = evt.touches ? 'translate3d(' + dx + 'px,' + dy + 'px,0)' : 'translate(' + dx + 'px,' + dy + 'px)'; // only set the status to dragging, when we are actually dragging if (!Sortable.active) { if (fallbackTolerance && min(abs(touch.clientX - this._lastX), abs(touch.clientY - this._lastY)) < fallbackTolerance ) { return; } this._dragStarted(); } // as well as creating the ghost element on the document body this._appendGhost(); moved = true; touchEvt = touch; _css(ghostEl, 'webkitTransform', translate3d); _css(ghostEl, 'mozTransform', translate3d); _css(ghostEl, 'msTransform', translate3d); _css(ghostEl, 'transform', translate3d); evt.preventDefault(); } }, |
index.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
<!DOCTYPE HTML> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"> <meta http-equiv="Content-Security-Policy" content="default-src * data: gap: https://ssl.gstatic.com; style-src * 'unsafe-inline'; script-src * 'unsafe-inline' 'unsafe-eval'"> <script src="components/loader.js"></script> <script src="lib/angular/angular.min.js"></script> <script src="lib/onsenui/js/onsenui.min.js"></script> <script src="lib/onsenui/js/angular-onsenui.min.js"></script> <link rel="stylesheet" href="components/loader.css"> <link rel="stylesheet" href="lib/onsenui/css/onsenui.css"> <link rel="stylesheet" href="lib/onsenui/css/onsen-css-components.css"> <link rel="stylesheet" href="css/style.css"> <script src="js/Sortable.js"></script> <script src="js/app.js"></script> </head> <body> <ons-page ng-controller="indexController"> <ons-toolbar> <div class="center">Sortable Test</div> </ons-toolbar> <ons-list move-list-item> <ons-list-item ng-repeat="item in list"> <ons-row> <ons-col width="10%"> <div class="div-drag"> <ons-icon icon="ion-drag" class="icon-drag"></ons-icon> </div> </ons-col> <ons-col width="90%"> {{item.name}} </ons-col> </ons-row> </ons-list-item> </ons-list> </ons-page> </body> </html> |
style.css
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
.list-item-ghost { } .list-item-chosen { opacity: 0.4; background-color: #ccc; } .list-item-drag { font-weight: bolder; background-color: #ff8; } .div-drag { position: relative; width: 100%; height: 100%; text-align: center; } .icon-drag { position: absolute; top: 50%; left: 50%; -webkit-transform: translate(-50%, -50%); transform: translate(-50%, -50%); width: 100%; height: 100%; } |
app.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
"use strict"; var app = ons.bootstrap("myApp", ["onsen"]); app.directive("moveListItem", ["$compile", function ($compile) { return { restrict: "A", link: function (scope, elem, attr) { var sortedListitem = function (e) { if (e.oldIndex != e.newIndex) { scope.list.splice(e.newIndex, 0, scope.list.splice(e.oldIndex, 1)[0]); } }; elem.ready(function () { scope.sortable = new Sortable(elem[0], { group: "jra", delay: 300, // 300ms後にドラッグを開始する ghostClass: "list-item-ghost", // 不要? chosenClass: "list-item-chosen", // 選択されたons-list-itemに設定するCSSクラス dragClass: "list-item-drag", // ドラッグ中のons-list-itemに設定するCSSクラス handle: "ons-icon", // ドラッグが有効となるタグ onEnd: sortedListitem, // ドラッグ終了後にコールバックする関数 vertical: true // X軸の移動を無効にする }); }); } }; }]); app.controller("indexController", ["$scope", function ($scope) { $scope.list = [ { id: 1, name: "C.ルメール" }, { id: 2, name: "M.デムーロ" }, { id: 3, name: "戸崎圭太" }, { id: 4, name: "福永祐一" }, { id: 5, name: "川田将雅" }, { id: 6, name: "田辺裕信" }, { id: 7, name: "北村友一" }, { id: 8, name: "松山弘平" }, { id: 9, name: "和田竜二" }, { id: 10, name: "内田博幸" }, { id: 11, name: "石橋脩" }, { id: 12, name: "藤岡佑介" }, { id: 13, name: "岩田康誠" }, { id: 14, name: "武豊" }, { id: 15, name: "大野拓弥" }, { id: 16, name: "藤岡康太" }, { id: 17, name: "幸英明" }, { id: 18, name: "池添謙一" }, { id: 19, name: "北村宏司" }, { id: 20, name: "浜中俊" } ]; }]); |