jade イベントリスナの本

JS-イベントリスナの本

script.js
function Person(name) {
  this.name = name;
}
Person.prototype.sayHello = function() {
  console.log(`Hello ${this.name}`);
}

const person = new Person('Tom');
const button = document.getElementById('button');

button.addEventListener('click', person.sayHello, false); // -> "Hello "

// thisを指定したオブジェクトに設定する

// bindを使う
button.addEventListener('click', person.sayHello.bind(person), false); // -> "Hello Tom"

// 無名関数を使う
button.addEventListener('click', function(e) {
  person.sayHello();
}, false);

// アロー関数を使う
// prototypeにアロー関数を定義するとthisはwindowオブジェクトになるのでコンストラクタに書く
// function Person(name) {
//   this.name = name;
//   this.sayHello = () => {
//     console.log(`Hello ${this.name}`);
//   };
// }

// handleEventメソッドを使う
Person.prototype.handleEvent = function() {
  console.log(`HandleEvent ${this.name}`);
}
const person2 = new Person('Bob');
button.addEventListener('click', person2, false);
js-this.markdown
JS-イベントリスナのthis
---------------


A [Pen](https://codepen.io/taquaki/pen/bYmapx) by [Takaaki Sato](https://codepen.io/taquaki) on [CodePen](https://codepen.io).

[License](https://codepen.io/taquaki/pen/bYmapx/license).
index.pug
input#button(type='button' value='button')

jade イベントフェーズ

JS-イベントフェーズ

style.css
#element {
  background: black;
  width: 50px;
  height: 50px;
  padding: 25px;
}

#content {
  background: red;
  width: 50px;
  height: 50px;
}
script.js
window.onload = function() {
  const wrapper = document.getElementById('wrapper');
  const element = document.getElementById('element');
  const content = document.getElementById('content');
  
  // イベントの伝搬
  wrapper.addEventListener('click', function() {
    console.log('wraper bubbling');
  }, false);
  element.addEventListener('click', function(e) {
    console.log('element');
    // イベントのキャンセル
    // e.stopPropagation(); // -> "content capturing" "element" "element stopPropagation"
  }, false);
  content.addEventListener('click', function(e) {
    console.log('content capturing');
    // イベントの伝搬を即時停止
    // e.stopImmediatePropagation(); // -> "content capturing"
  }, true);
}

// ブラウザデフォルトの動作をキャンセル
const anchor = document.getElementById('anchor');
anchor.addEventListener('click', function(e) {
  if(!confirm('ページを移動しても良いですか')) e.preventDefault();
}, false)
js.markdown
JS-イベントフェーズ
-----------


A [Pen](https://codepen.io/taquaki/pen/pdxzvb) by [Takaaki Sato](https://codepen.io/taquaki) on [CodePen](https://codepen.io).

[License](https://codepen.io/taquaki/pen/pdxzvb/license).
index.pug
#wrapper
  #element
    #content

a#anchor(href="google.com") アンカー

jade イベントハンドラとイベントオブジェクト

JS-イベントハンドラとイベントオブジェクト

style.css
#element {
  background: black;
  width: 50px;
  height: 50px;
  padding: 25px;
}

#content {
  background: red;
  width: 50px;
  height: 50px;
}
script.js
function log() {
  console.log('HELLO');
}

// #1 HTML要素
// <input id="button" type="button" onclick="log();">

// #2 DOMオブジェクトのイベントハンドラプロパティ
const btn = document.getElementById('button');
btn.onclick = log;

// #3 addEventListener
btn.addEventListener('click', log, false);
btn.removeEventListener('click', log, false);
// lisnerに無名関数が指定されている場合
btn.addEventListener('click', function() {
  console.log('HELLO');
  btn.removeEventListener('click', arguments.callee, false);
}, false);


// イベントオブジェクト
const element = document.getElementById('element');
element.addEventListener('click', function(e) {
  // イベントオブジェクト共通プロパティ
  console.log(e.type);
  console.log(e.target);
  console.log(e.currentTarget);
  console.log(e.eventPhase);
  console.log(e.timeStamp);
  console.log(e.bubbles);
  console.log(e.cancelable);
  console.log(e.defaultPrevented);
  console.log(e.isTrusted);
  
  // マウスイベントのイベントオブジェクト
  console.log(e.screenX); // -> クリックした位置のスクリーン座標
  console.log(e.screenY); // -> クリックした位置のスクリーン座標
  console.log(e.pageX); // -> クリックした位置のドキュメント座標
  console.log(e.pageY); // -> クリックした位置のドキュメント座標
  console.log(e.clientX); // -> クリックした位置のウィンドウ座標
  console.log(e.clientY); // -> クリックした位置のウィンドウ座標
  console.log(e.offsetX); // -> イベントが発生した要素に対する相対座標
  console.log(e.offsetY); // -> イベントが発生した要素に対する相対座標
  console.log(e.altKey);
  console.log(e.ctrlKey);
  console.log(e.shiftKey);
  console.log(e.detail);
  console.log(e.button);
  console.log(e.relatedTarget);  
}, false);


