Creating a jQuery UI sortable in an iframe

2019-02-04 17:53发布

On a page I have an iframe. In this iframe is a collection of items that I need to be sortable. All of the Javascript is being run on the parent page. I can access the list in the iframe document and create the sortable by using context:

var ifrDoc = $( '#iframe' ).contents();

$( '.sortable', ifrDoc ).sortable( { cursor: 'move' } );

However, when trying to actually sort the items, I'm getting some aberrant behavior. As soon as an item is clicked on, the target of the script changes to the outer document. If you move the mouse off of the iframe, you can move the item around and drop it back by clicking, but you can not interact with it within the iframe.

Example: http://robertadamray.com/sortable-test.html

So, is there a way to achieve what I want to do - preferably without having to go hacking around in jQuery UI code?

4条回答
甜甜的少女心
2楼-- · 2019-02-04 18:38

I don't know why your code isn't working. Looks like it should be.

That said, here are two alternative ways to implement this feature:

  1. If you can modify the iframe

    Move your JavaScript from the parent document into iframe-test.html. This may be the cleanest way because it couples the JavaScript with the elements its actually executing on.

    http://dl.dropbox.com/u/3287783/snippets/rarayiframe/sortable-test.html

  2. If you only control the parent document

    Use the jQuery .load() method to fetch the content instead of an HTML iframe.

    http://dl.dropbox.com/u/3287783/snippets/rarayiframe2/sortable-test.html

查看更多
虎瘦雄心在
3楼-- · 2019-02-04 18:41

Having played with their javascript a bit, Campaign Monitor solves this by basically having a custom version of jQuery UI. They've modified ui.mouse and ui.sortable to replace references to document and window with code that gets the document and window for the element in question. document becomes this.element[0].ownerDocument

and they have a custom jQuery function called window() which lets them replace window with this.element.window() or similar.

查看更多
Ridiculous、
4楼-- · 2019-02-04 18:50

Dynamically add jQuery and jQuery UI to the iframe (demo):

$('iframe')
    .load(function() {
        var win = this.contentWindow,
            doc = win.document,
            body = doc.body,
            jQueryLoaded = false,
            jQuery;

        function loadJQueryUI() {
            body.removeChild(jQuery);
            jQuery = null;

            win.jQuery.ajax({
                url: 'http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.18/jquery-ui.min.js',
                dataType: 'script',
                cache: true,
                success: function () {
                    win.jQuery('.sortable').sortable({ cursor: 'move' });
                }
            });
        }

        jQuery = doc.createElement('script');

        // based on https://gist.github.com/getify/603980
        jQuery.onload = jQuery.onreadystatechange = function () {
            if ((jQuery.readyState && jQuery.readyState !== 'complete' && jQuery.readyState !== 'loaded') || jQueryLoaded) {
                return false;
            }
            jQuery.onload = jQuery.onreadystatechange = null;
            jQueryLoaded = true;
            loadJQueryUI();
        };

        jQuery.src = 'http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js';
        body.appendChild(jQuery);
    })
    .prop('src', 'iframe-test.html');

Update: Andrew Ingram is correct that jQuery UI holds and uses references to window and document for the page to which jQuery UI was loaded. By loading jQuery / jQuery UI into the iframe, it has the correct references (for the iframe, rather than the outer document) and works as expected.


Update 2: The original code snippet had a subtle issue: the execution order of dynamic script tags isn't guaranteed. I've updated it so that jQuery UI is loaded after jQuery is ready.

I also incorporated getify's code to load LABjs dynamically, so that no polling is necessary.

查看更多
劳资没心,怎么记你
5楼-- · 2019-02-04 18:52

Instead of loading jQuery and jQueryUI inside the iFrame and evaluating jQueryUI interactions both in parent and child - you can simply bubble the mouse events to the parent's document:

var ifrDoc = $( '#iframe' ).contents();

$('.sortable', ifrDoc).on('mousemove mouseup', function (event) {
    $(parent.document).trigger(event);
});

This way you can evaluate all your Javascript on the parent's document context.

查看更多
登录 后发表回答