Vue组件中v-for无输出问题:页面仅显示<!---->
问题:Vue中v-for无法渲染骨架文本,仅显示
<!----> 你的代码里skeleton-body组件的v-for没有生成预期的5行骨架文本,浏览器只输出注释节点,核心原因和修复方案如下:
问题根源
- 数据类型不匹配:父组件中
lines="5"是字符串类型,Vue的v-for="n in lines"会把字符串当作字符序列遍历(仅循环1次),而非数字对应的5次循环。 - 无效的类绑定:
skeleton-body里的:class="lines"将数字/字符串直接作为类名,无实际意义,还可能干扰渲染逻辑。 - Props修改违规:
translation组件的计算属性中直接修改this.size,违反Vue props只读规则,会触发警告并可能导致逻辑异常。 - Vue版本过旧:2.3.2版本存在一些已修复的渲染bug,可能影响组件正常工作。
修复方案
1. 修改父组件传入的lines类型
将HTML中的lines="5"改为:lines="5",通过v-bind传入数字类型:
<div id="app"> <translation :phrase="language.test" type="body" :lines="5"></translation> </div>
2. 修正skeleton-body组件代码
移除无效的类绑定,确保v-for基于数字循环,并添加唯一key(Vue 2要求v-for必须有key):
Vue.component('skeleton-body', { props: ['lines'], template: `<div> <div v-for="n in lines" :key="n"> <div class="Polaris-SkeletonBodyText"></div> </div> </div>` });
3. 修复translation组件的props修改问题
不要直接修改props的size,改用计算属性处理后的值传递:
Vue.component('translation', { props: ['phrase', 'type', 'lines', 'size'], template: `<template v-if="!phrase"> <component :is="getSkeletonComponent" :lines="lines" :size="formattedSize"></component> </template> <template v-else> <span>{{ phrase }}</span> </template>`, computed: { formattedSize() { if (this.type !== 'display') return this.size; switch (this.size) { case 'small': return 'Small'; case 'large': return 'Large'; case 'extraLarge': return 'ExtraLarge'; default: return 'Medium'; } }, getSkeletonComponent() { if (this.type === 'body') { return 'skeleton-body'; } else if (this.type === 'display') { return 'skeleton-display'; } } } });
4. 升级Vue版本(可选但推荐)
将Vue版本从2.3.2升级到稳定的2.6.14,避免旧版本的潜在bug:
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.14/vue.min.js"></script>
完整修改后代码
JS部分
Vue.component('skeleton-body', { props: ['lines'], template: `<div> <div v-for="n in lines" :key="n"> <div class="Polaris-SkeletonBodyText"></div> </div> </div>` }); Vue.component('skeleton-display', { props: ['size'], template: `<div :class="['Polaris-SkeletonDisplayText__DisplayText', 'Polaris-SkeletonDisplayText--size--' + size]"></div>` }); Vue.component('translation', { props: ['phrase', 'type', 'lines', 'size'], template: `<template v-if="!phrase"> <component :is="getSkeletonComponent" :lines="lines" :size="formattedSize"></component> </template> <template v-else> <span>{{ phrase }}</span> </template>`, computed: { formattedSize() { if (this.type !== 'display') return this.size; switch (this.size) { case 'small': return 'Small'; case 'large': return 'Large'; case 'extraLarge': return 'ExtraLarge'; default: return 'Medium'; } }, getSkeletonComponent() { if (this.type === 'body') { return 'skeleton-body'; } else if (this.type === 'display') { return 'skeleton-display'; } } } }); new Vue({ el: '#app', data: { language: {} }, methods: {} })
HTML部分
<head> <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.14/vue.min.js"></script> <link type="text/css" rel="stylesheet" href="https://unpkg.com/@shopify/polaris@10.30.0/build/esm/styles.css"> </head> <body> <div id="app"> <translation :phrase="language.test" type="body" :lines="5"></translation> </div> </body>
内容的提问来源于stack exchange,提问作者Asa Carter
相关产品推荐
相关产品推荐

