มาสรุปสิ่งที่ได้จาก js21days challenge [week2]

course & workshop Apr 20, 2020

หลังจากจบ week แรกแล้ว มาต่อ day 8 กันต่อเลยดีกว่า

https://www.js21.dev/

ส่วนของ week แรก อยู่ที่นี่จ้า

มาสรุปสิ่งที่ได้จาก js21days challenge [week1]
รอบแรกลืมกดสมัครคอร์สฟรีและเต็มไว้ในนาทีแรก รอบสองไม่พลาดที่จะกดสมัครจ้า เผื่อเราจะถนัด js ขึ้นมาบ้าง (รอบนี้เหมือนรับสมัครเรื่อยๆยังไม่ปิดรับน้าา)

การบ้านทั้งหมดจ้า

https://js21days-challenge.firebaseapp.com/


Day8: What is "this"?

this หรือ context เป็น concept ที่สำคัญมากๆใน javascript เลยแหละ ที่ beginner ไปถึง advance

1) Lexical scope & Dynamic scope

ก่อนอื่นมาทดลองกัน โดยการ print this ออกมาดูกันก่อนนะ

function printName() {
  console.log(this);
}
printName();

ผลที่ได้ this คือ window ที่เป็น global object นั่นเอง ต่างจากภาษาอื่นๆคือ วิธีการที่เรียกใช้งาน ในที่นี้คือไม่มีอะไรนำหน้าการใช้งาน function ตัวนี้ เลยใส่ค่าเป็น window object ให้เอง

2) this คืออะไรและทำงานอย่างไร

  • Invoker object : เรียกใช้งาน function เป็น object.function
const beeber = { name: 'Beeber', printName };
const jane = { name: 'Jane', printName };

beeber.printName();
jane.printName();

ในตัวอย่างนี้ สร้าง object มาสองตัวเนอะ ใน ES6 มันสามารถใส่ค่าของ field ลงไปได้เลยถ้าชื่อมันเหมือนกันงี้ ตามที่เราจดทันอะนะ การเรียกใช้งาน เอา object.function เพื่อดูว่า this ที่ได้ คืออะไร

สรุป this ไม่ได้ขึ้นว่าเขียนไว้ตรงไหน แต่ขึ้นว่าเราเรียกใช้มันอย่างไร และมีการเปลี่ยนค่าไปเรื่อยๆตามวิธีใช้

  • Global object (window, global)

ประกาศตัวแปรตัวนึงแบบ global เพิ่มให้ print name ออกมา และเรียกใช้งานตามปกติ

function printName() {
  console.log(this);
  console.log(`My name is ${this.name}`)
}

name = 'Global';
printName();

ผลที่ได้นั้น object สองตัวแรกเหมือนเดิม เพิ่มเติมคือ print ชื่อออกมาด้วย ส่วนตัวแปร name ที่เราเพิ่งประกาศไปเมื่อกี้ ถูก assign ให้เป็น property ของ global object หรือ window object อัตโนมัติ ดังนั้น

  • Constructor function : function ธรรมดาที่สร้าง object จาก function นั้นได้ (ถ้าเราเขียนโปรแกรมกันมา จะพบเห็นได้บ่อย เป็นการ init ค่าของ object ตัวนั้นๆนั่นเอง)

ตั้งชื่อ function ตัวหน้าเป็นตัวใหญ่ เพื่อบอกว่า function ไหน สร้างเป็น object ได้

function Person(name) {
  this.name = name;
  this.printName = printName;
}

const joylada = new Person('Joylada');
joylada.printName();

this ตอนนี้จะเป็น object Person ที่ชื่อ joylada แล้วนะ สรุปคือ ใช้ในการ set property ของ function ได้

3) set ค่า this โดย 3 functions call(), apply(), and bind()

ก่อนอื่นเรามาประกาศเจ้า Person ในรอบนี้ใส่ nationality และ city ร่วมด้วย แล้วสร้าง object ใหม่ จากนั้นใน printName() ให้พิมพ์ของเพิ่มมาด้วย

