首頁  >  問答  >  主體

vue 3 組合 api 元件,帶有複選框數組並切換所有

<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;"><script set lang="ts"> import { ref } 從 'vue'; import AppList, { type Item } from '@/components/AppList.vue'; const fooItems = ref<Item[]>([ { 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<number[]>([]); </script> <template> <AppList :items="fooItems" v-model:selected="fooSelected"></AppList> <div>fooselected: {{ fooSelected }}</div> </範本></pre> </p> <p>組件/Applist.vue:</p> <p>
<腳本設定lang="ts">
從“vue”導入{計算,toRef};

導出介面項{
    身分證字號;
    名稱:字串;
}

const 道具 = DefineProps<{
    項目:項目[];
    已選擇?:編號[];
}>();

const internalModel = toRef(props.selected ?? []);

const 發出 = DefineEmits<{
    '更新:選定':[選定:數字[]];
}>();

const selectedHandler = (e: 事件) => {
    const target = e.target;
    if (props.selected && target) {
        if (目標.檢查) {
            發出('更新:選定',[...props.selected,Number(目標.值)]);
        } 別的 {
            發射(
                '更新:已選擇',
                props.selected.filter((i: number) => i !== Number(target.value))
            );
        }
    }
};

consttoggleAll = 計算({
    得到:() => InternalModel.value.length === props.items.length && InternalModel.value.every((s) => props.items.map((item) => item.id).includes(s)),
    設定:(值)=> {
        如果(值){
            發射(
                '更新:已選擇',
                props.items.map((i) => i.id)
            );
            InternalModel.value = props.items.map((i) => i.id);
        } 別的 {
            發出('更新:所選',[]);
            內部模型.值= [];
        }
    },
});
</腳本>

<模板>
    <標籤>
        >
        全部切換
    </標籤>
    
  • <標籤> id {{ item.name }}; </標籤> </li> </ul> 內部模型:{{內部模型}} </範本></pre> </p>
P粉670838735P粉670838735415 天前595

全部回覆(1)我來回復

  • P粉203792468

    P粉2037924682023-08-31 15:28:23

    在我看來,這可以以某種更簡單的方式完成。
    fooItems 可能應該有一個初始狀態「已檢查」。
    selectedHandler中,只需呼叫emit()即可。
    toggleAll 最終將建立一個與 internalModel 配合使用的函數。
    這是一個範例 Vue SFC Playground。 < /p>


    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>

    回覆
    0
  • 取消回覆