Search code examples
vue.jsvuejs3naiveui

Why is the content empty when mounting contentShow.value[index]? (a vue project)


When I try to mount contentShow.value[index], it couldn't show normally and just empty.If I don't mount contentShow.value[index], other part is normal, but when I mount it, the whole page couldn't show. The browser caught error as follows: Uncaught (in promise) TypeError: Cannot read properties of undefined (reading '0')

Here is the code in this file,the wrong is just relative of the part I wrap it with **, but for the coherence of the code, I put code as much as possible.

<template>
        <n-tabs type="line" animated size="large" justify-content="start" :bar-width="100">
            <n-tab-pane name="list" tab="文章列表">
                **↓
                <div v-for="(blog,index) in blogListInfo" :key="index">
                    <n-card :title="blog.title" size="huge" style="min-width: 80%;">
                        {{ contentShow.value[index] }}
                        <template #footer>
                            <n-space align="center">
                                <div>发布时间:{{ blog.create_time }}</div>
                                <n-button>修改</n-button>
                                <n-button>删除</n-button>
                            </n-space>
                        </template>
                    </n-card>
                </div>
                **↑
            </n-tab-pane>
            <n-tab-pane name="add" tab="添加文章">
                <n-form>
                    <n-form-item label="标题">
                        <n-input v-model:value="addArticle.title" placeholder="请输入标题" size="large"></n-input>
                    </n-form-item>
                    <n-form-item label="分类">
                        <n-select v-model:value="addArticle.category_id" :options="categoryOptions" />
                    </n-form-item>
                    <n-form-item label="内容">
                        <RichTextEditor v-model="addArticle.content"></RichTextEditor>
                    </n-form-item>
                    <n-form-item label="">
                        <n-button @click="add">提交</n-button>
                    </n-form-item>
                </n-form>
            </n-tab-pane>
        </n-tabs>
</template>

<script setup>
import { AdminStore } from '../../stores/AdminStore';
import {ref,reactive,inject,onMounted} from 'vue'
import RichTextEditor from '../../components/RichTextEditor.vue';
const axios = inject("axios");
const message = inject("message");
const addArticle = reactive({
    category_id:0,
    title:"",
    content:"",
});
const categoryOptions = ref([]);
**↓
const blogListInfo = ref([]);
onMounted(()=>{
    loadBlogs();
    loadCategories();
});
const contentShow = ref([]);
const loadBlogs = async ()=>{
    let res = await axios.get("/blog/search");
    blogListInfo.value = res.data.data.rows;
    for(let index = 0 ; index < blogListInfo.value.length ; index++){
        if(blogListInfo.value[index].content.length>10){
            contentShow.value[index] = blogListInfo.value[index].content.substring(0,10)+"...";
        }else{
            contentShow.value[index] = blogListInfo.value[index].content;
        }
        console.log(contentShow.value[index]);
    }
}
**↑
const loadCategories = async ()=>{
    let res= await axios.get("/category/list");
    categoryOptions.value = res.data.rows.map((item)=>{
        return {
            label:item.name,
            value:item.id
        };
    });
}
const add = async ()=>{
    let res = await axios.post("/blog/_token/add",addArticle);
    if(res.data.code==200){
        message.info(res.data.msg);
        addArticle.title="";
        addArticle.content="";
    }else{
        message.error(res.data.msg);
    }
}
</script>

Solution

  • Refs are unwrapped in templates, it should be:

    {{ contentShow[index] }}
    

    Also, this line doesn't trigger an immediate update because state updates are currently batched in Vue:

    blogListInfo.value = res.data.data.rows
    

    But under some conditions it could results in accessing contentShow.value[index] when contentShow.value is an empty array that contains no index element. A better practice to avoid potential problems is to process an iterated array to contain ready to use values:

    <div v-for="(blog,index) in processedBlogEntries" :key="index">
        <n-card :title="blog.title">
            {{ blog.truncatedContent }}
            ...