Firefox'ta çalışmaz


164

Bu işlev iyi çalışıyor. Vücudu istenen bir kabın ofsetine kaydırır

function scrolear(destino){
    var stop = $(destino).offset().top;
    var delay = 1000;
    $('body').animate({scrollTop: stop}, delay);
    return false;
}

Ancak Firefox'ta değil. Neden?

-DÜZENLE-

Kabul edilen cevapta çift tetiği işlemek için, öğeyi animasyondan önce durdurmanızı öneririm:

$('body,html').stop(true,true).animate({scrollTop: stop}, delay);

2
Son kodunuz, buradaki tüm şeylerin en zarifidir.
Lizardx

Yanıtlar:


331

Firefox html, özellikle farklı davranacak şekilde tasarlanmamışsa taşmayı düzeye yerleştirir.

Firefox'ta çalışmasını sağlamak için

$('body,html').animate( ... );

Çalışma örneği

CSS çözümü aşağıdaki stilleri ayarlamak olacaktır:

html { overflow: hidden; height: 100%; }
body { overflow: auto; height: 100%; }

JS çözüm en az invaziv olacağını varsayalım.


Güncelleme

Aşağıdaki tartışmaların çoğu, scrollTopiki öğenin canlandırılmasının geri aramanın iki kez çağrılmasına neden olacağına odaklanmaktadır . Tarayıcı algılama özellikleri önerilmiş ve daha sonra kullanımdan kaldırılmıştır ve bazıları tartışmasız oldukça uzaktır.

Geri arama idempotent ise ve çok fazla bilgi işlem gücü gerektirmiyorsa, iki kez ateşlemek tam bir sorun olmayabilir. Geri aramanın birden çok çağrılması gerçekten bir sorun oluşturuyorsa ve özellik algılamasından kaçınmak istiyorsanız, geri aramanın geri aramanın yalnızca bir kez çalıştırılmasını zorlamak daha kolay olabilir:

function runOnce(fn) { 
    var count = 0; 
    return function() { 
        if(++count == 1)
            fn.apply(this, arguments);
    };
};

$('body, html').animate({ scrollTop: stop }, delay, runOnce(function() {
   console.log('scroll complete');
}));

51
JS çözümünün bir kusuru var! animate işlevi html öğesi ve gövde öğesi için iki kez yürütülür . Görünüşe göre Webkit tarayıcıları gövde kullanıyor, geri kalanı html kullanıyor . Bu düzeltme işi yapmalı$(jQuery.browser.webkit ? "body": "html").animate(...);
Andreyco

2
Andreyco'nun çözümünün, kullandığım jQuery <1.4'te çalışmadığını buldum. Böyle düzeltmek başardı: $(jQuery.browser.mozilla ? "html" : "body").animate(...);. Göz atma kokusunu değil, özellik algılamayı kullanmak harika olurdu. Yine de CSS'de özellik tespiti nasıl yapılacağından emin değilim
Rustavore

23
Not, jQuery.browserson jQuery sürümünde kullanımdan kaldırıldı ve eksik
spiderplant0

2
4 yıl geçti ve bu cevap hala faydalı oluyor. Çok teşekkürler!
Matt

1
@DFFa: Temelde, çünkü window.scrollanimasyon değil. Elbette aralıklarla ve kendi şeylerinizi yuvarlayabilirsiniz scrollBy. Buna hareket hızı eklemek istiyorsanız, birdenbire ürününüzün küçük bir yönü için yazmak için çok fazla kodunuz olur.
David Hedlund

19

Özellik algılama ve ardından desteklenen tek bir nesne üzerinde animasyon yapmak iyi olurdu, ancak tek satırlık bir çözüm yoktur. Bu arada, yürütme başına tek bir geri arama yapmak için bir söz vermenin bir yolu.

$('html, body')
    .animate({ scrollTop: 100 })
    .promise()
    .then(function(){
        // callback code here
    })
});