เมื่อใช้ printName() ใน Person ซึ่งจริงๆอาจจะเป็น function อื่นๆหรือ 3rd-party library ที่มีอยู่แล้ว และไม่สามารถควบคุมได้ ดังนั้น this ในที่นี้ น่าจะเป็น global เนอะ

function printName(nationality, city) {
  console.log(this);
  console.log(`My name is ${this.name}, I'm ${nationality} and am living in ${city}`);
}

function Person(name, nationality, city) {
  this.name = name;
  this.nationality = nationality;
  this.city = city;

  printName(this.nationality, this.city);
}

const beeber = new Person('Beeber', 'Thai', 'Bangkok');

ซึ่งผลที่ได้ก็ตรงกับที่เราเดาไว้เลย ส่วน name = 'Global' ก็คือตัวที่เรา set ก่อนหน้านี้และยังไม่ได้ถูก refresh เลยยังไม่หายไปจ้า

ดังนั้น เราจะมา force ค่า this ด้วย call โดยใส่ไปใน Person เพิ่ม โดย parameter แรกใส่ this ส่วนสองตัวถัดมาเหมือนเดิม

printName.call(this, this.nationality, this.city);

เราจะได้ object this เป็นเจ้า Person ของ object ที่ชื่อว่า beeber

จากนั้นมาลองใช้ apply ดู โดยวิธีเรียกจะเปลี่ยนไป โดย parameter แรกยังคงเหมือนใน call แต่ parameter ตัวที่สองให้ใส่เป็น array ซึ่งข้างในคือสิ่งที่เราต้องการนั่นเอง

printName.apply(this, [this.nationality, this.city]);

ผลที่ได้จะเหมือนกับ call เลย

สุดท้าย bind การเรียกใช้จะต่างกับ call และ apply ตรงที่สองตัวนั้นจะเรียกใช้ function ทันที ส่วน bind จะทำการ return function อันใหม่มาให้เรา แบบนี้ ซึ่งผลที่ได้ก็จะเหมือนกันนั่นแหละ

const printBeeber = printName.bind(this);
printBeeber(this.nationality, this.city);

Day9: Parallax Scrolling

เลื่อนลงมาแล้วโชว์ effect บางอย่าง เลื่อนให้เจอพระจันทร์และ text ซะ

  •  สร้าง run() ข้างในเพิ่ม event listener ของ document จับตอนที่เรา scroll
document.addEventListener('scroll', onScroll);
  • สร้าง onScroll() เพื่อ get moon และ wish element และลองพิมพ์ค่า window.scrollY จะพบว่า scroll ไปด้านล่าง ค่าจะเพิ่มขึ้นเรื่อยๆ ส่วนถ้า scroll ขึ้นไป ค่าจะลดลงเรื่อยๆนั่นเองจนเป็น 0 และนำค่านี้ไปคำนวณต่อ
  • ให้พระจันทร์เลื่อนไปบนขวา
moonElement.style.transform = `translate(${window.scrollY * 0.7}%, ${window.scrollY * -0.7}%`;
  • และให้ text เลื่อนขึ้นลงไปอย่างเดียว (ในตัวอย่างคูณ - 1.2 แต่มันไม่สวยง่ะเลยเพิ่มไปหน่อยนึง)
wishElement.style.transform = `translateY(${window.scrollY * -1.5}%)`;

จบจ้า สวยๆ อย่างรวดเร็ว เราสามารถประยุกต์ใช้ได้ โดยตัดพวก background และอื่นๆไปทำแบบนี้ได้นะ

https://js21days-challenge.firebaseapp.com/09-Parallax-Scrolling/index.html

Day10: Kanban Board

บอร์ด todo-list ที่เราใช้ list ว่างานที่ต้องการทำ กำลังทำ และทำเสร็จแล้ว คืออะไร เช่นใน Trello นั่นเอง มี feature drag and drop เหมือนกันเลยด้วยยย

