Vue 3 使用 v-model 作为 props 而不是 :prop 和 @emit

问题描述

所以我已经阅读了 this 几篇文章,据我所知,我可以使用 v-model 而不是 props,将值从父组件传递给子组件,并在 prop 的时候自动发出事件值在子级中被修改,从而以更少的代码获得双向绑定(无需在父级中捕获已发出的事件)。然而,它并不像我认为的那样工作。

这是我的代码

<template>
  <!-- This is ParentComponent.vue -->
  <ChildComponent v-model:documents="user.documents" />
</template>
<script lang="ts">
  // This is ParentComponent.vue
  import { Vue,Options } from 'vue-class-component';
  import UserClass from '@/some/place/UserClass';
  import ChildComponent from '@/components/ChildComponent.vue';

  @Options({
    components: {
      ChildComponent,}
  })
  export default class ParentComponent extends Vue {
    // Local state.
    user: UserClass = new UserClass();
  }
</script>
<template>
  <!-- This is ChildComponent.vue -->
  <section v-for="document in documents" :key="document.id">
    {{ document.name }}
    <button @click="remove(document.id)">Delete document</button>
  </section>
</template>
<script lang="ts">
  // This is ChildComponent.vue
  import { Vue,Options } from 'vue-class-component';
  import IDocument from '@/interfaces/IDocument';

  @Options({
    props: ['documents'],emits: ['update:documents'],})
  export default class ChildComponent extends Vue {
    // Types.
    documents!: IDocument[];

    // Methods.
    remove(documentId: string): void {
      this.documents = this.documents.filter((document) => document.id !== documentId);
    }
  }
</script>

我希望当单击子组件内的按钮时,它应该触发“remove()”方法,而不是直接将新值分配给 this.documents,它应该发出 update:documents 事件,反过来应该被父组件捕获并应该用于更新父组件的本地状态。

但是,我收到以下警告:

试图改变道具“文档”。道具是只读的。

还有以下错误

未捕获的类型错误:代理集处理程序为属性“文档”返回 false

我哪里错了?提前致谢。

解决方法

我想我错过了 v-model 工作原理的一个重要功能。我假设像这样使用 v-model 传递值

public class WeekChallengeBroadcast extends BroadcastReceiver {
    @Override
    public void onReceive(Context context,Intent intent) {

        String userID = FirebaseAuth.getInstance().getCurrentUser().getUid();
        DatabaseReference myRef = FirebaseDatabase.getInstance().getReference().child(userID).child("CurrentChallenge");
        myRef.addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot snapshot) {
                int id = snapshot.child("numOfActiveChallenge").getValue(Integer.class);

                MyDBHandler myDBHandler = new MyDBHandler(context,null,MyDBHandler.DB_VERSION);

                int challengeWeek = id;

                Vibrator v = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
                if (challengeWeek != 0) {
                    NotificationCompat.Builder notification = new NotificationCompat.Builder(context,CHANNEL_1_ID)
                            .setSmallIcon(R.drawable.ic_stat_name)
                            .setContentTitle("Challenge for this week :")
                            .setContentText(myDBHandler.loadChallengeNotification(challengeWeek))
                            .setStyle(new NotificationCompat.BigTextStyle())
                            .setPriority(Notification.PRIORITY_MAX)
                            .setSound(Settings.System.DEFAULT_NOTIFICATION_URI)
                            .setAutoCancel(false);


                    v.vibrate(500);
                    NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);

                    notificationManager.notify(2,notification.build());
                } else
                    return;


            }

            @Override
            public void onCancelled(@NonNull DatabaseError error) {

            }
        });

    }
}

当 ChildComponent 中的文档属性值发生更改时,将自动发出 update:documents 事件。但似乎您仍然需要手动发出此事件,如下所示:

public void MyAlarmWeekChallenge() {
    Calendar calendar = Calendar.getInstance();
    calendar.set(Calendar.HOUR_OF_DAY,12);
    calendar.set(Calendar.MINUTE,0);
    calendar.set(Calendar.SECOND,0);

    if (calendar.getTime().compareTo((new Date())) < 0)
    {
        calendar.add(Calendar.DAY_OF_MONTH,1);
    }

    Intent intent = new Intent(getApplicationContext(),WeekChallengeBroadcast.class);
    PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(),intent,0);
    AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);

    if(alarmManager != null){
        alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,calendar.getTimeInMillis(),AlarmManager.INTERVAL_DAY,pendingIntent);
    }
}