Skip to content

v-model مع المكون

يمكن استخدام v-model على مكون لتنفيذ ارتباط ثنائي الاتجاه.

أولا دعونا نعيد النظر في كيفية استخدام v-model على عنصر أصلي:

template
<input v-model="searchText" />

خلف الكواليس، يقوم مصرّف القوالب بتجزئة v-model إلى الحدث input@ و السمة value. لذلك، تقوم الشيفرة أعلاه بنفس الأمر الذي تقوم به الشيفرة الموالية:

template
<input
  :value="searchText"
  @input="searchText = $event.target.value"
/>

عند استخدامه على مكون، يُجزّء v-model إلى ما يلي:

template
<CustomInput
  :model-value="searchText"
  @update:model-value="newValue => searchText = newValue"
/>

لكن ليشتغل هذا فعلا، يجب على <CustomInput> القيام بأمرين:

  1. اربط السمة value لعنصر <input> الأصلي مع الخاصية modelValue
  2. عندما تُشغل حدث input الأصلي ، ارسل حدث مخصص update:modelValue مع القيمة الجديدة

عمليا:

vue
<!-- CustomInput.vue -->
<script>
export default {
  props: ['modelValue'],
  emits: ['update:modelValue']
}
</script>

<template>
  <input
    :value="modelValue"
    @input="$emit('update:modelValue', $event.target.value)"
  />
</template>
vue
<!-- CustomInput.vue -->
<script setup>
defineProps(['modelValue'])
defineEmits(['update:modelValue'])
</script>

<template>
  <input
    :value="modelValue"
    @input="$emit('update:modelValue', $event.target.value)"
  />
</template>

الآن يجب أن يعمل v-model بشكل مثالي مع هذا المكون:

template
<CustomInput v-model="searchText" />

طريقة أخرى لتنفيذ v-model داخل هذا المكون هي استخدام خاصية computed قابلة للكتابة مع الدالتين المحصلة و المعينة. يجب أن تعيد الدالة get الخاصية modelValue ويجب أن ترسل الدالة set الحدث الموافق:

vue
<!-- CustomInput.vue -->
<script>
export default {
  props: ['modelValue'],
  emits: ['update:modelValue'],
  computed: {
    value: {
      get() {
        return this.modelValue
      },
      set(value) {
        this.$emit('update:modelValue', value)
      }
    }
  }
}
</script>

<template>
  <input v-model="value" />
</template>
vue
<!-- CustomInput.vue -->
<script setup>
import { computed } from 'vue'

const props = defineProps(['modelValue'])
const emit = defineEmits(['update:modelValue'])

const value = computed({
  get() {
    return props.modelValue
  },
  set(value) {
    emit('update:modelValue', value)
  }
})
</script>

<template>
  <input v-model="value" />
</template>

وسائط v-model

افتراضيًا، يستخدم v-model على المكون modelValue كخاصية و update:modelValue كحدث. يمكننا تعديل هذه الأسماء من خلال إرسال وسيط إلى v-model:

template
<MyComponent v-model:title="bookTitle" />

في هذه الحالة، يجب أن يتوقع المكون الابن خاصية title ويرسل الحدث update:title لتحديث القيمة في المكون الأب:

vue
<!-- MyComponent.vue -->
<script setup>
defineProps(['title'])
defineEmits(['update:title'])
</script>

<template>
  <input
    type="text"
    :value="title"
    @input="$emit('update:title', $event.target.value)"
  />
</template>

اختبرها في حقل التجارب

vue
<!-- MyComponent.vue -->
<script>
export default {
  props: ['title'],
  emits: ['update:title']
}
</script>

<template>
  <input
    type="text"
    :value="title"
    @input="$emit('update:title', $event.target.value)"
  />
</template>

اختبرها في حقل التجارب

الربط المتعدد بـ v-model

باستخدام قدرة تحديد خاصية معينة وحدث معين كما تعلمنا من قبل مع وسائط v-model ، يمكننا الآن إنشاء عدة ارتباطات v-model على نسخة واحدة من المكون.

كل v-model سيتزامن مع خاصية مختلفة ، دون الحاجة إلى خيارات إضافية في المكون:

template
<UserName
  v-model:first-name="first"
  v-model:last-name="last"
/>
vue
<script setup>
defineProps({
  firstName: String,
  lastName: String
})

defineEmits(['update:firstName', 'update:lastName'])
</script>

<template>
  <input
    type="text"
    :value="firstName"
    @input="$emit('update:firstName', $event.target.value)"
  />
  <input
    type="text"
    :value="lastName"
    @input="$emit('update:lastName', $event.target.value)"
  />
</template>

اختبرها في حقل التجارب

vue
<script>
export default {
  props: {
    firstName: String,
    lastName: String
  },
  emits: ['update:firstName', 'update:lastName']
}
</script>

<template>
  <input
    type="text"
    :value="firstName"
    @input="$emit('update:firstName', $event.target.value)"
  />
  <input
    type="text"
    :value="lastName"
    @input="$emit('update:lastName', $event.target.value)"
  />