ก่อนอื่น ใน index.html นั้น จะมี class แม่ที่ชื่อว่า title และมีลูกหมูสามตัวคือ Todo, Doing และ Done ใน TODO เขาก็จะเตรียม content ไว้ให้เราก่อนเนอะ มี class หลานที่ชื่อว่า drop-zone คือของข้างในนี้เราสามารถ drag and drop ได้จ้า นั่นคือ task นั่นเอง และมี attribute ที่ชื่อว่า draggable มีค่าเป็น true บอกว่าอันนี้ลากได้นะ

  • เราจะดึง element ชื่อว่า task ทั้งหมด โดย document.querySelectorAll('.task') แต่จะได้ผลเป็น node list ดังนั้นต้องใส่ Array.from(document.querySelectorAll('.task')) ให้ออกมาเป็น array list เพื่อเอาไปทำ forEach ให้กับ task แต่ละตัวได้
  • และดึง element ที่ชื่อว่า drop-zone ทำเหมือน task
  • เพิ่ม event listener ให้กับ task แต่ละตัว ให้สามารถลากการ์ดได้
taskElements.forEach((taskElement) => {
      taskElement.addEventListener('dragstart', onDragStart);
    });

และเจ้า onDragStart ก็ save element ที่ถูก drag ไป

let dragingElement;
function onDragStart() {
  dragingElement = this;
}
  • และก็เพิ่ม event listener ให้กับเจ้า drop-zone
dropZoneElements.forEach((dropZoneElement) => {
  dropZoneElement.addEventListener('drop', onDrop);
});

ปัญหาใน HTML5 ก็คือ มันไม่ drop อ่ะ มันจะเกิด event drop ไม่ได้ ถ้าไม่ทำการ prevent default ใน event dragOver และ dragEnter

dropZoneElements.forEach((dropZoneElement) => {
  dropZoneElement.addEventListener('drop', onDrop);
  dropZoneElement.addEventListener('dragover', onDragOver);
  dropZoneElement.addEventListener('dragenter', onDragEnter);
});

event.preventDefault(); คือเป็นการ cancel behavior ปกติ ของ event นี้ออกไปนั่นเอง เมื่อใส่ไปแล้วทำให้เราสามารถ drop ได้หล่ะ

function onDragOver(event) {
  event.preventDefault();
}

function onDragEnter(event) {
  event.preventDefault();
}
  • สุดท้าย drop แล้วไปไหน? add element ที่เราลากอยู่ ไปยัง column นั้นๆ เมื่อใส่เสร็จแล้ว reset ค่าให้เป็น null ซะ เป็นอันจบจ้าา
function onDrop() {
  this.append(dragingElement);
  dragingElement = null;
}

สรุป เราได้แค่ตัวลากวาง kanban board ยังเซฟเก็บและเพิ่มใหม่ไม่ได้ เดี๋ยวเราลองไปทำเพิ่มดีกว่าตอนว่างๆ

https://js21days-challenge.firebaseapp.com/09-Parallax-Scrolling/index.html

Day11: Text Reveal

ทำให้เว็บมีสีสันมากขึ้น เมื่อเลื่อนลงมา text จะค่อยๆเลื่อนขึ้นมาจากด้านล่าง

