Angular中DOM元素访问的生命周期陷阱与解决方案

angular中dom元素访问的生命周期陷阱与解决方案

本文深入探讨了在Angular应用中,为何不能直接在`ngOnInit`中访问DOM元素,并提供了两种主要解决方案。首先介绍使用`ngAfterViewInit`确保视图初始化后访问DOM,接着针对异步数据加载和动态视图渲染的复杂场景,详细阐述了如何结合RxJS的`Subject`、`forkJoin`以及`ngAfterViewChecked`生命周期钩子,实现健壮的DOM元素访问策略,确保在数据和视图均准备就绪后进行操作。

在Angular开发中,开发者经常需要与组件模板中的DOM元素进行交互。然而,一个常见的误区是尝试在ngOnInit生命周期钩子中直接访问这些元素,这通常会导致获取到null或undefined的结果。理解Angular的生命周期是解决这一问题的关键。

理解ngOnInit与DOM渲染时机

ngOnInit是Angular组件或指令初始化时触发的钩子。在这个阶段,Angular已经完成了数据绑定属性的初始化,但组件的视图(即模板中的HTML元素)尚未完全渲染到DOM中。因此,此时通过document.getElementById()等原生DOM API尝试获取元素,自然会失败。

例如,考虑以下模板代码:

如果rolesData包含一个role为’Software Developer’的项,我们希望在组件初始化后获取ID为’Software Developer’的复选框。直接在ngOnInit中执行:

