主题
订单支付与问诊室通知(四)
本页对应 订单支付与问诊室通知,共 6 段视频,约 49 分钟。
学习目标
- 能够将接口返回的嵌套
items数据展开并合并到消息列表中,使用unshift保持聊天消息倒序。 - 能够拆分患者信息组件,并在问诊室页面按消息类型
21条件渲染,通过props将patientInfo传入子组件。 - 能够渲染患者姓名、性别、年龄、病情描述等字段,并将患病时长、就诊状态等数值通过数组映射为对应文字。
- 能够根据
pictures数量条件显示“暂无图片”或“查看图片”,点击后提取图片 URL 数组并调用uni.previewImage预览大图。 - 能够说明长轮询的实现思路与适用场景,区分其与 HTTP、WebSocket 在聊天场景中的差异。
- 能够封装通知消息组件,使用插槽展示消息内容,接收
type参数并按31/32/33及>=31条件控制温馨提示和列表过滤。
知识点
目标与数据形状:先把深层列表拍平
为什么需要:问诊室消息返回的数据层级较深,真正要渲染的消息在 data[].items 里;如果直接把整个响应塞给列表,模板取值会多一层,后续判断类型和传参都别扭。
怎么想:先打开网络面板看请求,找到 messageList 相关响应,展开后确认真正数据在 items;转写里的“艾特姆斯”就是 items。
怎么做:遍历 data,把每个 items 取出,用 unshift 展开放入新数组。转写里的“un shift”就是 unshift,“微杠报”是 v-for,“微杠意”是 v-if。
js
// 转写思路:真正数据在 data[].items
const list = []
res.data.forEach(item => {
list.unshift(...item.items)
})
this.messageList = list易错点:不要直接要 data,而要 data 下的 items;字段名和层级要按接口核对,unshift 会改变顺序,聊天列表要确认倒序是否符合预期。
患者信息:用条件渲染并抽成组件
为什么需要:患者信息类型是 21,页面里如果直接堆模板,代码会乱,所以抽成 patient-info 组件。
怎么想:先 v-for 遍历 messageList,再判断 messageType === 21 才显示;组件通过 props 接收 info。转写中先出现“显示三次”的调试现象,就是因为只遍历没加条件。
怎么做:页面引入组件,用 template 包住条件;组件内声明 info 对象,默认空对象。
html
<template v-for="message in messageList" :key="message.id">
<template v-if="message.messageType === 21">
<patient-info :info="message.patientInfo" />
</template>
</template>js
props: {
info: { type: Object, default: () => ({}) }
}易错点:组件不是全局的,必须导入;v-for 不能替代 v-if;props 默认值用函数返回对象,避免引用共享。
患者基本信息与病情描述渲染
为什么需要:患者信息里还有 patientInfo 层级,姓名、性别、年龄等字段要逐项取值。
怎么想:先渲染简单字段,复杂枚举后处理;转写里“李富贵、性别、年龄”就是按接口字段插值。
怎么做:在组件模板中用 info.patientInfo.name、genderValue、age 等字段;病情描述用对应字段插值。
html
<view>{{ info.patientInfo.name }}</view>
<view>{{ info.patientInfo.genderValue }}</view>
<view>{{ info.patientInfo.age }}</view>易错点:字段名以接口为准;转写里“音否”是 info,“普拉普斯”是 props;不要漏掉 patientInfo 这一层。
数字转文字:用数组下标做映射
为什么需要:患病时长、是否就诊返回的是数值,页面要显示“一周内”“未去医院就诊”等文字。
怎么想:数值当数组下标,定义文字数组,模板里用 数组[数值] 取文案。
怎么做:在组件 data 中按接口枚举定义文案数组,模板中取值。
html
<view>{{ durationText[info.patientInfo.duration] }}</view>
<view>{{ visitText[info.patientInfo.flags] }}</view>易错点:数组顺序必须和接口枚举一致;字段名按实际接口核对;不要固定写死 0 或 1,要拿返回数值。
查看大图:previewImage 需要纯 URL 数组
为什么需要:有图片才显示“查看图片”,无图片显示“暂无图片”;点击后要能预览。
怎么想:先判断 pictures.length > 0,再绑定点击;uni.previewImage 的 urls 要纯图片地址数组,而接口里是对象数组,所以用 map 取 url。
怎么做:
html
<view v-if="info.pictures.length > 0" @click="onPreview(info.pictures)">
查看图片
</view>
<view v-else>暂无图片</view>js
onPreview(pictures) {
uni.previewImage({
urls: pictures.map(item => item.url)
})
}易错点:previewImage 不是直接传对象数组;map 会返回新数组;转写里的“迈普”是 map,“优阿拉艾斯”是 urls。
通知消息:31/32/33 合用一个组件
为什么需要:普通消息、温馨提示、已取消状态样式接近,可以合为一个 notify-info,减少重复。
怎么想:用 type 区分,默认 31;只有 32 才显示“温馨提示”;文字内容用插槽。
怎么做:父级用 messageType >= 31 过滤通知消息,传 type,插槽放 content。
html
<template v-for="message in messageList" :key="message.id">
<template v-if="message.messageType >= 31">
<notify-info :type="message.messageType">
{{ message.content }}
</notify-info>
</template>
</template>html
<view class="notify">
<text v-if="type === 32">温馨提示:</text>
<slot />
</view>js
props: {
type: { type: Number, default: 31 }
}易错点:不要漏掉 21 的过滤;>= 31 可覆盖 31、32、33;插槽内容由父级传入,组件只负责样式和类型判断。
长轮询:作为了解
为什么需要:聊天通常用 WebSocket;若浏览器不支持,才考虑轮询。
怎么想:HTTP 一次请求一次响应,聊天要持续获取消息,就用定时器反复发请求。
怎么做:转写中仅作概念说明,setInterval 定时发 HTTP 请求即可。
js
setInterval(() => {
// 定时发送 HTTP 请求
}, 500)易错点:长轮询不是首选,性能不如 WebSocket;转写里的“常轮循/长轮巡”应纠正为“长轮询”。
先处理接口数据:把层级压平
为什么需要:问诊室消息列表接口返回的数据并不是直接一个数组,真正要用的消息在 data.items 里。如果直接把整个响应存到 messageList,后面模板取数据就会多一层 items,层级越深越容易写错。
怎么想:先确认“我真正要渲染的是哪一段数据”,只把 items 取出来,再放进页面使用的列表里。
怎么做:遍历返回的 data,把每个 items 取出来,用 unshift 放进 messageList。聊天消息通常新消息在前,所以这里用 unshift 而不是 push。
易错点:不要直接把整个响应塞进列表;unshift 和 push 的顺序相反;变量名 items 不要写成 iteoms 这类同音错字。
js
// 思路示例
data.forEach(item => {
messageList.unshift(...item.items)
})用 v-for 和 v-if 只显示患者信息
为什么需要:列表里可能有多条消息,而当前只处理类型为 21 的患者信息。如果直接把组件写进页面,它会被渲染多次。
怎么想:先遍历消息列表,再判断消息类型,只有 messageType === 21 时才渲染患者信息组件。
怎么做:外层用 template 做 v-for,内层用 v-if 控制。调试时先看列表长度,再看条件是否命中。转写稿里一开始出现“显示三次”的现象,就是因为只写了遍历,没有加类型判断。
易错点:v-if 条件不要写成赋值;key 建议用消息 id;条件数字 21 要和接口字段一致。
html
<template v-for="item in messageList" :key="item.id">
<patient-info
v-if="item.messageType === 21"
:info="item"
/>
</template>把患者信息抽成独立组件
为什么需要:一个页面里同时写患者信息、通知消息等模板,代码会越来越乱。患者信息适合单独放到 components/patient-info.vue。
怎么想:先建组件文件,再把模板和样式搬进去;组件不是全局注册,使用时必须导入。
怎么做:在页面中 import PatientInfo from './components/patient-info.vue',注册后在模板里使用。父组件把消息对象传给子组件,子组件用 props 接收。转写稿中 info 默认给空对象,是为了避免初始渲染时报错。
易错点:组件名和导入名要一致;props 名字要和父组件传参一致;默认值写空对象,不要直接写 null 后马上取属性。
js
props: {
info: {
type: Object,
default: () => ({})
}
}渲染字段:注意数据层级
为什么需要:患者信息里包含姓名、性别、年龄、病情描述、图片等字段,字段不一定都在第一层。
怎么想:先在控制台展开 props.info,确认 patientInfo、name、genderValue、age 等字段的实际位置,再写模板。转写稿里强调“患者信息下面又多了一个层级”,所以取姓名时要注意 props.info.patientInfo.name 这种路径,具体以你传入的是消息对象还是患者对象为准。
怎么做:模板里用插值表达式取字段,长表达式可以换行。
易错点:不要凭感觉写字段;性别、年龄等字段名要看接口;传参层级不同,模板路径也要跟着变。
html
<view>{{ info.patientInfo.name }}</view>
<view>{{ info.patientInfo.genderValue }}</view>
<view>{{ info.patientInfo.age }}</view>数字状态转文字与查看图片
为什么需要:患病时长、是否就诊这类字段接口给的是数字,但页面要显示“一周内”“一个月内”“就诊过”等文字;图片字段给的是对象数组,不能直接交给预览 API。
怎么想:数字转文字可以定义一个文字数组,用接口数值当下标取;图片先判断有没有,再决定显示“暂无图片”还是“点击查看图片”。
怎么做:模板中用 v-if="pictures.length > 0" 判断;点击时调用 uni.previewImage,但它的 urls 需要纯图片地址数组,所以用 map 把对象数组转成 url 数组。
易错点:previewImage 不能直接传对象数组;map 要返回 item.url;没有图片时不要绑定点击事件或不要显示“查看图片”。
html
<view v-if="info.patientInfo.pictures.length > 0" @click="onPreview">
点击查看图片
</view>
<view v-else>暂无图片</view>js
onPreview() {
const urls = this.info.patientInfo.pictures.map(item => item.url)
uni.previewImage({ urls })
}调试时可以先 console.log(urls),确认输出的是 ["xxx.jpg", "xxx.png"] 这样的纯地址数组,再调用预览 API。这样患者信息的数据展开、条件渲染、组件传参、字段渲染和图片预览就串起来了。
本节要解决什么
这一节围绕“问诊室患者信息”做两件事:先把接口返回的深层数据展开成更好用的 messageList,再把类型为 21 的患者信息交给独立组件渲染。随后补充了图片预览、长轮询概念,以及通知类消息组件的复用。学习时不要只盯模板,要先理解数据层级和组件边界。
本节笔记没有独立配图,以下按转写稿整理关键代码;字段名以实际接口返回为准,不能凭记忆硬写。
先展开数据:别让层级拖累模板
为什么需要:接口返回的数据层级较深,真正要用的消息在 date 下的 items 里。如果直接把整段数据塞进列表,模板里就要层层点下去,容易写错,也不方便复用。
怎么想:先遍历 date,把每个 items 拿出来,再展开到 messageList。转写稿里强调用 unshift,因为聊天消息顺序需要倒过来。
怎么做:按转写稿可整理为:
js
// 示意:把 date 中每个 items 展开到 messageList
date.forEach(item => {
messageList.unshift(...item.items)
})易错点:items 和 item 别混;unshift 会改变原数组;展开运算符 ... 不能漏。处理后调试面板里 messageList 应直接看到消息本身,而不是还包一层 items。
患者信息组件:先过滤 21,再传 props
为什么需要:页面里有很多类型消息,患者信息只对应 21。如果每个消息都渲染患者组件,就会出现多次重复。
怎么想:用 v-for 遍历 messageList,再用 v-if 判断 messageType === 21。转写稿中用 template 包住循环,因为它解析后不产生额外标签。
怎么做:
html
<template v-for="msg in messageList" :key="msg.id">
<patient-info
v-if="msg.messageType === 21"
:info="msg.patientInfo"
/>
</template>组件内接收:
js
props: {
info: {
type: Object,
default: () => ({})
}
}易错点:messageType 不要写成 message.type;props 默认对象要用函数返回;子组件使用前必须 import 并注册。
渲染患者字段:简单字段直接取,数字字段做映射
为什么需要:姓名、性别、年龄可直接渲染,但“一周内”“未去医院就诊”这类内容接口给的是数字,不能直接把数字显示给用户。
怎么想:简单字段从 props.info 往下取;数字字段定义文字数组,用数字当下标映射。
怎么做:
html
<text>{{ info.name }}</text>
<text>{{ info.genderValue }}</text>
<text>{{ info.age }}岁</text>数字转文字示意:
js
// 以实际字段名为准
const timeText = ['一周内', '一个月内', '三个月内']模板中按转写稿思路写:
html
<text>{{ timeText[info.illnessTime] }}</text>易错点:info.patientInfo.name 这类层级要看清;数组下标从 0 开始;不要固定写死 0 或 1,要拿真实数据。
图片有无判断与 previewImage 预览
为什么需要:没有图片时点“查看图片”没有意义,所以要先判断 pictures 是否为空。
怎么想:pictures.length > 0 显示“点击查看图片”,否则显示“暂无图片”;点击时调用 uni.previewImage,但它要求的是纯图片地址数组。
怎么做:
html
<text v-if="info.pictures && info.pictures.length > 0"
@click="onPreview(info.pictures)">
点击查看图片
</text>
<text v-else>暂无图片</text>js
onPreview(pictures) {
const urls = pictures.map(item => item.url)
uni.previewImage({ urls })
}转写稿还演示了可继续简化为:
js
const urls = pictures.map(({ url }) => url)易错点:previewImage 的 urls 是纯路径数组,不是对象数组;map 要 return,箭头函数简写时别加大括号;字段是 url,不是 uil。
长轮询:作为了解,别和 WebSocket 混用
为什么需要:聊天需要服务器持续给结果,普通 HTTP 一次请求一次响应,不适合实时聊天。
怎么想:优先用 WebSocket;浏览器不支持时,才用定时器不断发请求,这就是长轮询。
怎么做:转写稿用 setInterval 每隔一段时间发请求来保持联系。
易错点:长轮询不是新协议;它性能不如 WebSocket;面试可能问“没有 WebSocket 怎么做聊天”,要能答出定时轮询。
通知消息组件:31/32/33 复用,插槽放内容
为什么需要:普通消息、温馨提示、已取消外观相近,没必要写三个组件。
怎么想:内容用插槽传入;是否显示“温馨提示”由 type 决定,32 才显示;通知类消息类型都 >= 31,可用一个条件过滤。
怎么做:
html
<notify-info
v-if="msg.messageType >= 31"
:type="msg.messageType"
>
{{ msg.content }}
</notify-info>组件内:
html
<view>
<text v-if="props.type === 32">温馨提示</text>
<slot></slot>
</view>js
props: {
type: {
type: Number,
default: 31
}
}易错点:>= 31 能覆盖 31、32、33;插槽内容别忘了在使用组件时写;type 默认值写 31;判断条件建议放模板前部,便于阅读。
代码示例
示例 1:问诊室页面——数据扁平化 + 按 messageType 条件渲染
vue
<!-- pages/room/index.vue -->
<template>
<view class="room">
<!-- v-for 用 block 包一层,v-if 不写在 v-for 的同一个标签上 -->
<block v-for="msg in messageList" :key="msg.id">
<!-- 患者信息:messageType === 21 -->
<patient-info
v-if="msg.messageType === 21"
:info="msg.patientInfo"
/>
<!-- 通知消息:31 普通消息 / 32 温馨提示 / 33 已取消,共用一个组件 -->
<notify-info
v-if="msg.messageType >= 31"
:type="msg.messageType"
>
{{ msg.content }}
</notify-info>
</block>
</view>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import patientInfo from './components/patient-info.vue'
import notifyInfo from './components/notify-info.vue'
const messageList = ref([])
const getMessageList = async () => {
const res = await uni.request({ url: 'https://your-api/message/list' })
// 返回结构形如:[{ items: [...] }, { items: [...] }]
const list = []
res.data.forEach((item) => {
// 把每层的 items 展开,放进同一个数组
list.unshift(...item.items)
})
messageList.value = list
}
onMounted(() => {
getMessageList()
})
</script>
<style>
.room {
padding: 24rpx;
background: #f5f5f5;
}
</style>要点:
- 原来直接把整个
res.data存进列表,层级深(data[i].items[j]);这里遍历res.data,用unshift(...item.items)把真正的消息摊平成一维数组,渲染时只写msg.xxx。 - 用
unshift而不是push:聊天消息接口返回的顺序是倒的,靠前插入才能保证页面顺序正确。 v-for与v-if不写在同一个标签上,用<block>包一层,避免两个指令优先级带来的判断错乱。- 31 / 32 / 33 有共同规律,用
>= 31一个条件代替三个||,患者信息(21)就不会被误渲染出来。 - 患者信息组件用
:info="msg.patientInfo"把子对象传进去,父组件只传数据,不传结构。
示例 2:患者信息组件 patient-info.vue(含数字转文字、预览大图)
vue
<!-- pages/room/components/patient-info.vue -->
<template>
<view class="patient-info">
<view class="item">
<text class="label">病情描述</text>
<text class="value">{{ props.info.illnessDesc }}</text>
</view>
<view class="item">
<text class="label">患者信息</text>
<text class="value">
{{ props.info.patientInfo.name }}
{{ props.info.patientInfo.genderValue }}
{{ props.info.patientInfo.age }}岁
</text>
</view>
<!-- 接口给的是数字,用数组下标映射成文字 -->
<view class="item">
<text class="label">患病时长</text>
<text class="value">{{ durationText[props.info.illnessTime] }}</text>
</view>
<view class="item">
<text class="label">是否就诊过</text>
<text class="value">{{ visitText[props.info.visited] }}</text>
</view>
<view class="item">
<text class="label">病情图片</text>
<text
v-if="props.info.pictures.length > 0"
class="value link"
@click="onPreview(props.info.pictures)"
>点击查看图片</text>
<text v-else class="value">暂无图片</text>
</view>
</view>
</template>
<script setup>
const props = defineProps({
info: {
type: Object,
// 对象类型的默认值必须写成函数
default: () => ({})
}
})
// 数字 -> 文字,下标就是接口返回的数值
const durationText = ['一周内', '一个月内', '半年内', '一年以上']
const visitText = ['未去医院就诊', '已去医院就诊']
const onPreview = (pictures) => {
// pictures 是对象数组,previewImage 只认纯 url 字符串数组
const urls = pictures.map(({ url }) => url)
uni.previewImage({
urls,
current: urls[0]
})
}
</script>
<style>
.patient-info {
background: #fff;
border-radius: 12rpx;
padding: 24rpx;
margin-bottom: 20rpx;
}
.item {
display: flex;
margin-bottom: 16rpx;
}
.label {
width: 160rpx;
color: #999;
}
.value {
flex: 1;
color: #333;
}
.link {
color: #1aad19;
}
</style>要点:
props里用default: () => ({}),写成default: {}会让所有实例共享同一个对象,是常见坑。patientInfo是info下的二级对象,.name / .genderValue / .age层级不要写漏;患病时长、是否就诊过与patientInfo平级,直接在info下取。- 数字转文字用“数组下标取值”:
durationText[props.info.illnessTime],不要写死成durationText[0]。 - 预览图片前必须
map出纯url数组:pictures.map(({ url }) => url),直接把对象数组交给uni.previewImage是无效的;map返回新数组,不会改动原数据。 - 图片判断用
props.info.pictures.length > 0,没图时走v-else显示“暂无图片”,否则会出现能点但点不出图的情况。
示例 3:通知消息组件 notify-info.vue(插槽 + 类型判断)
vue
<!-- pages/room/components/notify-info.vue -->
<template>
<view class="notify-info">
<view class="msg-box">
<!-- 只有 32(温馨提示)才显示这个前缀 -->
<text v-if="props.type === 32" class="tips">温馨提示:</text>
<!-- 具体文字由父组件通过插槽传入 -->
<slot></slot>
</view>
</view>
</template>
<script setup>
const props = defineProps({
type: {
type: Number,
default: 31 // 默认按普通消息处理
}
})
</script>
<style>
.notify-info {
text-align: center;
margin-bottom: 20rpx;
}
.msg-box {
display: inline-block;
background: #fff;
color: #333;
padding: 12rpx 24rpx;
border-radius: 8rpx;
font-size: 26rpx;
}
.tips {
color: #1aad19;
}
</style>要点:
- 31 / 32 / 33 三种状态共用这一个组件:结构完全一样,只是 32 多一段绿色文字,所以没必要拆成三个组件。
- 文字内容用
<slot></slot>交给父组件写({{ msg.content }}),组件只负责“长什么样”;父组件不传内容时插槽为空。 type声明为Number,默认31;如果在父组件写成type="32"(字符串),=== 32就会判断失败,必须用:type="msg.messageType"动态绑定。- 模板里通过
props.type判断而不是直接写type,避免和保留字/局部变量混淆。 - 样式上“白底黑字”是 31、32、33 的公共表现,绿色文字只加在
.tips上,不要给整个盒子改颜色。
常见错误
1. 患者信息渲染了三遍
- 现象:页面上一模一样的患者卡片出现 3 次,或医生/患者消息混着渲染。
- 原因:
v-for遍历messageList时只做了循环,没有做类型过滤,模板本身不判断messageType。 - 修法:用
<template v-for>包一层,内部v-if="msg.messageType === 21";同理通知消息用>= 31一次性覆盖 31/32/33。
2. 组件标签不报错但页面上什么都没有 / 控制台提示未知组件
- 现象:
<patient-info>写在模板里,浏览器里既没内容也没报错,或者提示 component 未注册。 - 原因:组件放在
components目录下属于局部组件,只 import 了没注册,或者注册名与使用名大小写/短横线写法不一致。 - 修法:
import后在components: { PatientInfo }中注册;使用时统一短横线写法<patient-info>。找组件时用编辑器搜索find components定位文件。
3. 模板里取值为 undefined,插值全空
- 现象:
props.info.patientInfo.name这类长链取值渲染空白,控制台报Cannot read property of undefined。 - 原因:后端返回体是
data[].items[],直接把整个返回体当成消息数组用,层级多了一层;或者 props 默认值给的是null而不是空对象。 - 修法:取数据时遍历
data拿每一条items,用unshift展开成一个扁平数组;props 默认值统一给{},模板取值前用v-if兜底。
4. 患病时长、是否就诊显示成数字 0 / 1 / 2
- 现象:本该显示"一周内""未去医院就诊",页面上却是数字。
- 原因:直接把接口返回的枚举数值插值到模板,没有做值到文案的转换。
- 修法:定义文案数组,用返回的数值做下标取值;取值处加默认值或
||兜底,避免下标越界拿到undefined。
5. 点"查看图片"没反应,或只预览一张
- 现象:调用
previewImage后什么都没弹出,或只弹出第一张。 - 原因:直接把
pictures对象数组传给了urls,而该 API 只接受纯图片路径字符串数组。 - 修法:先
map出url字段组成新数组再传入;没有图片时不要绑点击事件,用v-if / v-else切换成"暂无图片"文案。
6. 温馨提示的绿字永远不出现
- 现象:31 和 32 两条通知样式一样,绿字标签丢失。
- 原因:
type没传或写死成默认值 31,组件内v-if="type === 32"永远为假。 - 修法:使用处动态绑定
:type="msg.messageType",props 里声明type: { type: Number, default: 31 },改完清缓存刷新验证。
练习
练习 1|组件拆分与条件渲染 把患者信息从问诊室页面抽成独立组件,在列表循环中通过 v-if 控制只渲染 messageType === 21 的那一条,并验证页面上卡片只出现一次。
练习 2|枚举值转文案 写一个工具函数,把患病时长(0/1/2)和是否就诊(0/1)的数值转成中文文案,要求传入非法值时不返回 undefined。
练习 3|图片预览全流程 实现"点击查看图片 → 大图预览",并在没有图片时显示"暂无图片"且不可点击。完成后自己创建一条带图片的问诊订单,验证有图分支也走通。
练习 4|通知消息组件复用 用一个组件承载 31/32/33 三种通知状态,正文用插槽传入,仅当类型为 32 时显示"温馨提示"标签,并在列表循环里用一条条件把 21 的患者信息排除掉。
练习 5|长轮询模拟 用 setInterval 每 500ms 发一次请求模拟长轮询,跑通后用自己的话说明:为什么聊天场景优先用 WebSocket 而不是它。
课堂画面