ในโปรเจกจะมี index.html ที่รูปแล้วก็ text และก็ style.css ที่ set การ display ต่างๆและก็สี โดย text มี opacity เป็น 0 และสุดท้าย start.js มาลุยกันเลยดีกว่าาาา

  • เพิ่ม event listener ในการ scroll document.addEventListener('scroll'. onScroll);
  • ต่อมาสร้าง onScroll() จ้า จะทำคล้ายตอนทำ Kanban Board ตรง เราดึง class section ออกมา และแปลงเป็น array เพื่อใช้คำสั่ง forEach ได้
  • ใช้คำสั่ง forEach เพื่อดึง element ต่างๆภายใน section ในที่นี้จะมี img กับ textElement เนอะ
  • สร้างตัวแปร const scrollPosition = window.pageYOffset; เพราะเราจะดูว่าเลื่อนจอไปเท่าไหร่
  • ตำแหน่งที่แสดง text คือ ค่าสูงสุดของรูปเรา imageElement.offsetTop บวกกับความสูงของรูปหารด้วย 10 imageElement.offsetHeight / 10 ให้เป็นค่าของตัวแปร revealPosition
  • ใน style.css นั้น มี class 2 class ที่น่าสนใจ คือ .text เป็นตัว default เนอะ ให้ opacity เป็น 0,  transform ให้อยู่ตํ่ากว่าที่ควรเป็น 25px, transition เหมือน animation ค่อยๆเลื่อนขึ้นมา 0.4 วินาที และ class .reveal คือให้ opacity เป็น 1 และ transform ให้กลับมาอยู่ตำแหน่งปัจจุบันที่ควรจะเป็น
  • ถ้าเรา scroll ไปแล้วมากกว่าหรือเท่ากับ revealPosition ก็ให้แสดง text ขึ้นมา โดยให้ textElement เพิ่ม class reveal เข้าไป เป็นอันจบ textElement.classList.add('reveal');
https://js21days-challenge.firebaseapp.com/11-text-reveal/index.html ยังไม่ได้ทำอะไรเพิ่ม แหะๆ

Day12: Air Quality Visualizer

สร้างแอพได้ดูฝุ่นแบบเรียลทามกัน แต่เข้าใจว่าไม่น่าวัดได้ในกรณีที่ คำว่ารักมันกลายเป็นฝุ่นไปแล้ว แน่นอนนน!!!

ในที่นี้จะใช้ API ของ AirVisual ที่เราใช้วัดค่าฝุ่น PM2.5 ในช่วงก่อนหน้านี้ว่า เอ๊ะ วันนี้ต้องใส่หน้ากากออกจากบ้านไหมนะ ก่อนที่จะ Work From Home อะนะ เอ้ออออ หมดไปกับค่าแมสก์ก็เยอะอยู่จ้า ฮือออออออ สามารถเข้าไปสมัครได้ทางนี้จ้า

AirVisual API | Trusted Live and Forecast Air Pollution Data
Enhance your projects with free trusted historical, real-time and forecast air quality data. Air pollution and weather data for more than 60 countries worldwide.

แน่นอนว่าเราเลือก Community ซึ่งฟรี และเราคงใช้ไม่เกิน 10,000 call/month เนอะ

จากนั้นก็สร้าง key เนอะ และเอาไปใช้ต่อได้ ซึ่งอายุของ key ที่สร้างมีอายุประมาณ 1 ปีด้วยกันเนอะ

  • มีการ set สีที่จะแสดง ใน style.css ที่ :root
  • ก้อป key ที่ได้เมื่อกี้จากการสร้าง key มาสร้างตัวแปร แล้วมาใส่เป็นตัวแปร const
  • สร้างตัวแปร city, state, country
  • จากนั้นสร้าง getAirQuality({city, state, country}) แต่ function นี้พิเศษ ตรงใส่ parameter เป็น object ทำให้เราสามารถดึงค่า parameter มาใช้โดยไม่ต้องคำนึงถึงลำดับได้ ช่วยแก้ปัญหาเวลาเรา pass ค่าไปหลายๆตัวแปร เช่น 3 4 5 ตัว อาจจะทำให้เราเองงงได้
  • ยิง API โดยใช้ fetch() ซึ่ง parameter เป็น path ของ API นั้นๆ และใส่ parameter ต่างๆลงไปด้วย คือ city, state, country และ key
  • ใช้เจ้า async นำหน้า function และ await นำหน้าตอน fetch() เพื่อรอให้เรียก API เสร็จก่อนนั่นเอง
  • response ที่ได้ เราได้ 200 OK มาเนอะ แต่เรายังไม่ได้ data
  • เราจึงต้องแปลงให้เป็น json ก่อน แน่นอนว่าต้องทำหลังจากที่เรียก API เสร็จแล้ว จึงใส่ await เข้าไป
