Добавление переупорядочения и перетаскивания в ListView
[ Эта статья адресована разработчикам приложений среды выполнения Windows для Windows 8.x и Windows Phone 8.x. В случае разработки приложений для Windows 10 см. раздел последняя документация]
Сведения о том, как добавить переупорядочение и перетаскивание элементов в элемент управления ListView. (только Windows)
Что необходимо знать
Технологии
Необходимые условия
Вы должны уметь создавать простое приложение Магазина Windows на JavaScript, в котором используются элементы управления WinJS. Указания по началу работы с элементами управления WinJS см. в статье Краткое руководство. Добавление элементов управления и стилей WinJS.
Прежде чем добавлять дополнительные функции, нужно научиться создавать простой элемент управления ListView. Краткий обзор создания простого элемента управления ListView см. в разделе Краткое руководство: добавление элемента ListView или в справочнике по элементу управления ListView.
Инструкции
Этап 1: Настройка примера
В этом примере показано, как создать элемент управления ListView и контейнер ItemContainer для отображения сведений об элементе в списке.
Используйте следующую разметку HTML в качестве основы для элемента управления ListView. Вы можете скопировать и вставить этот код в файл default.html из шаблона Пустое приложение в Microsoft Visual Studio 2013.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>List_View_demo</title>
<!-- WinJS references -->
<link href="//Microsoft.WinJS.2.0/css/ui-dark.css" rel="stylesheet" />
<script src="//Microsoft.WinJS.2.0/js/base.js"></script>
<script src="//Microsoft.WinJS.2.0/js/ui.js"></script>
<!-- List_View_demo references -->
<link href="/css/default.css" rel="stylesheet" />
<script src="/js/default.js"></script>
<script src="js/data.js"></script>
</head>
<body>
<div id="listViewTemplate">
<div id="listTemplate"
data-win-control="WinJS.Binding.Template">
<div class="listTemplate">
<div>
<h4 data-win-bind="innerText: title"></h4>
<h6 data-win-bind="innerText: text"></h6>
</div>
</div>
</div>
<div id="listView"
data-win-control="WinJS.UI.ListView"
data-win-options="{
itemDataSource : DataExample.itemList.dataSource,
itemTemplate: select('#listTemplate'),
itemsDraggable: true,
itemsReorderable: true,
layout: { type: WinJS.UI.GridLayout }
}">
</div>
</div>
<div id="listViewDetail" >
<h2>Details</h2><br/><br/>
<div id="listViewDetailInfo"
draggable="true"
data-win-control="WinJS.UI.ItemContainer">
<h4>Cherry chocolate swirl</h4>
<h6>Ice cream</h6>
<p>Description:
<span>A sumptious blending of cherry
and dark chocolate.</span>
</p>
</div>
</div>
</body>
</html>
В примере также используются стили CSS для настройки элемента управления ListView и контейнера ItemContainer на HTML-странице. Добавьте приведенный ниже код CSS в таблицу стилей, связанную с элементом управления ListView (css/default.css в шаблоне Пустое приложение).
/* Layout the app page as a grid. */
body {
display: -ms-grid;
-ms-grid-columns: 600px 1fr;
-ms-grid-rows: 1fr;
}
/* Style the template for the ListView control.
.listTemplate {
width: 282px;
height: 70px;
padding: 5px;
overflow: hidden;
}
.listTemplate div {
margin: 5px;
}
/* Style the ListView control. */
#listView {
-ms-grid-column: 1;
-ms-grid-row: 1;
height: 500px;
width: 500px;
border: 2px solid gray;
}
#listView .win-container {
margin: 10px;
}
#listView .win-container:hover {
color: red;
}
/* Style the ItemContainer control.*/
#listViewDetail {
-ms-grid-column: 2;
-ms-grid-row: 1;
}
#listViewDetailInfo {
width: 300px;
}
В примере используются некоторые предопределенные данные для заполнения элемента управления ListView. Эти данные содержатся в файле data.js, который находится в папке js (js/data.js). Чтобы добавить данные ListView в приложение, следуйте приведенным далее инструкциям.
Добавление файла данных JavaScript в приложение
В окне Обозреватель решений щелкните правой кнопкой мыши папку js и выберите пункты Добавить > Новый файл JavaScript.
В диалоговом окне Добавление нового элемента в поле Имя введите "data.js" и нажмите кнопку Добавить.
В окне Обозреватель решений дважды щелкните новый файл JavaScript и добавьте следующий код.
(function () { "use strict"; // Define the dataset. var dataArray = [ { title: "Basic banana", text: "Low-fat frozen yogurt", description: "Go bananas for some frozen yogurt." }, { title: "Banana blast", text: "Ice cream", description: "More banana than allowed by law." }, { title: "Brilliant banana", text: "Frozen custard", description: "Custard with banana; an excellent desert." }, { title: "Orange surprise", text: "Sherbet", description: "Orange sherbert with a little extra something." }, { title: "Original orange", text: "Sherbet", description: "The orange sherbert you know and love." }, { title: "Vanilla", text: "Ice cream", description: "The one and only, classic vanilla ice cream." }, { title: "Very vanilla", text: "Frozen custard", description: "What's better than custard with vanilla flavoring?" }, { title: "Marvelous mint", text: "Gelato", description: "Mint meets gelato in this delicious desert." }, { title: "Succulent strawberry", text: "Sorbet", description: "A joyful confection of strawberries." } ]; // Load the dataset into a List object. var dataList = new WinJS.Binding.List(dataArray); // Expose the List object to the rest of the app. WinJS.Namespace.define("DataExample", { itemList: dataList }); })();
Примечание Приведенные данные можно заменить любыми другими по своему усмотрению. Чтобы заменить источник данных, можно изменить набор данных, передаваемый в метод конструктора WinJS.Binding.List.
Если вы хотите использовать источник данных, отличный от объекта IListDataSource, он должен реализовать методы moveBefore, moveAfter и moveToStart. На практике рекомендуется заключать источник данных в объект List, предоставляемый WinJS.
Также обратите внимание, что объект Template, определенный в разметке HTML для приложения, использует источник данных, содержащий элементы со свойствами title
и text
. Если ваши данные не содержат свойств title
или text
, необходимо скорректировать определение объекта Template.
Этап 2: Добавление возможностей переупорядочения в элемент управления ListView
Добавить возможности переупорядочения в элемент управления ListView очень легко. Для этого требуется лишь незначительное изменение или дополнение кода. В общем случае нужно просто задать для свойства itemsReorderable элемента управления ListView значение "true". (Значение по умолчанию — "false".)
Можно декларативно задать это свойство в разметке HTML для элемента управления либо добавить эту возможность во время выполнения при помощи JavaScript. В следующем примере показано, как добавить возможность переупорядочения, скорректировав разметку HTML для элемента управления.
<!-- The definition of the ListView control.
Note that the data-win-options attribute for the
control includes the itemsReorderable property. -->
<div id="listView"
data-win-control="WinJS.UI.ListView"
data-win-options="{
itemDataSource : DataExample.itemList.dataSource,
itemTemplate: select('#listTemplate'),
itemsReorderable : true,
layout: { type : WinJS.UI.GridLayout }
}">
</div>
Затем продемонстрировано добавление возможности переупорядочения в элемент управления ListView во время выполнения при помощи JavaScript.
(function () {
// Other JavaScript code ...
// Get a reference to the ListView control.
var listView =
document.querySelector('#listView').winControl;
// Set the controls itemsReorderable property.
listView.itemsReorderable = true;
// Other JavaScript code ...
})();
Изменив свойство itemsReorderable элемента управления ListView, запустите проект (нажмите клавишу F5). Выберите элемент в ListView и перетащите его в другое расположение в том же элементе ListView.
Этап 3: Добавление функции перетаскивания в ListView
На базовом уровне добавить функцию перетаскивания в элемент управления ListView так же легко, как и возможность переупорядочения. Элемент управления ListView содержит свойство itemsDraggable, которое можно задать декларативно в разметке HTML для элемента управления либо изменить во время выполнения.
В следующем примере показано, как добавить простую функцию перетаскивания в ListView в разметке HTML для этого элемента управления.
<!-- The definition of the ListView control.
Note that the data-win-options attribute for the
control includes the itemsDraggable property. -->
<div id="listView"
data-win-control="WinJS.UI.ListView"
data-win-options="{
itemDataSource : DataExample.itemList.dataSource,
itemTemplate: select('#listTemplate'),
itemsDraggable : true,
layout: { type : WinJS.UI.GridLayout }
}">
</div>
Затем продемонстрировано добавление простой функции перетаскивания в элемент управления ListView во время выполнения при помощи JavaScript.
(function () {
// Other JavaScript code ...
// Get a reference to the ListView control.
var listView =
document.querySelector('#listView').winControl;
// Set the controls itemsReorderable property.
listView.itemsDraggable = true;
// Other JavaScript code ...
})();
Задав для свойства itemsDraggable значение "true", запустите приложение (нажмите клавишу F5). В приложении выберите элемент из элемента управления ListView и перетащите его за пределы ListView. Будет создана копия элемента через интерфейс приложения за пределами ListView. Когда вы отпустите кнопку мыши, элемент исчезнет. Затем создаются соответствующие события перетаскивания.
Чтобы взаимодействовать с базовым источником данных элемента управления ListView, необходимо также реализовать обработчики некоторых событий перетаскивания ListView. В следующем примере был добавлен обработчик события ListView.itemdragstart, а также события dragover и drop контейнера ItemContainer.
Чтобы использовать этот код с предыдущим образцом, добавьте его в обработчик событий app.onactivated, определенный в файле default.js из шаблона Blank app (js/default.js).
// Get the data from the ListView when the user drags an item.
listView.addEventListener("itemdragstart", function (evt) {
// Store the index of the item from the data source of
// the ListView in the DataTransfer object of the event.
evt.detail.dataTransfer.setData("Text",
JSON.stringify(evt.detail.dragInfo.getIndices()));
});
// Allows the drop to occur. The default behavior disallows
// an element from being dropped upon another.
listViewDetailInfo.addEventListener('dragover', function (evt) {
evt.preventDefault();
});
// Insert the content (from the ListView) into the ItemContainer.
listViewDetailInfo.addEventListener('drop', function (evt) {
// Get the index of the selected item out of the event object.
var dragIndex = JSON.parse(evt.dataTransfer.getData("Text")),
dataSource = listView.winControl.itemDataSource;
// Extract the selected data from the data source
// connected to the ListView control.
dataSource.itemFromIndex(Number(dragIndex)).
then(function (item) {
if (item) {
var itemData = item.data;
// Update the ItemContainer with the data from
// the item dragged from the ListView control.
listViewDetailInfo.querySelector('h4').innerText = itemData.title;
listViewDetailInfo.querySelector('h6').innerText = itemData.text;
istViewDetailInfo.querySelector('span').innerText = itemData.description;
}
});
});
В предыдущем примере выбранные данные, перетащенные из ListView, были сохранены в объекте DataTransfer, связанном с событием itemdragstart. Поскольку оба обработчика могут обращаться к одному и тому же источнику данных, сохраняется только индекс выбранного элемента. В противном случае вы можете сериализовать объект как строку в формате JSON в объекте DataTransfer.
В обработчике события dragover для ItemContainer обработка по умолчанию (запрет перетаскивания одного элемента на другой) блокируется. В обработчике событий drop для объекта ItemContainer индекс выбранного элемента из источника данных извлекается из объекта DataTransfer, а затем элемент извлекается из источника данных ListView. Наконец, HTML-код контейнера ItemContainer изменяется с учетом новых данных.
Примечание Если в приложении выполняется переупорядочение или перетаскивание элементов между группами в элементе управления ListView, необходимо удалить элементы из источника данных, а затем вставить их в новую группу. Для решения этой задачи нельзя использовать методы moveAfter, moveBefore или moveToStart.
Этап 4: Добавление функции перетаскивания в ListView
Добавить функцию перетаскивания в элемент управления ListView можно таким же образом, как мы добавляли ее в ItemContainer в предыдущем примере.
Чтобы добавить возможность перетаскивания данных из ItemContainer в ListView, воспользуйтесь следующим примером кода.
Чтобы использовать этот код с предыдущим образцом, добавьте его в обработчик событий app.onactivated, определенный в файле default.js из шаблона Blank app (js/default.js).
// Drop content (from the ItemContainer) onto the ListView control.
listView.addEventListener("itemdragdrop", function (evt) {
if (evt.detail.dataTransfer) {
var dragData = JSON.parse(
evt.detail.dataTransfer.getData("Text"));
// It's a good idea to validate the data before
// attempting to insert it into the data source!
if (dragData && dragData.title && dragData.text) {
var dropIndex = evt.detail.insertAfterIndex;
// Insert the new item into the data source.
DataExample.itemList.splice(dropIndex, 0, {
title: dragData.title,
text: dragData.text,
description: dragData.description
});
}
}
});
// Allows the drop to occur. The default behavior disallows
// an element from being dropped upon another.
listView.addEventListener("itemdragenter", function (evt) {
if (evt.detail.dataTransfer &&
evt.detail.dataTransfer.types.contains("Text")) {
evt.preventDefault();
}
});
// Drag content from the ItemContainer.
listViewDetailInfo.addEventListener('dragstart', function (evt) {
// Get the data displayed in the ItemContainer and
// store it in an anonymous object.
var target = evt.target,
title = target.querySelector('h4').innerText,
text = target.querySelector('h6').innerText,
description = target.querySelector('span').innerText,
dragData = {
source: target.id,
title: title,
text: text,
description: description
};
// Store the data in the DataTransfer object as a
// JSON-formatted string.
evt.dataTransfer.setData("Text",
JSON.stringify(dragData));
});
В предыдущем примере кода был добавлен обработчик событий dragstart для контейнера ItemContainer, а также события itemdragenter и itemdragdrop элемента управления ListView. Обработчик событий ItemContainer.dragstart извлекает данные из ItemContainer и сохраняет их в объекте DataTransfer, связанном с событием, в виде строки в формате JSON. В обработчике событий ListView.onitemdragenter обработка события по умолчанию блокируется, чтобы содержимое HTML можно было перетаскивать на элемент управления ListView. Наконец, при возникновении события ListView.onitemdragdrop данные извлекаются из объекта DataTransfer и вставляются в источник данных элемента управления ListView.
Примечание Если пользователь попытается переупорядочить элемент управления ListView при помощи клавиатуры, объект DataTransfer, передаваемый в качестве аргумента событию itemdragdrop, будет не определен. В обработчике событий itemdragdrop нужно убедиться в существовании объекта DataTransfer перед считыванием данных, которые он содержит.
Примечания
Подробнее об использовании элементов управления ListView и добавлении возможностей переупорядочения и перетаскивания в элементы управления ListView см. в примере перетаскивания и переупорядочения элемента управления HTML ListView.
Полный пример
Связанные разделы
Пример перетаскивания и переупорядочения элемента управления ListView на HTML