ngOnInit() {  console.log("element", document.getElementById('Software Developer')); // 此时会打印 null}

将无法如预期般工作。

解决方案一:使用ngAfterViewInit

为了在Angular组件的视图完全渲染并初始化后访问DOM元素,我们应该使用ngAfterViewInit生命周期钩子。ngAfterViewInit在Angular完成组件视图及其子视图的初始化之后触发。这意味着在这个钩子中,组件的模板元素已经存在于DOM中,可以安全地进行访问和操作。

import { Component, AfterViewInit } from '@angular/core';@Component({  selector: 'app-my-component',  template: `    
`})export class MyComponent implements AfterViewInit { rolesData = [{ role: 'Software Developer' }, { role: 'Project Manager' }]; ngAfterViewInit() { console.log('element', document.getElementById('Software Developer')); // 此时可以成功获取到元素并进行操作 const checkbox = document.getElementById('Software Developer') as HTMLInputElement; if (checkbox) { checkbox.checked = true; } }}

注意事项:

ngAfterViewInit适用于视图内容是同步渲染的场景。对于父组件而言,ngAfterViewInit在其子组件的视图初始化完成后才触发。

解决方案二:处理异步数据与动态视图渲染

在更复杂的场景中,组件的视图内容可能依赖于异步获取的数据(例如,通过HTTP请求从Observable获取数据),并且使用*ngFor等结构动态渲染。在这种情况下,仅仅依靠ngAfterViewInit可能不足以保证元素可用,因为ngAfterViewInit在组件视图初始化后立即触发,但此时异步数据可能尚未返回,导致*ngFor尚未完成元素的渲染。

为了解决这个问题,我们需要确保两个条件同时满足:

异步数据已经成功获取。基于异步数据渲染的HTML元素已经呈现在DOM中。

这可以通过结合使用RxJS的Subject、forkJoin以及ngAfterViewChecked生命周期钩子来实现。

ngAfterViewChecked在每次Angular检测到视图发生变化并渲染后都会触发。虽然它触发频率较高,但可以作为视图渲染完成的信号。

以下是一个综合性的解决方案:

import { Component, OnInit, AfterViewChecked, OnDestroy } from '@angular/core';import { Subject, forkJoin } from 'rxjs';import { takeUntil } from 'rxjs/operators';@Component({  selector: 'app-dynamic-component',  template: `    
`})export class DynamicComponent implements OnInit, AfterViewChecked, OnDestroy { rolesData: any[] = []; rolesData$: Subject = new Subject(); // 模拟异步数据源 private isDataFetchedSubject: Subject = new Subject(); isDataFetched$ = this.isDataFetchedSubject.asObservable(); private isViewRenderedSubject: Subject = new Subject(); isViewRendered$ = this.isViewRenderedSubject.asObservable(); private destroyed$: Subject = new Subject(); // 用于管理订阅的生命周期 ngOnInit() { // 模拟异步数据获取 // 实际应用中,rolesData$会是一个HTTP请求或其他Observable setTimeout(() => { const fetchedData = [{ role: 'Software Developer' }, { role: 'Project Manager' }]; this.rolesData = fetchedData; this.rolesData$.next(fetchedData); // 触发数据流 this.isDataFetchedSubject.next(true); this.isDataFetchedSubject.complete(); // 标记数据已获取 }, 1000); // 延迟1秒模拟异步 // 监听数据获取和视图渲染完成的信号 forkJoin([this.isDataFetched$, this.isViewRendered$]) .pipe(takeUntil(this.destroyed$)) .subscribe(([dataFlag, viewFlag]) => { console.log('Observable is completed - Data:', dataFlag, 'View:', viewFlag); if (dataFlag && viewFlag) { // 数据和视图都已准备就绪,可以安全地访问DOM元素 // 使用setTimeout延迟执行,以确保DOM更新完全完成 let checkElementExist = setTimeout(() => { const element = document.getElementById('Software Developer') as HTMLInputElement; if (element) { console.log('(2) element', element); element.checked = true; clearTimeout(checkElementExist); // 找到元素后清除定时器 } else { // 如果元素仍未找到,可以考虑再次延迟或重试逻辑 // 但在forkJoin确保了数据和视图都准备好的情况下,通常第一次就能找到 console.warn('Element "Software Developer" not found after view and data readiness.'); } }, 0); // 0ms延迟,将操作放入事件队列末尾,确保当前DOM更新周期完成 } }); } ngAfterViewChecked() { // 每次视图检查后,发送视图已渲染的信号 // 注意:isViewRenderedSubject只在第一次视图检查后complete if (!this.isViewRenderedSubject.closed) { this.isViewRenderedSubject.next(true); this.isViewRenderedSubject.complete(); } } ngOnDestroy() { this.destroyed$.next(); this.destroyed$.complete(); }}

代码解析:

isDataFetchedSubject 和 isViewRenderedSubject:这两个Subject作为信号源,分别表示异步数据是否已获取和视图是否已渲染。当对应的事件发生时,通过next(true)发送信号,并通过complete()标记信号完成。forkJoin:forkJoin([this.isDataFetched$, this.isViewRendered$]) 会等待两个Observable都发出值并完成。只有当数据和视图都准备好时,其subscribe回调才会执行。ngAfterViewChecked:在这个钩子中,我们发送isViewRenderedSubject.next(true)并complete(),表示视图已渲染。由于ngAfterViewChecked会多次触发,我们使用!this.isViewRenderedSubject.closed来确保complete()只调用一次。setTimeout(…, 0):即使forkJoin条件满足,DOM更新也可能在当前JavaScript执行周期之后才完全生效。使用setTimeout(…, 0)可以将DOM操作推迟到当前事件循环的末尾,确保在浏览器完成所有挂起的DOM更新后执行。这是一种常见的技巧,用于处理DOM更新的异步性。takeUntil(this.destroyed$):这是一个重要的RxJS操作符,用于在组件销毁时自动取消所有订阅,防止内存泄漏。

总结与最佳实践

ngOnInit: 用于组件的初始化逻辑,如数据获取、服务注入等,但不适合直接访问DOM元素。ngAfterViewInit: 当组件的视图(包括子组件视图)完全初始化并渲染到DOM后触发。这是访问静态DOM元素的理想时机。ngAfterViewChecked: 在每次Angular检测到视图变化并更新DOM后触发。它触发频率高,应谨慎使用,避免性能问题。结合RxJS信号可以有效管理动态和异步场景下的DOM访问。

虽然document.getElementById()在某些场景下可用,但Angular通常鼓励使用更声明式和类型安全的方式与DOM交互,例如:

@ViewChild 或 @ViewChildren: 用于获取模板中的特定元素或组件实例。ElementRef: 如果确实需要直接访问底层DOM元素,可以通过ElementRef获取。但应尽量减少直接DOM操作,因为这会绕过Angular的抽象,可能导致性能问题或与平台无关性冲突。

选择正确的生命周期钩子并结合适当的策略,是确保Angular应用中DOM操作健壮和高效的关键。

以上就是Angular中DOM元素访问的生命周期陷阱与解决方案的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1535083.html

赞 (0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
WebRTC连接建立超时问题解析:手动信令交换与ICE机制的挑战
上一篇 2025年12月21日 02:07:45
React开发者如何高效掌握CSS:实用工具链与学习策略
下一篇 2025年12月21日 02:07:58

相关推荐

  • 360极速浏览器手机版怎么扫描二维码_移动版扫一扫功能使用入口

    360极速浏览器手机版怎么扫描二维码_移动版扫一扫功能使用入口360极速浏览器手机版怎么扫描二维码_移动版扫一扫功能使用入口360极速浏览器手机版怎么扫描二维码_移动版扫一扫功能使用入口360极速浏览器手机版怎么扫描二维码_移动版扫一扫功能使用入口

    360极速浏览器手机版可通过搜索框二维码图标或底部工具栏“更多”按钮进入扫一扫功能,授权相机后对准二维码即可快速识别并跳转页面。 如果您需要在手机上快速扫描二维码以访问链接或获取信息,360极速浏览器手机版提供了便捷的扫一扫功能。以下是具体的操作方法和使用入口。 本文运行环境:小米14,Androi…

    2026年9月27日 • 用户投稿
    000
  • 百度极速版如何开启安全浏览_百度极速版安全模式的设置步骤

    百度极速版如何开启安全浏览_百度极速版安全模式的设置步骤百度极速版如何开启安全浏览_百度极速版安全模式的设置步骤百度极速版如何开启安全浏览_百度极速版安全模式的设置步骤百度极速版如何开启安全浏览_百度极速版安全模式的设置步骤

    进入百度极速版【我的】页面,点击右上角设置图标;2. 选择【隐私设置】,关闭【历史记录】和【搜索历史】开关,实现类似安全浏览效果,保护隐私。 百度极速版开启安全浏览功能,主要是通过设置中的隐私与安全选项来完成。目前版本中,直接的“安全浏览模式”开关可能不明显,但可以通过关闭历史记录等方式实现类似效果…

    2026年9月27日 • 用户投稿
    100
  • Spring Boot 的自动配置原理是什么?(@SpringBootApplication)

    Spring Boot 的自动配置原理是什么?(@SpringBootApplication)Spring Boot 的自动配置原理是什么?(@SpringBootApplication)Spring Boot 的自动配置原理是什么?(@SpringBootApplication)Spring Boot 的自动配置原理是什么?(@SpringBootApplication)

    Spring Boot自动配置基于“约定优于配置”和“有主见但可扩展”的设计哲学,通过@SpringBootApplication注解整合@Configuration、@ComponentScan和@EnableAutoConfiguration,实现组件自动装配。其核心是@EnableAutoCo…

    2026年9月27日 • 用户投稿
    000
  • 楼层定位,是如何实现的?

    楼层定位,是如何实现的?楼层定位,是如何实现的?楼层定位,是如何实现的?楼层定位,是如何实现的?

    最近带孩子在外地旅行,频繁使用小天才 Z10 儿童电话手表。某次打开配套 App 查看定位时,我注意到一个令人惊讶的细节:App 的地图界面竟然能准确显示孩子当前所在的建筑楼层。 作为一名通信领域的工程师,这个现象立刻引起了我的注意。 我们都知道,常见的电子设备定位方式主要包括 GPS、北斗(GNS…

    2026年9月27日 • 用户投稿
    000
  • sublime怎么让自动补全菜单显示更多信息_sublime自动补全菜单增强信息显示

    sublime怎么让自动补全菜单显示更多信息_sublime自动补全菜单增强信息显示sublime怎么让自动补全菜单显示更多信息_sublime自动补全菜单增强信息显示sublime怎么让自动补全菜单显示更多信息_sublime自动补全菜单增强信息显示sublime怎么让自动补全菜单显示更多信息_sublime自动补全菜单增强信息显示

    启用LSP插件并配置语言服务器,可使Sublime Text补全菜单显示函数签名、参数、类型及文档等详细信息,提升编码效率。 Sublime Text 默认的自动补全菜单只显示简单的函数名或变量名,信息有限。想要让补全项显示更多上下文信息(如参数列表、类型、文档摘要等),可以通过配置设置和安装插件来…

    2026年9月27日 • 用户投稿
    000
  • 淘宝平台投诉最有效的方法是什么?举报中心在哪里?淘宝维权必看!投诉成功率92%!3招让商家秒怂,举报中心入口藏在这里!

    淘宝平台投诉最有效的方法是什么?举报中心在哪里?淘宝维权必看!投诉成功率92%!3招让商家秒怂,举报中心入口藏在这里!淘宝平台投诉最有效的方法是什么?举报中心在哪里?淘宝维权必看!投诉成功率92%!3招让商家秒怂,举报中心入口藏在这里!淘宝平台投诉最有效的方法是什么?举报中心在哪里?淘宝维权必看!投诉成功率92%!3招让商家秒怂,举报中心入口藏在这里!淘宝平台投诉最有效的方法是什么?举报中心在哪里?淘宝维权必看!投诉成功率92%!3招让商家秒怂,举报中心入口藏在这里!

    在淘宝平台购物时,用户有时会遇到实物与描述严重不符、商家夸大宣传或售后态度消极等情况。最有力的维权途径是通过淘宝的官方举报中心发起投诉,该功能入口可在淘宝app的「我的淘宝」界面中快速找到。本文将通过图文详解整个投诉操作流程,并提供三项实用技巧,助你大幅提升维权效率。 一、淘宝官方投诉通道实操指南 …

    2026年9月27日 • 用户投稿
    100
  • uc浏览器下载任务失败怎么解决_UC浏览器下载中断或失败处理方法

    uc浏览器下载任务失败怎么解决_UC浏览器下载中断或失败处理方法uc浏览器下载任务失败怎么解决_UC浏览器下载中断或失败处理方法uc浏览器下载任务失败怎么解决_UC浏览器下载中断或失败处理方法uc浏览器下载任务失败怎么解决_UC浏览器下载中断或失败处理方法

    下载失败时,先检查网络连接,确保信号稳定;清理UC浏览器缓存数据;确认设备存储空间充足;删除失败任务并重新下载;关闭省电模式,允许后台运行以提升稳定性。 如果您在使用UC浏览器下载文件时遇到下载任务失败或中断的情况,可能是由于网络连接不稳定、存储空间不足或浏览器缓存异常导致的。以下是针对此问题的多种…

    2026年9月27日 • 用户投稿
    000
  • 什么是泛型?泛型擦除是什么意思?有什么好处和局限?

    什么是泛型?泛型擦除是什么意思?有什么好处和局限?什么是泛型?泛型擦除是什么意思?有什么好处和局限?什么是泛型?泛型擦除是什么意思?有什么好处和局限?什么是泛型?泛型擦除是什么意思?有什么好处和局限?

    泛型通过类型参数提升代码复用与编译期类型安全,Java采用泛型擦除机制以兼容旧版本并简化JVM,但导致运行时无法获取泛型信息,需通过Class对象、通配符、类型令牌等策略应对。 泛型,简单来说,就是我们在编写代码时,能够让方法、类或接口处理多种数据类型的一种能力。它就像给我们的代码加了一层“智能外壳…

    2026年9月27日 • 用户投稿
    000
  • 高德外卖怎么上传图片_高德外卖评价上传图片教程

    高德外卖怎么上传图片_高德外卖评价上传图片教程高德外卖怎么上传图片_高德外卖评价上传图片教程高德外卖怎么上传图片_高德外卖评价上传图片教程高德外卖怎么上传图片_高德外卖评价上传图片教程

    首先在订单评价页点击“+图片”上传相册内餐品照片,其次追加评价时也可插入图片,最后检查高德地图的存储权限以确保功能正常。 如果您在使用高德外卖进行订单评价时,想要上传图片以更直观地展示餐品情况或用餐体验,但不清楚具体操作方式,可以通过以下步骤完成图片上传。该功能有助于提升评价的可信度和参考价值。 本…

    2026年9月27日 • 用户投稿
    000
  • sublime怎么处理超大日志文件_sublime超大日志文件处理技巧

    sublime怎么处理超大日志文件_sublime超大日志文件处理技巧sublime怎么处理超大日志文件_sublime超大日志文件处理技巧sublime怎么处理超大日志文件_sublime超大日志文件处理技巧sublime怎么处理超大日志文件_sublime超大日志文件处理技巧

    通过设置大文件提示阈值和关闭高亮索引功能,可提升Sublime Text处理大日志文件的性能;2. 启用只读模式并分段查看,结合外部工具拆分文件,能有效避免卡顿崩溃;3. 对于GB级日志,建议配合Less、LogExpert等专用工具使用以获得更佳效率。 Sublime Text 虽然轻量高效,但在…

    2026年9月27日 • 用户投稿
    000
  • PowerShell安装及基础介绍

    PowerShell安装及基础介绍PowerShell安装及基础介绍PowerShell安装及基础介绍PowerShell安装及基础介绍

    在文章底部你的每一次随手 → 分享、点赞、在看都很重要,感谢!!! 精华推荐:精选20篇满足你对前沿理论、技术和经验总结 PowerShell定义 我们先看下PowerShell官方的定义: 启动方式 一般情况下,在win 10已经预装了PowerShell,启动方式如下: 方式一,在cmd终端,输…

    2026年9月27日 • 用户投稿
    100
  • SpringCloud 2025微服务架构实战:实现99.99%高可用性的5个关键设计

    SpringCloud 2025微服务架构实战:实现99.99%高可用性的5个关键设计SpringCloud 2025微服务架构实战:实现99.99%高可用性的5个关键设计SpringCloud 2025微服务架构实战:实现99.99%高可用性的5个关键设计SpringCloud 2025微服务架构实战:实现99.99%高可用性的5个关键设计

    要实现99.99%高可用,需融合多区域部署、熔断限流、异步通信、高可用数据存储与自动化运维;通过地理冗余防止单点故障,利用Resilience4j等工具实现服务自我保护,采用消息队列解耦服务并保障最终一致性,确保数据库、缓存、消息队列集群化部署,并依托监控、日志、自动化运维实现快速恢复,构建具备韧性…

    2026年9月27日 • 用户投稿
    000
  • qq浏览器如何更新到最新版本 QQ浏览器手动检查与自动更新设置

    qq浏览器如何更新到最新版本 QQ浏览器手动检查与自动更新设置qq浏览器如何更新到最新版本 QQ浏览器手动检查与自动更新设置qq浏览器如何更新到最新版本 QQ浏览器手动检查与自动更新设置qq浏览器如何更新到最新版本 QQ浏览器手动检查与自动更新设置

    更新QQ浏览器可解决功能异常问题。①通过“我的-设置-关于”手动检查更新;②官网下载最新安装包覆盖安装;③在设置和应用商店中开启自动更新功能,确保版本同步。 如果您发现QQ浏览器功能异常或无法正常加载网页,可能是由于浏览器版本过低导致与当前网站技术不兼容。及时更新至最新版本可以修复已知漏洞并提升浏览…

    2026年9月27日 • 用户投稿
    300
  • 《索尼克赛车 交叉世界》8月29日起开展4天免费网络测试

    《索尼克赛车 交叉世界》8月29日起开展4天免费网络测试《索尼克赛车 交叉世界》8月29日起开展4天免费网络测试《索尼克赛车 交叉世界》8月29日起开展4天免费网络测试《索尼克赛车 交叉世界》8月29日起开展4天免费网络测试

    来源:官方 《索尼克赛车 交叉世界》将于8月29日开启为期4天的免费网络测试 世嘉正式宣布,《索尼克赛车 交叉世界》将于北京时间2025年8月29日中午12:00起至9月2日中午12:00止,开展为期四天的免费网络测试。本次测试面向所有玩家开放,支持平台包括PlayStation®5、Nintend…

    2026年9月27日 • 用户投稿
    000
  • win10注册表保存不了提示出错怎么办

    win10注册表保存不了提示出错怎么办win10注册表保存不了提示出错怎么办win10注册表保存不了提示出错怎么办win10注册表保存不了提示出错怎么办

    注册表编辑器是计算机系统中的重要组件之一,然而近期有部分windows 10用户在编辑注册表后尝试保存时,遇到了“无法创建值,写入注册表失败”的错误提示。出现这种情况通常是因为当前用户权限不足所致。针对这一问题的具体解决办法如下: Windows 10注册表保存失败的处理方法 首先以管理员身份登录W…

    2026年9月27日 • 用户投稿
    000
  • 多核处理器在运行单线程任务时为何表现不佳?

    多核处理器在运行单线程任务时为何表现不佳?多核处理器在运行单线程任务时为何表现不佳?多核处理器在运行单线程任务时为何表现不佳?多核处理器在运行单线程任务时为何表现不佳?

    多核处理器在运行单线程任务时表现不佳,根本原因在于任务的串行性使其无法并行执行,即便拥有更多核心也难以提升性能。1. 单线程任务只能在一个核心上运行,其他核心无法参与;2. 任务内部存在严格的顺序依赖(如A→B→C),导致无法拆分并行处理;3. 根据Amdahl定律,程序加速比受限于串行部分比例,纯…

    2026年9月27日 • 用户投稿
    500
  • sublime怎么显示文档结构图或大纲_Sublime使用插件生成代码大纲视图

    sublime怎么显示文档结构图或大纲_Sublime使用插件生成代码大纲视图sublime怎么显示文档结构图或大纲_Sublime使用插件生成代码大纲视图sublime怎么显示文档结构图或大纲_Sublime使用插件生成代码大纲视图sublime怎么显示文档结构图或大纲_Sublime使用插件生成代码大纲视图

    安装Package Control后,通过它安装CTags插件并生成tags文件实现代码结构可视化;2. 使用Ctrl+T或Ctrl+R快速跳转符号;3. 配合SideBarEnhancements提升导航效率。 Sublime Text 虽然本身不带文档结构图(大纲视图)功能,但可以通过安装插件来…

    2026年9月27日 • 用户投稿
    500
  • ️「领域驱动设计」Java微服务拆分策略与界限上下文划分

    ️「领域驱动设计」Java微服务拆分策略与界限上下文划分️「领域驱动设计」Java微服务拆分策略与界限上下文划分️「领域驱动设计」Java微服务拆分策略与界限上下文划分️「领域驱动设计」Java微服务拆分策略与界限上下文划分

    微服务拆分的核心在于通过领域驱动设计(DDD)识别业务的“自然边界”,其中界限上下文(Bounded Context)是关键。它强调从业务语言和领域专家沟通出发,而非技术视角,确保服务高内聚、低耦合。通过事件风暴、通用语言、业务能力分析等方法识别界限上下文,并结合团队结构与上下文映射明确服务边界。在…

    2026年9月26日 • 用户投稿
    100
  • 有好看漫画合集的app推荐 推荐十个有好看漫画的软件大全

    有好看漫画合集的app推荐 推荐十个有好看漫画的软件大全有好看漫画合集的app推荐 推荐十个有好看漫画的软件大全有好看漫画合集的app推荐 推荐十个有好看漫画的软件大全有好看漫画合集的app推荐 推荐十个有好看漫画的软件大全

    为了帮助广大爱好者找到心仪的阅读平台,我们精心整理了十款备受好评的漫画软件。这些应用不仅拥有海量作品库,还在阅读体验和社区互动方面各具特色,让你轻松告别书荒。 小编推荐一、☞☞☞☞点击必备的看漫APP☜☜☜☜☜ 小编推荐二、☞☞☞☞点击漫画资源最全的平台入口☜☜☜☜☜ 一、快看 1、这是一款非常受年…

    2026年9月26日 • 用户投稿
    200
  • win11任务栏卡死重启也没用怎么办

    win11任务栏卡死重启也没用怎么办win11任务栏卡死重启也没用怎么办win11任务栏卡死重启也没用怎么办win11任务栏卡死重启也没用怎么办

    在安装windows 11系统之后,许多用户的电脑可能会遇到一些使用上的问题,其中较为常见的就是任务栏卡死的现象。那么,当win11的任务栏卡死且重启无效时,该如何处理呢?接下来就为大家介绍几种解决win11任务栏卡死的有效方法。 第一种方法(官方提供的临时解决方案): 首先按下Ctrl+Alt+D…

    2026年9月26日 • 用户投稿
    600

发表回复

登录后才能评论
关注微信