代码共享一直是 NativeScript 的强项,毕竟它只是 JavaScript。这也是一个永远令人着迷和兴奋的话题,因为有许多有效的策略可以与 NativeScript 共享代码。
以下文章由才华横溢的开发人员 Mahmoud Abduljawad 撰写,对这个有趣的话题提供了另一种视角。你可以从以下平台了解到更多关于 Mahmoud 的信息:
文章内容也可以在 dev.to 找到。
使用 Angular 和 NativeScript 在 Web、Android 和 iOS 上运行单个代码库。
最近使用 Flutter 的经历让我对 Web 和移动端代码共享充满热情。Flutter 团队对此做出了雄心勃勃的承诺,但从我自己的角度来看,这似乎还需要一年的时间。我最终回到了 NativeScript,我已经使用它三年来开发移动应用程序,并开始思考如何在 Web 和移动端实现终极代码共享状态。
共享单个代码库的挑战在于每个平台都拥有不同的机制。在 NativeScript、React Native 或 Xamarin 等混合框架中,很容易发现此类问题,你可能最终需要根据平台添加条件代码。将所有不同的底层结构(从移动 API 到 Web API)统一起来,也是一项艰巨的任务。
当我查看一个按照 NativeScript 自身指南 创建的新项目时,它已经是 Web 和移动端代码共享的绝佳路径,但我仍然对分离的模板文件感到困扰。对于那些不熟悉的人来说,NativeScript 使用 MVVM 结构,其中模板与代码隔离。我更喜欢这种方法,而不是 React(或 Flutter),在 React 中,一切都汇聚在一个意大利面条式的代码中(仅代表个人意见)。当我查看移动端的模板文件(一种 XAML 的变体)和 Web 端的模板文件(一个基本的 HTML Angular 模板)时,我产生了一个想法:如果我能使用单一的模板语言来同时处理 Web 和移动端!幸运的是,Angular 一直在结构上帮助我构建概念验证。我开始为以下元素构建组件:
这项工作非常基础,我只是在以下元素中添加了一些 Input
和 Output
属性来与 XAML 组件进行交互:
@Component({
selector: 'Label',
template: `{{ text }}`,
})
export class XAMLLabel {
@Input('text') text: string = '';
}
@Component({
selector: 'Button',
template: `{{ text }}`,
})
export class XAMLButton {
@Input('text') text: string = '';
@Output('tap') tap: EventEmitter<any> = new EventEmitter<any>();
@HostListener('click', ['$event']) onTap($event) {
if (this.tap.observers.length > 0) {
this.tap.next($event);
}
}
}
@Component({
selector: 'Image',
template: `
<img [src]="_src" [attr.async]="(loadMode == 'async') ? 'on' : 'off'">
`,
})
export class XAMLImage {
_src: string = '';
@Input('src')
set src(v: string) {
try {
if (v[0] == '~') {
this._src = v.slice(2);
} else {
this._src = v;
}
} catch (error) {
}
}
@Input('loadMode') loadMode: 'async' | 'sync' = 'async';
}
这在 Angular 中非常基础,我只需要添加一些 Input
和 Output
属性来与 XAML 组件交互。我创建了一个 XAMLModule
,它只在 Web 应用程序中导入,而不是在移动端导入,而且令人高兴的是,我有一个展示 Web 和移动端代码共享的概念验证。
取得了小小的成功后,我开始实现更多组件。我添加了 StackLayout
和 GridLayout
,顾名思义,它们是 XAML 中的布局元素。由于我是 Bootstrap 的粉丝,经常使用它,所以我决定在 Bootstrap 框架的基础上构建布局元素,并且确实有效。我不得不引入一些重大更改和替代用法,以便元素在 Web 上的行为与移动端一致。也就是说,这并不是一条特别棘手的道路,但我最终用纯 CSS 网格方法构建了大部分工作。此时,我的概念验证已经开始成形--我的 Pokédex 应用程序正逐渐成为一个在 Web 和移动端都能运行的应用程序。我一直用 Pokédex 应用程序作为概念验证,因为它可以让我摆脱提出想法的痛苦,同时还可以享受再次看到我童年的宠物的乐趣。
在页面(或屏幕)级别,我总共编写了 321 行代码,跨越模板和代码。其中 17 行(或 5.2%)是 Web 特定的,12 行(或 3.7%)是移动端特定的!这意味着应用程序页面之间高达 96.3% 的代码共享。这对我来说是一个非常惊人的结果!
除了这篇文章的封面图片,这里还有两个屏幕截图:
除了跨 Web 和移动端共享代码库之外,我还实现了一些事件处理流程,以及 CSS 网格值的动态生成,这使我能够使用相同的 XAML 模板为 Web 创建响应式布局。
我惊讶于自己在两周内就能取得这样的成果。原因是,如果可行,为什么不呢!用 Flutter 为 Web 构建的应用程序的 SEO 评级是 O(1) 的。当我开始使用 Flutter 时,这确实让我担心。这个项目在 Web 上的结果远远好于我在 Flutter 中能达到的任何结果,这让我有了最终的想法,那就是将这个项目作为基线,开始更广泛地尝试构建一个完整的方案,让开发人员能够更轻松地在 Web 和移动端共享代码。
目前,你可以自己查看该项目的成果:
https://mahmoudajawad.github.io/nativescript-pokedex/dist/nativescript-pokedex/
你也可以查看完整的源代码: