Vue.js 3模板无法渲染后端获取的Proxy数据问题求助
问题描述
已从后端成功获取数据,控制台显示为包含3个对象的Proxy数组,但数据无法在Vue.js 3模板中显示。
控制台输出
Proxy { <target>: (3) […], <handler>: {…} } <target>: Array(3) [ {…}, {…}, {…} ] 0: Object { id: 3, user_id_as_sender: 5, user_id_as_receiver: 4, … } 1: Object { id: 2, user_id_as_sender: 5, user_id_as_receiver: 4, … } 2: Object { id: 1, user_id_as_sender: 5, user_id_as_receiver: 4, … } length: 3 <prototype>: Array [] <handler>: Object { _isReadonly: false, _shallow: false }
代码片段
HTML模板
<div class="card-body"> <div class="table-responsive" v-if="pinboards"> <table class="table table-head-custom table-vertical-center mt-5 mb-5"> <thead> <tr> <th>{{trans('custom.name')}}</th> <th>{{trans('custom.time')}} </th> <th>{{trans('custom.date')}}</th> <th v-if="userId == 'HumanResource' || userId == 'dispatcher'" class="text-center">{{trans('custom.read')}}</th> <th class="text-right">{{trans('custom.action')}}</th> </tr> </thead> <tbody> <tr v-for="(document, index) in pinboards" :class="((document.user_id_as_receiver).split(',')).includes(String(current_user_id)) && !((document.is_read_by_receiver).split(',')).includes(String(current_user_id)) ? 'active' : ''" :key="index"> <td > <a href="" @click.prevent="readMessage(index, document.id)"> <template v-if="document.is_grouped_msg">{{translateDocumentName(document.subject)}}</template> <template v-else>{{document.user_name}} {{document.user_surname}}</template> </a> </td> <td >{{document.updated_at | formatHours}}</td> <td >{{document.updated_at | formatDate}}</td> <td v-if="userId == 'HumanResource' || userId == 'dispatcher'" class="text-center"> <template v-if="!document.is_grouped_msg"> <i v-if="document.is_read_by_receiver != 0" class="la la-check-double text-success"></i> <i v-else class="la la-check-double"></i> </template> <template v-else> {{(((document.is_read_by_receiver).split(',')).length)-1}} / {{((document.user_id_as_receiver).split(',')).length}} </template> </td> <td class="text-right"> <a @click.prevent="readMessage(index, document.id)" href="#" class="btn btn-sm btn-primary btn-clean delete" title="read"> <i class="la la-eye"></i> {{trans('custom.read')}} </a> <a @click.prevent="removeMessage(index, document.id, 'single')" href="#" class="btn btn-sm btn-danger btn-clean delete" title="Delete"> <i class="la la-trash"></i> {{trans('custom.delete')}} </a> <a v-if="current_user_id == document.user_id_as_sender" @click.prevent="removeMessage(index, document.id, 'all')" href="#" class="btn btn-sm btn-danger btn-clean delete" title="Delete from all"> <i class="la la-trash"></i> {{trans('custom.deleteFromAll')}} </a> </td> </tr> </tbody> </table> </div> <p class="text-center" v-else>{{trans('custom.noPinboard')}}</p> </div>
JavaScript代码
getPinboards() { let that = this; const url = new URLSearchParams(window.location.search); const column_id = url.get("column_id"); const user_id = url.get("u_id"); if (column_id && user_id) { axios.get(`/get-pinboard/${column_id}/${user_id}`) .then(function(response){ if(response.data.success){ that.pinboards = response.data.pinboards; }else{ toastr.error("Error getting pinboards!"); } }); } else { axios.get('/get-pinboard') .then(function(response){ if(response.data.success){ that.pinboards = response.data.pinboards; console.log(that.pinboards); }else{ toastr.error("Error getting pinboards!"); } }); } },
排查原因及解决方法
Vue 3已移除过滤器语法:模板中使用的
formatHours和formatDate是Vue 2的过滤器写法,Vue 3不再支持该语法,会导致模板渲染报错,进而无法显示内容。解决方法是将过滤器替换为组件方法或计算属性,比如定义formatHours(date)方法,模板中改为{{ formatHours(document.updated_at) }}。pinboards初始值未正确声明:如果pinboards在组件data中未初始化为空数组[],而是默认的undefined,赋值后虽会转为响应式Proxy,但可能导致v-if="pinboards"初始状态为false,赋值后无法触发模板重新渲染。解决方法是在data()中明确声明pinboards: []。复杂表达式的容错问题:
v-for中的:class表达式直接对document.user_id_as_receiver调用split(','),若该字段为数字或null,会抛出错误导致渲染失败。解决方法是添加容错处理,改为(document.user_id_as_receiver || '').split(','),确保调用split的是字符串类型。响应式变量声明问题:若
pinboards未通过Vue响应式API声明(如选项式API的data,或组合式API的ref/reactive),赋值后无法触发模板更新。需确认pinboards是组件data中定义的响应式变量。
内容的提问来源于stack exchange,提问作者Mohammad Murad

