Http://www.sitepen.com/blog/2011/12/05/dojo-drag-n-drop-redux/
Author: Colin snover
Translator: Ruan Qi
As one of the basic functions of dojo, you can drag and drop page elements or objects between multiple containers visually. Dojo/DND also supports dragging multiple objects at the same time. In addition, you can set rules to filter the target containers of drag-and-drop objects. For example, "tables" should be placed in "Furniture" containers, it should not be placed in the "appliance" container. The following is an interesting story about how to use the dojo drag function.
1. Drag and Drop in a single container
First, let's introduce Dylan. The biggest hobby of Dylan is to collect old and used goods. Just now, he decided to remove some of the old goods and make room for new junk goods. No, he rented a store and started a small business for the old store. Like all ambitious store owners, Dylan also decided to open an online store to sell his old goods. Dylan has a younger brother who is pursuing a degree in a market economy. He suggested building his own brand to make Dylan's old online store stand out. The two brothers decided to use Dylan 'soriginal as their trademark. Dylan decided to add a cool-to-Mess user experience function to its online stores, so customers could not help but buy their home's second-hand old products. So Dylan invited us here. We gave him a demo called Dylan's original junkoutlet to demonstrate the drag-and-drop effect on the page.
We use the basic drag-and-drop function to demonstrate a list that can be dynamically sorted by users. First, you must complete the overall UI framework of the page, and import the dojo toolkit and a little bit of CSS. See the original page.
You can see that this page contains a simple list of second-hand goods Dylan recently wants to sell: watches, life jackets, toy bulldozers, vintage mobile phones, and a toy plane.
<div id="store"><div class="wishlistContainer">
Drag the basic class: dojo/DND/source
Dojo provides the dojo. DND. the source class implements the drag-and-drop effect. The source class is equivalent to a container, and the objects contained in it have the ability to be dragged and dropped, in the following sections, "internal objects" are used to refer to the Child items that can be pulled multiple times in source. The following code (the dojo version of the relevant code in this article is 1.7) implements a drag-and-drop list of internal objects:
require([ "dojo/dnd/Source", "dojo/domReady!" ], function(Source){ var wishlist = new Source("wishlistNode"); wishlist.insertNodes(false, [ "Wrist watch", "Life jacket", "Toy bulldozer", "Vintage microphone", "TIE fighter" ]);});
That's all. Check the sortable list. If you prefer to create a dojo control through declaration, see the following code:
<ol data-dojo-type="dojo.dnd.Source" id="wishlistNode" class="container"> <li class="dojoDndItem">Wrist watch</li> <li class="dojoDndItem">Life jacket</li> <li class="dojoDndItem">Toy bulldozer</li> <li class="dojoDndItem">Vintage microphone</li> <li class="dojoDndItem">TIE fighter</li></ol>
The running results of the two are identical. See the sortable list created by declaration.
Create a drag-and-drop list using declarative statements. dojo. DND. Source creates different subnodes Based on the HTML tag of the container, mainly including the following:
- If the container is <div> or <p>, the sub-node is <div>.
- If the container is <ul> or <ol>, the sub-node is <li>.
- If the container is <Table>, create <tbody> first, and then add the subnode <tr> <TD> under <tbody>.
- In other cases, the sub-node situation is <span>.
The following describes some common functions of dojo. DND. Source:
- Select multiple.Dragging multiple objects at the same time is a basic requirement. Of course, dojo. DND. source supports this function. The operation method complies with the standard: Ctrl + mouse click, or SHIFT + mouse click.
- Internal Object Management. In addition to the insernodes method shown above, dojo. DND. source also provides a number of methods to operate internal objects:
- Getallnodes ()-returns all internal objects in the case of dojo. nodelist.
- Forinitems (FN, CTX)-similar to dojo. foreach, it traverses all internal objects.
- Selectnone (), selectall (), getselectednodes (), and deleteselectednodes ()-the function is the same as that for naming: all are not selected, all are selected, the selected object is returned, and the selected object is deleted.
- For more information, see dojoreference guide.
- Copy internal objects. When you select an object and move the mouse, the selected object is dragged. If you press Ctrl before the selection, the previous operation will copy and drag the selected object.
Undrag. Click esc to cancel the drag.
Custom drag-and-drop icon. You can customize the icon automatically generated during drag and drop, which will be described in detail below.
Drag and Drop between two containers
Of course, if the page only provides the function of dragging objects in a single list, it is not enough to impress users. So we upgraded the online shop UI of Dylan: Please refer to the new online shop page.
What content have we added? First, there are three lists on the page: Catalog, cart, and wishlist ). Now you can drag and drop items between the three lists. Some items marked as "out" cannot be dragged to the shopping cart.
Drag and Drop object type
The new version introduces the drag-and-drop object type. Note the accept and type attributes in the following code:
require([ "dojo/dom-class", "dojo/dnd/Source", "dojo/domReady!" ], function(domClass, Source){ var catalog = new Source("catalogNode", { accept: [ "inStock", "outOfStock" ] }); catalog.insertNodes(false, [ { data: "Wrist watch", type: [ "inStock" ] }, { data: "Life jacket", type: [ "inStock" ] }, { data: "Toy bulldozer", type: [ "inStock" ] }, { data: "Vintage microphone", type: [ "outOfStock" ] }, { data: "TIE fighter", type: [ "outOfStock" ] }, { data: "Apples", type: [ "inStock" ] }, { data: "Bananas", type: [ "inStock" ] }, { data: "Tomatoes", type: [ "outOfStock" ] }, { data: "Bread", type: [ "inStock" ] } ]); catalog.forInItems(function(item, id, map){ domClass.add(id, item.type[0]); }); var cart = new Source("cartNode", { accept: [ "inStock" ] }); var wishlist = new Source("wishlistNode", { accept: [ "inStock", "outOfStock" ] });});
The code for creating three lists through declaration is as follows:
<div class="catalogContainer">
Each drag-and-drop object can be specified with one or more types. If the type list matches the accept list of the container, the object can be placed in the corresponding container. Otherwise, the object will not work. The default values of type and accept are "text ".
Here, we use "instock" and "outofstock" to identify whether the product is out of stock, which also determines whether the product can be dragged to the "Shopping Cart" list. If you drag and drop "goods in stock" and "out of stock" to the shopping cart at the same time, the entire drag and drop will fail.
So far, Dylan's old online store looks good. However, there are several issues that need to be solved:
- After the items in the "directory" are added to the "Shopping Cart" or "Favorites list", they disappear from the "directory. The same item cannot be added to the "Shopping Cart" or "Favorites list" at the same time unless you use the copy operation. This greatly affects the user experience.
- If you use the copy operation, multiple duplicate items may appear in the same list.
- There are only three lists on the page, which is a bit monotonous and the user experience needs to be further improved.
Next we will continue to improve our page.
3. Custom list items
As we have mentioned before, objects in the drag-and-drop list can be customized. Dylan wants his product catalog to provide product images, descriptions, and inventory quantity. According to his needs, the product data structure should look like this:
{ name: "Wrist watch", image: "watch.jpg", description: "Tell time with Swiss precision", quantity: 3}
Dojo. DND provides a method for customizing internal objects-The Creator function. The following is a sample code:
Define (["dojo/string", "dojo/dom-construct", "dojo/dom-class", "dojo/DND/source", "dojo/Text !. /Itemtemplate.html "," dojo/Text !. /Avatartemplate.html "], function (stringutil, domconstruct, domclass, source, template, avatartemplate) {// old product data var junk = [{name:" wrist watch ", image: "watch.jpg", Description: "Tell time with Swiss precision", quantity: 3 },{ name: "life jacket", image: "life-jacket.jpg", description: "stay afloat during your frequent shipwrecks", quantity: 1},...]; // construct the function catalognodecreator (item, Hint) {var node = domconstruct. todom (stringutil. substitute (hint = "Avatar "? Avatartemplate: Template, {Name: item. name | "product", imageurl: "images/" + (item. image | "_blank.gif"), quantity: item. quantity | 0, Description: item. description? "<Br> <span" + item. Description + "</span>": ""}), type = item. quantity? ["Instock"]: ["outofstock"]; return {node: node, data: item, type: Type };} // create the source and import the old data var junkcatalog = new source ("junkcatalogcontainer", {Creator: catalognodecreator}); junkcatalog. insertnodes (false, junk );});
The following is the template(itemtemplate.html In the intent Code) of the internal object ):
<tr> <td class="itemImg dojoDndHandle"></td> <td class="itemText">${name} ${description}</td> <td class="itemQty">${quantity}</td></tr>
This is the template(avatartemplate.html) of the object when we drag the object ):
<table> <tr> <td class="itemImg"></td> <td class="itemText">${name}</td> </tr></table>
Demonstrate the differences between item and Avatar:
Here are some changes to the product catalog:
- To facilitate the layout, we use table as the container of the commodity list. We can see that the itemtemplate above is also changed to <tr> <TD>.
- The product dynamically marks its type value based on the inventory quantity.
- The Creator function in the dojo. DND. Source constructor also accepts the hint parameter. When the hint is set to "Avatar", the Creator function constructs the dom structure of the dragged object.
Let's take a look at the updated Dylan's original outlet store.
The new version of the page seems to have been greatly improved. In addition to the product list divided into the old product list and the food list, the favorite list and shopping cart list are put into dijit. titlepane saves a lot of page space.
Dojo. DND. Target
var cart = new Target("cartPaneNode", { accept: [ "inStock" ] });
Here we introduce a new class: dojo. DND. Target. In fact, target is a source that can only be dragged, which is equivalent to setting the issource attribute in the source class to false. Interestingly, the issource attribute can also be changed at runtime, which is shown in the following example.
Drag and Drop changes to the target container
cart.parent =dom.byId("cartNode");
Products dragged to cart will directly create subnodes under cartpanenode. However, after cart. parent is assigned a value, all products dragged to cartpanenode will<table id="cartNode">
Create a subnode.
Next we will introduce some additional features of dojo drag-and-drop based on our old stores.
4. Listen to drag-and-drop events
"Subscription/release" is applied to the drag and drop of dojo to handle event response. Here we first use the aspect mode to handle the ondrop event.
// sets the count of items in a TitlePanefunction setListCount(){ query(".count", this.node)[0].innerHTML = this.getAllNodes().length;} // update the cart’s displayed item count when dropped onaspect.after(cart, "onDrop", setListCount); // update the wishlist’s displayed item count when dropped onaspect.after(wishlist, "onDrop", setListCount);
When the ondrop event is triggered, the number of items displayed in the list is updated. Note that the ondrop event is triggered only when the object is dragged to the container that accepts it, And the ondnddrop event is triggered when the object is dragged to any location on the page.
Directly listen to topics
Next we will use the subscription/publish mode to add some dynamic effects to our old goods shop: When the drag starts, the highlighted container can accept the drag object.
// Highlight the available container function highlighttargets (show, source, nodes) {domclass. toggle ("wishlistpanenode", "highlight", show); domclass. toggle ("cartpanenode", "highlight", show & arrayutil. every (nodes, function (node) {return domclass. contains (node, "instock");} // function glowtarget (source, nodes, copy, target) {domclass. add (target. node, "Glow"); setTimeout (Lang. hitch (domclass, "Remove", target. node, "Glow"), 1000);} // start the drag action // (/DND/start) topic. subscribe ("/DND/start", Lang. partial (highlighttargets, true); // drag the end Of the action // (/DND/cancel or/DND/drop) topic. subscribe ("/DND/cancel,/DND/drop", Lang. partial (highlighttargets, false); topic. subscribe ("/DND/drop", glowtarget );
Avoid repeated object Replication
The problem of object multi-copy mentioned in the previous article is also easy to solve, as long as the dojo. DND. if copyonly: True is set for source, source does not remove the internal object at the beginning of the drag-and-drop operation, but only copies are dragged and dropped. In addition, setting selfaccept: false can prevent repeated problems caused by dragging the copy back to the source container.
The final version of our old store is as follows:
Summary
The steps for creating an old store are as follows:
- Build a page framework;
- Drag a single list;
- Drag Multiple lists;
- You can drag and drop the custom list items;
- Event monitoring and processing;
We also provide source code download for the demo of the old goods shop, happy dragging and dropping!