// キーボードのイベントオブジェクト
document.addEventListener('keydown', showKey, false);
const display = document.getElementById('display');
function showKey(e) {
  const prop = ['altKey', 'ctrlKey', 'shiftKey', 'metaKey', 'key', 'code', 'keyCode'];
  let s = '';
  for(let i in prop) {
    s += `<br>${prop[i]}: ${e[prop[i]]}`;
  }
  s += '->' + String.fromCharCode(e.keyCode);
  display.innerHTML = s;
}
js.markdown
JS-イベントハンドラとイベントオブジェクト
----------------------


A [Pen](https://codepen.io/taquaki/pen/bYxKQg) by [Takaaki Sato](https://codepen.io/taquaki) on [CodePen](https://codepen.io).

[License](https://codepen.io/taquaki/pen/bYxKQg/license).
index.pug
input#button(type="button" value="button")
#wrapper
  #element
    #content
#display

jade CSSの制御

JS-CSSの制御

style.css
#title {
  color: white;
}

.bigText {
  font-size: 60px;
}

.smallText {
  font-size: 10px;
}
script.js
const title = document.getElementById('title');
title.style.backgroundColor = 'green';

console.log(title.style.color) // -> ""
// 算出スタイル 読み出し専用
console.log(getComputedStyle(title).color) // -> "rgb(255, 255, 255)"

title.onmouseover = function() {
  title.className = 'bigText';
}
title.onmouseout = function() {
  title.className = '';
}

let classList = title.classList;
console.log(classList);
classList.add('smallText');
classList.remove('smallText');
classList.toggle('smallText');
console.log(classList.contains('smallText'));
classList.toggle('smallText');
console.log(classList.contains('smallText'));
js-css.markdown
JS-CSSの制御
---------


A [Pen](https://codepen.io/taquaki/pen/gXdeeG) by [Takaaki Sato](https://codepen.io/taquaki) on [CodePen](https://codepen.io).

[License](https://codepen.io/taquaki/pen/gXdeeG/license).
index.pug
h1#title title

jade 构成要素の取得

JS-形式要素の取得

script.js
// formの取得
console.log(document.forms[0]);
console.log(document.forms.form1);
console.log(document.forms.question);
console.log(document.question);

// 子要素の取得
console.log(document.forms.form1[0]); // -> "<input name='name'>"
console.log(document.forms.form1.name); // -> "<input name='name'>"
console.log(document.forms.form1.nameinput); // -> "<input name='name'>"

// elementsプロパティで取得する
console.log(document.forms.form1.elements[3]); // -> "<select id='menu1' ame='bloodtype'><option>A</option><option>B</option><option>O</option>   <option>AB</option></select>"
console.log(document.forms.form1.elements.bloodtype); // -> "<select id='menu1' ame='bloodtype'><option>A</option><option>B</option><option>O</option>   <option>AB</option></select>"
console.log(document.forms.form1.elements.menu1); // -> "<select id='menu1' ame='bloodtype'><option>A</option><option>B</option><option>O</option>   <option>AB</option></select>"
js-form.markdown
JS-form要素の取得
------------


A [Pen](https://codepen.io/taquaki/pen/XzPEXO) by [Takaaki Sato](https://codepen.io/taquaki) on [CodePen](https://codepen.io).

[License](https://codepen.io/taquaki/pen/XzPEXO/license).
index.pug
form#form1(method='post' action='pst.cgi' name='question')
  p
    label 名前
    input#nameinput(type=text name='name')
  p
    label 性別
    label
      input(type='radio' name='sex' value='male')
      | 男
    label
      input(type='radio' name='sex' value='female')
      | 女
  p
    label 血液型
    select#menu1(name='bloodtype')
      option A
      option B
      option O
      option AB
  p
    textarea(name='opinion' row=10 cols=80 placeholder='ご意見')
  p
    input(type='submit' value='送信')
    input(type='reset' value='取消')

jade スクロール制御

JS-スクロール制御

style.css
@use postcss-nested;
#element {
  
  &1,
  &2,
  &3 {
    width: 100px;
    height: 50px;
    position: absolute;
  }
  
  &1 {
    background: black;
    top: 500px;
    left: 50px;
  }
  
  &2 {
    background: red;
    top: 1000px;
    left: 50px;
  }
  
  &3 {
    background: green;
    top: 1500px;
    left: 50px;
  }
}
script.js
// スクロール量

// IE、Firefox
console.log(document.documentElement.scrollLeft);
console.log(document.documentElement.scrollTop);

// Chrome、Safari、Opera、Edge
console.log(document.body.scrollLeft);
console.log(document.body.scrollTop);

// Firefox,、chrome、Safari、Opera、Edge、IE9以降
console.log(window.pageXOffset);
console.log(window.pageYOffset);

// スクロール量を取得する
function getScrollTop() {
  if (window.pageYOffset !== undefined) {
    return window.pageYOffset;
  } else {
    return document.documentElement.scrollTop || document.body.scrollTop;
  }
}

console.log(getScrollTop());

// windowのスクロール 
scrollBy(0, 100);

function smoothScroll(id, durationTime) {
  const TIME_INTERVAL = 30;
  const element = document.getElementById(id);
  if(!element) return;
  // ボーダーを入れたelement
  let ey = element.getBoundingClientRect().top;
  let dy = ey*TIME_INTERVAL/durationTime;
  let direction = dy>0 ? 1 : -1;
  const timer = setInterval(function() {
    scrollBy(0,dy); ey -= dy;
    if(direction*ey <= 0) clearInterval(timer);
  }, TIME_INTERVAL);
}
smoothScroll('element2', 5000);

const btn = document.getElementById('button');
const greenBox = document.getElementById('element3');
btn.onclick = function() {
  greenBox.scrollIntoView();
}



js.markdown
JS-スクロール制御
----------


A [Pen](https://codepen.io/taquaki/pen/NwLyej) by [Takaaki Sato](https://codepen.io/taquaki) on [CodePen](https://codepen.io).

[License](https://codepen.io/taquaki/pen/NwLyej/license).
index.pug
input#button(type='button' value='go to green')
#element1
#element2
#element3

jade ウィンドウ操作

JS-ウィンドウ操作

script.js
 window.onload = function() {
  let w;
  document.getElementById('open').onclick = function() {
    // ウィンドウを開く
    w = open('newpage.html', 'new page', 'width=400, height=300');
    document.getElementById('close').onclick = function() {
      // ウィンドウを閉じる
      if(w) w.close();
    }
  }
}
js.markdown
JS-ウィンドウ操作
----------


A [Pen](https://codepen.io/taquaki/pen/QOBMYE) by [Takaaki Sato](https://codepen.io/taquaki) on [CodePen](https://codepen.io).

[License](https://codepen.io/taquaki/pen/QOBMYE/license).
index.pug
input#open(type='button' value='open')
input#close(type='button' value='close')

jade 原型オブジェクトを利用したパーティクル

原型オブジェクトを利用したパーティクル

script.js
window.onload = () => {
  const NBALL = 200;
  const R = 5;
  const TIME_INTERVAL = 33;
  const BACK_ALPHA = 0.3;
  
  const canvas = document.getElementById('mycanvas');
  const ctx = canvas.getContext('2d');
  
  const wall = {left: 0, right: canvas.width, top: 0, bottom: canvas.height};
  const balls = [];
 
  for(let i=0; i<NBALL; i++) {
    balls[i] = new Ball(wall.right/2, wall.bottom/2, R);
    balls[i].setVelocityAsRandom(2, 7).setColorAsRandom(50, 255);
  }
  
  setInterval(drawFrame, TIME_INTERVAL);
  
  function drawFrame() {
    ctx.fillStyle = `rgba(0, 0, 0, ${BACK_ALPHA})`;
    ctx.fillRect(0, 0, canvas.width, canvas.height);
    for(let i=0; i<balls.length; i++) {
      balls[i].move().collisionWall(wall).draw(ctx);
    }
  }
}

function Ball(x, y, r, vx, vy, color) {
  this.x = x;
  this.y = y;
  this.r = r;
  this.vx = vx;
  this.vy = vy;
  this.color = color;
}

Ball.prototype = {
  setVelocityAsRandom: function(vmin, vmax) {
    const v = vmin + Math.random() * (vmax-vmin);
    const t = 2*Math.PI*Math.random();
    this.vx = v*Math.cos(t);
    this.vy = v*Math.sin(t);
    return this;
  },
  setColorAsRandom: function(lmin, lmax) {
    const R = Math.floor(lmin+Math.random()*(lmax-lmin));
    const G = Math.floor(lmin+Math.random()*(lmax-lmin));
    const B = Math.floor(lmin+Math.random()*(lmax-lmin));
    this.color = `rgb(${R}, ${G}, ${B})`;
    return this;
  },
  draw: function(ctx) {
    ctx.fillStyle = this.color;
    ctx.beginPath();
    ctx.arc(this.x, this.y, this.r, 0, 2*Math.PI, true);
    ctx.fill();
    return this;
  },
  move: function() {
    this.x += this.vx;
    this.y += this.vy;
    return this;
  },
  collisionWall: function(wall) {
    if(this.x - this.r < wall.left) {
      this.x = wall.left + this.r;
      if(this.vx < 0) this.vx *= -1;
    }
    if(this.x + this.r > wall.right) {
      this.x = wall.right - this.r;
      if(this.vx > 0) this.vx *= -1;
    }
    if(this.y - this.r < wall.top) {
      this.y = wall.top + this.r;
      if(this.vy < 0) this.vy *= -1;
    }
    if(this.y + this.r > wall.bottom) {
      this.y = wall.bottom - this.r;
      if(this.vy > 0) this.vy *= -1;
    }
    return this;
  }
}

prototype.markdown
prototypeオブジェクトを利用したパーティクル
--------------------------


A [Pen](https://codepen.io/taquaki/pen/jaYgEa) by [Takaaki Sato](https://codepen.io/taquaki) on [CodePen](https://codepen.io).

[License](https://codepen.io/taquaki/pen/jaYgEa/license).
index.pug
canvas#mycanvas(width='640' height='480')

jade 帆布で角丸の矩形を描く

JS- Canvasで角丸の矩形を描く

script.js
window.onload = function() {
  const canvas = document.getElementById('mycanvas');
  const ctx = canvas.getContext('2d');
  
  strokeRoundedRect(ctx, 10, 10, 100, 80, 20)

  function strokeRoundedRect(ctx, x, y, width, height, radius) {
    ctx.beginPath();
    ctx.moveTo(x+radius, y);
    ctx.arcTo(x+width, y, x+width, y+height, radius);
    ctx.arcTo(x+width, y+height, x, y+height, radius);
    ctx.arcTo(x, y+height, x, y, radius);
    ctx.arcTo(x, y, x+width, y, radius);
    ctx.stroke();
  }
}
js-canvas.markdown
JS- Canvasで角丸の矩形を描く
-------------------


A [Pen](https://codepen.io/taquaki/pen/jaagGe) by [Takaaki Sato](https://codepen.io/taquaki) on [CodePen](https://codepen.io).

[License](https://codepen.io/taquaki/pen/jaagGe/license).
index.pug
canvas#mycanvas(width='640' height='400')

jade ストライプテーブル

ストライプテーブル

style.css
@use postcss-cssnext;

th, td {
  padding: 1em;
}

th {
  background: #222;
  color: white;
}

tr {
  &:nth-child(even) {
    background: #f2f2f2;
  }
  
  &:nth-child(odd) {
    background: #ccc;
  }
}

.hover {
  background: #aaf!important;
}
.html
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
script.js
$(function() {
  
  $("tbody tr").mouseover(function() {
    $(this).addClass("hover");
  }).mouseout(function() {
    $(this).removeClass("hover");
  });
  
  $("td").mouseover(function() {    
    $("td:nth-child(" + ($("td").index(this)%$("th").length+1) + ")").addClass("hover");
  }).mouseout(function() {
    $("td:nth-child(" + ($("td").index(this)%$("th").length+1) + ")").removeClass("hover");
  });
});
jquery.markdown
ストライプテーブル jQuery
----------------


A [Pen](https://codepen.io/taquaki/pen/pWGeWN) by [Takaaki Sato](https://codepen.io/taquaki) on [CodePen](https://codepen.io).

[License](https://codepen.io/taquaki/pen/pWGeWN/license).
index.pug
table
  thead
    tr
      th no
      th name
      th content
  tbody
    - for (var i=1; i<=5; i++)
      tr
        td #{i}
        td name #{i}
        td content #{i}