Muuri 能够创建响应式，可排序，可过滤和可拖动的网格布局。

Muuri

Muuri creates responsive, sortable, filterable and draggable grid layouts. Yep, that's a lot of features in one library, but we have tried to make it as tiny as possible. Comparing to what's out there Muuri is a combination of Packery, Masonry, Isotope and jQuery UI sortable. Wanna see it in action? Check out the demo on the website.

Muuri's layout system allows positioning the grid items within the container in pretty much any way imaginable. The default "First Fit" bin packing layout algorithm generates similar layouts as Packery and Masonry. The implementation is heavily based on the "maxrects" approach as described by Jukka Jylänki in his research A Thousand Ways to Pack the Bin. However, you can also provide your own layout algorithm to position the items in any way you want.

Muuri uses Velocity for animating the grid items (positioining/showing/hiding) and Hammer.js for handling the dragging. Hammer.js is an optional dependency that is only required if dragging is enabled, but Velocity is a hard dependency.

And if you're wondering about the name of the library "muuri" is Finnish meaning a wall.

A word of warning. Muuri is currently under active development and might be still a bit rough on the edges so production use is not recommended just yet. But when did that ever stop you ;)

Getting started

Hammer.js (2.0.x) optional, required only if you are using the dragging feature

First, include Muuri and it's dependencies in your site.

<scriptsrc="velocity.js"></script>
<scriptsrc="hammer.js"></script>
<!-- Needs to be within in body element or have access to body element -->
<scriptsrc="muuri.js"></script>

An important note for including Muuri to your site is that it needs to have access to the body element when it's loaded. Muuri does some feature checking on init and might not work correctly if it does not have access to the body element.

Then, define your grid markup.

Every grid must have a container element and item element(s) within the container element.

A grid item must always consist of at least two elements. The outer element is used for positioning the item and the inner element (first direct child) is used for animating the item's visibility (show/hide methods). You can insert any markup you wish inside the inner item element.

The grid element must be "positioned" meaning that it's CSS position property must be set to relative, absolute or fixed. Also note that Muuri automatically resizes the container element depending on the area the items cover.

The item elements must have their CSS position set to absolute and their display property set to block, unless of course the elements have their display set to block inherently.

The item elements must not have any CSS transitions or animations applied to them since it might conflict with Velocity's animations.

You can control the gaps between the tiles by giving some margin to the item elements.

var grid =newMuuri({
container:document.getElementsByClassName('grid')[0],
// Muuri does not convert a node list to array automatically// so we have to do it manually.
items: [].slice.call(document.getElementsByClassName('item'))
});

Options

container — element

Default value: null.

The container element. Must be always defined.

items — array of elements

Default value: [].

The initial item elements wrapped in an array. The elements must be children of the container element.

positionDuration — number

Default value: 300.

The duration for item's positioning animation in milliseconds. Set to 0 to disable.

The object should contain duration (integer, milliseconds) and easing properties. Set to null to disable hide animation altogether.

hide — object

Default value: {duration: 300, easing: "ease-out"}.

The object should contain duration (integer, milliseconds) and easing properties. Set to null to disable hide animation altogether.

layout — array / function / string

Default value: "firstFit".

Define the layout method to be used for calculating the positions of the items. If you provide a string or an array Muuri will try to locate a registered layout method in Muuri.Layout.methods object. Currently there is only one built-in method: "firstFit".

The array syntax is the only way to use the built-in layout methods and provide arguments for them. The first value should be a string (name of the method) and the second value (optional) should be a configuration object, e.g. ["firstFit", {horizontal: true}].

You can always just provide a function which will receive a Muuri.Layout instance as it's context which you can manipulate as much as you want to get the items to the wanted positions. More info about rolling your own layout method is coming up later on, but in the meantime you can check the source code and see how the default method is implemented.

Available methods and related settings:

"firstFit"

horizontal (type: boolean, default: false)

When true the grid works in landscape mode (grid expands to the right). Use for horizontally scrolling sites. When false the grid works in "portrait" mode and expands downwards.

alignRight (type: boolean, default: false)

When true the items are aligned from right to left.

alignBottom (type: boolean, default: false)

When true the items are aligned from the bottom up.

fillGaps (type: boolean, default: false)

When true the algorithm goes through every item in order and places each item to the first available free slot, even if the slot happens to be visually before the previous element's slot. Practically this means that the items might not end up visually in order, but there will be less gaps in the grid. By default this options is false which basically means that the following condition will be always true when calculating the layout: nextItem.top > prevItem.top || (nextItem.top === prevItem.top && nextItem.left > prevItem.left). This also means that the items will be visually in order.

layoutOnResize — null / number

Default value: 100.

Should Muuri automatically trigger layout on window resize? Set to null to disable. When a number (0 or greater) is provided Muuri will automatically trigger layout when window is resized. The provided number equals to the amount of time (in milliseconds) that is waited before the layout is triggered after each resize event. The layout method is wrapped in a debouned function in order to avoid unnecessary layout calls.

layoutOnInit — boolean

Default value: true.

Should Muuri trigger layout automatically on init?

dragEnabled — boolean

Default value: false.

Should items be draggable?

dragContainer — null / element

Default value: null.

Which item should the dragged item be appended to for the duration of the drag? If null is provided the item's muuri container element will be used.

dragPredicate — null / function

Default value: null.

A function that determines when dragging should start. Set to null to use the default predicate.

