เรียนรู้ Vue.js part 2: Conditionals, Loops, Handling Input and Components
สืบเนื่องจาก part 1 นั้นขายดี ขนาดหนังยังมีภาคต่อดังนั้นนี่จึงเป็น part 2 ที่นำ Vue user guide มาเล่าในแบบฉบับด้นสดเอามันส์อย่างเคย
อะไรนะ!ยังเขียน Angular อยู่อีกเหรอ อุ้ยตาย! บอกเลิก React เลยใช่ไหม
ฮ่า แซวเล่นนะครับ
ความเดิม part ที่แล้ว
Vue ทำให้เหล่า front end developer ได้รู้จักกับขุมพลังใหม่ที่จะยิ่งใหญ่กว่าเก่า แต่ความยิ่งใหญ่อธิบายยาก part นี้จึงขอแยกเป็น 4 เรื่องย่อยชิมลางก่อน ได้แก่
- Conditionals
- Loops
- Handling Input
- Composing with Components
Conditionals
เบื้องต้นง่ายๆคือ if ซึ่งมีผลต่อโครงสร้าง DOM กล่าวคือทำให้ DOM เกิดขึ้นหรือหายไปก็ได้ ผลลัพธ์เกิดจากค่าจริง (true) หรือเท็จ (false) ของเงื่อนไขใดๆ
จาวาสคริปต์ตีความค่าของตัวแปรใน if ที่เป็น 0 (ศูนย์) หรือ null หรือ undefined หรือสตริงว่าง (empty string) หรือ false มีค่าเท่ากับ false
ตัวอย่างต่อไปนี้ทุกคำตอบได้ค่าเท่ากับ no
สำหรับ Vue ใช้ directive ชื่อ v-if
ตัวอย่าง
<div id="app-3">
<span v-if="seen">Now you see me</span>
</div>
จากนั้นเข้าควบคุม
var app3 = new Vue({
el: '#app-3',
data: {
seen: true
}
})
ผล
ลองคิดว่าเราเป็นทีมใหญ่ที่มี designer มาช่วยวาดหน้าเว็บให้ (ฟินมาก~) หมอนี่ก็จะลากวาง HTML เอาตามใจชอบ แก้แล้วแก้อีกแก้แล้วแก้อีกจวบกระทั่งสมประสงค์แห่งความปรารถนาทุกฝ่าย คำถามคือ เมื่อ template นี้มี logic ซ่อนแสดงผลโครงสร้าง HTML แบบ dynamic งานของ designer จะทำออกมากี่แบบ?
คำตอบที่ดีคือหลายแบบ คำตอบที่ชั่วร้ายคือแบบเดียว
สุดท้ายแล้วไม่ว่าจะแบบไหน front end progamon (ไฟฟ้าแสนโวลต์!) ก็ต้องเอาไฟล์นั้นมาทำงานอีกที ถ้าเขาเขียนด้วย Angualr เขาจะใช้ *ngIf ถ้าเขาเขียนด้วย React เขาอาจต้องเขียนฟังก์ชันเพื่อ render JSX ตาม logic อันประหลาด แต่ถ้าเขาเขียนด้วย Vue เขาจะพบกับความอัศจรรย์
ชมกันเลยสดๆให้เห็นคาตาว่าแค่กำหนด app3.seen = false
ชิ้นส่วนนี้ก็จะหายไป
หรือกลับมาใหม่ได้ดั่งใจฝัน app3.seen = true
เจ๋งใช่ไหมล่ะ
Loops
ภาษาจาวาสคริปต์กล่าวว่าเมื่อเรามีของอยู่เป็นกลุ่มพวกมันจะถูกเรียกว่า array
สมาชิกของ array มีได้ตั้งแต่ 0 ถึง n
ส่วน index ของ array มีได้ตั้งแต่ 0 ถึง n-1
ตัวอย่าง
var items = [] // ไม่มีสมาชิก
หรือ
var items = [{}] // มี 1 สมาชิก
หรือ
var items = [{}, {}] // มี 2 สมาชิก
จาวาสคริปต์ให้สามาชิกเป็นได้ทุกสิ่งอย่างในโลกแห่งค่าของตัวแปร ตัวอย่างข้างต้นคือมีค่าเป็น empty object หรือเรียกว่า ออบเจ็กต์ว่าง
ตัวอย่างอื่นๆสำหรับให้มือใหม่มองแล้วเข้าใจเลย เช่น
var items = [11, -1, 99.9] // มี 3 สมาชิก
เวลาอ้างอิงก็ใช้ index เช่น
items[0] // ให้ค่าเป็น 11
หรือ
items[2] // ให้ค่าเป็น 99.9
ส่วน
items[3] // ให้ค่าเป็น undefined
โดยทั่วไปเรามักทำงานกับ array และมักเป็น array of object เช่น
var p1 = {code: '12345', name: 'John'}
var p2 = {code: '12346', name: 'Jim'}
var persons = [p1, p2]
ซึ่งใช้ index อ้างอิงไม่ต่างจากตัวอย่างก่อนหน้า
เพิ่ม HTML นี้ลงไป
<div id="app-4">
<ol>
<li v-for="person in persons">
{{person.name}}
</li>
</ol>
</div>
จับคู่ id ค่า app-4 กับ Vue instance จากนั้นผูก persons ใน HTML กับ persons ในจาวาสคริปต์ด้วย v-for
directive ซึ่งทำหน้าที่เป็น loop
var p1 = { code: '12345', name: 'John' }
var p2 = { code: '12346', name: 'Jim' }
var persons = [p1, p2]
var app4 = new Vue({
el: '#app-4',
data: {
persons
}
})
สิ่งที่ได้คือ array ถูกอ่านค่าที่ index 0 ถึง n-1 อัตโนมัติ
หรือถ้าต้องการ index ของ loop บนหน้า HTML ก็เขียนได้ว่า
<div id="app-4">
<div v-for="(person, i) in persons">
{{i}} - {{person.name}}
</div>
</div>
เมื่อ i เป็นชื่อตัวแปรที่ตั้งเองตามใจชอบ ตำแหน่งของมันหมายถึง index ซึ่งจะเพิ่มค่าเองอัตโนมัติ
อ่านเพิ่มเติม
Handling Input
มาถึง event ที่เกี่ยวข้องกับ user input ไม่ว่าจะ click, change, key press, key down และอื่นๆ Vue สร้าง v-on
directive มาเพื่อสิ่งนี้
<div id="app-5">
<p>{{ message }}</p>
<button v-on:click="reverseMessage">Reverse Message</button>
</div>
ควบคุม
var app5 = new Vue({
el: '#app-5',
data: {
message: 'Hello Vue.js!'
},
methods: {
reverseMessage: function () {
this.message = this.message.split('').reverse().join('')
}
}
})
v-on
ถูกจับให้ทำงานกับ click event เมื่อปุ่มถูกคลิกจะทำงานฟังก์ชัน reverseMessage
ที่น่าสนใจคือออบเจ็กต์ data กับออบเจ็กต์ methods ตรงนี้ละไว้ก่อน คำถามคือ Vue แยกสองสิ่งนี้ออกจากกันด้วยเงื่อนไขอะไร?
Angular มี two-way data binding กล่าวคือค่าของตัวแปรฝั่ง model (จาวาสคริปต์) เปลี่ยนจะมีผลให้ค่าของตัวแปรเดียวกันฝั่ง view (HTML template หรือหน้าเว็บ) เปลี่ยนตาม นี่เรียก one-way ในทิศทางตรงข้ามเมื่อค่าของตัวแปรฝั่ง view เปลี่ยนจะมีผลให้ค่าของตัวแปรเดียวกันฝั่ง model เปลี่ยนตาม นี่จึงเรียกว่า two-way การผูกข้อมูลลักษณะนี้วิธีดั่งเดิมจะใช้ ng-model แต่ถ้าเป็นวิธีใหม่จะใช้ reactive from โดยอาศัย RxJS
React ผมลืมไปแล้ว
ส่วน Vue มี v-model
รับผิดชอบ data binding
ตัวอย่าง
<div id="app-6">
<p>{{message}}</p>
<input v-model="message">
</div>
ควบคุม
var app6 = new Vue({
el: '#app-6',
data: {
message: 'Hello Vue!'
}
})
ผล
ความเก่งกาจของจาวาสคริปต์สมัยใหม่นอกเหนือจาก syntax ใหม่ๆยังต้องมีวิธีการจัดการที่ดีด้วย ไม่ว่าจะเป็นด้านของข้อมูลหรือการจัดการโครงสร้าง แท้จริงแล้วเราเขียนจาวาสคริปต์เพียวเลยก็ได้ถ้าชีวิตไม่ลำบากเกินไป แต่ความเป็นจริงนั้นมันลำบากเกินไปที่จะหาคนที่เชียวชาญจาวาสคริปต์อย่างที่สุดเพื่อจะทำงาน front end อย่างเดียวกับโปรเจกต์ขนาดใหญ่ (เดี๋ยวนี้มี Node.js แล้ว — เขียนจาวาสคริปต์ back end) นี่ยังไม่นับการดูแลรักษาโค้ด การเขียนเทสตลอดจนการส่งมอบชิ้นงานให้กับลูกค้าหรือทีมอื่นพัฒนาต่อ โลกจึงมักสร้างสรรค์วิธีการต่างๆออกมาทุ่นแรงหนุนส่งกำลังให้สามารถจัดการกับปัญหาเหล่านี้อยู่ตลอดเวลา
ไม่แปลกที่จะมีจาวาสคริปต์แล้วก็มี jQuery มี React มี Angualr และ Vue
สุดท้ายนี้พูดถึงการจัดการโครงสร้าง แบ่งหน้าเว็บออกเป็นส่วนย่อย เรียกแต่ละส่วนย่อยว่า component แต่ละ component จะมีชื่อและชื่อของมันจะนำไปเป็นแท็กแปะไว้ในหน้าเว็บอีกที
Composing with Components
เพื่อนๆต้องรู้ก่อนว่าแต่ไหนแต่ไรมาเราสามารถสร้างแท็ก HTML ที่ชอบได้และควบคุมมันได้ด้วยจาวาสคริปต์ เช่น
<pros>Hello I am ProS</pros>
var pros = document.getElementsByTagName('pros')[0]
pros.style.display = 'block'
pros.style.color = 'white'
pros.style.backgroundColor = 'orange'
var div = document.createElement('div')
div.innerHTML = 'this is my short name'
pros.append(div)
เมื่อหน้าเว็บมีขนาดใหญ่ การจัดการที่ดีที่สุดในตอนนี้คือเราจะแยกมันออกเป็นส่วนย่อย แต่ละส่วนย่อยจะเรียกว่า component
หรือกล่าวได้ว่า component ใดๆจะประกอบด้วย 2 ส่วน
- view (HTML template)
- model (จาวาสคริปต์)
ตัวอย่าง
<div id="app-7">
<todo-item></todo-item>
</div>
ควบคุม
Vue.component('todo-item', {
template: '<li>This is a todo</li>'
})var app7 = new Vue({
el: '#app-7'
})
ผล
เมื่อเราจะ reuse component ก็ง่ายๆแบบนี้เลย
<div id="app-7">
<todo-item></todo-item>
<todo-item></todo-item>
<todo-item></todo-item>
</div>
ผล
แถมเรายังสามารถส่งตัวแปรเข้าไปได้ด้วยผ่านช่องทางที่เรียกว่า props
แปลงไส้ก่อนเพื่อจะส่งตัวแปร todo เข้ามา
Vue.component('todo-item', {
props: ['todo'],
template: '<li>{{todo.text}}</li>'
})
แล้วใช้ v-bind
มาเชื่อม data ใช้ v-for
มา loop
<div id="app-7">
<todo-item
v-for="item in groceryList"
v-bind:todo="item"
v-bind:key="item.id"
></todo-item>
</div>
ควบคุม
var app7 = new Vue({
el: '#app-7',
data: {
groceryList: [
{ id: 0, text: 'Vegetables' },
{ id: 1, text: 'Cheese' },
{ id: 2, text: 'Whatever else humans are supposed to eat' }
]
}
})
ผล
Vue ถูกออกแบบมาดีใช่ไหมล่ะ รออะไรล่ะ โปรเจกต์ถัดไปก็ใช้ได้เลยนะครับ
โค้ดทั้งหมด
อ้างอิง
https://vuejs.org/v2/guide/