GÜNCELLEME: Bunun yerine özellik algılamayı nasıl kullanabileceğiniz aşağıda açıklanmıştır. Bu kod parçasının animasyon çağrınızdan önce değerlendirilmesi gerekiyor:

// Note that the DOM needs to be loaded first, 
// or else document.body will be undefined
function getScrollTopElement() {

    // if missing doctype (quirks mode) then will always use 'body'
    if ( document.compatMode !== 'CSS1Compat' ) return 'body';

    // if there's a doctype (and your page should)
    // most browsers will support the scrollTop property on EITHER html OR body
    // we'll have to do a quick test to detect which one...

    var html = document.documentElement;
    var body = document.body;

    // get our starting position. 
    // pageYOffset works for all browsers except IE8 and below
    var startingY = window.pageYOffset || body.scrollTop || html.scrollTop;

    // scroll the window down by 1px (scrollTo works in all browsers)
    var newY = startingY + 1;
    window.scrollTo(0, newY);

    // And check which property changed
    // FF and IE use only html. Safari uses only body.
    // Chrome has values for both, but says 
    // body.scrollTop is deprecated when in Strict mode.,
    // so let's check for html first.
    var element = ( html.scrollTop === newY ) ? 'html' : 'body';

    // now reset back to the starting position
    window.scrollTo(0, startingY);

    return element;
}

// store the element selector name in a global var -
// we'll use this as the selector for our page scrolling animation.
scrollTopElement = getScrollTopElement();

Şimdi sayfa kaydırma animasyonu için seçici olarak tanımladığımız var ve normal sözdizimini kullanın:

$(scrollTopElement).animate({ scrollTop: 100 }, 500, function() {
    // normal callback
});

Normal şartlar altında harika çalışıyor, teşekkürler! Ancak farkında olmak için birkaç gotchas var. (1) Özellik testi çalıştığında gövdede pencerenin taşması için yeterli içerik yoksa, pencere kaymaz ve test sahte bir "gövde" sonucu döndürür. (2) Test iOS'ta bir iframe içinde çalışıyorsa aynı nedenden dolayı başarısız olur. İOS'ta iframe'ler, içerik kaydırılmadan içeri girene kadar dikey olarak (yatay değil) genişler. (3) Test ana pencerede yürütüldüğünden, zaten yerinde olan kaydırma işleyicilerini tetikler. ... (devam)
hashchange

... Bu nedenlerden ötürü, kurşun geçirmez bir testin, yatay kaydırma (çözme (2)) için test edilen yeterince büyük içeriğe (çözme (1)) sahip özel bir iframe (çözme (3)) içinde çalışması gerekir.
hashchange

Aslında bu tutarlı sonuçlar vermek için bir zaman aşımı komut dosyasında bu işlevi çalıştırmak zorunda kaldı, aksi takdirde bazen dönmek htmlve bazen dönmek gibi görünüyordu body. İşte işlevi bildirdikten sonra benim kod İşte var scrollTopElement; setTimeout( function() { scrollTopElement = getScrollTopElement(); console.log(scrollTopElement); }, 1000); bunun için teşekkür ederim, ama sorunumu çözdü.
Tony M

Boş ver, asıl sorunun ne olduğunu anladım. Eğer yeniden zaten sayfanın alt (f5) yerindeyseniz, bu komut dönecektir htmlyerine bodyo gerektiği gibi. Bu, yalnızca web sayfasında aşağı doğru kaydırıldığınızda ve yeniden yüklerseniz, aksi takdirde çalışır.
Tony M

Sayfanın alt kısmında açılıp açılmadığını kontrol ettikten sonra bu benim için çalıştı.
scott

6

Kodumu neden işe yaramıyor?

$('body,html').animate({scrollTop: 50}, 500);

Sorun benim css oldu -

body { height: 100%};

Bunun autoyerine ayarladım (ve neden 100%ilk etapta ayarlandığı konusunda endişelenmeye bırakıldım ). Bu benim için sorunumu çözdü.


