Flutter 研发阶段性总结(四) 基本设计模式BLoC

本文介绍了Flutter中的BLoC设计模式,它是一种响应式编程模式,源于DartConf 2018。BLoC通过将变化视为流,实现了业务逻辑与界面的解耦。文章详细讲解了BLoC的实现,包括流的概念、基本的BLoC结构、状态管理和界面与BLoC的绑定,提供了具体的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

BLoC(Business Logic Component)设计模式是一个新鲜词汇, 在2018年1月的DartConf上被提出,其实是在Rx系列思想之下发展出来的响应式编程模式。
PS: 有时候从后端研发的角度来看,前端领域的一些想法确实挺前卫的。
其核心在于:将变量的变化看作一种流,并把Widget的状态绑定在流上,从而当变量改变时候,Widget接收到事件并作出响应的改变。因此BLoC可以做到完全将业务逻辑封装起来,Widget仅通过输入、输出和逻辑模块交互,做到完全的解耦。
BLoC的结构盗图一下:
在这里插入图片描述

BLoC的具体实现

这里的实现 90% 出自这位知乎大佬的文章,各位可以去围观一下:
在 Flutter 中使用 Bloc 来处理数据并更新 UI

流 Stream 的概念

可以把Stream看作管道,事件从一端输入,监听方从另一端获取事件并作出相应的改变。这里我们的Widget需要使用到StreamBuilder。

在Flutter中 StreamController 管理流, controller.sink 是入口, controller.stream 是出口

基本的BLoC实现

假设我们需要一个环境变量代表开和关,而App有多个页面的Switch开关控件与这个变量进行关联,我需要在任何页面拨动开关的时候,其它页面对应的开关的状态保持一致。
这里我们可以设想到的输入事件有两种:

  1. 变量的值改变 --> 导致开关状态变化
  2. 用户拨动开关 --> 导致值改变

因此会有两个Stream: 值的Stream,和用户操作事件Stream

class AppSwitchBLoC {
   
   
    bool _switchValue = false;
	StreamController<bool> _appSwitchController = StreamControler();
	// 用于值改变事件的输入(私有变量,不暴露出来)
	StreamSink<bool> get _inSwitch = _appSwitchController.sink;
	// 用于值改变事件的输入(值的输出暴露出来)
	Stream<bool> get outSwitchValue = _appSwitchController.stream;
	
	StreamController _switchActionController = StreamController();
	// 用户输入触发(暴露出来)
	StreamSink get changeSwitchValue = _switchActionController.sink;
	
	AppSwitchBLoC() {
   
   
	  // 指定_handleEvent函数处理用户的输入事件
	  _switchActionController.stream.listen(_handleEvent);
	}