const result = await response.json(); 

และนี่คือผลที่ได้จ้า

  • ใช้ destructuring ใน ES6 เข้ามาช่วยดึงตัวแปรที่เราต้องการออกมา โดย destructuring ชั้นนอกเป็น data และทำอีกชั้นนึงเป็น current เพื่อดึงอาการ และค่าฝุ่นมาอีกรอบนึง และใช้ destructuring อีกชั้นนึง เพื่อดึง pollution กับ weather
  • แล้วก็ return ค่า aqi, temperature, humidity, wind ออกมา
const {aqi, temperature, humidity, wind} = await getAirQuality({city, state, country});
  • จากนั้นเอาค่าต่างๆที่ได้นำไปแสดงในหน้าเว็บที่ displayAirQuality() จะได้ดังนี้
https://js21days-challenge.firebaseapp.com/12-air-quality-visualizer/index.html
  • แต่ยังไม่จบ เอาค่า aqi มาเปลี่ยนสีพื้นหลังหน่อยว่าอากาศตอนนี้เป็นยังไง ตอนนี้ผลต่างกันไม่เยอะอะเนอะ แบบเปลี่ยนสีพื้นหลังงี้

เราเองก็เห็นหน้า document API ของ AirVisual เลยคิดว่า น่าจะทำอะไรได้มากกว่านี้ อาจจะให้ใส่ location ที่ต้องการเอง หรือเอาไปใช้ในแชทบอทแล้วทำ Flex Message สวยๆก็ได้เนอะ

AirVisual API
Interested in using AirVisual’s most comprehensive global air quality data for your own application? You are at the right place! Let’s get you started. First of all, please refer to the [air quality API page on our website](https://www.airvisual.com/api), in order to get familiar with our plans and…

Day13: JavaScript Weird Parts

รวมของแปลกๆจากภาษา JavaScript ที่ผลออกมา ไม่ตรงกับที่เราอยากได้

1) NaN : Not a Number

ตามปกติ ค่าใดค่าหนึ่งจะเท่ากับตัวมันเอง

if (null === null) {
  console.log('Equal');
}

NaN เป็น preventive type เป็นค่าพื้นฐานของ javascript เทียบเท่า undefined เทียบเท่ากับ null แต่ความพิเศษคือ ไม่เท่ากับตัวมันเอง อย่างโค้ดตัวอย่างด้านล่างก็คือจะได้ค่า false เนอะ

if (NaN === NaN) {
  console.log('Equal');
}

แล้วทำไมถึงไม่เท่ากับตัวมันเองอ่ะ? เพราะว่า เพื่อป้องกันการคำนวณที่ผิดพลาด ในเคสต่างๆเหล่านี้