dragSort — boolean

Default value: true.

Should the items be sorted during drag?

dragSortInterval — number

Default value: 50.

When an item is dragged around the grid Muuri automatically checks if the item overlaps another item enough to move the item in it's place. The overlap check method is debounced and this option defines the debounce interval in milliseconds. In other words, this is option defines the amount of time the dragged item must be still before the overlap is checked.

dragSortTolerance — number

Default value: 50.

Allowed values: 1 - 100.

How many percent the intersection area between the dragged item and the compared item should be from the maximum potential intersection area between the two items in order to justify for sorting to occur.

dragSortAction — string

Default value: "move".

Allowed values: "move", "swap".

Should the dragged item be moved to the new position or should it swap places with the item it overlaps?

muuri.get( [targets], [state] )

Get all items. Optionally you can provide specific targets (indices or elements) and filter the results by the items' state (active/inactive). Note that the returned array is not the same object used by the instance so modifying it will not affect instance's items. All items that are not found are omitted from the returned array.

muuri.add( elements, [index] )

Add new items by providing the elements you wish to add to the instance and optionally provide the index where you want the items to be inserted into. All elements that are not already children of the container element will be automatically appended to the container.

If an element has it's CSS display property set to none it will be marked as inactive during the initiation process. As long as the item is inactive it will not be part of the layout, but it will retain it's index. You can activate items at any point with muuri.show() method.

This method will automatically call muuri.layout() if one or more of the added elements are visible. If only hidden items are added no layout will be called. All the new visible items are positioned without animation during their first layout.

Parameters

elements — array / element

An array of DOM elements.

index — number

Optional.

Default value: 0.

The index where you want the items to be inserted in. A value of -1 will insert the items to the end of the list while 0 will insert the items to the beginning. Note that the DOM elements are always just appended to the instance container regardless of the index value. You can use the muuri.synchronize() method to arrange the DOM elments to the same order as the items.

Returns — array

Returns an array of Muuri.Item instances.

Examples

// Add two new items to the beginning.muuri.add([elemA, elemB]);
// Add two new items to the end.muuri.add([elemA, elemB], -1);

// Remove the first item, but keep the element in the DOM.muuri.remove(0);
// Remove items and the associated elements.muuri.remove([elemA, elemB], true);

muuri.synchronize()

Order the item elements to match the order of the items. If the item's element is not a child of the container it is ignored and left untouched. This comes handy if you need to keep the DOM structure matched with the order of the items.

Examples

muuri.synchronize();

muuri.layout( [instant], [callback] )

Calculate item positions and move items to their calculated positions unless they are already positioned correctly. The container's height is also adjusted according to the position of the items.

Parameters

instant — boolean

Optional.

Default value: false.

Should the items be positioned instantly without any possible animation?

callback — function

Optional.

A callback function that is called after the items have positioned. Receives two arguments. The first one is an array of all the items that were successfully positioned without interruptions and the second is a layout data object.

muuri.move( targetFrom, targetTo )

DOM element or Muuri.Item instance or index of the item as an integer.

targetTo — element / Muuri.Item / number

DOM element or Muuri.Item instance or index of the item as an integer.

Examples

// Move elemA to the index of elemB.muuri.move(elemA, elemB);
// Move first item as last.muuri.move(0, -1);

muuri.swap( targetA, targetB )

Swap positions of two items.

Parameters

targetA — element / Muuri.Item / number

DOM element or Muuri.Item instance or index of the item as an integer.

targetB — element / Muuri.Item / number

DOM element or Muuri.Item instance or index of the item as an integer.

Examples

// Swap positions of elemA and elemB.muuri.swap(elemA, elemB);
// Swap positions of the first and the last item.muuri.swap(0, -1);

muuri.destroy()

Destroy the instance.

Examples

muuri.destroy();

Events

refresh

Triggered after the muuri.refresh() method is called.

Listener parameters

items — array

An array of Muuri.Item instances which were refreshed.

Examples

muuri.on('refresh', function (items) {
console.log(items);
});

synchronize

Triggered after the muuri.synchronize() is called.

Examples

muuri.on('synchronize', function () {
console.log('Synced!');
});

layoutstart

Triggered when muuri.layout() method is called, just before the items are positioned.

Listener parameters

items — array

An array of Muuri.Item instances that were succesfully positioned. If, for example, an item is being dragged it is ignored by the layout method.

layout — object

A Muuri.Layout instance.

layout.muuri — Muuri

A Muuri instance for which the layout was generated.

layout.items — array

An array of Muuri.Item instances that were positioned.

layout.slots — object

An object containing the positions of the layout.items. Indexed with the ids of the items. For example, to get the first item's position you would do layout.slots[layout.items[0]._id]. Each slot contains the the item's width, height, left and top.

layoutend

Triggered when muuri.layout() method is called, after the items have positioned.

Listener parameters

items — array

An array of Muuri.Item instances that were succesfully positioned. If, for example, an item is being dragged it is ignored by the layout method.

layout — object

A Muuri.Layout instance.

layout.muuri — Muuri

A Muuri instance for which the layout was generated.

layout.items — array

An array of Muuri.Item instances that were positioned.

layout.slots — object

An object containing the positions of the layout.items. Indexed with the ids of the items. For example, to get the first item's position you would do layout.slots[layout.items[0]._id]. Each slot contains the the item's width, height, left and top.