[Vue.js] ใช้ ref เรียก DOM แทน jQuery แบบเดิม

ใน vue.js เราสามารถประกาศ ref ใน html attribute และเรียก dom ตัวนั้นด้วย this.$refs ได้

ยกตัวอย่าง ถ้าเราอยาก set focus ให้ textbox

ถ้าเป็น jQuery

<input id="password" />
$("#password").focus()

แต่ใน vue เราสามารถเรียกได้ผ่าน this.$refs

<input ref="password" />
this.$refs.password.focus()

ข้อดีของการใช้ this.$ref คือ จะไม่ใช้ standard html DOM ทำให้โอกาสที่ทำให้เราไป แตะโดน html id หรือ class อื่นๆที่ไม่เกี่ยวข้องก็ลดลงไปด้วย และที่สำคัญคือเราจะได้ไม่ต้องไปยุ่งกับ DOM โดยตรง เราเรียกผ่าน this นั่นก็คือ instance ของ vue นั่นเอง ทำให้เรียกตรงไหนก็ได้ใน vue file ของเรา

จบแล้ว.. เรียกต่างกันแค่นี้แหละ แต่ถ้าให้ดีเรามาดูตัวอย่างเรื่อง $nextTick กันอีกเล็กน้อย

มาลองชมตัวอย่างกัน

สิ่งที่กำลังจะทำคือเรามี form การเปลี่ยน password โดยเริ่มต้นให้เห็นปุ่ม Click Here to Change ก่อน หลังจากกดปุ่มค่อยแสดง textbox ขึ้นมาแทนที่ ตามรูป

Step 1 เริ่มต้น

Step 2 หลังจากกดปุ่ม Click Here to Change ซ่อนปุ่มและ focus textbox

เขียน code โดยใช้ pug ในการประกาศ html เพื่อง่ายต่อการไล่โค๊ด ดูง่ายๆเร็วๆคือ เรามีตัวแปร changePassword เป็น true/false เอาไว้ซ่อน/แสดงปุ่ม Click Here to Change

ถ้ากดปุ่ม Click Here to Change เราจะให้ซ่อนปุ่ม และโชว์ textbox แทน

<template lang="pug">
div
.form-group.floating-label
label Password
div(v-if="changePassword")
input.form-control(v-model="password", ref="inputPassword")
div(v-else)
span(@click="enableChangePassword") Click Here to Change
</template>
<script>
export default {
name: 'settingPassword'
data () {
changePassword: false,
password: ''
},
methods: {
enableChangePassword () {
this.changePassword = true
this.$refs.inputPassword.focus()
}
}
}
</scrip>

ปัญหาที่เจอคือ หลังจากที่เรากดปุ่ม Click Here to Change เราก็จะไปเรียก enableChangePassword() ให้ทำงาน แต่จะเกิด error ขึ้น

ปัญหาคืออะไร?

ปัญหาคือ หลังจากเปลี่ยน this.changePassword ให้เป็น true แล้วแต่ html ยัง render ไม่เสร็จ ทำให้หา this.$refs.inputPassword ไม่เจอ

แก้ยังไง?

รอให้ html render เสร็จก่อนแล้วค่อยเรียกหา this.$refs.inputPassword โดยใช้คำสั่ง this.$nextTick()

this.$nextTick(() => {
this.$refs.inputPassword.focus()
})

ลองมาดู code ใหม่กัน

<template lang="pug">
div
.form-group.floating-label
label Password
div(v-if="changePassword")
input.form-control(v-model="password", ref="inputPassword")
div(v-else)
span(@click="enableChangePassword") Click Here to Change
</template>
<script>
export default {
name: 'settingPassword'
data () {
changePassword: false,
password: ''
},
methods: {
enableChangePassword () {
this.changePassword = true
this.$nextTick(() => {
this.$refs.inputPassword.focus()
})
}
}
}
</scrip>

แค่นี้ก็เจอ this.$refs.inputPassword แล้ว

ถ้าใน angular1 การรอ html render ให้เสร็จก็ใช้วิธีเดียวกันผ่านคำสั่ง setTimeout

setTimeout(() => {
// code here
}, 0)

จบแล้ว.. ไม่ได้ install อะไรเพิ่มเลย แค่ทำความเข้าใจ แต่ทำไมเขียน blog ยาวจัง 55

references

Show your support

Clapping shows how much you appreciated Nuttawoot Singhathom’s story.