2

Bir eklenti kullanarak sorunu atlatmak isteyebilirsiniz - daha spesifik olarak eklentim :)

Ciddi olarak, temel sorun çoktan beri ele alınmış olsa da (farklı tarayıcılar pencere kaydırma için farklı öğeler kullanıyor), hatta sizi uyandırabilecek birkaç önemsiz sorun var:

Açıkçası önyargılıyım, ancak jQuery.scrollable aslında bu sorunları ele almak için iyi bir seçimdir. (Aslında, hepsini işleyen başka bir eklenti bilmiyorum.)

Eğer ilerleyin tek - - ile kurşun geçirmez bir şekilde ek olarak, hedef konuma hesaplayabilirsiniz bu ve özü işlevi .getScrollTargetPosition()

Hepsi seni terk edecek

function scrolear ( destino ) {
    var $window = $( window ),
        targetPosition = getScrollTargetPosition ( $( destino ), $window );

    $window.scrollTo( targetPosition, { duration: 1000 } );

    return false;
}

1

Buna dikkat et. Aynı sorunu yaşadım, ne Firefox ne de Explorer ile

$('body').animate({scrollTop:pos_},1500,function(){do X});

David'in dediği gibi kullandım

$('body, html').animate({scrollTop:pos_},1500,function(){do X});

Harika çalıştı, ama yeni sorun, çünkü iki eleman var, vücut ve html, fonksiyon iki kez yürütülür, bu, X iki kez çalışır.

yalnızca 'html' ile çalıştı ve Firefox ve Explorer çalışıyor, ancak şimdi Chrome bunu desteklemiyor.

Chrome için gerekli gövde ve Firefox ve Explorer için html. Bir jQuery hatası mı? bilmiyorum.

İki kez çalışacağı için işlevinize dikkat edin.


bunun için bir çözüm buldunuz mu? Ve jquery tarayıcı algılaması kullanımdan kaldırıldığından, krom ve firefox'u ayırt etmek için özellik algılamayı nasıl kullanabileceğimi bilmiyorum. Belgelerinde, firefox veya viceversa'da değil kromda bulunan bir özellik belirtilmez. :(
Mandeep Jain

2
.stop (true, true) .animate?
Toni Michel Caubet

0

Ben öneriyoruz değil güvenerek bodyne de htmlbir daha taşınabilir bir çözüm olarak. Sadece gövdeye kaydırılan öğeleri içermeyi amaçlayan bir div ekleyin ve tam boyutlu kaydırmayı etkinleştirmek için ona stil verin:

#my-scroll {
  position: absolute;
  width: 100%;
  height: 100%;
  overflow: auto;
}

( display:block;ve top:0;left:0;hedefinizle eşleşen varsayılan değerler olduğu varsayılırsa), ardından $('#my-scroll')animasyonlarınız için kullanın .


0

Gerçek anlaşma bu. Chrome ve Firefox'ta kusursuz bir şekilde çalışır. Bazı cahillerin bana oy vermesi bile üzücü. Bu kod, tüm tarayıcılarda olduğu gibi tam anlamıyla mükemmel çalışır. Sadece bir bağlantı eklemeniz ve kaydırmak istediğiniz öğenin kimliğini href'e koymanız yeterlidir ve hiçbir şey belirtmeden çalışır. Saf yeniden kullanılabilir ve güvenilir kod.