    _handleEvent(data) {
   
   
      // 业务处理逻辑,这里就是将_switchValue的值变为用户输入的值
<think>好的,我现在需要解决用户的问题,即如何在Vue中使用Bloc模式实现左侧显示后端返回的HTML字符串,右侧显示对应的JSON Schema数据,并且能够动态修改和实时渲染HTML。用户还提到之前的问题中关于JSON Schema和动态表单的内容,以及引用了几个相关的代码示例。 首先,我需要理解Bloc模式。Bloc(Business Logic Component)是一种设计模式,用于分离业务逻辑和UI层,常见于Flutter,但在Vue中也可以应用类似的思想。Bloc模式的核心是将业务逻辑抽离到独立的组件中,通过事件和状态来驱动UI更新。在Vue中,这可以通过使用Vuex或自定义的store来实现,保持组件专注于展示,而逻辑由Bloc处理。 接下来,用户的需求是将后端返回的HTML字符串在左侧显示,右侧根据该HTML生成对应的JSON Schema表单,并且表单的修改能实时反映在HTML的渲染上。之前回答中提到了使用v-html渲染HTML,解析占位符生成Schema,并用计算属性实现双向绑定。现在结合Bloc模式,需要将业务逻辑(如解析HTML、生成Schema、状态管理)移到Bloc层。 我需要考虑如何将Bloc模式整合到Vue中。可能的步骤包括: 1. **创建Bloc层**:编写一个Bloc类或模块,负责处理HTML解析、Schema生成、状态管理(如表单数据)以及事件处理(如用户输入)。 2. **状态管理**:使用Vuex或响应式对象来存储HTML字符串、JSON Schema和表单数据,确保状态变化能触发UI更新。 3. **解析HTML生成Schema**:参考之前的方法,使用正则表达式提取占位符,动态生成对应的JSON Schema结构,比如每个占位符对应一个输入字段。 4. **双向绑定**:在Bloc中处理表单数据的变化,当用户修改表单时,更新状态,并通过计算属性或监听器实时更新HTML预览。 5. **组件结构**:左侧使用v-html显示经过处理的HTML,右侧使用如vue-json-schema-form或其他表单库根据Schema渲染表单,并与Bloc中的状态绑定。 可能会遇到的问题包括如何安全地处理HTML中的XSS风险,以及如何高效地解析和生成Schema。之前回答提到使用DOMPurify来净化HTML,这点需要保留。另外,Bloc模式需要处理事件流,可能需要使用观察者模式或Vue的自定义事件来通知UI更新。 还需要参考用户提供的引用内容,比如引用[2]中提到的vue-json-schema-form库,以及使用ajv进行校验,这些可以作为实现表单部分的参考。引用[3]中的省市区联动选择器展示了如何在Vue中处理动态表单,这可能对复杂Schema的处理有帮助。 最后,确保整个架构符合Bloc模式,将业务逻辑与UI分离,使代码更易于维护和测试。同时,需要提供示例代码和可能的相关问题,帮助用户进一步理解和解决问题。</think>在Vue中结合Bloc模式实现动态HTML与JSON Schema联动,可通过分层架构设计实现业务逻辑与UI解耦。以下是具体实现方案: ### 一、Bloc模式分层架构 ```bash ├─ bloc/ ├─ template.bloc.js # HTML模板处理逻辑 ├─ schema.bloc.js # JSON Schema生成逻辑 └─ form.bloc.js # 表单状态管理 ├─ components/ ├─ Preview.vue # 左侧HTML渲染组件 └─ SchemaForm.vue # 右侧JSON Schema表单组件 ``` ### 二、核心实现步骤 #### 1. Bloc业务逻辑层 ```javascript // template.bloc.js export class TemplateBloc { constructor() { this.rawHtml = ref('<h1>{{title}}</h1><img src="{{banner}}">') this.placeholders = computed(() => [...this.rawHtml.value.matchAll(/{{(.*?)}}/g)].map(m => m[1]) ) } } // schema.bloc.js export class SchemaBloc { generateSchema(placeholders) { return { type: "object", properties: placeholders.reduce((acc, key) => ({ ...acc, [key]: { type: key === 'banner' ? 'file' : 'string', title: key.toUpperCase() } }), {}) } } } ``` #### 2. 状态管理中心 ```javascript // form.bloc.js export const useFormBloc = () => { const formData = reactive({}) const errors = ref(null) const updateField = (key, value) => { formData[key] = value // 触发校验逻辑 validateForm() } return { formData, errors, updateField } } ``` #### 3. 视图层组件 ```vue <!-- Preview.vue --> <template> <div v-html="compiledHtml" class="preview-area"></div> </template> <script setup> import { computed } from 'vue' import { useTemplateBloc } from '../bloc/template.bloc' import { useFormBloc } from '../bloc/form.bloc' const { rawHtml } = useTemplateBloc() const { formData } = useFormBloc() const compiledHtml = computed(() => rawHtml.value.replace(/{{(.*?)}}/g, (_, key) => formData[key.trim()] || '❌ 未填写' ) ) </script> ``` ### 三、双向绑定实现机制 ```mermaid graph LR A[后端HTML] --> B(Bloc解析占位符) B --> C{生成JSON Schema} C --> D[Schema表单组件] D --> E[用户输入事件] E --> F[Bloc状态更新] F --> G[HTML实时重渲染] ``` ### 、增强功能实现 #### 1. 文件上传特殊处理 ```javascript // 在form.bloc.js中扩展 const handleFileUpload = (key, file) => { const objectURL = URL.createObjectURL(file) updateField(key, objectURL) } ``` #### 2. 安全渲染策略 ```javascript // 使用DOMPurify增强安全性 import DOMPurify from 'dompurify' const compiledHtml = computed(() => DOMPurify.sanitize(rawHtml.value.replace(...)) ) ``` ### 五、完整工作流程 1. **初始化阶段**: - 接收后端HTML字符串 - Bloc解析占位符并生成Schema - 初始化响应式formData对象 2. **渲染阶段**: - 左侧通过`v-html`渲染已替换值的HTML - 右侧通过`vue-jsonschema-form`渲染表单 3. **交互阶段**: - 表单修改触发Bloc状态更新 - 计算属性自动更新预览内容 - 支持自定义组件扩展(如图片上传) ### 六、Bloc模式优势体现 1. **关注点分离**:HTML解析、Schema生成、状态管理各自独立 2. **可测试性**:业务逻辑可单独进行单元测试 3. **可扩展性**:新增字段类型只需扩展Schema生成逻辑 4. **状态可追踪**:所有数据流动通过Bloc层管控
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值