在div元素上调整大小


80

jQuery具有resize()-事件,但仅适用于window。

jQuery(window).resize(function() { /* What ever */ });

这样很好!但是,当我想将事件添加到div元素时,它不起作用。

例如

jQuery('div').resize(function() { /* What ever */ });

我想在div元素的大小已更改时启动回调。我不想启动可调整大小的事件-仅是一个检查div-元素大小是否已更改的事件。

有解决方案吗?


2
调整大小事件仅在窗口对象上触发(也许是iframe吗?)。
BiAiB 2012年


这可能会有所帮助:resizeObserver。 developer.mozilla.org/zh-CN/docs/Web/API/ResizeObserver。受Chrome 64,Firefox 69的支持...
puget船长

Answers:


35

DIV不会触发resize事件,因此您将无法完全执行已编写的代码,但是可以考虑监视DOM属性

如果您实际上正在使用可调整大小的东西,而这是div更改大小的唯一方法,那么您的resize插件可能会实现自己的回调。


您可以使用$(window).trigger(“ resize”);触发窗口调整大小事件。
洛朗

32

我只对元素的宽度更改时的触发器感兴趣(我不在乎高度),所以我创建了一个jquery事件,它使用不可见的iframe元素来做到这一点。

$.event.special.widthChanged = {
  remove: function() {
      $(this).children('iframe.width-changed').remove();
  },
  add: function () {
      var elm = $(this);
      var iframe = elm.children('iframe.width-changed');
      if (!iframe.length) {
          iframe = $('<iframe/>').addClass('width-changed').prependTo(this);
      }
      var oldWidth = elm.width();
      function elmResized() {
          var width = elm.width();
          if (oldWidth != width) {
              elm.trigger('widthChanged', [width, oldWidth]);
              oldWidth = width;
          }
      }

      var timer = 0;
      var ielm = iframe[0];
      (ielm.contentWindow || ielm).onresize = function() {
          clearTimeout(timer);
          timer = setTimeout(elmResized, 20);
      };
  }
}

它需要以下css:

iframe.width-changed {
    width: 100%;
    display: block;
    border: 0;
    height: 0;
    margin: 0;
}

您可以在这里看到它的运行widthChanged小提琴


这是正确的答案。将事件附加到iframe的窗口比间隔时间要少得多。
凯文·比尔

1
太棒了!我通过动态添加样式表使我的js完全基于js:var ss = document.createElement('style'); ss.type = "text/css"; ss.innerHTML = "iframe.width-changed {width: 100%;display: block;border: 0;height: 0;margin: 0;}"; document.body.appendChild(ss);
sroskelley,2016年

这是纯粹的天才。
托马斯

我将要使用它,但我想知道:计时器和setTimeout的作用是什么?就像“去抖” /油门一样,可以防止在用户调整元素大小时检测到太多调整大小?
Mathieu

是的,这是为了防止调用太多次“ widthChanged”触发器
Panos

21
// this is a Jquery plugin function that fires an event when the size of an element is changed
// usage: $().sizeChanged(function(){})

(function ($) {

$.fn.sizeChanged = function (handleFunction) {
    var element = this;
    var lastWidth = element.width();
    var lastHeight = element.height();

    setInterval(function () {
        if (lastWidth === element.width()&&lastHeight === element.height())
            return;
        if (typeof (handleFunction) == 'function') {
            handleFunction({ width: lastWidth, height: lastHeight },
                           { width: element.width(), height: element.height() });
            lastWidth = element.width();
            lastHeight = element.height();
        }
    }, 100);


    return element;
};

}(jQuery));

IMO,这应该是公认的答案!
pa4080

7

我已经创建了jquery插件jquery.resize,如果受支持,则使用resizeObserver或基于marcj / css-element-queries滚动事件(无setTimeout / setInterval)的解决方案。

你只用

 jQuery('div').on('resize', function() { /* What ever */ });

或作为调整大小插件

jQuery('div').resizer(function() { /* What ever */ });

