NativeScript Observable 数据观察实战:从 fromObject 创建到 propertyChange 事件响应
【免费下载链接】NativeScript⚡ Write Native with TypeScript ✨ Best of all worlds (TypeScript, Swift, Objective C, Kotlin, Java, Dart). Use what you love ❤️ Angular, React, Solid, Svelte, Vue with: iOS (UIKit, SwiftUI), Android (View, Jetpack Compose), Flutter and you name it compatible.项目地址https://gitcode.com/gh_mirrors/na/NativeScript点击查看免费下载data/observable是 NativeScript 核心包nativescript/core中最基础的数据观察模块应用中的 ViewModel、属性绑定、propertyChange事件分发全部建立在它之上。本文以 observable.md 为主线完整讲解如何引入该模块、通过fromObject创建可观察对象、以及监听并响应属性变化并结合 packages/core/data/observable/index.ts 的源码与 observable-tests.ts 的自动化用例深入剖析其底层实现与注意事项。读完本文你将掌握 Observable 的完整用法并能直接看懂 NativeScript 数据绑定与事件系统的运行原理。引入 data/observable 模块使用 Observable 对象必须先引入data/observable模块。在 NativeScript 8 中模块统一从nativescript/core导出示例代码如下取自 observable-tests.tsimport { Observable, PropertyChangeData, EventData, WrappedValue, fromObject, fromObjectRecursive, ObservableArray } from nativescript/core;这一行 import 覆盖了data/observable的全部核心导出其语义如下导出用途Observable可观察对象基类提供set/get、on/off、事件通知能力PropertyChangeDatapropertyChange事件的载荷类型含propertyName、value、oldValue、originEventData通用事件载荷类型eventNameobjectWrappedValue用于强制触发同对象属性变更通知的包装器fromObject由普通 JSON 对象创建 Observable仅顶层属性可观察fromObjectRecursive递归创建 Observable嵌套对象也会被转换为 ObservableObservableArray可观察数组元素变化时触发change事件版本提示早期 NativeScriptv3.0 之前支持new Observable({ ... })构造器传入初始化对象该写法自 v3.0 起已标记为obsolete见 index.ts必须改用fromObject({})或fromObjectRecursive({})。创建 ObservablefromObject 与源码剖析基本用法创建 Observable 最简单的方式是把一个普通 JavaScript 对象交给fromObject随后用get读取属性取自 observable-tests.tsvar json { Name: John, Age: 34, Married: true, }; var person fromObject(json); var name person.get(Name); var age person.get(Age); var married person.get(Married); // console.log(name age married); // Prints out John 34 true if uncommented.这段代码在自动化测试中对应test_Observable_Constructor断言name John、age 34、married true验证了fromObject创建的实例能够按原样读出初始化数据。底层实现ObservableFromObject 与属性重定义fromObject的实现位于 index.ts它内部创建了一个ObservableFromObject实例Observable的私有子类再调用addPropertiesFromObject为每个源对象属性执行两件事index.ts通过Object.defineProperty为实例定义同名访问器属性getter/setter 均委托给_map与set见 index.ts调用observable.set(prop, value)写入初始值。这意味着fromObject创建的实例不仅支持get(Age)还支持直接点号/方括号读写如person.Age或person[Age]并且任何赋值都会自动触发propertyChange通知——这正是数据绑定能够工作的关键。测试用例test_Observable_WhenCreatedWithJSON_PropertyChangedWithDotNotation_RaisesPropertyChangedEvent与test_Observable_WhenCreatedWithJSON_PropertyChangedWithBracketsNotation_RaisesPropertyChangedEventobservable-tests.ts分别验证了两种访问方式都能正确触发事件。另外注意fromObject对相同值的赋值会被set内部抑制if (currentValue value) return;见 index.ts因此重复赋同一个值不会产生多余通知fromObject创建的实例之间完全隔离各自的属性存储与监听器互不干扰对应测试test_ObservablesCreatedWithJSON_shouldNotInterfereWithOneAnotherobservable-tests.ts。嵌套对象fromObjectRecursive如果源对象含有嵌套对象数组与函数除外fromObject只让顶层属性可观察。需要整体可观察时使用fromObjectRecursive——它会对每个非数组、非Observable实例的对象值递归调用自身把嵌套层级也转换为 Observableindex.ts。相关测试还验证了fromObjectRecursive不会覆盖源对象的属性引用test_fromObjectRecursive_does_not_override_source_object_propertyobservable-tests.ts且能安全处理null值与ObservableArray混合场景test_NestedObservableWithNullShouldNotCrash、test_NestedObservablesWithObservableArrayShouldNotCrashobservable-tests.ts。响应属性变化propertyChange 事件基本用法监听属性变化有两种等价的 API 组合on/off与addEventListener/removeEventListener。以下示例使用new Observable()手动set属性并监听Observable.propertyChangeEvent即字符串propertyChange事件取自 observable-tests.tsvar person new Observable(); person.set(Name, John); person.set(Age, 34); person.set(Married, true); person.addEventListener(Observable.propertyChangeEvent, function (pcd: PropertyChangeData) { //console.log(pcd.eventName.toString() pcd.propertyName.toString() pcd.value.toString()); }); person.set(Age, 35); person.set(Married, false); // If uncommented, the console.log above produces the following output: // propertyChange Age 35 // propertyChange Married false可以看到只有set之后发生值变化的Age与Married触发了回调Name在监听注册前已设置不会触发回调中能拿到eventName、propertyName、value三个关键字段。PropertyChangeData 载荷详解PropertyChangeData接口定义于 index.ts在EventDataeventName、object基础上扩展了四个字段字段类型说明propertyNamestring发生变化的属性名valueany变化后的新值oldValueany可选变化前的旧值originPropertyChangeOrigin可选变化的来源仅样式/视图层使用origin是PropertyChangeOrigin联合类型取值包括script应用代码写入、native原生视图反馈如用户交互、css、inherited、animationindex.ts。普通notifyPropertyChange调用者拿到的origin为undefined。触发链路set → notifyPropertyChange → notifyset的完整流程index.ts读取旧值oldValue this[name]若新值与旧值全等直接返回不触发事件对传入值调用WrappedValue.unwrap解包写入新值调用notifyPropertyChange(name, newValue, oldValue)。notifyPropertyChange构造PropertyChangeData后交给notifyindex.tsnotify内部先补全data.object默认指向当前实例再按注册顺序调用监听器当没有任何静态全局事件处理器时走快速路径只遍历实例自身的监听列表index.ts。此外setProperty(name, value)是set的增强版本index.ts除了触发propertyChange它还会检查是否存在形如name Change的专属事件名例如ageChange并在存在监听器时额外触发适合需要属性专属回调的场景。进阶监听器管理与 WrappedValueon / off / once 与 thisArg 语义on(eventName, callback, thisArg?)与addEventListener等价off与removeEventListener等价index.ts。几个值得注意的行为重复注册去重同一事件名下注册相同的(callback, thisArg)组合会被忽略_indexOfListener检查index.ts监听器的身份由[eventName, callback, thisArg]三元组决定所有 falsy 的thisArg0、false、null、undefined、被视为同一身份而任意 truthythisArg相互区分——这一行为由test_Observable_identity完整覆盖observable-tests.ts。thisArg绑定非 falsy 的thisArg会作为回调执行时的this上下文index.ts。onceonce(eventName, callback)注册的监听器触发一次后自动移除index.ts递归触发与自我移除等边界场景由 index.spec.ts 的测试保障。批量移除off(eventName)不传 callback 时移除该事件名下全部监听器对应test_Observable_removeEventListener_SingleEvent_NoCallbackSpecifiedobservable-tests.ts传入 callback 与 thisArg 时可精确移除单个监听器。事件名不再支持逗号分隔多事件监听器已不再拆分propertyChange,tested这类复合事件名相关测试明确断言其已放弃支持见 observable-tests.ts。异常不会吞掉回调若返回 Promise其 rejection 会被显式打印到控制台避免异步错误被静默吞掉index.ts。注意Observable类上的静态事件 APIObservable.on、Observable.addEventListener等面向所有实例的全局处理器已标记deprecated将在未来版本移除index.ts新代码请一律使用实例方法。WrappedValue强制触发同对象变更默认情况下set对相同值会直接返回。但某些场景如数组原地push后重新赋同一引用确实需要发出通知此时使用WrappedValue包装即可绕过同值抑制index.tsimport { WrappedValue } from nativescript/core; let arr [1]; testObservable.set(property1, arr); arr.push(2); testObservable.set(property1, arr); // 不触发同一实例 testObservable.set(property1, WrappedValue.wrap(arr)); // 触发 propertyChange其原理是set内部用WrappedValue.unwrap解包后才比较与写入因此包装本身不会污染存储值get拿到的仍是原始数组测试见 observable-tests.ts。实现上WrappedValue使用一个长度为 5 的实例池循环复用_wrappedValues[_wrappedIndex % 5]避免频繁创建对象。在 UI 场景中的延伸可观察数组与数据绑定基础data/observable是整个 NativeScript 双向数据绑定的地基。在实际应用中Observable实例通常充当 ViewModel 挂在视图上例如apps/automated与apps/toolbox中页面 ViewModel 的基类视图通过{{ propertyName }}绑定表达式订阅propertyChange事件自动刷新。当数据是列表时应使用继承自Observable的ObservableArrayTpackages/core/data/observable-array/index.ts它在push、pop、splice、shift、unshift、setItem等变更后触发change事件并通过ChangedDataT携带actionadd | delete | update | splice、index、removed、addedCount等结构信息observable-array/index.ts供ListView等组件做增量刷新同时它还会在长度变化时额外触发length的propertyChange通知_notifyLengthChangeobservable-array/index.ts。测试验证与可运行性本文所有代码片段均来自仓库内可实际运行的测试observable-tests.ts 是apps/automatedNativeScript 自动化测试应用的一部分其中的test_Observable_Constructor、tests_DummyTestForCodeSnippet分别对应创建 Observable与响应属性变化两个片段并借助TKUnit.assert对返回值与事件载荷做了严格断言index.spec.ts 是核心包内的单元测试覆盖once、notify顺序、thisArg绑定、监听器自我移除以及静态全局事件处理器等行为。小结围绕data/observable这个最小却最核心的模块可以总结出三条实践准则创建用fromObject/fromObjectRecursive代替已废弃的new Observable({...})顶层属性即可观察嵌套对象按需递归变更属性赋值一律走set或直接赋值访问器属性相同值不触发事件需要强制通知时用WrappedValue监听用实例级on/off/once或addEventListener/removeEventListener订阅propertyChange注意thisArg对监听器身份的影响并避开已废弃的静态全局事件 API。掌握了这些你不仅能自如地写出响应式的 NativeScript 页面与 ViewModel也具备了阅读和调试其数据绑定源码的能力。更完整的 API 签名与最新行为可直接查阅 packages/core/data/observable/index.ts 及配套测试。赞分享【免费下载链接】NativeScript⚡ Write Native with TypeScript ✨ Best of all worlds (TypeScript, Swift, Objective C, Kotlin, Java, Dart). Use what you love ❤️ Angular, React, Solid, Svelte, Vue with: iOS (UIKit, SwiftUI), Android (View, Jetpack Compose), Flutter and you name it compatible.项目地址https://gitcode.com/gh_mirrors/na/NativeScript点击查看免费下载相关推荐NativeScript ObservableArray 完整实战指南从创建、变更事件到数组操作全解析NativeScript ObservableArray 完整实战指南从创建、变更事件到数组操作全解析 本文围绕 NativeScript 核心模块 nat详解RxBinding的Observable创建过程从View到事件流详解RxBinding的Observable创建过程从View到事件流 在Android开发中UI事件处理是核心环节之一。传统的监听器模式Listener移动开发异步编程RxLifecycle与LiveData响应式数据观察最佳实践RxLifecycle与LiveData响应式数据观察最佳实践 在Android应用开发中内存泄漏是常见问题尤其当使用RxJava等响应式编程库时未正确移动开发上一篇终极指南如何使用渔人的直感FF14钓鱼计时器提升你的钓鱼效率下一篇DBeaver终极驱动包一站式解决所有数据库连接问题 创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考