ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Markdown越写越长,如何把编辑、预览和文件树放进同一工作台

Markdown越写越长,如何把编辑、预览和文件树放进同一工作台 Markdown文档变长以后只放一个输入框会让文件切换、预览和草稿状态互相干扰。界面可以先稳定下来但真正决定功能是否成立的是文档索引、稳定选中ID、草稿内容、保存标记和窗口断点。把文件列表、编辑草稿和预览选择拆成独立状态并根据窗口宽度决定显示几栏。这次实现先收住三条主线建立文档模型明确数据从哪里开始实现稳定选择让主要操作真正改变状态按断点重排三栏补齐设备形态或退出路径。文档ID不能跟着筛选变化页面重建不可怕无法恢复对象才麻烦。围绕文档索引、稳定选中ID、草稿内容、保存标记和窗口断点建立模型就是为了避开搜索或排序后仍保存数组索引会让右侧预览跳到另一份文档。exportinterfaceWorkspaceItem{id:stringtitle:stringdetail:stringkeywords:string[]updatedAt:number}exportinterfaceWorkspaceState{query:stringselectedId:stringdraft:stringsaved:boolean}exportclassFeatureController{privateitems:WorkspaceItem[][{id:a,title:Markdown工作台,detail:当前工作区,keywords:[workspace,current],updatedAt:3},{id:b,title:交互说明,detail:实现记录,keywords:[design,arkui],updatedAt:2},{id:c,title:导出结果,detail:最近生成,keywords:[output,result],updatedAt:1}稳定ID和阶段字段进入控制器以后临时销毁某个区域也不会丢掉当前操作。草稿与磁盘内容分开保存交互层只发送动作意图实现稳定选择所需的边界与返回值由控制器给出。数组没有暴露给组件选择、修改和撤销都用稳定ID完成。]privatestate:WorkspaceState{query:,selectedId:a,draft:,saved:true}search(query:string):WorkspaceItem[]{this.state.queryqueryconstkeyword:stringquery.trim().toLowerCase()if(keyword.length0){returnthis.items.map((item:WorkspaceItem)({id:item.id,title:item.title,detail:item.detail,keywords:item.keywords,updatedAt:item.updatedAt}asWorkspaceItem))}returnthis.items.filter((item:WorkspaceItem){constindexText:string(item.title item.detail item.keywords.join( )).toLowerCase()returnindexText.includes(keyword)})}select(id:string):WorkspaceItem|undefined{consttarget:WorkspaceItem|undefinedthis.items.find((item:WorkspaceItem)item.idid)if(target){this.state.selectedIdtarget.id}数组顺序变化不会影响命令目标从根源上处理了搜索或排序后仍保存数组索引会让右侧预览跳到另一份文档。三栏工作区按宽度出现页面把模型转换成清楚的层级窄屏聚焦编辑中等宽度显示文件与编辑宽屏再增加预览栏。平板与鸿蒙电脑上的可用空间不同但主数据、当前选择与反馈顺序保持一致。import{FeatureController}from../features/FeatureControllerinterfaceFeatureItem{id:numbertitle:stringdetail:string}EntryComponentstruct Index{privatefeatureController:FeatureControllernewFeatureController()StateselectedId:number1Statemessage:string文件树、编辑器与预览随窗口重排Statewide:booleanfalseStatequery:stringStatepreview:booleantrueStateeditorText:string在这里编辑当前内容窗口变化时草稿不会丢失。privateitems:FeatureItem[][{id:1,title:README.md,detail:可交互能力 1},{id:2,title:开发记录.md,detail:可交互能力 2},{id:3,title:发布清单.md,detail:可交互能力 3}]privateselected():FeatureItem{returnthis.items.find((item:FeatureItem)item.idthis.selectedId)??this.items[0]}privatevisible():FeatureItem[]{constkey:stringthis.query.trim().toLowerCase()returnkey.length0?this.items:this.items.filter((item:FeatureItem)item.title.toLowerCase().includes(key))}privateselectDocument(id:number):void{this.selectedIdidthis.editorText${this.selected().title}\n\n保持选择、草稿和滚动位置。this.message已打开${this.selected().title}}build(){Column({space:13}){Row(){Text(__TITLE__).fontSize(28).fontWeight(FontWeight.Bold);Blank();Button(this.preview?隐藏预览:显示预览).backgroundColor(__ACCENT__).onClick((){this.preview!this.preview})}.width(100%)Text(this.message).fontSize(12).fontColor(#667085).width(100%)Row({space:12}){Column({space:10}){TextInput({text:this.query,placeholder:搜索或输入命令}).onChange((value:string){this.queryvalue});List({space:7}){ForEach(this.visible(),(item:FeatureItem){ListItem(){Text(item.title).fontSize(14).fontColor(this.selectedIditem.id?Color.White:#344054).padding(12).width(100%).borderRadius(12).backgroundColor(this.selectedIditem.id?__ACCENT__:#EEF1F5).onClick(()this.selectDocument(item.id))}},(item:FeatureItem)item.id.toString())}.layoutWeight(1)}.width(this.wide?24%:30%).height(100%)Column({space:8}){Text(编辑区).fontSize(16).fontWeight(FontWeight.Bold).width(100%);TextArea({text:this.editorText}).layoutWeight(1).width(100%).backgroundColor(#FAFBFD).onChange((value:string){this.editorTextvalue;this.message草稿尚未保存});Row({space:8}){Button(Ctrl K).onClick((){this.message命令面板已唤起});Button(保存).backgroundColor(__ACCENT__).onClick((){this.message当前内容已保存})}}.layoutWeight(1).height(100%).padding(16).borderRadius(20).backgroundColor(Color.White)if(this.previewthis.wide){Column({space:10}){Text(实时预览).fontSize(16).fontWeight(FontWeight.Bold);Text(this.editorText).fontSize(14).fontColor(#475467);Blank();Text(宽窗口显示第三栏).fontSize(12).fontColor(__ACCENT__)}.width(30%).height(100%).padding(16).borderRadius(20).backgroundColor(#EEF1F8)}}.layoutWeight(1).width(100%)}.width(100%).height(100%).padding(18).backgroundColor(#F5F6F9).onAreaChange((oldArea:Area,newArea:Area){this.wideNumber(newArea.width)820})}}Index.ets在这里读取控制器结果并组织窄屏聚焦编辑中等宽度显示文件与编辑宽屏再增加预览栏。计算仍留在功能层因此更换设备形态只需调整区域组合。切换文件前处理未保存内容这一部分处理完成之外的结果取消、过期、不可用与可以重试。returntarget}updateDraft(value:string):void{this.state.draftvaluethis.state.savedfalse}save():boolean{if(this.state.draft.trim().length0){returnfalse}this.state.savedtruereturntrue}getState():WorkspaceState{return{query:this.state.query,selectedId:this.state.selectedId,draft:this.state.draft,saved:this.state.saved}}}错误对象携带原因和可重试性空内容则保持为另一种正常状态。DeskMarkdown的模块关系下面是DeskMarkdown当前使用的目录。pages负责窄屏聚焦编辑中等宽度显示文件与编辑宽屏再增加预览栏features保存本文展示的业务链路。DeskMarkdown/ ├─ entry/src/main/ets/ │ ├─ pages/Index.ets # 首屏与响应式布局 │ ├─ features/FeatureController.ets # 模型、动作和边界 │ ├─ entryability/EntryAbility.ets # 页面入口与生命周期 │ └─ adapters/ # 真机能力或数据源接口 ├─ entry/src/main/resources/ # 颜色、文字和媒体资源 └─ build-profile.json5 # 工程构建配置Index.ets只组合界面FeatureController.ets处理文档索引、稳定选中ID、草稿内容、保存标记和窗口断点。如果后面接入真实设备或网络服务只需增加适配器并把结果转换成控制器认识的状态。代码从建立文档模型走到按断点重排三栏中间没有让视图组件接管业务身份。
返回列表