在 div 元素上调整大小

JQuery 具有 resize()事件,但它只能用于窗口。

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

这个工作得很好! 但是当我想将事件添加到 div 元素时,它就不工作了。

例如。

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

我想在 div 元素的大小发生变化时启动一个回调。我不想启动一个可调整大小的事件——只是一个检查 div-的大小的事件 元素变了。

有什么解决办法吗?

176682 次浏览

Only window is supported yes but you could use a plugin for it: http://benalman.com/projects/jquery-resize-plugin/

DIV does not fire a resize event, so you won't be able to do exactly what you've coded, but you could look into monitoring DOM properties.

If you are actually working with something like resizables, and that is the only way for a div to change in size, then your resize plugin will probably be implementing a callback of its own.

what about this:

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);

BTW I suggest you to add an id to the div and change the $("div") to $("#yourid"), it's gonna be faster, and it won't break when later you add other divs

For a google maps integration I was looking for a way to detect when a div has changed in size. Since google maps always require proper dimensions e.g. width and height in order to render properly.

The solution I came up with is a delegation of an event, in my case a tab click. This could be a window resize of course, the idea remains the same:

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 in this case is my map div. Since my parent is invisible on load, the computed width and height are 0 or don't match. By using .bind(this) I can delegate the script execution (this.activate) to an event (click).

Now I'm confident the same applies for resize events.

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

Hope it helps anyone!

There is a really nice, easy to use, lightweight (uses native browser events for detection) plugin for both basic JavaScript and for jQuery that was released this year. It performs perfectly:

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

I was only interested for a trigger when a width of an element was changed (I don' care about height), so I created a jquery event that does exactly that, using an invisible iframe element.

$.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);
};
}
}

It requires the following css :

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

You can see it in action here widthChanged fiddle

// 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));

Just try this func (it may work not only for divs):

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);
}

You can use it like this

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"!']);

UPDATE: You can also use more progressive watcher (it can work for any objects, not only DOM elements):

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);
}

Just try it:

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')})

It will log 'changed' every time when you change b, a.foo or a.ext directly

I've created jquery plugin jquery.resize it use resizeObserver if supported or solution based on marcj/css-element-queries scroll event, no setTimeout/setInterval.

You use just

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

or as resizer plugin

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

I've created this for jQuery Terminal and extracted into separated repo and npm package, but in a mean time I switched to hidden iframe because I had problems with resize if element was inside iframe. I may update the plugin accordingly. You can look at iframe based resizer plugin in jQuery Terminal source code.

EDIT: new version use iframe and resize on it's window object because the previous solutions was not working when page was inside iframe.

EDIT2: Because the fallback use iframe you can't use it with form controls or images, you need to add it to the wrapper element.

EDIT3:: there is better solution using resizeObserver polyfill that use mutation observer (if resizeObserver is not supported) and work even in IE. It also have TypeScript typings.

You can change your text or Content or Attribute depend on Screen size: 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>

If you just want to resize the div itself you need to specify that in css style. You need to add overflow and resize property.

Below is my code snippet

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


<div id="div1">


</div>

There now exists Resize Observer

You could use it like so:

const resizeObserver = new ResizeObserver((entries) => {
entries.forEach(console.log);
})
resizeObserver.observe(document.getElementById("ExampleElement"));

document.addEventListener('transitionend', function(e) {
if ($(e.target).is("div")) {
$("div").text("width: "+$("div").width());
}
});
$("div").css({"width":"150px"});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div style="width: 100px;transition-delay: 0.000000001s;">width: 100</div>