Vue3 Composition API数组初始化后无法渲染问题求助
问题原因与解决方案
问题根源
- 数组误用为对象:你将
sessionList声明为数组[],但通过字符串日期作为键赋值(如sessionList["2024-05-20"] = tab),这只是给数组对象附加了属性,而非添加数组元素。数组的length仅统计数字索引对应的元素,因此长度始终为0,v-for遍历数组时无法读取这些属性。 - 缺少响应式处理:当前
sessionList是普通变量,未用Vue的响应式API(ref/reactive)包裹,后续数据变更无法触发视图更新(即使初始化赋值,也建议规范处理)。 - Moment对象引用问题:原代码中
nextDate = date.add(1,'days')会直接修改原date对象(Moment是可变对象),导致所有日期最终指向同一值,需用clone()避免此问题。
方案一:改为响应式对象(符合你期望的日期键值对结构)
将sessionList声明为reactive对象,直接用日期作为键存储时段数组:
修改脚本代码
<script setup> import { ref, reactive } from "vue" import { mdiContentSavePlusOutline } from "@mdi/js" import moment from "moment" moment.locale('fr'); const terrain = ref({ id: 1, name: "terrain 1", capacity: 11, duration: 1, price: 8, external: true, complexe: "Stade 1", formatted_created_at: "10/10/2022", }) const sessionList = reactive({}) let date = moment() let datesList = [] let nextDate = date.clone() // 克隆Moment对象,避免修改原日期 for (let index = 0; index < 15; index++) { const currentDateStr = nextDate.format('YYYY-MM-DD') datesList.push(currentDateStr) let tab = [] for (let i = 0; i < 4; i++) { // 每次添加小时时克隆对象,避免污染原日期 let debut = nextDate.clone().add(i+1,'hours').format('HH:mm:ss') let fin = nextDate.clone().add(i+2,'hours').format('HH:mm:ss') tab.push({ debut: debut, fin: fin, reserved: i % 2 == 0 }) } sessionList[currentDateStr] = tab nextDate.add(1,'days') } </script>
修改模板遍历逻辑
遍历对象时,v-for语法为(value, key) in 对象:
<div v-for="(item, dateKey) in sessionList" :key="dateKey" class="rounded-lg ml-2 shadow-lg bg-white max-w-sm"> <h5 class="text-gray-900 text-center font-medium m-2">{{ dateKey }}</h5> <a href="#!"> <img class="rounded-t-lg m-auto w-16 h-16" src="/img/green-ball.png" alt=""/> </a> <div class="p-2"> <p class="text-gray-700 text-base mb-4"> Some quick example text to {{ dateKey }} </p> <button type="button" class=" inline-block px-6 py-2.5 bg-blue-600 text-white font-medium text-xs leading-tight uppercase rounded shadow-md hover:bg-blue-700 hover:shadow-lg focus:bg-blue-700 focus:shadow-lg focus:outline-none focus:ring-0 active:bg-blue-800 active:shadow-lg transition duration-150 ease-in-out"> Réserver </button> </div> </div>
方案二:改为响应式数组(包含日期与时段的对象结构)
若需保持数组形式,将每个日期和对应时段包装为对象存入数组:
修改脚本代码
<script setup> import { ref } from "vue" import { mdiContentSavePlusOutline } from "@mdi/js" import moment from "moment" moment.locale('fr'); const terrain = ref({ id: 1, name: "terrain 1", capacity: 11, duration: 1, price: 8, external: true, complexe: "Stade 1", formatted_created_at: "10/10/2022", }) const sessionList = ref([]) let date = moment() let nextDate = date.clone() for (let index = 0; index < 15; index++) { const currentDateStr = nextDate.format('YYYY-MM-DD') let tab = [] for (let i = 0; i < 4; i++) { let debut = nextDate.clone().add(i+1,'hours').format('HH:mm:ss') let fin = nextDate.clone().add(i+2,'hours').format('HH:mm:ss') tab.push({ debut: debut, fin: fin, reserved: i % 2 == 0 }) } sessionList.value.push({ date: currentDateStr, sessions: tab }) nextDate.add(1,'days') } </script>
修改模板遍历逻辑
<div v-for="(item, index) in sessionList" :key="index" class="rounded-lg ml-2 shadow-lg bg-white max-w-sm"> <h5 class="text-gray-900 text-center font-medium m-2">{{ item.date }}</h5> <a href="#!"> <img class="rounded-t-lg m-auto w-16 h-16" src="/img/green-ball.png" alt=""/> </a> <div class="p-2"> <p class="text-gray-700 text-base mb-4"> Some quick example text to {{ item.date }} </p> <button type="button" class=" inline-block px-6 py-2.5 bg-blue-600 text-white font-medium text-xs leading-tight uppercase rounded shadow-md hover:bg-blue-700 hover:shadow-lg focus:bg-blue-700 focus:shadow-lg focus:outline-none focus:ring-0 active:bg-blue-800 active:shadow-lg transition duration-150 ease-in-out"> Réserver </button> </div> </div>
内容的提问来源于stack exchange,提问作者MAHA OUEGHLANI
相关产品推荐
相关产品推荐

