หลังจากพยายามเขียนตัว Format input เองสำหรับ Vuejs แล้วพบว่าไม่ค่อยเวิร์คเท่าไหร่ เช่นตอนกรอกเครื่องหมายจุดแล้วตรวจสอบไม่ละเอียดลบได้บ้างไม่ได้บ้างเป็นต้น เลยหา lib คนอื่นมาใช้ดีกว่าเจอตัวนี้น่าสนใจดีอย่างแรกเลยก็ตอบโจทย์ที่กำลังหาพอดีเลยเอามาใช้แล้วพบว่ามีปัญหากับ vuetify เล็กน้อยเลยแงะจนมันใช้งานได้บันทึกไว้
DEMO
https://mrchoke.github.io/vuetify-cleave/
Source
Create VueJs & Veutify Project
vue create vuetify-cleave cd vuetify-cleave vue add vuetify
Add Cleave.js
yarn add cleave.js
Add Global Directive
main.js
import Cleave from 'cleave.js'; Vue.directive('cleave', { inserted: (el, binding) => { el.cleave = new Cleave(el, binding.value || {}) }, update: (el) => { const event = new Event('input', {bubbles: true}); setTimeout(function () { el.value = el.cleave.properties.result el.dispatchEvent(event) }, 100); } })
link: https://github.com/nosir/cleave.js/blob/master/doc/vue.md
ตอนนี้ Vue จะเห็น directive cleave แล้วลองสร้าง text field ดูครับ
<v-text-field v-model="comma" label="Number with Comma" **v-cleave="{ numeral: true, numeralThousandsGroupStyle: 'thousand' }"** > </v-text-field>
ถ้าลอง input จะมี error ขึ้นมา แต่ถ้าใช้ input ปกติของ HTML จะไม่มีปัญหา
<input type="text" v-model="comma2" **v-cleave="{ numeral: true, numeralThousandsGroupStyle: 'thousand' }"** />
ลองค้นหาข้อมูลพบว่า input ของ vuetify นั้นเป็นแบบ component สิ่งที่เห็นนั้นประกอบไปด้วย element ต่างๆ มากมายมันไม่ใช่ input ที่แท้จริงผมเลยไปแกะ directive ที่เค้าทำมาแล้วใช้ได้กับ Vuetify ซึ่งเค้าจำหา element ที่แท้จริงส่งให้นั่นเองเอาแบบง่ายๆ แก้ที่ main.js โดยสร้าง function เพิ่มมาแล้วเรียกใช้
**function getInput(el) { if (el.tagName.toLocaleUpperCase() !== 'INPUT') { const els = el.getElementsByTagName('input') if (els.length !== 1) { throw new Error(`v-cleave requires 1 input, found ${els.length}`) } else { el = els[0] } } return el }** Vue.directive('cleave', { inserted: (el, binding) => { **el = getInput(el)** el.cleave = new Cleave(el, binding.value || {}) }, update: el => { **el = getInput(el)** const event = new Event('input', { bubbles: true }) setTimeout(function() { el.value = el.cleave.properties.result el.dispatchEvent(event) }, 100) } })
TypeScript
สำหรับ TypeScript จะมีปัญหาเรื่อง properties ที่ Cleave.js แปะเข้าไปใน HTMLElement ทำให้เกิดการเตือนหรืออาจจะใช้งานไม่ได้
ขั้นแรกเพิ่ม @type/cleave.js ก่อน
yarn add -D @types/cleave.js
หลังจากนั้นให้สร้าง interface โดย extents HTMLElement เช่น
import Cleave from 'cleave.js' import { CleaveOptions } from 'cleave.js/options' class Cl extends Cleave { properties?: Record<string, string> constructor(selector: string | HTMLElement, options: CleaveOptions) { super(selector, options) } } export interface HTMLElementA extends HTMLElement { cleave?: Cl value?: string }
แล้วแก้ในส่วนของการประกาศ directive ใน main.ts
function getInput(el: **HTMLElementA** ) { if (el.tagName.toLocaleUpperCase() !== 'INPUT') { const els = el.getElementsByTagName('input') if (els.length !== 1) { throw new Error(`v-cleave requires 1 input, found ${els.length}`) } else { el = els[0] } } return el } Vue.directive('cleave', { inserted: (el: **HTMLElementA** , binding) => { el = getInput(el) el.cleave = new Cleave(el, binding.value || {}) }, update: (el: **HTMLElementA** ) => { el = getInput(el) const event = new Event('input', { bubbles: true }) setTimeout(function() { el.value = **el.cleave?.properties?.result** el.dispatchEvent(event) }, 100) } })
ก็จะประมาณนี้ครับ
Top comments (0)