mirror of
https://github.com/tenrok/maska.git
synced 2026-06-20 20:00:34 +03:00
Optimize directive work
This commit is contained in:
+16
-4
@@ -7,13 +7,18 @@ const masks = new WeakMap<HTMLInputElement, MaskInput>()
|
|||||||
|
|
||||||
export const vMaska: MaskaDirective = (el, binding) => {
|
export const vMaska: MaskaDirective = (el, binding) => {
|
||||||
const input = el instanceof HTMLInputElement ? el : el.querySelector('input')
|
const input = el instanceof HTMLInputElement ? el : el.querySelector('input')
|
||||||
|
const opts = { ...(binding.arg as MaskInputOptions) } ?? {}
|
||||||
|
|
||||||
if (input == null) return
|
if (input == null) return
|
||||||
|
|
||||||
if (masks.get(input) != null) {
|
const existed = masks.get(input)
|
||||||
masks.get(input)?.destroy()
|
if (existed != null) {
|
||||||
}
|
if (!existed.needUpdate(input, opts)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
const opts = { ...(binding.arg as MaskInputOptions) } ?? {}
|
existed.destroy()
|
||||||
|
}
|
||||||
|
|
||||||
if (binding.value != null) {
|
if (binding.value != null) {
|
||||||
const binded = binding.value
|
const binded = binding.value
|
||||||
@@ -32,4 +37,11 @@ export const vMaska: MaskaDirective = (el, binding) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
masks.set(input, new MaskInput(input, opts))
|
masks.set(input, new MaskInput(input, opts))
|
||||||
|
|
||||||
|
// check initial value for v-model
|
||||||
|
setTimeout(() => {
|
||||||
|
if (input.value !== '') {
|
||||||
|
input.dispatchEvent(new InputEvent('input'))
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
+21
-4
@@ -22,12 +22,16 @@ export class MaskInput {
|
|||||||
target: string | NodeListOf<HTMLInputElement> | HTMLInputElement,
|
target: string | NodeListOf<HTMLInputElement> | HTMLInputElement,
|
||||||
readonly options: MaskInputOptions = {}
|
readonly options: MaskInputOptions = {}
|
||||||
) {
|
) {
|
||||||
const { onMaska, preProcess, postProcess, ...opts } = options
|
|
||||||
|
|
||||||
if (typeof target === 'string') {
|
if (typeof target === 'string') {
|
||||||
this.init(Array.from(document.querySelectorAll(target)), opts)
|
this.init(
|
||||||
|
Array.from(document.querySelectorAll(target)),
|
||||||
|
this.getMaskOpts(options)
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
this.init('length' in target ? Array.from(target) : [target], opts)
|
this.init(
|
||||||
|
'length' in target ? Array.from(target) : [target],
|
||||||
|
this.getMaskOpts(options)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,6 +43,19 @@ export class MaskInput {
|
|||||||
this.items.clear()
|
this.items.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
needUpdate (input: HTMLInputElement, opts: MaskInputOptions): boolean {
|
||||||
|
const mask = this.items.get(input) as Mask
|
||||||
|
const maskNew = new Mask(parseInput(input, this.getMaskOpts(opts)))
|
||||||
|
|
||||||
|
return JSON.stringify(mask.opts) !== JSON.stringify(maskNew.opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
private getMaskOpts (options: MaskInputOptions): MaskOptions {
|
||||||
|
const { onMaska, preProcess, postProcess, ...opts } = options
|
||||||
|
|
||||||
|
return opts
|
||||||
|
}
|
||||||
|
|
||||||
private init (inputs: HTMLInputElement[], defaults: MaskOptions): void {
|
private init (inputs: HTMLInputElement[], defaults: MaskOptions): void {
|
||||||
for (const input of inputs) {
|
for (const input of inputs) {
|
||||||
const mask = new Mask(parseInput(input, defaults))
|
const mask = new Mask(parseInput(input, defaults))
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { ref } from 'vue'
|
||||||
|
|
||||||
|
import { vMaska } from '../../src'
|
||||||
|
import CustomInput from './CustomInput.vue'
|
||||||
|
|
||||||
|
const value = ref('')
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<CustomInput v-maska data-maska="#-#" data-maska-eager v-model="value" />
|
||||||
|
<div>{{ value }}</div>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<script setup>
|
||||||
|
defineProps(['modelValue'])
|
||||||
|
defineEmits(['update:modelValue'])
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<input
|
||||||
|
:value="modelValue"
|
||||||
|
@input="$emit('update:modelValue', $event.target.value)"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { vMaska } from '../../src'
|
||||||
|
|
||||||
|
const value = ref('123')
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<input v-maska data-maska="#-#" data-maska-eager v-model="value" />
|
||||||
|
<div>{{ value }}</div>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { reactive, ref } from 'vue'
|
||||||
|
import { vMaska } from '../../src'
|
||||||
|
|
||||||
|
const emit = defineEmits(['mask1', 'mask2'])
|
||||||
|
|
||||||
|
const isEager = ref(false)
|
||||||
|
|
||||||
|
const value1 = ref('123')
|
||||||
|
const value2 = ref('321')
|
||||||
|
|
||||||
|
const options = reactive({
|
||||||
|
eager: isEager,
|
||||||
|
onMaska: () => null
|
||||||
|
})
|
||||||
|
|
||||||
|
const onMaska1 = () => {
|
||||||
|
emit('mask1')
|
||||||
|
}
|
||||||
|
|
||||||
|
const onMaska2 = () => {
|
||||||
|
emit('mask2')
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<input id="checkbox" type="checkbox" v-model="isEager" />
|
||||||
|
<input
|
||||||
|
id="input1"
|
||||||
|
v-maska:[options]
|
||||||
|
data-maska="#-#"
|
||||||
|
v-model="value1"
|
||||||
|
@maska="onMaska1"
|
||||||
|
/>
|
||||||
|
<input
|
||||||
|
id="input2"
|
||||||
|
v-maska
|
||||||
|
data-maska="#-#"
|
||||||
|
v-model="value2"
|
||||||
|
@maska="onMaska2"
|
||||||
|
/>
|
||||||
|
<div id="value1">{{ value1 }}</div>
|
||||||
|
<div id="value2">{{ value2 }}</div>
|
||||||
|
</template>
|
||||||
@@ -8,10 +8,13 @@ import BindUnmasked from './components/BindUnmasked.vue'
|
|||||||
import Callbacks from './components/Callbacks.vue'
|
import Callbacks from './components/Callbacks.vue'
|
||||||
import Completed from './components/Completed.vue'
|
import Completed from './components/Completed.vue'
|
||||||
import Config from './components/Config.vue'
|
import Config from './components/Config.vue'
|
||||||
|
import Custom from './components/Custom.vue'
|
||||||
import DataAttr from './components/DataAttr.vue'
|
import DataAttr from './components/DataAttr.vue'
|
||||||
import Dynamic from './components/Dynamic.vue'
|
import Dynamic from './components/Dynamic.vue'
|
||||||
import Events from './components/Events.vue'
|
import Events from './components/Events.vue'
|
||||||
import Hooks from './components/Hooks.vue'
|
import Hooks from './components/Hooks.vue'
|
||||||
|
import Model from './components/Model.vue'
|
||||||
|
import Multiple from './components/Multiple.vue'
|
||||||
import Options from './components/Options.vue'
|
import Options from './components/Options.vue'
|
||||||
import Parent from './components/Parent.vue'
|
import Parent from './components/Parent.vue'
|
||||||
import Simple from './components/Simple.vue'
|
import Simple from './components/Simple.vue'
|
||||||
@@ -103,6 +106,67 @@ test('bind completed', async () => {
|
|||||||
expect(wrapper.get('div').element.textContent).toBe('Completed')
|
expect(wrapper.get('div').element.textContent).toBe('Completed')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('v-model', async () => {
|
||||||
|
const wrapper = mount(Model)
|
||||||
|
const input = wrapper.get('input')
|
||||||
|
|
||||||
|
await new Promise((r) => setTimeout(r))
|
||||||
|
|
||||||
|
expect(input.element.value).toBe('1-2')
|
||||||
|
expect(wrapper.get('div').element.textContent).toBe('1-2')
|
||||||
|
|
||||||
|
await input.setValue('1')
|
||||||
|
expect(input.element.value).toBe('1-')
|
||||||
|
expect(wrapper.get('div').element.textContent).toBe('1-')
|
||||||
|
|
||||||
|
await input.setValue('123')
|
||||||
|
expect(input.element.value).toBe('1-2')
|
||||||
|
expect(wrapper.get('div').element.textContent).toBe('1-2')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('custom component', async () => {
|
||||||
|
const wrapper = mount(Custom)
|
||||||
|
const input = wrapper.get('input')
|
||||||
|
|
||||||
|
await input.setValue('1')
|
||||||
|
expect(input.element.value).toBe('1-')
|
||||||
|
expect(wrapper.get('div').element.textContent).toBe('1-')
|
||||||
|
|
||||||
|
await input.setValue('123')
|
||||||
|
expect(input.element.value).toBe('1-2')
|
||||||
|
expect(wrapper.get('div').element.textContent).toBe('1-2')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('multiple inputs', async () => {
|
||||||
|
const wrapper = mount(Multiple)
|
||||||
|
const input = wrapper.get<HTMLInputElement>('#input1')
|
||||||
|
const checkbox = wrapper.get<HTMLInputElement>('#checkbox')
|
||||||
|
|
||||||
|
await new Promise((r) => setTimeout(r))
|
||||||
|
|
||||||
|
expect(wrapper.get('#value1').element.textContent).toBe('1-2')
|
||||||
|
expect(wrapper.get('#value2').element.textContent).toBe('3-2')
|
||||||
|
|
||||||
|
expect(wrapper.emitted()).toHaveProperty('mask1')
|
||||||
|
expect(wrapper.emitted()).toHaveProperty('mask2')
|
||||||
|
expect(wrapper.emitted('mask1')).toHaveLength(1)
|
||||||
|
expect(wrapper.emitted('mask2')).toHaveLength(1)
|
||||||
|
|
||||||
|
await input.setValue('1')
|
||||||
|
expect(input.element.value).toBe('1')
|
||||||
|
expect(wrapper.get('#value1').element.textContent).toBe('1')
|
||||||
|
expect(wrapper.emitted()).toHaveProperty('mask1')
|
||||||
|
expect(wrapper.emitted('mask1')).toHaveLength(2)
|
||||||
|
expect(wrapper.emitted('mask2')).toHaveLength(1)
|
||||||
|
|
||||||
|
await checkbox.setValue()
|
||||||
|
expect(checkbox.element).toBeChecked()
|
||||||
|
|
||||||
|
expect(input.element.value).toBe('1-')
|
||||||
|
expect(wrapper.emitted('mask1')).toHaveLength(3)
|
||||||
|
expect(wrapper.emitted('mask2')).toHaveLength(1)
|
||||||
|
})
|
||||||
|
|
||||||
test('config and bind', async () => {
|
test('config and bind', async () => {
|
||||||
const wrapper = mount(Config)
|
const wrapper = mount(Config)
|
||||||
const input = wrapper.get('input')
|
const input = wrapper.get('input')
|
||||||
|
|||||||
Reference in New Issue
Block a user