Semua orang sangat biasa dengan arahan v-model
dalam Vue.js, yang melaksanakan pengikatan data dua hala antara komponen. Tetapi apabila melaksanakan v-model
secara manual untuk komponen tersuai, anda biasanya menghadapi beberapa isu.
Pendekatan biasa adalah seperti berikut:
const props = defineProps(['modelValue']); const emit = defineEmits(['update:modelValue']); <template></template>
Sila ambil perhatian bahawa kami tidak akan mengubah suai nilai prop modelValue
di dalam komponen. Sebaliknya, kami menghantar nilai yang dikemas kini kembali kepada komponen induk melalui kaedah emit
dan komponen induk membuat pengubahsuaian sebenar. Ini kerana: Komponen anak tidak seharusnya menjejaskan keadaan komponen induk, yang merumitkan aliran data dan menyukarkan penyahpepijatan.
Seperti yang dinyatakan dalam dokumentasi Vue, prop tidak boleh diubah suai di dalam komponen anak. Jika anda melakukan ini, Vue akan mengeluarkan amaran dalam konsol.
Bagaimana keadaan subjek?
Objek dan tatasusunan dalam JavaScript ialah kes khas kerana ia diluluskan melalui rujukan. Ini bermakna komponen boleh secara langsung mengubah suai sifat bersarang prop objek. Walau bagaimanapun, Vue tidak memberi amaran tentang pengubahsuaian dalam sifat objek bersarang (menjejaki pengubahsuaian ini dikenakan penalti prestasi). Oleh itu, perubahan yang tidak dijangka itu boleh menyebabkan masalah dalam aplikasi anda yang sukar untuk dikesan dan nyahpepijat.
Kebanyakan masa kami menggunakan nilai asas sebagai v-model
. Walau bagaimanapun, dalam beberapa kes, seperti semasa membina komponen borang, kita mungkin memerlukan v-model
tersuai yang boleh mengendalikan objek. Ini membawa kepada soalan penting:
Bagaimana untuk melaksanakan
v-model
tersuai untuk mengendalikan objek sambil mengelakkan perangkap di atas?
Salah satu cara ialah menggunakan sifat pengiraan boleh tulis atau defineModel
fungsi pembantu. Walau bagaimanapun, kedua-dua penyelesaian mempunyai kelemahan yang ketara: ia secara langsung mengubah suai objek asal, yang mengalahkan tujuan mengekalkan aliran data yang jelas.
Untuk menggambarkan masalah ini, mari lihat contoh komponen "bentuk". Komponen ini direka bentuk untuk memancarkan salinan objek yang dikemas kini kembali ke komponen induk apabila nilai dalam bentuk berubah. Kami akan cuba mencapai ini menggunakan sifat pengiraan boleh tulis.
Dalam contoh ini, sifat pengiraan boleh tulis masih mengubah suai objek asal.
import { computed } from 'vue'; import { cloneDeep } from 'lodash-es'; type Props = { modelValue: { name: string; email: string; }; }; const props = withDefaults(defineProps<Props>(), { modelValue: () => ({ name: '', email: '' }), }); const emit = defineEmits<{ 'update:modelValue': [value: Props['modelValue']]; }>(); const formData = computed({ // 返回的getter对象仍然是可变的 get() { return props.modelValue; }, // 注释掉setter仍然会修改prop set(newValue) { emit('update:modelValue', cloneDeep(newValue)); }, });
Ini tidak berfungsi kerana objek yang dikembalikan daripada pengambil masih boleh berubah, menyebabkan objek asal diubah suai tanpa diduga.
defineModel
Perkara yang sama. Memandangkan update:modelValue
tidak dipancarkan daripada komponen dan sifat objek diubah suai tanpa sebarang amaran.
"Cara Vue" untuk mengendalikan situasi ini ialah menggunakan nilai reaktif dalaman untuk mewakili objek, dan melaksanakan dua pemerhati:
modelValue
prop untuk perubahan dan mengemas kini nilai dalaman. Ini memastikan bahawa keadaan dalaman mencerminkan nilai prop terkini yang diluluskan oleh komponen induk. Untuk mengelakkan gelung maklum balas yang tidak berkesudahan antara kedua-dua pemerhati ini, kami perlu memastikan kemas kini pada prop modelValue
tidak secara tidak sengaja mencetuskan semula pemerhati untuk nilai dalaman.
const props = defineProps(['modelValue']); const emit = defineEmits(['update:modelValue']); <template></template>
Saya tahu apa yang anda fikirkan: "Ini terlalu banyak!"
Mengekstrak logik ini ke dalam fungsi tersusun boleh guna semula ialah cara yang bagus untuk memudahkan proses. Tetapi berita baiknya ialah: kita tidak perlu berbuat demikian! useVModel
fungsi gabungan dalam VueUse boleh membantu kami menangani masalah ini!
VueUse ialah perpustakaan utiliti Vue yang berkuasa, sering dirujuk sebagai "Pisau Tentera Swiss" bagi utiliti yang terdiri. Ia boleh digoncangkan sepenuhnya oleh pokok, jadi kami hanya boleh menggunakan bahagian yang kami perlukan tanpa perlu risau tentang meningkatkan saiz bungkusan.
Berikut ialah contoh sebelum pemfaktoran semula menggunakan useVModel
:
import { computed } from 'vue'; import { cloneDeep } from 'lodash-es'; type Props = { modelValue: { name: string; email: string; }; }; const props = withDefaults(defineProps<Props>(), { modelValue: () => ({ name: '', email: '' }), }); const emit = defineEmits<{ 'update:modelValue': [value: Props['modelValue']]; }>(); const formData = computed({ // 返回的getter对象仍然是可变的 get() { return props.modelValue; }, // 注释掉setter仍然会修改prop set(newValue) { emit('update:modelValue', cloneDeep(newValue)); }, });
Lebih ringkas!
Itu sahaja! Kami telah meneroka cara menggunakan objek dengan betul dengan v-model
dalam Vue tanpa mengubah suai terus daripada komponen anak. Dengan menggunakan pemerhati atau memanfaatkan fungsi gubahan seperti useVModel
VueUse, kami boleh mengekalkan pengurusan keadaan yang jelas dan boleh diramal dalam aplikasi kami.
Berikut ialah pautan Stackblitz dengan semua contoh dalam artikel ini. Jangan ragu untuk meneroka dan mencuba.
Terima kasih kerana membaca dan selamat mengekod!
Atas ialah kandungan terperinci Cara menggunakan objek dengan model v dalam Vue. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!