原视频对照
| # | 视频 | 时长 |
|---|---|---|
| 1 | 优医咨询-问诊室患者信息组件模板 | 06:13 |
| 2 | 优医咨询-问诊室患者信息-1 | 08:46 |
| 3 | 优医咨询-问诊室患者信息-2 | 08:32 |
| 4 | 什么是长轮循 | 04:47 |
| 5 | 优医咨询-查看大图 | 08:11 |
| 6 | 优医咨询-问诊室通知消息 | 13:05 |
小结
- 接口返回层级越深,模板取值越容易出错;进组件前先拍平数据结构,是省事不是多事。
v-for和v-if必须成对出现——循环负责"有几条",条件负责"该不该显示",缺一个就会出现重复渲染。- 组件拆分的第一判据是"这块内容会不会被复用、会不会把页面撑乱",患者信息和通知消息都属于该拆的。
- 父传子一律走 props,默认值给空对象而不是
null,能挡掉大半的 undefined 报错。 - 接口给的是枚举数字,界面要的是中文文案,中间这层转换必须显式做,别指望模板自动翻译。
- 调用第三方 API 前先看它要什么格式,
previewImage要的是纯路径数组,对象数组必须map一遍。 - 组件复用靠"插槽管内容、props 管状态",同类不同款的消息没必要写三个组件。
- WebSocket 与长轮询是场景选择问题:能用 WebSocket 就别用定时器轮询,性能差距是实打实的。