我已为jQuery Terminal创建了此文件,并将其提取到单独的repo和npm程序包中,但与此同时,我切换到隐藏的iframe,因为如果元素位于iframe中,则无法调整大小。我可能会相应地更新插件。您可以在jQuery Terminal源代码中查看基于iframe的大小调整器插件

编辑:新版本使用iframe并在其window对象上调整大小,因为当页面位于iframe内时,先前的解决方案不起作用。

EDIT2:由于后备使用iframe,因此无法将其与表单控件或图像一起使用,因此需要将其添加到wrapper元素中。

EDIT3::使用resizeObserver polyfill的更好的解决方案是使用突变观察器(如果不支持resizeObserver),即使在IE中也可以使用。它还具有TypeScript类型。


那是个好主意。做得好,真的。
马可·卢扎拉

6

那这个呢:

divH = divW = 0;
jQuery(document).ready(function(){
    divW = jQuery("div").width();
    divH = jQuery("div").height();
});
function checkResize(){
    var w = jQuery("div").width();
    var h = jQuery("div").height();
    if (w != divW || h != divH) {
        /*what ever*/
        divH = h;
        divW = w;
    }
}
jQuery(window).resize(checkResize);
var timer = setInterval(checkResize, 1000);

顺便说一句,我建议您向div添加一个id并将$(“ div”)更改为$(“#yourid”),这样会更快,并且在以后添加其他div时也不会中断


当然-这只是一个例子-当然我使用id和class选择我的元素。我喜欢您的想法-我认为这行得通!非常感谢。我将在几分钟后尝试并提供反馈。
TJR 2012年

每当窗口resize事件被触发时,它将监视DIV的大小更改。非常有可能的是,div的大小将在不立即调整窗口大小的情况下进行更改,在这种情况下/* what ever */将不评估零件。
David Hedlund '04年

对!这是我项目中的问题。div元素位于具有css属性Overflow:hidden的外​​部包装中-因此窗口不会更改大小。但是以其他方式,该示例可以正常工作-我刚刚对其进行了测试。
TJR 2012年

@Timo:$(window).resize通过拖动右下角来监听调整浏览器窗口大小的行为。没有DOM事件触发过此事件overflow:hidden。此答案不能解决您的问题。在计时器中运行此代码比附加到可能永远不会触发的随机事件侦听器要有意义。如果您可以使用DOM属性监视并返回到计时器(或在div大小可以更改的位置手动引发一些事件),那将更好。
David Hedlund '04年

为setInterval添加了代码。您需要对其进行微调,因为1000ms可能对您来说太多了,另一方面,太小的数字很容易导致CPU死亡。如果您知道不需要再听了,请致电:clearInterval(timer)!
加夫里耶尔(Gavriel)2012年

5

今年基本发布了一个非常好的,易于使用的轻量级(使用本机浏览器事件进行检测)的插件,用于基本JavaScript和jQuery。它表现完美:

https://github.com/sdecima/javascript-detect-element-resize


1
您说它不会持续轮询,但它会使用requestAnimationFrame:github.com/sdecima/javascript-detect-element-resize/blob/master/…–
Muhammad Umer

1
有趣的是:引用的GitHub项目是受此博客文章启发的:backalleycoder.com/2013/03/18/…但是文章中的代码后来发生了重大变化,而GitHub项目似乎使用了较旧的方法。因此,在决定使用什么之前,有必要先对两者进行研究。
CF CF


0

对于谷歌地图集成,我正在寻找一种方法来检测div的大小已更改。由于Google地图始终需要适当的尺寸(例如宽度和高度)才能正确呈现。

我想出的解决方案是事件的委派,在我的情况下是单击选项卡。当然,这可能是调整窗口大小,但思路仍然相同:

if (parent.is(':visible')) {
    w = parent.outerWidth(false);
    h = w * mapRatio /*9/16*/;
    this.map.css({ width: w, height: h });
} else {
    this.map.closest('.tab').one('click', function() {
        this.activate();
    }.bind(this));
}

this.map在这种情况下是我的地图div。由于我的父母在加载时不可见,因此计算出的宽度和高度为0或不匹配。通过使用,.bind(this)我可以将脚本执行(this.activate)委托给事件(click)。

现在,我有信心调整大小事件也是如此。

$(window).one('resize', function() {
    this.div.css({ /*whatever*/ });
}.bind(this));

希望它能帮助任何人!


0

只需尝试以下功能(它可能不仅适用于div):

function resized(elem, func = function(){}, args = []){
    elem = jQuery(elem);
    func = func.bind(elem);
    var h = -1, w = -1;
    setInterval(function(){
        if (elem.height() != h || elem.width() != w){
            h = elem.height();
            w = elem.width();
            func.apply(null, args);
        }
    }, 100);
}

你可以这样使用

resized(/*element*/ '.advs-columns-main > div > div', /*callback*/ function(a){
    console.log(a);
    console.log(this); //for accessing the jQuery element you passed
}, /*callback arguments in array*/ ['I\'m the first arg named "a"!']);

更新: 您还可以使用更多的渐进式观察器(它可以用于任何对象,不仅限于DOM元素):

function changed(elem, propsToBeChanged, func = function(){}, args = [], interval = 100){
        func = func.bind(elem);
        var currentVal = {call: {}, std: {}};
        $.each(propsToBeChanged, (property, needCall)=>{
            needCall = needCall ? 'call' : 'std';
            currentVal[needCall][property] = new Boolean(); // is a minimal and unique value, its equivalent comparsion with each other will always return false
        });
        setInterval(function(){
            $.each(propsToBeChanged, (property, needCall)=>{
                try{
                    var currVal = needCall ? elem[property]() : elem[property];
                } catch (e){ // elem[property] is not a function anymore
                    var currVal = elem[property];
                    needCall = false;
                    propsToBeChanged[property] = false;
                }
                needCall = needCall ? 'call' : 'std';
                if (currVal !== currentVal[needCall][property]){
                    currentVal[needCall][property] = currVal;
                    func.apply(null, args);
                }
            });
        }, interval);
    }

去尝试一下:

var b = '2',
    a = {foo: 'bar', ext: ()=>{return b}};
changed(a, {
// prop name || do eval like a function?
    foo:        false,
    ext:        true
}, ()=>{console.log('changed')})

每次直接更改b,a.foo或a.ext时,它将记录“已更改”


setInterval会不断尝试调整大小,因此可能会变得非常昂贵

@ton:我认为你并不完全正确。仅在尝试调整元素的大小时才发生这种情况。:/或者您担心性能?在最新的浏览器上,即使在“繁重”的网站上,它也可以完美运行
KaMeHb

如果您console.log在之前添加一个简单的$.each100msinterval
ton

@ton:你理解我错了。我知道如何setInterval运作。这就像一封“运行中”的电子邮件-不断ping服务器。我知道。那又怎样 性能?阅读我上面的评论。担心其他吗?写给我,我的朋友。
KaMeHb

0

您可以根据屏幕尺寸更改文本,内容或属性:HTML:

<p class="change">Frequently Asked Questions (FAQ)</p>
<p class="change">Frequently Asked Questions </p>

Javascript:

<script>
const changeText = document.querySelector('.change');
function resize() {
  if((window.innerWidth<500)&&(changeText.textContent="Frequently Asked Questions (FAQ)")){
    changeText.textContent="FAQ";
  } else {
    changeText.textContent="Frequently Asked Questions (FAQ)";
  }
}
window.onresize = resize;
</script>

-2

如果只想调整div本身的大小,则需要以CSS样式指定它。您需要添加溢出调整大小属性

以下是我的代码段

#div1 {
        width: 90%;
        height: 350px;
        padding: 10px;
        border: 1px solid #aaaaaa;
        overflow: auto;
        resize: both;
    }

<div id="div1">

</div>

此答案不适用于原始帖子。这里的广泛讨论是关于侦听元素大小的更改(然后执行操作),而不是设置元素的大小。
MarsAndBack
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.