カテゴリー: JavaScript/jQuery

  • iOS SafariでリロードするとjQueryが動かなくなったとき

    iOS SafariでリロードするとjQueryが動かなくなったとき

    「ページをリロードすると、iOSのSafariだけアニメーションが動かない」と報告を受けたので、調べた結果、

    $(window).on(‘load’, function(){}) が同じ関数内で2回使われていると、うまく動かないようでした。よく考えたら確かにおかしい書き方なんですが、他のブラウザでは動いてしまうので、なかなか気づけませんでした。

     

    正確には、僕のコードは以下のようになっていたところ、

    $(function () {
      // When Document Ready
      animation();
    });
    
    function animation() {
    
      $(window).on('load scroll', function () {
        // ロードおよびスクロールしたときに動くアニメーション
      });
    
      $(window).on('load', function () {
        // ロードしたときに動く別のアニメーション
      });
    
    }

    こう直すと動きました↓

    $(function () {
      // When Document Ready
      animation();
    });
    $(window).on('load',function(){
      // When Window Load
      animation2();
    });
    
    function animation() {
    
      $(window).on('load scroll', function () {
        // ロードおよびスクロールしたときに動くアニメーション
      });
    
    }
    
    function animation2() {
      // ロードしたときに動く別のアニメーション
    }

    「ロードしたときに動く別のアニメーション」を、分離したわけですね。

    現場からは以上です。

  • 複数のslickスライダーを設置し、自動スライドの開始タイミングをずらす

    複数のslickスライダーを設置し、自動スライドの開始タイミングをずらす

    「ええ!?複数設置したslickスライダーのスライド開始タイミングをずらす!?」

    「できらぁっ!」




    実装

    単純にsettimeoutでslick()の実行タイミングを遅らせるだけでは、slick()が実行されていない段階のレイアウト崩れが発生してしまう。

    というわけで、「読み込まれてから〇秒後に、自動スライドを開始する」作戦でいきましょう。

    こうです。

    $('#pickupSlider01').slick({
      /* 1つ目のスライダーのオプション */
    });
    // 0.5秒後に2つ目のスライダーのautoplayを開始
    $('#pickupSlider02').on('init', function () {
      var $self = $(this);
      setTimeout(function () {
        $self.slick('slickSetOption', 'autoplay', true, true);
      }, 500);
    });
    $('#pickupSlider02').slick({
      /* 2つ目のスライダーのオプション */
    });
    // 1秒後に3つ目のスライダーのautoplayを開始
    $('#pickupSlider03').on('init', function () {
      var $self = $(this);
      setTimeout(function () {
        $self.slick('slickSetOption', 'autoplay', true, true);
      }, 1000);
    });
    $('#pickupSlider03').slick({
      /* 3つ目のスライダーのオプション */
    });

    もっとあるときはeachで回すのもあり。
    現場からは以上です。

  • MW WP Formの日付ピッカーが動かないときの覚書

    MW WP Formの日付ピッカーが動かないときの覚書

    MW WP Formの日付ピッカーが動かなくて時間を食ったので、また同じことにならないように覚書。

    エラーを見ると、

    $(...).datepicker is not a function

    と言われている。

    wp_headやwp_footerも忘れてないし、他にjsのエラーが出ているわけでもないのに何だろうと思って調べていたら、どうもdatepickerはjQuery本体の他にjQuery UIもないと動かないらしい。

    本来、wp_enqueue_script()を使ってwp_head()内でスクリプトたちを読み込んでいると、それに合わせてMW WP Formのプラグインもwp_head内にjQuery UIを読み込んでくれるんだと思うんだけど、僕はめんどくさくてテンプレートに直に書いてスクリプトを呼び出してるので、スクリプトを読み込む順番がおかしくなっていて、jQuery UIを読み込む前にdatepickerを実行しちゃっていたのが原因っぽい。

     

    これを回避するには、WP推奨通りちゃんとwp_enqueue_script()を使ってスクリプトを読み込むか、

    <script src="https://code.jquery.com/ui/1.11.4/jquery-ui.min.js"></script>

    手抜きする場合はこれをjQuery本体呼び出しの後に書いてやれば動きます。

     

    以上、現場からでした!

  • 【jQuery】ゆっくり流れる無限ループスライダー(逆向きも)

    【jQuery】ゆっくり流れる無限ループスライダー(逆向きも)

    昔、下の記事でSlick.jsを使った無限ループスライダーの実装方法を紹介しましたが、

    【簡単】slick.jsで無限ループスライダー

    いろいろ問題があるうえ逆向き(左から右)ができないということで、今回はプラグインなしでjQuery+CSSで実装する方法を紹介します。

    こんな感じになります↓

    それでは実装してみましょう。




    html

    <div class="slider">
      <div class="slider__inner">
        <div class="slider__item"><img src="https://meshikui.com/wp-content/uploads/2020/07/iphone8IMGL8205_TP_V.jpg" alt="" width="300"></div>
        <div class="slider__item"><img src="https://meshikui.com/wp-content/uploads/2020/07/200713.jpg" alt="" width="300"></div>
        <div class="slider__item"><img src="https://meshikui.com/wp-content/uploads/2020/07/200701.jpg" alt="" width="300"></div>
        <div class="slider__item"><img src="https://meshikui.com/wp-content/uploads/2020/05/blackmondayIMGL0444_TP_V.jpg" alt="" width="300"></div>
        <div class="slider__item"><img src="https://meshikui.com/wp-content/uploads/2020/04/200402.jpg" alt="" width="300"></div>
      </div>
    </div>

     

    jQuery

    グループ一つではループできないので、jQueryで3つに分身させます

    <script>
      $(function(){
        $('.slider__inner').each(function(){
          var sliderWidth = $(this).width();
    
          $(this).clone(true).insertBefore(this);
          $(this).clone(true).insertAfter(this);
    
          $('.slider').css('width', sliderWidth*3); // 親要素の横幅を子要素の3倍にする
        });
      });
    </script>

     

    CSS

    CSS Animationを使って動かします。
    まずは、全てを横並びにしましょう。

    .slider {
      display: flex;
    }
    .slider__inner {
      display: flex;
    }

    続いてアニメーションの部分。

    右から左

    .slider__inner:first-child {
      animation: loop 90s linear infinite;
    }
    
    .slider__inner:nth-child(2) {
      animation: loop2 90s -60s linear infinite;
    }
    
    .slider__inner:last-child {
      animation: loop3 90s -30s linear infinite;
    }
    
    @keyframes loop {
      0% {
        transform: translateX(200%);
      }
      to {
        transform: translateX(-100%);
      }
    }
    
    @keyframes loop2 {
      0% {
        transform: translateX(100%);
      }
      to {
        transform: translateX(-200%);
      }
    }
    
    @keyframes loop3 {
      0% {
        transform: translateX(0%);
      }
      to {
        transform: translateX(-300%);
      }
    }

    2つめと3つめのグループのdulationを、speedの-1/3、-2/3にするのがポイント。

    左から右

    .slider__inner:first-child {
      animation: loop 90s linear infinite;
    }
    
    .slider__inner:nth-child(2) {
      animation: loop2 90s -60s linear infinite;
    }
    
    .slider__inner:last-child {
      animation: loop3 90s -30s linear infinite;
    }
    
    @keyframes loop {
      0% {
        transform: translateX(-100%);
      }
      to {
        transform: translateX(200%);
      }
    }
    
    @keyframes loop2 {
      0% {
        transform: translateX(-200%);
      }
      to {
        transform: translateX(100%);
      }
    }
    
    @keyframes loop3 {
      0% {
        transform: translateX(-300%);
      }
      to {
        transform: translateX(0%);
      }
    }

    地味に需要があるかもしれない!最初ちょっと崩れるかもなぁってときは、ローディング画面にするか透明にしとくか、適当に隠しておきましょう。
    現場からは以上です。

  • jQuery スクロールでふわっと出てきてフッターで止まる追従ボタン

    jQuery スクロールでふわっと出てきてフッターで止まる追従ボタン

    「トップへ戻る」ボタンなど、ページ開いたときは出てないけど、ちょっとスクロールすると出てきてスクロールとともに追従し、フッター手前とかでピタッと止まる、そんなボタン。

    割とよく実装する割に面倒なので、すぐ使えるようメモ。




    実装

    $(function () {
      var topBtn = $('#goTop'); // ボタンを指定
      topBtn.hide(); //最初は隠しておく。CSSで隠してもオッケー
    
      $(window).on("scroll", function () {
        if ($(this).scrollTop() > 100) { // 100px以上スクロールしたら出てくる
          topBtn.fadeIn();
        } else {
          topBtn.fadeOut();
        }
    
        scrollHeight = $(document).height();
        scrollPosition = $(window).height() + $(window).scrollTop();
        footHeight = $("#footer").innerHeight(); // ここでフッターの高さを取得
        if ( scrollHeight - scrollPosition  <= footHeight ) { // フッター付近まで来たら
          topBtn.css({
            "position":"absolute",
            "bottom": footHeight + 65 // フッターの65px上で止まる
          });
        } else { // それ以外は画面下から20pxの位置に固定
          topBtn.css({
          "position":"fixed",
          "bottom": "20px"
        });
        }
    
      });
    });

    #goTopは#footerの中に入れておき、#footerはposition:relative;にしておく

    例↓

    <footer id="footer" class="footer">
      <div id="goTop" class="goTop"><a href="#header">トップへ戻る</a></div>
    </footer>

    現場からは以上です。

  • jQuery メニューを開いているときはbodyのスクロールを禁止する

    jQuery メニューを開いているときはbodyのスクロールを禁止する

    スマホのハンバーガーメニューとかでメニューが開いているとき、bodyがスクロールするのが嫌な人が多いらしいので、スクロールできないようにする。

    よく実装する割にややこしいので、実装方法をメモ。




    実装

    $(function () {
      /*
      * Menu SP
      */
      var flag = false;
      $('.header-sp__menu a').on('click', function () {
        if (flag == false) {
          bodyFix(); // bodyを固定させる関数
    
          // その他、ナビを開くときに起きるあれこれを記述
    
          flag = true;
        } else {
          closeNavi();
          flag = false;
        }
      });
    });
    
    //ナビを閉じるときの関数
    function closeNavi() {
      bodyFixReset(); // body固定を解除する関数
    
      // その他、ナビを閉じるときに起きるあれこれを記述
    
    }
    
    //以下、bodyを固定する関数
    function bodyFix() {
      const scrollPosi = $(window).scrollTop();
      $('body').css({
        'position': 'fixed',
        'width': '100%',
        'z-index': '1',
        'top': -scrollPosi
      });
    }
    
    //以下、body固定を解除する関数
    function bodyFixReset() {
      const scrollPosi = $('body').offset().top;
      $('body').css({
        'position': 'relative',
        'width': 'auto',
        'top': 'auto'
      });
      //scroll位置を調整
      $('html, body').scrollTop(-scrollPosi);
    }

    bodyを固定する記述、bodyの固定を解除する記述をそれぞれ関数にして、メニューを開くボタンを押したとき、メニューを閉じるボタンを押したときにそれぞれ実行されるようにしています。

    メニューを閉じるときの処理は、いろんなボタンで行われる可能性があるので、使いまわせるように関数化。

    以前、以下の記事でflagを使わずにclickイベントを交互に制御する方法を書いたのですが、

    jQuery clickするごとに交互に処理を行う関数を作ってしまう

    例えば「ハンバーガーメニューをタップするとメニューが開き、閉じるときはメニュー内の”閉じるボタン”をクリックする」のように、別のボタン間で開閉を制御してやる必要がある場合は使えないので、素直にflagを使ってます。

    メニューの開閉、意外とややこしいよね。

     

    以上、現場からでした。

  • jQuery clickするごとに交互に処理を行う関数を作ってしまう

    jQuery clickするごとに交互に処理を行う関数を作ってしまう

    jQueryで’click()’というと、クリックしたときのイベント処理を行うメソッド。

    例えば以下のように使います

    <script>
        $('button').on('click', function() {
            alert('クリックしたぞ');
        })
    </script>

    しかし、これだけでは「クリックするごとに交互に処理を行う」というときに、若干めんどくさい。アコーディオンとかね。

    slideToggleとかtoggleClassでなんとかなるレベルの処理ならいいけど、それ以上のこと、例えばテキストを変えたりしなきゃいけないとき、よく紹介されているのは、なんかflagをfalseにしといて、1回クリックされたらflagをtrueにして、もしflagがtrueだったときはこっちの処理を…とかもうややこしいので、もっとシンプルにやりたい。そうだ、どうせなら関数を作ってしまおうよ。




    関数を作る

    こんな感じで関数を作りましょう

    $.fn.clickToggle = function (a, b) {
      return this.each(function () {
        var clicked = false;
        $(this).on('click', function () {
          clicked = !clicked;
          if (clicked) {
            return a.apply(this, arguments);
          }
          return b.apply(this, arguments);
        });
      });
    };

    これで、’clickToggle()‘という関数が使えるようになりました!関数は一度作ってしまえばどこでも使えます。

    使う

    使うときは以下のように使います

    $('button').clickToggle(function () {
      // 1回目のクリック
      $(this).next('.target').slideDown(300);
      $(this).text('閉じる');
    }, function () {
      // 2回目のクリック
      $(this).next('.target').slideUp(300);
      $(this).text('開く');
    });

    だいぶすっきり書けますね!’hover’とだいたい同じような書き方になる。

     

    昔は’toggle()’という超便利な関数があったんですが、jQuery2以上から使えなくなりました。今でも普通に紹介されている記事いっぱいありますが、使えません。気をつけましょう

    現場からは以上です。

  • 【jQuery】フォームの二重送信を防止するシンプルな方法

    【jQuery】フォームの二重送信を防止するシンプルな方法

    フォームの「送信」ボタンを連続で押すとメールが多重送信されちゃうから、それを阻止したいとなった。

    独自でフォームを作っているなら、phpでトークンを使って検証して動作を制御なんてこともできるんですが、WordPressでプラグインとかを使っている場合、phpをいじるのはちょっと現実的ではない。

    というわけで、今回はjQueryで3分でできちゃう方法をご紹介します。




    実装

    HTML

    フォームのHTML。とりあえずサブミットボタンにIDをつけましょう。

    <input type="submit" id="double" value="送信する">

    余談ですが、cssでスタイリングするときはclass、javascriptで動かす場合はidにしておくとわかりやすくていいですよ。また、classじゃなくてidで動かしたほうが圧倒的に処理が速いみたいです。僕はスタイリングの際はほとんどidを使用しません。

    jQuery

    たった3行。

    $('#double').on('click', function () {
      $(this).css('pointer-events','none');
    });

    “#double”をクリックしたら、それに{pointer-events:none;}をつけてるだけですね。シンプルー!

    pointer-events: none;はマウスホバーやクリック等のイベントの一切を禁止する神のようなプロパティで、便利すぎるのでちょいちょい使ってます。ボタンを1回クリックしたら、cssでそれ以降のイベントを禁止する。簡単ですね。

    欠点

    例のごとく、IE10以下では使えません。まぁ、もういいんじゃない?

    安全性も動作も完璧に仕上げたいのであれば、phpでがんばるしかないかなと思いますが、実装費用に比べて効果はどんなものかといったところで相談しましょう。けっこう大変ですよ。

    disabledじゃだめなの?

    フォームのパーツの操作を全面的に禁止する”disabled”というものがありますよね。実は僕も最初これを使ってやってみたんですが、サブミットボタンがdisabledになった瞬間、フォームの送信も中断されてしまうんですね。送信ボタンを押しても何も起きない。そして2度とボタンは押せないのである。

    巷ではこれを回避するために、ボタンが押されたらdisabledとなると同時に、ajaxで別途フォームの内容を送信するという方法が紹介されていましたが、これまたWordPressプラグインでやるのはきついです。

    cssでイベントを禁止するだけなら、フォーム送信を妨げることもありません。

     

    以上、現場からでした。

  • jQuery – アコーディオンを開いたら、他のアコーディオンが閉じるようにする

    jQuery – アコーディオンを開いたら、他のアコーディオンが閉じるようにする

    複数のアコーディオンがあるとき、全部開くとすごいことになるので、1つ開いたら他のアコーディオンは閉じるようにしてほしいというご要望。




    ソースは以下の通り

    var parent = $('dt');
    parent.each(function(){
    	var self = $(this);
    	self.on('click',function(){
    		parent.not(self).next('dd').slideUp(300);
    		self.next('dd').slideToggle(300);
    	});
    });

     

    dtをクリックしたら、その次のddがslideToggleするよというコードですが、クリックしてないdtの次のddは閉じるようにしてやります。

    ポイントは、$(this)を変数’self’に格納して使いやすくしたうえで、‘.not(self)’で「$(this)以外」という指定をしている点。$(this)も変数に格納できるんですね!これに気づけばいろいろ捗りそう。

     

    現場からは以上です。

  • 【簡単】slick.jsで無限ループスライダー

    【簡単】slick.jsで無限ループスライダー

    この記事の方法はちょっと苦しいので、プラグインなしで実装する方法も紹介しています!

    ゆっくり流れる無限ループスライダー(逆方向も)

    ホームページ上にスライドショーを実装するとき、いつもお世話になっているslick.jsで、画像がずっと流れ続ける無限ループスライダーを実装。




    実装

    ソースは以下

    $('#slider').slick({
      slidesToShow: 5,
      centerMode: true,
      arrows: false,
      autoplay: true,
      autoplaySpeed: 0, //待ち時間を0に
      speed: 10000, // スピードをゆっくり
      swipe: false, // 操作による切り替えはさせない
      cssEase: 'linear', // 切り替えイージングを'linear'に
      // 以下、操作後に止まってしまう仕様の対策
      pauseOnFocus: false,
      pauseOnHover: false,
      pauseOnDotsHover: false,
    
      // 以下、レスポンシブ
      responsive: [
        {
          breakpoint: 750,
          settings: {
            slidesToShow: 3,
          }
        }
      ]
    });

    要するに、「常に均等なスピードでゆっくり動いていれば」それっぽい感じになるので、

    ・待ち時間をなくす
    ・スピードを遅くする
    ・イージングを’linear’にする

    といった設定をしてやればOK。

    ちょっとガタつくかなーと思ったら、

    slidesToScroll: 5

    とかで一気に動かしてやると、いい感じになる。

    現場からは以上です。

  • jQuery チェックしたラジオボタンの値を、テキストフィールドに反映させる方法

    jQuery チェックしたラジオボタンの値を、テキストフィールドに反映させる方法

    ラジオボタンでチェックさせ、その値を別のテキストフィールドに反映させる方法。

    例えば、メールアドレス入力のときに@以降を選択させることができる。




    <input type="email" name="your-email">
    
    <p>※@以降を以下から選択できます。</p>
    <ul class="addressList">
      <li><label><input type="radio" name="addressSelect" value="" checked>選択なし</label></li>
      <li><label><input type="radio" name="addressSelect" value="@docomo.ne.jp">@docomo.ne.jp</label></li>
      <li><label><input type="radio" name="addressSelect" value="@ezweb.ne.jp">@ezweb.ne.jp</label></li>
      <li><label><input type="radio" name="addressSelect" value="@softbank.ne.jp">@softbank.ne.jp</label></li>
      <li><label><input type="radio" name="addressSelect" value="@yahoo.co.jp">@yahoo.co.jp</label></li>
      <li><label><input type="radio" name="addressSelect" value="@gmail.com">@gmail.com</label></li>
    </ul>
    $(function(){
        var addressSelect = $('input[name="addressSelect"]');
        var yourEmail = $('input[name="your-email"]');
    
        addressSelect.change(function(){
            var selectVal = $(this).val();
            var getAddressData = yourEmail.val();
            var posData = getAddressData.indexOf('@');
            
            if(posData < 0) {
                addressData = getAddressData;
            } else {
                addressData = getAddressData.substring(0,posData);
            }
            yourEmail.val(addressData + selectVal);
        });
    });

     

    8行目の

    var posData = getAddressData.indexOf('@');

    で、テキストフィールド内の@以降の文字列を取得。

    if(posData < 0) {
        addressData = getAddressData;
    } else {
        addressData = getAddressData.substring(0,posData);
    }

    もし@以降に文字列があれば、@までの文字列を取得する。
    @以降に文字列がなければ、全ての文字列を取得する。

    これにより、例えば

    hogehoge@gmail.com

    と既に入力していても、@以降のみを変更することが可能。

     

    そんな処理は必要なく、ただ反映させたいだけであれば上記をまるっと削除し、

    $(function(){
        var addressSelect = $('input[name="addressSelect"]');
        var yourEmail = $('input[name="your-email"]');
    
        addressSelect.change(function(){
            var selectVal = $(this).val();
            var getAddressData = yourEmail.val();
    
            yourEmail.val(getAddressData + selectVal);
        });
    });

    これだけでOK。

    ラジオボタンで値を選択すると、テキストフィールドに入力した値は削除され上書きされる。