在iframe中创建可排序的jQuery UI

时间:2012-02-20 22:57:12

标签: jquery-ui iframe jquery-ui-sortable

在一个页面上,我有一个iframe。在这个iframe中,我需要对可排序的项目进行收集。所有Javascript都在父页面上运行。我可以访问iframe文档中的列表,并使用上下文创建sortable:

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

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

然而,当试图对物品进行实际排序时,我会遇到一些异常行为。单击某个项目后,脚本的目标将更改为外部文档。如果您将鼠标移离iframe,则可以移动项目并通过单击将其放回,但您无法在iframe中与其进行交互。

示例:http://robertadamray.com/sortable-test.html

那么,有没有办法实现我想做的事情 - 最好不必在jQuery UI代码中进行黑客攻击?

4 个答案:

答案 0 :(得分:9)

动态地将jQuery和jQuery UI添加到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');

更新: Andrew Ingram is correct jQuery UI保存并使用windowdocument的引用作为加载jQuery UI的页面。通过将jQuery / jQuery UI加载到iframe中,它具有正确的引用(对于iframe,而不是外部文档)并按预期工作。


更新2:原始代码段有一个微妙的问题:无法保证动态脚本代码的执行顺序。我已经更新了它,以便在jQuery准备就绪后加载jQuery UI。

我还将getify的代码合并到load LABjs dynamically,因此不需要轮询。

答案 1 :(得分:5)

稍微使用了他们的javascript,Campaign Monitor通过基本上拥有自定义版本的jQuery UI来解决这个问题。他们修改了ui.mouse和ui.sortable来替换对文档和窗口的引用,并使用获取相关元素的文档和窗口的代码。 document变为this.element[0].ownerDocument

他们有一个名为window()的自定义jQuery函数,它允许用window或类似代替this.element.window()

答案 2 :(得分:3)

我不知道为什么你的代码不起作用。看起来应该是这样。

也就是说,以下是实现此功能的两种替代方法:

  1. 如果您可以修改iframe

    将JavaScript从父文档移动到iframe-test.html。这可能是最干净的方式,因为它将JavaScript与其实际执行的元素耦合在一起。

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

  2. 如果您只控制父文件

    使用jQuery .load()方法获取内容而不是HTML iframe。

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

答案 3 :(得分:1)

不是在iFrame中加载jQuery和jQueryUI,而是在父级和子级中评估jQueryUI交互 - 您可以简单地将鼠标事件冒泡到父级文档中:

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

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

这样您就可以在父文档上下文中评估所有Javascript。