vue 3 组合 api 组件,带有复选框数组并切换所有
P粉670838735
P粉670838735 2023-08-30 20:55:11
[Vue.js讨论组]
<p>我们决定逐渐从淘汰赛转向使用 typescript 的 vue 3 组合 api,并且我正在尝试了解变异道具的反模式。我有一个正在执行其预期工作的工作组件,但基本上我想确认它的编写方式是建议的方法。</p> <p>一个相当简单的例子是一个复选框列表组件,上面有一个切换开关:</p> <p>我最大的问题是我在 AppList.vue 中所做的是否正确,我正在做 <code>const internalModel = toRef(props.selected ?? []);</code> 以获得不可变的组件中的变量和 <code>selectedHandler</code> - 事件和 <code>toggleAll</code> - 计算为发出 OUT,但在这里我手动保留 <code>selected</code> 和 <代码>内部模型</代码>同步。对于同一件事使用两个变量感觉很麻烦,但同时它确实有意义,因为内部模型不需要干扰视图。</p> <p>我知道 vuejs.org 上有一个示例,其中可以在 <code>v-model</code> 上使用数组来表示多个复选框,但它不在组件内部或作为道具,因此它不完全是同样,这感觉更复杂。我花了一天中的大部分时间试图让它正确,但没有那么多 vue 3 搜索结果,对于这个特定问题我根本没有找到任何结果。</p> <p>HomeView.vue:</p> <p> <pre class="brush:html;toolbar:false;">&lt;script set lang="ts"&gt; import { ref } from 'vue'; import AppList, { type Item } from '@/components/AppList.vue'; const fooItems = ref&lt;Item[]&gt;([ { id: 1, name: 'foo 1' }, { id: 2, name: 'foo 2' }, { id: 3, name: 'foo 3' }, { id: 4, name: 'foo 4' }, { id: 5, name: 'foo 5' }, ]); const fooSelected = ref&lt;number[]&gt;([]); &lt;/script&gt; &lt;template&gt; &lt;AppList :items="fooItems" v-model:selected="fooSelected"&gt;&lt;/AppList&gt; &lt;div&gt;fooselected: {{ fooSelected }}&lt;/div&gt; &lt;/template&gt;</pre> </p> <p>组件/Applist.vue:</p> <p> <pre class="brush:html;toolbar:false;">&lt;script setup lang="ts"&gt; import { computed, toRef } from 'vue'; export interface Item { id: number; name: string; } const props = defineProps&lt;{ items: Item[]; selected?: number[]; }&gt;(); const internalModel = toRef(props.selected ?? []); const emit = defineEmits&lt;{ 'update:selected': [selected: number[]]; }&gt;(); const selectedHandler = (e: Event) =&gt; { const target = &lt;HTMLInputElement&gt;e.target; if (props.selected &amp;&amp; target) { if (target.checked) { emit('update:selected', [...props.selected, Number(target.value)]); } else { emit( 'update:selected', props.selected.filter((i: number) =&gt; i !== Number(target.value)) ); } } }; const toggleAll = computed({ get: () =&gt; internalModel.value.length === props.items.length &amp;&amp; internalModel.value.every((s) =&gt; props.items.map((item) =&gt; item.id).includes(s)), set: (value) =&gt; { if (value) { emit( 'update:selected', props.items.map((i) =&gt; i.id) ); internalModel.value = props.items.map((i) =&gt; i.id); } else { emit('update:selected', []); internalModel.value = []; } }, }); &lt;/script&gt; &lt;template&gt; &lt;label&gt; &lt;input type="checkbox" v-model="toggleAll" /&gt; toggle all &lt;/label&gt; &lt;ul&gt; &lt;li v-for="item in items" :key="item.id"&gt; &lt;label&gt; &lt;input type="checkbox" :value="item.id" v-model="internalModel" @change="selectedHandler" /&gt; &lt;span&gt;id {{ item.name }}&lt;/span&gt; &lt;/label&gt; &lt;/li&gt; &lt;/ul&gt; internalModel: {{ internalModel }} &lt;/template&gt;</pre> </p>
P粉670838735
P粉670838735

全部回复(1)
P粉203792468

在我看来,这可以以某种更简单的方式完成。
fooItems 可能应该有一个初始状态“已检查”。
selectedHandler中,只需调用emit()即可。
toggleAll 最终将创建一个与 internalModel 配合使用的函数。
这是一个示例 Vue SFC Playground


HomeView.vue:

<script setup lang="ts">
import { ref } from 'vue';
import AppList, { type Item } from './AppList.vue';

const fooItems = ref<Item[]>([
  { id: 1, name: 'foo 1', checked: false },
  { id: 2, name: 'foo 2', checked: false },
  { id: 3, name: 'foo 3', checked: false },
  { id: 4, name: 'foo 4', checked: false },
  { id: 5, name: 'foo 5', checked: true },
]);
const fooSelected = ref<number[]>([]);
fooItems.value.map(item => item.checked && fooSelected.value.push(item.id))
</script>

<template>
  <AppList :items="fooItems" v-model:selected="fooSelected"></AppList>
  <div>fooselected: {{ fooSelected }}</div>
</template>

AppList.view:

<script setup lang="ts">
import { ref } from 'vue';

export interface Item {
  id: number;
  name: string;
  checked: boolean
}

const props = defineProps<{
  items: Item[];
  selected: number[]
}>();

const emit = defineEmits(['update:selected']);

const internalModel = ref(props.selected);
  
const selectedHandler = () => emit('update:selected', internalModel.value);

const toggleAll = ($event) => {
  internalModel.value = [];
  if ( ($event.target as HTMLInputElement).checked ) {
    props.items.map(item => internalModel.value.push(item.id));
  }
  emit('update:selected', internalModel.value);
};
</script>

<template>
  <label>
    <input type="checkbox" @change="toggleAll($event)" :checked="internalModel.length === items.length" />
    toggle all
  </label>
  <ul>
    <li v-for="item in items" :key="item.id">
      <label>
        <input type="checkbox" :value="item.id" v-model="internalModel" @change="selectedHandler(item.id)" :checked="item.checked"/>
        <span>{{ item.name }}</span>
      </label>
    </li>
  </ul>
  internalModel: {{ internalModel }}
</template>
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习
PHP中文网抖音号
发现有趣的

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号