</template>

اختبرها في حقل التجارب

معالجة معدلات v-model

عندما كنا نتعلم عن ارتباطات إدخال النموذج، رأينا أن v-model لديه المعدلات المدمجة - .trim , .number و lazy.. في بعض الحالات، قد ترغب أيضًا في أن يدعم v-model على مكون إدخال مخصص بعض المعدلات المخصصة.

لنقم بإنشاء مثال لمعدل مخصص، capitalize، يقوم بتكبير الحرف الأول من السلسلةالنصية المقدمة من خلال ربط v-model:

template
<MyComponent v-model.capitalize="myText" />

المُعدِّلات المضافة إلى v-model للمكون ستُمرر إلى المكون عبر خاصية modelModifiers. في المثال أدناه، قمنا بإنشاء مكون يحتوي على خاصية modelModifiers تعيد قيمة فارغة افتراضيًا:

vue
<script setup>
const props = defineProps({
  modelValue: String,
  modelModifiers: { default: () => ({}) }
})

defineEmits(['update:modelValue'])

console.log(props.modelModifiers) // { capitalize: true }
</script>

<template>
  <input
    type="text"
    :value="modelValue"
    @input="$emit('update:modelValue', $event.target.value)"
  />
</template>
vue
<script>
export default {
  props: {
    modelValue: String,
    modelModifiers: {
      default: () => ({})
    }
  },
  emits: ['update:modelValue'],
  created() {
    console.log(this.modelModifiers) // { capitalize: true }
  }
}
</script>

<template>
  <input
    type="text"
    :value="modelValue"
    @input="$emit('update:modelValue', $event.target.value)"
  />
</template>

تجدر الإشارة إلى أن خاصية modelModifiers للمكون تحتوي على المُعدِّل capitalize وقيمته true - بسبب تعيينها على v-model بالربط "v-model.capitalize="myText.

الآن، بعد أن قمنا بإعداد الخاصية، يمكننا التحقق من مفاتيح الكائن modelModifiers وكتابة مُعالِج لتغيير القيمة المرسلة. في الشيفرة أدناه، سنقوم بتكبير الحرف الأول من السلسلة النصية عندما يُطلق حدث input على عنصر </ input>.

vue
<script setup>
const props = defineProps({
  modelValue: String,
  modelModifiers: { default: () => ({}) }
})

const emit = defineEmits(['update:modelValue'])

function emitValue(e) {
  let value = e.target.value
  if (props.modelModifiers.capitalize) {
    value = value.charAt(0).toUpperCase() + value.slice(1)
  }
  emit('update:modelValue', value)
}
</script>

<template>
  <input type="text" :value="modelValue" @input="emitValue" />
</template>

اختبرها في حقل التجارب

vue
<script>
export default {
  props: {
    modelValue: String,
    modelModifiers: {
      default: () => ({})
    }
  },
  emits: ['update:modelValue'],
  methods: {
    emitValue(e) {
      let value = e.target.value
      if (this.modelModifiers.capitalize) {
        value = value.charAt(0).toUpperCase() + value.slice(1)
      }
      this.$emit('update:modelValue', value)
    }
  }
}
</script>

<template>
  <input type="text" :value="modelValue" @input="emitValue" />
</template>

اختبرها في حقل التجارب

Modifiers for v-model with arguments

بالنسبة لربط v-model مع كل من الوسيط والمعدلات، سيكون اسم الخاصية المولدة "arg + "Modifiers على سبيل المثال.

template
<MyComponent v-model:title.capitalize="myText">

التصريحات المقابلة يجب أن تكون:

js
const props = defineProps(['title', 'titleModifiers'])
defineEmits(['update:title'])

console.log(props.titleModifiers) // { capitalize: true }
js
export default {
  props: ['title', 'titleModifiers'],
  emits: ['update:title'],
  created() {
    console.log(this.titleModifiers) // { capitalize: true }
  }
}

Here's another example of using modifiers with multiple v-model with different arguments:

template
<UserName
  v-model:first-name.capitalize="first"
  v-model:last-name.uppercase="last"
/>
vue
<script setup>
const props = defineProps({
  firstName: String,
  lastName: String,
  firstNameModifiers: { default: () => ({}) },
  lastNameModifiers: { default: () => ({}) }
})
defineEmits(['update:firstName', 'update:lastName'])

console.log(props.firstNameModifiers) // { capitalize: true }
console.log(props.lastNameModifiers) // { uppercase: true}
</script>
vue
<script>
export default {
  props: {
    firstName: String,
    lastName: String,
    firstNameModifiers: {
      default: () => ({})
    },
    lastNameModifiers: {
      default: () => ({})
    }
  },
  emits: ['update:firstName', 'update:lastName'],
  created() {
    console.log(this.firstNameModifiers) // { capitalize: true }
    console.log(this.lastNameModifiers) // { uppercase: true}
  }
}
</script>
v-model مع المكون has loaded