$(document).ready(function() {
  function filterPath(string) {
    return string
    .replace(/^\//,'')
    .replace(/(index|default).[a-zA-Z]{3,4}$/,'')
    .replace(/\/$/,'');
  }
  var locationPath = filterPath(location.pathname);
  var scrollElem = scrollableElement('html', 'body');

  $('a[href*=#]').each(function() {
    var thisPath = filterPath(this.pathname) || locationPath;
    if (locationPath == thisPath
    && (location.hostname == this.hostname || !this.hostname)
    && this.hash.replace(/#/,'') ) {
      var $target = $(this.hash), target = this.hash;
      if (target) {
        var targetOffset = $target.offset().top;
        $(this).click(function(event) {
          event.preventDefault();
          $(scrollElem).animate({scrollTop: targetOffset}, 400, function() {
            location.hash = target;
          });
        });
      }
    }
  });

  // use the first element that is "scrollable"
  function scrollableElement(els) {
    for (var i = 0, argLength = arguments.length; i <argLength; i++) {
      var el = arguments[i],
          $scrollElement = $(el);
      if ($scrollElement.scrollTop()> 0) {
        return el;
      } else {
        $scrollElement.scrollTop(1);
        var isScrollable = $scrollElement.scrollTop()> 0;
        $scrollElement.scrollTop(0);
        if (isScrollable) {
          return el;
        }
      }
    }
    return [];
  }
});

1
Karmaşık olabilir, ama gerçekten yararlıdır. Temel olarak tüm tarayıcılarda Tak ve Çalıştır özelliğiyle çalışır. Daha basit bir çözüm bunu yapmanıza izin vermeyebilir.
drjorgepolanco

0

Son zamanlarda aynı sorunla karşılaştım ve bunu yaparak çözdüm:

$ ('html, body'). animate ({scrollTop: $ ('. class_of_div'). offset () .top}, 'fast'});

Ve youpi !!! tüm tarayıcılarda çalışır.

konumlandırma doğru değilse, bunu yaparak ofset () .top öğesinden bir değer çıkarabilirsiniz.

$ ('html, body'). animate ({scrollTop: $ ('. class_of_div'). offset () .top-desired_value}, 'fast'});

Bu çözüm mevcut cevaplarda zaten belirtilmiştir, ancak paylaştığınız için teşekkür ederiz
Toni Michel Caubet

Bu yöntem, Firefox'ta, az önce gönderdiğim soruda belirtildiği gibi bir aksaklıkla karşılaşıyor: stackoverflow.com/q/58617731/1056713
Chaya Cooper

-3

Benim için sorun, firefox'un URL'ye koyduğum karma adıyla aynı name-özniteliğiyle otomatik olarak çapa atlamasıydı. Bunu önlemek için .preventDefault () yazmış olmama rağmen. Bu nedenle, ad özniteliklerini değiştirdikten sonra, firefox otomatik olarak çapalara atlamadı, ancak animasyonu doğru gerçekleştirdi.

@Toni Bu anlaşılabilir değilse özür dilerim. Mesele şu ki, URL'deki karmaları www.someurl.com/#hashname gibi değiştirdim. Sonra örneğin <a name="hashname" ...></a>jQuery otomatik olarak kaydırmak gibi bir çapa vardı . Ancak, herhangi bir kaydırma animasyonu olmadan Firefox'ta eşleşen ad özelliğiyle doğrudan bağlantıya atladığı için olmadı. Name özniteliğini karma adından farklı bir şeyle değiştirdikten sonra, örneğin name="hashname-anchor"kaydırma çalıştı.


-5

Benim için, kimliği animasyon noktasına eklemekten kaçınıyordu:

Kaçınma:

 scrollTop: $('#' + id).offset().top

Kimliği önceden hazırlama ve bunun yerine bunu yapma:

 scrollTop: $(id).offset().top

FF'de düzeltildi. (Css eklemeleri benim için bir fark yaratmadı)


-8
setTimeout(function(){                               
                   $('html,body').animate({ scrollTop: top }, 400);
                 },0);

Umarım bu işe yarar.


4
Burada setTimeut nasıl yardımcı oluyor?
Toni Michel Caubet

2
@ToniMichelCaubet, muhtemelen animasyonu eşzamansız hale getirmektir. jQuery animasyonları zaten eşzamansızdır, bu nedenle bu hiçbir şey yapmaz.
mwcz

Soruna düşünceli bir cevap değil. Bunun ne yapacağından emin değilim.
erier
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.