- API 路由统一: 移除 /api/h5/,统一 /api/pms/ 入口 - 二进制改名: api-server -> pms-api(与服务名一致) - nginx: 合并 /api/ + /pms/api/ 为 /api/pms/ - 新增 docs/API.md 接口文档 - 后端: CabinetDetail 增加 rssi/pow_fail/address/soc 等字段 - Redis 管道批量读取仓体实时数据(SOC/电压/电流/功率) - DB: 所有 TIMESTAMP 列改为 DATETIME(修复类型不匹配) - 用户管理: 新增创建时间/修改时间列,状态改用 Switch - 角色管理/用户管理: 操作按钮改为图标 - PC 设备详情: 基本信息补全 RSSI/ICCID/电源/地址 - PC 卡片: 通道统计改用 Lucide 图标,颜色统一 - PC 二维码: canvas 渲染,含编号文字,支持右键下载 - H5: 按 uni-app 规范修正导航(navigateTo 替代 reLaunch) - H5: 详情页加返回导航条 - H5: 扫码支持摄像头(jsQR)+ ?id= 参数 - H5: 底部 tabBar 在所有页面常显 - H5: 首页统计改为 6 项(设备/通道/空闲/充电/充满/故障) - H5: 下拉刷新 / 上拉加载 - 产品首页: 添加业务联系 - 文档: 清理过时文件,补充缺失规范章节
4.2 KiB
4.2 KiB
title, impact, impactDescription, type, tags
| title | impact | impactDescription | type | tags | |||||
|---|---|---|---|---|---|---|---|---|---|
| Teleport Preserves Logical Component Hierarchy | LOW | Understanding that Teleport only changes DOM structure, not Vue's component tree | best-practice |
|
Teleport Preserves Logical Component Hierarchy
Impact: LOW - A common misconception is that Teleport breaks the Vue component relationship. In reality, <Teleport> only alters the rendered DOM structure, not the logical hierarchy. Props, events, provide/inject, and Vue Devtools all work as if the component wasn't teleported.
Task Checklist
- Continue using props and events normally with teleported components
- Use provide/inject across teleported boundaries
- Check Vue Devtools for component location (shows logical parent, not DOM location)
Key Concept:
<!-- ParentComponent.vue -->
<template>
<div class="parent">
<Teleport to="body">
<!-- ChildComponent is logically still a child of ParentComponent -->
<!-- even though it renders in <body> -->
<ChildComponent
:message="parentMessage"
@update="handleUpdate"
/>
</Teleport>
</div>
</template>
<script setup>
import { provide, ref } from 'vue'
const parentMessage = ref('Hello from parent')
// Provide still works across teleport
provide('theme', 'dark')
function handleUpdate(value) {
// Events bubble up through logical hierarchy, not DOM
console.log('Received from teleported child:', value)
}
</script>
<!-- ChildComponent.vue -->
<template>
<div class="modal">
<p>{{ message }}</p>
<p>Theme: {{ theme }}</p>
<button @click="$emit('update', 'new value')">Update</button>
</div>
</template>
<script setup>
import { inject } from 'vue'
// Props work normally
defineProps(['message'])
// Inject works across teleport boundary
const theme = inject('theme')
// Emit works normally
defineEmits(['update'])
</script>
What Teleport Changes vs. Preserves
| Aspect | Changed? | Notes |
|---|---|---|
| DOM position | Yes | Content moves to to target |
| CSS inheritance | Yes | Styles inherit from new DOM parent |
| Props | No | Work exactly as without Teleport |
| Events (emit) | No | Bubble through logical hierarchy |
| Provide/Inject | No | Work across teleport boundaries |
| Vue Devtools | No | Shows logical component tree |
| Slots | No | Work normally |
| Template refs | No | Parent can ref teleported content |
Practical Example: Modal with Form
<!-- ModalForm.vue -->
<template>
<Teleport to="body">
<div v-if="visible" class="modal-overlay">
<form @submit.prevent="handleSubmit" class="modal-form">
<!-- Slot content receives parent's scope -->
<slot :formData="formData" />
<button type="submit">Submit</button>
<button type="button" @click="$emit('close')">Cancel</button>
</form>
</div>
</Teleport>
</template>
<script setup>
import { reactive } from 'vue'
defineProps(['visible'])
const emit = defineEmits(['close', 'submit'])
const formData = reactive({})
function handleSubmit() {
emit('submit', formData)
}
</script>
<!-- ParentPage.vue -->
<template>
<button @click="showModal = true">Add User</button>
<!-- Events and slots work as expected despite teleportation -->
<ModalForm
:visible="showModal"
@close="showModal = false"
@submit="handleFormSubmit"
>
<template #default="{ formData }">
<input v-model="formData.name" placeholder="Name" />
<input v-model="formData.email" placeholder="Email" />
</template>
</ModalForm>
</template>
<script setup>
import { ref } from 'vue'
const showModal = ref(false)
function handleFormSubmit(data) {
console.log('Form submitted:', data)
showModal.value = false
}
</script>
Vue Devtools Behavior
In Vue Devtools, teleported components appear under their logical parent:
App
└── ParentPage
└── ModalForm <-- Shows here (logical parent)
└── form content
Not under their DOM location:
// This is NOT how it appears in Devtools
body
└── ModalForm <-- Does NOT show here