NaN/NaN === 1
NaN * ` === NaN

แล้วเราจะ check ได้อย่างไรว่า ตัวแปรนั้น มีค่าเป็น NaN หรือเปล่า?

เช่น ให้ result เป็น 1 / 'hello' ได้ผลเป็น NaN เพราะไม่สามารถเอาไปหารแบบนี้ได้เนอะ การ check ให้ใช้ Number.isNaN(result)

const result = 1 / 'hello';
if (Number.isNaN(result)) {
  console.log('Equal to Nan');
}

และนี่คือผลที่ได้

2) Type Coercion

Coercion แปลว่า การบังคับ ในที่นี้ก็คือการแปลง type อัตโนมัติโดย javascript นั่นเอง ตัวอย่าง

if (1 < 2 < 3) {
  console.log('Inside');
}

อันนี้เราแอบงงๆว่ามัน check condition ซ้อนกันแบบนี้ได้ด้วยหรอ ฮ่าๆ เลยเดาผลไม่ออกเลยว่าเป็นอะไร เมื่อเอาไป run ดูผลว่าเป็น true อ่ะ แล้วถ้าแบบนี้หล่ะ ผลจะออกมาเหมือนกันไหมนะ?

if (3 > 2 > 1) {
  console.log('Inside');
}

สรุปผลออกมาไม่เหมือนกันอ่ะ เป็น false ทำไมกันนะ?

3 > 2 ผลออกมาเป็น true และ true > 1 ซึ่ง true === 1 ทำให้ผลออกมาเป็น false

แล้วคิดว่า 2 - '1' ออกมาแล้วได้ผลอะไร เราเดาว่า 1 เพราะว่า มันแปลง String '1' เป็น 1 ซึ่งผลออกมาก็เป็น 1 จริงๆด้วย ซึ่งเราก็เดาถูกอีกล้าววว 555

แล้ว 2 + '1' ผลออกมาเป็นอะไร เราเดานะ 21 เพราะมันมองเลข 2 เป็น String ไปแล้ว มันเลยต่อ String ให้เลย ซึ่งเราก็เดาถูกอีกเช่นเคย 555

แล้ว true + true เดาไปในสองแนวทาง ไม่ออก true ก็พิมพ์ truetrue แล้วผลที่ได้ก็ครือออ 2 ห๊ะ เพราะว่ามันเห็นว่า true ทำการบวกกับอะไรสักอย่างอยู่ เลยแปลงตัวเองเป็น 1 นั่นเอง

สรุปเราต้องเข้าใจมัน + ถ้าไม่แน่ใจก็แปลง type ให้ถูกต้อง เช่น อยากให้บวกแล้วได้ผลเป็น 3 ก็แปลงจาก String เป็นเลขฐาน 10 ก่อน แบบนี้

2 + Number.parseInt('1', 10)

3) Interpreter & Compiler

คิดว่าผลลัพธ์ของสิ่งนี้คืออะไร ทางนี้เดาว่าน่าจะ return ออกมาเป็น object ก้อนนึง มั้งนะ

function getPerson() {
  return {
    name: 'Kotlin'
  };
}
console.log(getPerson());

จริงๆคำตอบคือได้ undefined มาอ่ะ แต่เราได้ object มา งงเลย

กลับไปดูตัวอย่าง พบว่าคุณปีกกาไม่เหมือนกันจ้า

function getPerson() {
  return 
  {
    name: 'Kotlin'
  };
  }
console.log(getPerson());

นั่นแหละได้ผลตามตัวอย่างแล้ว เพราะอะไรกันหล่ะ?

เพราะว่า การที่เรา return แล้วขึ้นบรรทัดใหม่ มันจะมองเป็น return; ที่มี ; เข้ามาให้เราเองเลย ทำให้สิ่งที่อยู่มนปีกกาไม่ถูกทำ เพราะคิดว่าทำจบแล้ว

ดูจาก VS Code พบว่าสีของ attribute name คนละสีอยู่เนอะ

สรุปอย่าลืมใส่ ; ในการเขียน javascript ด้วยเนอะ ถึงบางทีมันจะแอบใส่ให้เราก็ตาม เพื่อการทำงานที่ถูกต้องจ้า

ปล. แรกๆที่เรียนมีเผลอไม่ใส่ ด้วยสาเหตุง่ายๆ คือ เราเป็น Android Kotlin Developer หล่ะสิ ;) //ง่ายหรือโบ้ยย ตอบบบ!!!

4) Checking Object Type

สมมุติเราทำการ check type แบบนี้ แน่นอนเนอะว่าผลมันออกมาเป็น object อยู่แล้ว

const person = {};
if (typeof person === 'object') {
  console.log('Yes, object')
}

ถ้าเราเปลี่ยนค่า person เป็น null หล่ะ ผลออกมาเป็นอะไร นี่เดาแบบมั่วว่า เป็น object เนอะ ไม่รู้ทำไมเหมือนกัน 555555 จริงๆหลายๆคนคิดว่ามันน่าจะออกมาเป็น false สิ เพราะอะไรหล่ะ? มันน่าจะมองเป็น object ที่เป็นค่า null ดังนั้นต้อง check null เพิ่มด้วย ดังนี้

const person = null;
if (typeof person === 'object' && person != null) {
  console.log('Yes, object')
}

คลิกเพื่อหมุนรูปไปเรื่อยๆ เป็น image slider

  • ใน index.html นั้น มี carousel ซึ่งไส้ในมีรูป แล้วก็ปุ่มกดอยู่ด้านนอก
  • มาเริ่มเขียนโค้ดกันโดยการดึง element รูป, ปุ่ม previous, และปุ่ม start
  • สร้างตัวแปรเอาไว้ track ว่าเราเลื่อนดูรูป index ที่เท่าไหร่
  • เพิ่ม event ให้กับปุ่มกด
previousButtonElement.addEventListener('click', () => displayImage(imageElements, currentIndex-1));

แล้วผลที่ได้ มัน error ทางเราเดาก่อนว่า ถ้าให้ index แรกเป็น 0 ถ้าขยับซ้ายไป index -1 ก็น่าจะพังแหละจ้า ซึ่งทางเราก็เดาถูกต้องนะฮ๊าบบบ

  • เราต้องเพิ่ม condition ว่า ถ้าได้ index มาน้อยกว่า 0 แล้วน้านนน ให้แสดงรูปสุดท้ายในชุดนี้ มันจะมีความมูฟออนเป็นวงกลม ซึ่งถูกแล้วเนอะในที่นี้ แต่เอ้ยย มันมีความกระโดดปนหน่วงๆแหะ และอย่าลืม update currentImage ด้วยน้าาา
  • ส่วนปุ่ม next ทำเหมือนกัน แต่ +1 นะจ๊ะ
nextButtonElement.addEventListener('click', () => displayImage(imageElements, currentIndex+1));

แต่จะเจอเรื่อง index เกินจ้า ดังนั้นเพิ่ม condition ให้เขาหน่อย ขอสรุปโค้ดรวบตึงได้ที่นี่เลยแล้วกัน

function displayImage(imageElements, newIndex) {
  const lastIndex = imageElements.length - 1;

  if (newIndex < 0) {
    newIndex = lastIndex;
  } else if (newIndex > lastIndex) {
    newIndex = 0;
  }

  const newImage = imageElements[newIndex];
  newImage.scrollIntoView({ behavior: 'smooth'});

  currentIndex = newIndex;
}
https://js21days-challenge.firebaseapp.com/14-carousel/index.html ยังไม่ได้เปลี่ยนรูปหรือทำอะไรเพิ่มเลย

จบไปล้าว 14 วันด้วยกัน ยังเหลือโค้งสุดท้ายอีก 7 วัน บวกมีเซอร์ไพร์สด้วย มาติดตามกันจ้า

อย่าลืมกด like กด share บทความกันด้วยนะคะ :)

Posted by MikkiPastel on Sunday, 10 December 2017

7 วันถัดไปจ้า

มาสรุปสิ่งที่ได้จาก js21days challenge [week3]
มาถึงช่วงโค้งสุดท้ายของคอร์สนี้กันแล้วนะจ๊ะ เลยมาเล่าเรื่องของการทำเว็บส่งการบ้านแบบสั้นๆด้วยจ้า เราจะใช้ Firebase Hosting เพื่อเพิ่ม site ใหม่ในโปรเจก Firebase ส่วนตัวของเรา จะได้เว็บส่งการบ้านนี้มา

Tags

Minseo Chayabanjonglerd

Android Developer ผู้เป็นเจ้าของบล็อก MikkiPastel ที่ชอบทำหลายๆอย่างนอกจากเขียนแอพแอนดรอยด์ เช่น เขียนบล็อก เขียนแชทบอท เรียนออนไลน์ อ่านหนังสือ วาดรูปเล่น ดู netfilx สั่งอาหารอร่อยๆกัน เป็นต้น

Great! You've successfully subscribed.
Great! Next, complete checkout for full access.
Welcome back! You've successfully signed in.
Success! Your account is fully activated, you now have access to all content.