Tagfield滚动不起作用

时间:2017-03-20 07:21:21

标签: javascript extjs extjs6

我正在使用6.0 有时候我在ExtJS 6标签中遇到了奇怪的问题。我正在使用带有growMax : 3的标记字段。现在当为tagfield选择的值超过三个tyhen时,我在tagfield中获得了一个指针向上和向下选项。

这很好现在,当我点击向下箭头时,这个部分就是我正好把我带到了田野的底部。我无法看到其中放置了什么其他值。有什么方法可以减慢那些值的移动速度。

我的小提琴:Fiddle

重现的步骤。

  1. 选择少量值(超过2或3)
  2. 点击向下指针。 (图片中的红框)Image
  3. 它可能跳过第二个第三个值并引导你结束。

    注意:有时我需要在tagfield中为100个数据执行此操作。甚至不能看到我选择的内容和所有内容。我也无法改变身高。

    点击滚动按钮是否有任何更加激烈的事件。

2 个答案:

答案 0 :(得分:4)

更新(实际上是实现继承)

好的,看起来你真的需要一个基于继承的解决方案。这段代码显然不是一个惯用的ExtJS,但它似乎对我有用。首先定义自定义子类SingleLineTag并将'singleline-tagfield'指定为其xtype(在#34;旧答案&#34;部分中对此代码背后的主要想法有一些描述)< / p>

Ext.define('Ext.form.field.SingleLineTag', {
    extend: 'Ext.form.field.Tag',
    xtype: 'singleline-tagfield',

    initEvents: function () {
        var me = this;
        me.callParent(arguments);

        me.itemList.el.dom.parentElement.addEventListener('scroll', Ext.bind(me.zzzOnTagScroll, me));
    },

    zzzGetTagLastScroll: function () {
        var me = this;
        return me.zzzLastScroll = me.zzzLastScroll || {
                lastIndex: 0,
                lastTop: 0,
                lastTimeStamp: 0
            };
    },

    zzzScrollToTagIndex: function (index) {
        var tagField = this;
        var lastScroll = tagField.zzzLastScroll;
        if (lastScroll) {
            var lstDom = tagField.itemList.el.dom;
            var childrenDom = lstDom.children;
            var containerDom = tagField.itemList.el.dom.parentElement;

            if ((index >= 0) && (index < childrenDom.length)) {
                lastScroll.lastIndex = index;
                containerDom.scrollTop = lastScroll.lastTop = childrenDom[index].offsetTop - lstDom.offsetTop;
            }
        }
    },

    zzzOnTagScroll: function (ev) {
        var me = this;
        var lastScroll = me.zzzGetTagLastScroll();

        // throttle scroll events as thy occur to often and we might scroll to much
        if (Math.abs(lastScroll.lastTimeStamp - ev.timeStamp) < 200) {
            ev.preventDefault();
            return;
        }

        lastScroll.lastTimeStamp = ev.timeStamp;

        var lstDom = me.itemList.el.dom;
        var childrenDom = lstDom.children;
        var containerDom = me.itemList.el.dom.parentElement;
        var scrollTop = containerDom.scrollTop;

        var index = lastScroll.lastIndex;
        if (index >= childrenDom.length)
            index = childrenDom.length - 1;
        if (index < 0)
            index = 0;
        var lstTop = lstDom.offsetTop;
        if (scrollTop > lastScroll.lastTop) {
            // scrolling down, find next element
            for (; index < childrenDom.length; index++) {
                if (childrenDom[index].offsetTop - lstTop > scrollTop) {
                    break;
                }
            }
            if (index < childrenDom.length) {
                // we've found the next element so change scroll position to it's top
                me.zzzScrollToTagIndex(index);
            }
            else {
                lastScroll.lastIndex = childrenDom.length;
                lastScroll.lastTop = containerDom.scrollTop;
            }
        }
        else {
            // scrolling up, find prev element
            for (; index >= 0; index--) {
                if (childrenDom[index].offsetTop - lstTop < scrollTop) {
                    break;
                }
            }
            if (index >= 0) {
                // we've found the prev element so change scroll position to it's top
                me.zzzScrollToTagIndex(index);
            }
            else {
                lastScroll.lastIndex = 0;
                lastScroll.lastTop = 0;
            }
        }
    },


    onBeforeDeselect: function (list, record) {
        var me = this;
        me.callParent(arguments);
        var value = record.get(me.valueField);
        var index = me.getValue().indexOf(value);
        var lastScroll = me.zzzGetTagLastScroll();
        if (lastScroll.lastIndex > index)
            lastScroll.lastIndex -= 1;
        var nextIndex = (lastScroll.lastIndex > index) ? lastScroll.lastIndex - 1 : lastScroll.lastIndex;
        setTimeout(function () {
            me.zzzScrollToTagIndex(nextIndex);
        }, 0);
    },

    onItemListClick: function(ev) {
        var me = this;

        // HACK for IE: throttle click events after scroll
        // click on the scrollbar seem to generate click on the "itemList" as well
        // which lead to showing of the dropdown
        var lastScroll = me.zzzGetTagLastScroll();
        if (Math.abs(lastScroll.lastTimeStamp - ev.timeStamp) > 200) {
            me.callParent(arguments);
        }
    }
});

现在更改xtype个收藏集中的items

var shows = Ext.create('Ext.data.Store', {
    fields: ['id', 'show'],
    data: [
        {id: 0, show: 'Battlestar Galactica'},
        {id: 11, show: 'Doctor Who'},
        {id: 2, show: 'Farscape'},
        {id: 3, show: 'Firefly'},
        {id: 4, show: 'Star Trek'},
        {id: 5, show: 'Star Wars: Christmas Special'}
    ]
});

Ext.create('Ext.form.Panel', {
    renderTo: Ext.getBody(),
    title: 'Sci-Fi Television',
    height: 200,
    width: 300,
    items: [{
        //xtype: 'tagfield',          // old
        xtype: 'singleline-tagfield', // new 
        growMax: 18,
        fieldLabel: 'Select a Show',
        store: shows,
        displayField: 'show',
        valueField: 'id',
        queryMode: 'local',
        filterPickList: true,
    }]
}); 

请注意,如果您没有将此元素配置为实际只采用单行高度,则在滚动方面它会表现得很奇怪。

请参阅此Sencha fiddle

的合并代码

旧答案

我对ExtJS并不擅长,但我认为一些不那么好的答案总比没有答案好。首先,我同意growMax以像素为单位,因此3太少了。仍在考虑你的问题,似乎没有足够的空间来完成一个完整的滚动条,因此唯一的方法是添加自定义滚动逻辑。可能最好创建一个继承自Tag的新类,但我不确定在ExtJS中如何正确地完成它,所以这里有一些自定义的,可能是非惯用的代码。

function findComponentByElement(node) {
    var topmost = document.body,
        target = node,
        cmp;

    while (target && target.nodeType === 1 && target !== topmost) {
        cmp = Ext.getCmp(target.id);

        if (cmp) {
            return cmp;
        }

        target = target.parentNode;
    }

    return null;
}


var getTagLastScroll = function (tagField) {
    return tagField.zzzLastScroll = tagField.zzzLastScroll || {
            lastIndex: 0,
            lastTop: 0,
            lastTimeStamp: 0
        };
};

var scrollToTagIndex = function (tagField, index) {
    var lastScroll = tagField.zzzLastScroll;
    if (lastScroll) {
        var lstDom = tagField.itemList.el.dom;
        var childrenDom = lstDom.children;
        var containerDom = tagField.itemList.el.dom.parentElement;

        if ((index >= 0) && (index < childrenDom.length)) {
            lastScroll.lastIndex = index;
            containerDom.scrollTop = lastScroll.lastTop = childrenDom[index].offsetTop - lstDom.offsetTop;

            //console.log("Scroll to " + containerDom.scrollTop);
            //console.log(lastScroll);

        }
    }
};

var onTagScroll = function (ev) {
    var tagField = findComponentByElement(ev.target);
    var lastScroll = getTagLastScroll(tagField);

    // need to throttle scroll events or will scroll to much
    if (Math.abs(lastScroll.lastTimeStamp - ev.timeStamp) < 200) {
        ev.preventDefault();
        return;
    }

    //console.log(ev);
    lastScroll.lastTimeStamp = ev.timeStamp;

    var lstDom = tagField.itemList.el.dom;
    var childrenDom = lstDom.children;
    var containerDom = tagField.itemList.el.dom.parentElement;
    var scrollTop = containerDom.scrollTop;

    //console.log("Before " + containerDom.scrollTop);
    //console.log(lastScroll);

    var index = lastScroll.lastIndex;
    if (index >= childrenDom.length)
        index = childrenDom.length - 1;
    if (index < 0)
        index = 0;
    var lstTop = lstDom.offsetTop;
    if (scrollTop > lastScroll.lastTop) {
        // scrolling down, find next element
        for (; index < childrenDom.length; index++) {
            if (childrenDom[index].offsetTop - lstTop > scrollTop) {
                break;
            }
        }
        if (index < childrenDom.length) {
            // we've found the next element so change scroll position to it's top
            scrollToTagIndex(tagField, index);
        }
        else {
            lastScroll.lastIndex = childrenDom.length;
            lastScroll.lastTop = containerDom.scrollTop;
        }
    }
    else {
        // scrolling up, find prev element
        for (; index >= 0; index--) {
            if (childrenDom[index].offsetTop - lstTop < scrollTop) {
                break;
            }
        }
        if (index >= 0) {
            // we've found the prev element so change scroll position to it's top
            scrollToTagIndex(tagField, index);
        }
        else {
            lastScroll.lastIndex = 0;
            lastScroll.lastTop = 0;
        }
    }
    //console.log("After " + containerDom.scrollTop);
    //console.log(lastScroll);
};


var beforeDeselect = function (tagField, record) {
    var value = record.get(tagField.valueField);
    var index = tagField.getValue().indexOf(value);
    var lastScroll = getTagLastScroll(tagField);
    if (lastScroll.lastIndex > index)
        lastScroll.lastIndex -= 1;
    var nextIndex = (lastScroll.lastIndex > index) ? lastScroll.lastIndex - 1 : lastScroll.lastIndex;
    setTimeout(function () {
        scrollToTagIndex(tagField, nextIndex);
    }, 0);
};

var attachCustomScroll = function (tagField) {
    var containerDom = tagField.itemList.el.dom.parentElement;
    containerDom.addEventListener('scroll', onTagScroll);
    tagField.on('beforeDeselect', beforeDeselect);
};

您只需执行类似

的操作即可使用它
var pnl = Ext.create('Ext.form.Panel', { 
    ...
});
var tagField = pnl.items.items[0];
attachCustomScroll(tagField);

我的代码的主要思想是截取包含ul的容器元素的滚动事件和所选项目,并将事件视为真正的滚动,而不是将一个元素滚动到它的方向。正常工作所需的数据以希望独特的zzzLastScroll名称附加到小部件。

另外还有一些逻辑可以在删除某些项目时使滚动看起来更好。

<小时/> 完整代码(而不是小提琴)

不幸的是,我没有ExtJS帐户,没有它我无法在那里创建一个新的小提琴,所以以下是我使用的修改后的 app.js 的完整代码测试我的代码。

var shows = Ext.create('Ext.data.Store', {
    fields: ['id', 'show'],
    data: [
        {id: 0, show: 'Battlestar Galactica'},
        {id: 11, show: 'Doctor Who'},
        {id: 2, show: 'Farscape'},
        {id: 3, show: 'Firefly'},
        {id: 4, show: 'Star Trek'},
        {id: 5, show: 'Star Wars: Christmas Special'}
    ]
});


var pnl = Ext.create('Ext.form.Panel', {
    renderTo: Ext.getBody(),
    title: 'Sci-Fi Television',
    height: 200,
    width: 300,
    items: [{
        xtype: 'tagfield',
        growMax: 18,
        fieldLabel: 'Select a Show',
        store: shows,
        displayField: 'show',
        valueField: 'id',
        queryMode: 'local',
        filterPickList: true,


    }]
});

window.tagField = pnl.items.items[0];
window.lstDom = window.tagField.itemList.el.dom;
window.container = window.lstDom.parentElement;

tagField.setValue([11, 3, 4, 5]);

function findComponentByElement(node) {
    var topmost = document.body,
        target = node,
        cmp;

    while (target && target.nodeType === 1 && target !== topmost) {
        cmp = Ext.getCmp(target.id);

        if (cmp) {
            return cmp;
        }

        target = target.parentNode;
    }

    return null;
}


var getTagLastScroll = function (tagField) {
    return tagField.zzzLastScroll = tagField.zzzLastScroll || {
            lastIndex: 0,
            lastTop: 0,
            lastTimeStamp: 0
        };
};

var scrollToTagIndex = function (tagField, index) {
    var lastScroll = tagField.zzzLastScroll;
    if (lastScroll) {
        var lstDom = tagField.itemList.el.dom;
        var childrenDom = lstDom.children;
        var containerDom = tagField.itemList.el.dom.parentElement;

        if ((index >= 0) && (index < childrenDom.length)) {
            lastScroll.lastIndex = index;
            containerDom.scrollTop = lastScroll.lastTop = childrenDom[index].offsetTop - lstDom.offsetTop;

            //console.log("Scroll to " + containerDom.scrollTop);
            //console.log(lastScroll);

        }
    }
};

var onTagScroll = function (ev) {
    var tagField = findComponentByElement(ev.target);
    var lastScroll = getTagLastScroll(tagField);

    if (Math.abs(lastScroll.lastTimeStamp - ev.timeStamp) < 200) {
        ev.preventDefault();
        return;
    }

    //console.log(ev);
    lastScroll.lastTimeStamp = ev.timeStamp;

    var lstDom = tagField.itemList.el.dom;
    var childrenDom = lstDom.children;
    var containerDom = tagField.itemList.el.dom.parentElement;
    var scrollTop = containerDom.scrollTop;

    //console.log("Before " + containerDom.scrollTop);
    //console.log(lastScroll);

    var index = lastScroll.lastIndex;
    if (index >= childrenDom.length)
        index = childrenDom.length - 1;
    if (index < 0)
        index = 0;
    var lstTop = lstDom.offsetTop;
    if (scrollTop > lastScroll.lastTop) {
        // scrolling down, find next element
        for (; index < childrenDom.length; index++) {
            if (childrenDom[index].offsetTop - lstTop > scrollTop) {
                break;
            }
        }
        if (index < childrenDom.length) {
            // we've found the next element so change scroll position to it's top
            scrollToTagIndex(tagField, index);
        }
        else {
            lastScroll.lastIndex = childrenDom.length;
            lastScroll.lastTop = containerDom.scrollTop;
        }
    }
    else {
        // scrolling up, find prev element
        for (; index >= 0; index--) {
            if (childrenDom[index].offsetTop - lstTop < scrollTop) {
                break;
            }
        }
        if (index >= 0) {
            // we've found the prev element so change scroll position to it's top
            scrollToTagIndex(tagField, index);
        }
        else {
            lastScroll.lastIndex = 0;
            lastScroll.lastTop = 0;
        }
    }
    //console.log("After " + containerDom.scrollTop);
    //console.log(lastScroll);
};


var beforeDeselect = function (tagField, record) {
    var value = record.get(tagField.valueField);
    var index = tagField.getValue().indexOf(value);
    var lastScroll = getTagLastScroll(tagField);
    if (lastScroll.lastIndex > index)
        lastScroll.lastIndex -= 1;
    var nextIndex = (lastScroll.lastIndex > index) ? lastScroll.lastIndex - 1 : lastScroll.lastIndex;
    setTimeout(function () {
        scrollToTagIndex(tagField, nextIndex);
    }, 0);
};

var attachCustomScroll = function (tagField) {
    var containerDom = tagField.itemList.el.dom.parentElement;
    containerDom.addEventListener('scroll', onTagScroll);
    tagField.on('beforeDeselect', beforeDeselect);
};

attachCustomScroll(window.tagField);

答案 1 :(得分:1)

growMax的设置应为高度(以像素为单位)。要允许选择其中3个项目的空间并使用合理的空间进行滚动,您可以尝试设置growMax=60。查看更新的fiddle