jQuery

jQueryとは

jQueryはJavaScriptのライブラリ。
JavaScriptで行えるほぼ全てのことを、JavaScriptよりも簡単に行える。

jQueryへのリンク

コピーした記述をindex.htmlのhead内に以下のように貼り付けることでjQueryを読み込める。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>jQuery Practice</title>
    <link href="style.css" charset="utf-8">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
    <script src="./main.js"></script>
  </head>

Railsでjqueryを使う方法

gemファイルに以下を記入してbundle install

gem 'jquery-rails'

spp/asset/javascript/application.jsに以下の記述があるか確認。
なければ追記。

//= require jquery
//= require jquery_ujs

注意点として、require tree .より上にjqueryを書くこと。
require tree以下でjsファイルが読み込まれるため、下に書くとjqueryがロードされる前にjqueryの内容を含むjsファイルが読まれ、Uncaught ReferenceErrorを吐く。

予備知識

$(function() { … }

記述することでHTML要素が全て読み込み終わったタイミングで処理を実行してくれる。

無名関数

function() 

無名関数とは文字通り名前のついていない関数のこと。
1回しか使わないのであれば名前をつける必要はない。
関数の定義をする場合、 function methodName(){}のような記述をするが、このmethodName部分を省略したのが無名関数。

テンプレート文字列 (式展開)

“で囲んだ中で${}とすると展開できる。
rubyで言う所の”#{}”と同じ。
シングルクオートではなくバッククオート`であることに注意!

コールバック

必要なタイミングで呼び出せるように、あらかじめ定義しておく関数のことをコールバックと呼ぶ。

DOM要素

JavaScriptでhtmlの要素を操作するための仕組み

Document Object Model

DOMオブジェクトとjQueryオブジェクト

DOMオブジェクトに対するメソッドとjQueryオブジェクトに対するメソッドは別物。
メソッドの返す値がjQueryオブジェクトかDOMか、それ以外なのか注意が必要。
$(DOM)とするとjQuery要素になる。
jQueryオブジェクトは配列に似た構造であるが、厳密には配列ではないのでDOMオブジェクトを配列に格納したものとは挙動が異なる。

var dom = $("form").find("label");
dom[1].hide();
↑これは動かない
$(dom[1]).hide();
↑これは動く。∵hideはjQueryメソッドだから。
DOMオブジェクトとjQuery オブジェクトで取得できる属性の違い。
###疑問画面上のあるボタンをクリックし、クリックイベント中にボタンの属性を取得する際に、DOMオブジェクトから属性を取得する場合と、jQueryオブジェクトから属性を取得する場合とで、

「プロパティ」と「属性」

DOMメソッド
以下はプロパティと属性をそれぞれ参照したものであるが、プロパティは適切に設定されたものでなければundefinedとなる。
e.target.href;      //プロパティ
e.target.getAttribute('href');    //属性
jQueryオブジェクト
$target.prop('href');     //プロパティ
$target.attr("href");     //属性

要素の取得

HTML要素を取得 セレクタ

jQueryでのHTML/CSSの操作は以下の2ステップ。

  1. HTML要素を取得する
  2. 取得したHTMLを操作する
$(function() {

  console.log($("#title"));

});

IDセレクタ

HTML要素のid属性で指定する。
id属性の値に#(ハッシュ)を付けて取得する。

$("#idSelector") 

クラスセレクタ

HTML要素のclass属性で指定する。
class属性の値に.(ドット)を付けて取得する

$(".classSelector")

要素セレクタ

h1やpのようなHTML要素を取得する
要素名をそのまま用いる。

$("h1") 
h1要素をすべて取得

該当するすべてのHTML要素が取得される。

$("セレクタ").jQueryの命令(引数);

:contains(“”)

$(‘td:contains(“hogehoge”)’)

要素の指定に続けて指定することで、指定した文字列を含む要素を抽出する。

:has(”)

要素の指定に続けて指定し、子要素に指定のセレクタを持っていればその親要素を抽出する。

以下の場合はstrongを配下に持つtdのみが取得される。
strongを取得するわけではない。

$('td:has(strong)')

要素取得のためのメソッド

parent()

指定した要素の親要素を取得できる。

$('#parent_target').parent().css('background-color', 'red');
li要素の親であるulが変更される。

find()

指定した要素の子孫要素を取得できる。
引数に指定したい要素を渡すことで、子孫要素の中から引数と一致した要素を取得できる。
返る値はDOM要素の配列。not jQuery object!

$('#find').find('#find_target').css('background-color', 'blue');

siblings()

指定した要素の兄弟要素を取得できる。
引数がある場合は、引数の要素に一致するすべての兄弟要素を取得。
引数がない場合は、すべての兄弟要素を取得。
(指定した要素自身は含まない)

next()

指定した要素の次の兄弟要素を取得する。(子要素は無視する)
引数がある場合には、引数の要素の次の要素を取得。
引数を与えなかった場合には、セレクタとして指定した要素の次の要素を取得。

.eq()

指定した要素のn番目の要素を取得する。
0番目から数える。

$('.form__field--right').eq(1).append(buildHTML(user))

:last .last()

要素のうち、最後のものを取得する。

$('li:last')

以下も同様に使える。

$('li').last()

this

関数の中でthisを使うと、イベントの発生元となった要素を取得することができる。

メソッド

text()

HTML要素のテキストを書き換える。
引数に書き換えたいテキストを文字列で指定する。
text()のように引数を与えずに使うとテキストの取得ができる。

html()

取得したHTML要素のテキストをHTMLタグを含むテキストに書き換える。
引数に書き換えたいHTML要素を文字列で指定する。
html()と引数を省略するとhtmlの内容を取得できる。

$("p").html("<strong>変更されたコンテンツ</strong>");

hide()

hide()を使用すると、要素を非表示する。
display: none;

show()

show()を使用すると、非表示の要素を表示する。

fadeOut()

指定したHTML要素がフェードアウトさせる。
引数にはフェードアウトするまでの時間(ミリ秒)を渡す。
opacityが下がって最終的にdisplay:none;になる。

fadeIn()

指定したHTML要素がフェードインする。
引数にはフェードインするまでの時間を渡す。

append()

引数に文字列もしくはDOM要素、jQueryオブジェクトを持てる。
指定する要素の最後に子要素を追加する。
<div>に対して使うと</div>の直前に挿入される。

$("#lists").append('<li class="list">追加されたリスト</li>');

jQueryオブジェクトを渡す場合には、一か所に挿入する操作の場合はコピーではなく移動になるため注意が必要。

jQueryオブジェクトを.append()する時は気をつけよう - UNITRUST
「想い」に挑戦する。
append(content) - jQuery 日本語リファレンス
 var list = $("#list");

  function appendList(word) {
    var item = $('<li class="list">').append(word);
    list.append(item);
  }

jQueryオブジェクトに対してしか使えない。
不用意に使うとappend is not a functionエラーが出る。

target = e.srcElement
target.append(test_div);
↑これはDOMオブジェクトなのでエラー。

jQueryならこう。
$(target).append(test_div);

javascriptならこう。
target.appendChild(test_div);

remove()

指定したHTML要素を削除できる。
似たメソッドにempty()があるが、これは指定した要素の子要素全てを削除する。

emptyメソッド

指定したDOM要素の子要素のみを削除する。
removeメソッドは指定した要素を削除する。

addClass()

要素に引数で設定したクラスを追加できる。

$("#addClassButton").on("click", function() {
  $("p").addClass("red");
});

removeClass()

要素から引数で設定したクラスを削除できる。

toggleClass()

そのクラスがすでにある場合はremoveClass()を、ない場合はaddClass()が行われる

$("#title").on("mouseover mouseout", function(){
  $(this).toggleClass("red");
});

条件を複数指定することもできる。
$(this)で起点となっているインスタンスを取得できる。

attr()

attr()を使用すると、HTML要素の属性値を取得・変更できる。
取得したい場合には、第一引数に取得したい属性を指定。
変更したい場合には、第一引数に変更したい属性を、第二引数に変更したい属性値を指定。

$("#changeAttrButton").on("click", function() {
  $("img").attr("src", "http://hogehoge.jpg");
});

.data()

引数なしの場合カスタムデータ属性を取得する。

$('p').data();

引数をつけた場合、該当するカスタムデータを取得する。

$('p').data('name');
↑
これはdata-nameの属性情報を取得する。

2つ引数をつけた場合、該当する属性に値を代入する。
属性がない場合には属性を付与する。(jQuery内部だけ有効)

.data( 属性名, 値 )
$('p').data('name', 'taro');

.data()と.attr()の違い

.attr()で情報を取得する場合は”data-”を省略できない。
また.data()に関しては取得した情報や代入した情報はjQuery内部でだけ扱われ(キャッシュされ)、htmlそのものへは影響しない。
一方、attr()で属性情報を変更した場合にはhtml自体が書き換えられる。

val()

val()を使用すると、フォームに入力された値を取得できる。
textboxの中身はtext()で取り出すのではなくval()

$("#valButton").on("click", function() {
  console.log($("input").val());
});

each()

JavaScriptにはForEachがあるが、こちらはjQuery用のeach文。
配列や連想配列に用いるeachと、jQueryオブジェクトに対するeachでは書き方が異なる。

配列用

$.each( collection, callback(index, value) )

callback関数の引数を省略する場合は、valueを取り出すのにthisを使う。
連想配列の場合はindexがキーの値です。

jQueryオブジェクト.each

jQueryオブジェクト.each( function(index, element){} )

配列

map(), filter(), reduce()

配列に対して配列順に処理して配列で返す。
eachでは処理をするのみで返り値を受け取れないので、配列の結果が欲しい際に使う。

array.map( コールバック関数, オブジェクト );

コールバック関数は3つの引数を持つ。
配列内の値、順番、そして配列そのもの。
array要素に対して処理を加えることで、元の配列のデータを変更できる。

products.map( function( value, index, array ) {
    array[index] = value + 1;
});

mapの第2引数は指定しなくてもよいが、指定することでthisとして参照できる。

products.map( function( value, index, array ) {
    return this[value];
}, reviews);

filter()は指定した条件のものを抜粋した配列を作りたい場合に、
reduceを配列内の連続する要素で処理を行って、配列の要素数を減らす際に用いる。
配列1と配列2を足すというような連続する処理を行う場合。

mapに関してはjava側の知識かも。jQueryとは別物?

jQuery.map() | jQuery API Documentation

fliter()

var arr = arr.filter(function(e){
    return e;
});

条件式がvalueになっており値があればtrueを返すので、上記の式では値のあるもののみ返す。

value、index、arrayのかき分けは?

$.each()

第一引数に繰り返し処理を行いたい配列を取り、第二引数に取り出した要素に対して行いたい処理を記述する。
この処理の第一引数には、配列の要素の番号(インデックス)をとり、第二引数には配列の要素が入る。

var fruits = ['apple', 'grape', 'lemon','berry'];

$(function() {
  $("#submit").on("click", function() {
    var input = $("#keyword").val();
    $.each(fruits, function(i, fruit) {
      if (input === fruit) {
        $("#result").text(input);
        return false;
      }
    });
  });
});

条件式

if文

if (pref == 'hogehoge') {
    console.log(pref+'です。');
  }

オブジェクト

formオブジェクト

非同期通信でのsubmitボタンの連続入力

連続送信を避けるため、標準で送信中は再び押せないようになっている。
いつの頃からかdata: disable_withが標準実装されたらしい。

f.submit "Send", data: {disable_with: '送信'}

非同期通信する際には入力が連続できずに困るのでこれを解除する。

$('#submit-btn').removeAttr('data-disable-with');

もしくはformないしsubmitに対してfalseを返してやれば再び押せるようになる。

$("#new_message").on('submit',function(e){
return false;
})

.reset()

フォームオブジェクトに対して使う。
フォーム内容を全てクリアする。
JSのメソッドのため[0]でDOMオブジェクトに戻す必要あり。

$("#new_message")[0].reset();
  • フォーム要素をresetすることで全ての項目をリセット可能
    (個別にvalをしなくて済み、コード量が減って可読性も向上)
  • inputの初期値があった場合、resetを使うとvalueにその初期値を入れることが可能

正規表現オブジェクト

regexp = new RegExp(patern[, flags])

var str = "abcde"
reg = new RegExp(str)
.match(reg)

正規表現を用いてmatch等を行う場合に直接文字列が扱えないので一旦オブジェクトに格納する。

文字列や複数検索をさせる時などに便利。
単体文字列ならばあえてregexpを使う必要性は低い?
var reg = RegExp(array.join(“|”))などとして、配列要素をバラして検索条件に入れる。

前方一致と後方一致

^をつけると前方一致。$をつけると後方一致。
^あいう なら「あいう」から始まる文字列の検索。
わをん$ なら「わをん」で終わる文字列で検索。

windowオブジェクト

クライアントサイドJavaScriptでは、実行される時に自動でwindowオブジェクトが作られる。
windowオブジェクトはブラウザに関する様々なプロパティ・メソッドを持つ。

プロパティ機能
navigatorブラウザ自身に関する情報をもつNavigatorオブジェクト
location現在のページに関する情報をもつLocationオブジェクト
historyブラウザの履歴をたどる back()forward() をもつHistoryオブジェクト
screen画面に関する情報をもつScreenオブジェクト
documentページのHTML文書に関する情報をもつDocumentオブジェクト
$(function() {
  $('.index1').click(function() {
    window.location = './index1.html';
  });
});
$('.forward').click(function() {
  window.history.forward();
});

イベント

on()メソッド

on()は、jQueryオブジェクトに対してイベントを設定するメソッド。
オブジェクトに対して「どんなイベントが起きたら」「何を実行するか」を設定できる。

$(function() {
  $("セレクタ").on("イベント", function() {
    イベントが起きた時に行う処理
  });
});

onメソッドの第2引数は関数を渡す。

イベント名該当するタイミング
clickクリックされた時
dblclickダブルクリックされた時
mouseoverマウスが要素の上に乗った時
mouseoutマウスが要素から離れた時
keydownキーが押された時
keyupキーが離されたとき
change入力内容が変更された時
submitsubmitボタンが押された時
$(function() {
  $("#title").on("click", function() {
    console.log("タイトルがクリックされました");
  });
});

イベントオブジェクト

targetやkeyCodeなどのプロパティを使うことでイベントの発生元の要素や押されたキーの種類などがわかる。

$(function() {
  $('form').on('submit', function(e) {
    console.log('送信ボタンが押されました');
    e.preventDefault();
  });
});

function(e)とすると(eはどんな文字列でも良いがeventの略が用いられる)イベントオブジェクトが渡される。イベントオブジェクトには、イベントの発生元の要素や押されたキーの情報などが入っているので、console.log(e);とすればコンソール上で確認できる。

preventDefault()

ブラウザが最初から持っているアクションをキャンセルする。

.prop()

引数で指定したプロパティを参照できる。

if (checkbox.prop('checked')) {
  output += checkbox.attr('value') + '\n';
}

動的に生成した要素に対してイベントを設定する方法

通常は以下のようにするが、このイベントで追加された要素に対してイベントが設定できない。

$(selector).on(event, function)

後から追加した要素にイベントを設定するには、元から存在する要素にイベントを設定する。そしてイベントの発生源が第2引数のtargetだった場合にイベントを発生させる。

$(selector).on(event, target, function)

これなら後から生成した要素に対してもイベントを起こせる。
なおこのfunction内で$(this)とした場合には、$(selector)ではなく、targetが格納される。

ナビゲーションバーに現在地を示すクラスを付与

navbar上のliタグに含まれるaタグからhrefを抜粋。
現在のlocation.hrefを抜粋し、aタグと対比。
同じであればcurrentを示すclassを付与し、違えばclassを削除する。

正規表現

「^」文頭を示す。
「$」文末を示す。

$(document).on('turbolinks:load', function() {
  $('.nav-item a').each(function(){
    var href = $(this).attr('href');
    var reg = new RegExp(href+'$')
    if(location.href.match(reg)){
      $(this).parent().addClass('active')
    }else{
      $(this).parent().removeClass('active')
    }
  })
});

Ajaxとは

Ajaxとは、Asynchronous JavaScript + XMLの略。
JavaScriptによる非同期通信を用いたプログラミングの手法のこと。
ユーザーがアクションを起こした際にページ全体を書き換えるのではなく、JavaScriptにサーバとの通信をさせ、ページの一部を書き換えることで、スムーズなUX(User Experience)を提供する。

$.ajax()

jqXHRオブジェクトを返す。
jqXHRは、JavaScriptから発行するHTTPリクエストとそのレスポンスに関する包括的な処理方法を提供

メソッド引数としてセットする値
done()レスポンスのJSONをJavaScriptの連想配列としたもの
fail()XMLHTTPRequestオブジェクト

API

APIとは、Application program interfaceの略で、何らかの目的を達成するための処理のまとまりのこと

HTTP通信

ブラウザ(=クライアント)からサーバへの通信を HTTPリクエスト 、
サーバからブラウザへの通信を HTTPレスポンス

HTTPリクエスト

  • リクエスト行
  • リクエスト・ヘッダ
  • ボディ部
> GET / HTTP/2
> Host: www.google.co.jp
> User-Agent: curl/7.54.0
> Accept: */*

1行目がHTTPメソッド、パス(この場合は”/” = ルート)、HTTPのバージョン情報
2行目〜がヘッダ部分

HTTPレスポンス

  • ステータス行
  • レスポンス・ヘッダ
  • ボディ部

ステータス行

種類概要説明
1xxInformational 情報リクエストは受け取られた。処理は継続される。
2xxSuccess 成功リクエストは受け取られ、理解され、受理された。
3xxRedirection リダイレクションリクエストを完了させるために、追加的な処理が必要。
4xxClient Error クライアントエラークライアントからのリクエストに誤りがあった。
5xxServer Error サーバエラーサーバがリクエストの処理に失敗した。
ステータスコード説明
200 OKリクエストは成功し、レスポンスとともに要求に応じた情報が返される。
301 Moved Permanentlyリクエストしたリソースが恒久的に移動されているときに返される。Location:ヘッダに移動先のURLが示されている。
302 Foundリクエストしたリソースが一時的に移動されているときに返される。Location:ヘッダに移動先のURLが示されている。
403 Forbiddenリソースにアクセスすることを拒否された。リクエストはしたが処理できないという意味。
404 Not Foundリソースが見つからなかった。
410 Goneリソースは恒久的に移動・消滅した。どこに行ったかもわからない。
500 Internal Server Errorサーバ内部エラー。
503 Service Unavailableサービスが一時的に過負荷やメンテナンスで使用不可能である。

FormData

フォームのデータの送信に使用できる。フォームの情報を取得するのに使う。
フォームとは独立して使用することもできます。

$(function(){
  $('#new_comment').on('submit', function(e){
    e.preventDefault();
    var formData = new FormData(this);
    console.log(formData)
    var url = $(this).attr('action')
    $.ajax({
      url: url,
      type: "POST",
      data: formData,
      dataType: 'json',
      processData: false,
      contentType: false
    })
  })
})

attrメソッド

要素が持つ指定属性の値を返す。
要素が指定属性を持っていない場合、関数はundefinedを返す。

processDataオプション

デフォルトはtrue。
dataに指定したオブジェクトをクエリ文字列に変換する役割がある。
FormDataを扱う場合にはfalseにする。

contentTypeオプション

サーバにデータのファイル形式を伝えるヘッダ。
デフォルトでは「text/xml」でコンテンツタイプをXMLとして返す。

ajaxのリクエストがFormDataのときはどちらの値も適切な状態で送ることが可能なため、falseにすることで設定が上書きされることを防ぐ。
FormDataで扱う場合にはfalseにする。

$(function(){
  function buildHTML(comment){
    var html = "<div> hoge </div>"
    return html;
  }
  $('#new_comment').on('submit', function(e){
    e.preventDefault();
    var formData = new FormData(this);
    var url = $(this).attr('action')
    $.ajax({
      url: url,
      type: "POST",
      data: formData,
      dataType: 'json',
      processData: false,
      contentType: false
    })
    .done(function(data){
      var html = buildHTML(data);
      $('.comments').append(html)
      $('.textbox').val('')
    })
    .fail(function(){
      alert('error');
    })
  })
});

インクリメンタルサーチ

jQueryを有効にする。
jsファイルにonメソッドでアクションを起こし、(form系の処理ならe.priventDefault)
ajaxでurl, type, data, datatypeを投げる。
controllerでrespond_to do |format|で条件分岐。
json.jbuolderファイルが必要なら作成。
viewファイルを参考に返ったデータを再びjqueryで処理するための記述を追加。done
・表示内容を.empty()で初期化し、新たな内容を表示させる。append
・適合内容の有無を条件判定させる。array.length!==0 
エラー時の挙動を追加。fail

エラー

Uncaught ReferenceError: $ is not defined

jqueryを読み込む前にjqueryの記法を使っている場合に起こるエラー。
javaファイルの読み込み順の上位にjqueryを読み込ませると解決する。

Ajax

400 bad request

送信するデータの形が間違っていてもbad request

$.ajax({
  url: url,
  type: 'POST',
  data: {message: {body: body} },
  dataType: "json"
})

下のように手抜きしてるとエラーを吐く。コントローラーで処理できない値を投げるとエラーになるっぽい。
data: {body: body},

コメント