对于任何想要在阅读其余帖子之前立即尝试演示的人。
- Open Stackblitz Nativescript preview
- 下载nativescript预览应用程序:android ios
- 登录,扫描代码并享受
语境
表格总是很痛苦,尤其是当它们尺寸较大时。想一想在高度受监管的行业中,有很多步骤和几个复杂性。作为开发人员,我们一遍又一遍地编码不同的元素,并照顾所有依赖性。开发完成后,两个月过去了,需求会发生变化,而贫穷的开发人员需要访问代码基础,并(希望)重构以适应更改。形式越大,依赖性变得越复杂。依赖性变得越复杂,涉及的重构就越多。
此外,移动团队还需要与更改保持同步,这也可能导致进一步的分歧。
我们不要忘记,开发API层的团队。他们还需要能够通过验证等维护字段等。
如果有一种可以在所有团队中共享schema
的方法怎么办? ðÖ反映数据的模式,包括验证,可以照顾依赖关系,可以跨平台,可以与后端开发人员共享。
输入阿里巴巴的Formily,它确实做了上述。使用JSON模式,可以生成表单,同时控制数据模型。
官方:非常简短的描述
几个月前,我正式遇到了。它照顾了状态管理。
它不提供自己的组件库,而是提供 bridges ,您可以通过它连接组件库或自己的组件集。
作为蛋糕上的额外樱桃也提供:
- 可以复制模式的拖放设计师
- Web DevTools扩展程序能够调试。
- 几个组件库的包装器(元素UI,Ant Design,Vant,Semi等)
由于它是不可知论的,所以这是与Nativecript一起使用的理想选择。
入门
使用Nativescript团队与Stackblitz一起完成的惊人预览环境,是时候开始黑客入侵了。 (更多信息可以在https://preview.nativescript.org/上找到)
对于来自Web开发的人,NativeScript利用V8引擎直接与本机平台进行交互。这意味着基于您的移动开发专业知识,您可以:
- 写JavaScript,就好像您不知道基础平台一样。在这里,您可以选择您的味道,无论是反应,Vue Svelte,Vanilla。我的选择:绝对Vue
- 使用NativeScript SDK编写JavaScript以访问本地元素
- 写出反映平台SDK的JavaScript并将其编码为母语(Java/kotlin/objc/swift) 为了更好地解释这一点,请看一下this Youtube video by Nathan Walker
配置
我遇到的第一个打ic是,NativeScript正式支持Vue2(有一种使用DOMiNATIVE使用{n}运行vue3的方法,但这是另一个不同的主题)
正式,已经为此而征服了,但是它使用了一个称为vue-demi
的软件包。
这花了一段时间来整理和stackblitz工作,我必须使用npm vue-demi-switch 2 nativescript-vue
,根据文档用于:
a)指定版本
b)指定Vue的别名。
还使用
安装了构图API
import Vue from 'nativescript-vue';
import VueCompositionAPI from '@vue/composition-api';
Vue.use(VueCompositionAPI);
在页面中的下一个我遵循了formily
的设置
import { createForm } from "@formily/core";
import { createSchemaField } from "@formily/vue";
const { SchemaField } = createSchemaField({
components: {}
})
从我的理解中,createForm
负责数据方面和重新vitivitiy,而createSchemaField
则创建了一个支持一组桥接组件的VUE组件。它需要一个JSON模式,从中生成儿童组件。
复制了基本的JSON模式,给出了模板
<Form :form="form">
<SchemaField :schema="schema" />
</Form>
....并崩溃了。
由于正式是一个仍针对网络的框架,因此很明显,在某个时候将有一个<div/>
或<form/>
。目前,使用两个polyfills
解决了这一点
Vue.registerElement('div', () => StackLayout);
Vue.registerElement('form', () => StackLayout);
一旦完成,崩溃就停止了ð。
但是,到目前为止,还没有可见的组件。
创建桥梁。
到目前为止,SchemaField
没有注册组件。因此,现在该建造一些桥梁了。
正好为此提供了一个vue库。
这些桥梁由3个部分组成。
- 您的组件。在我的情况下,nativescript vue组件。
- 使用
@formily/vue
的connect
函数能够在格式中桥接您的组件具有的属性,属性,事件和儿童。通常,您还会使用mapProps
函数来在两侧之间映射。一个示例将是使用value
,但是Nativescript Textfield组件采用了称为text
的道具,因此我们映射了Props - 我说3?
这是一个简单的例子:
import { connect, mapProps, h } from '@formily/vue';
import { defineComponent } from 'vue-demi';
let input = defineComponent({
name: 'FormilyTextField',
props: {},
setup(customProps: any, { attrs, slots, listeners }) {
return () => {
return h(
'TextField',
{
attrs,
on: listeners,
},
slots
);
};
},
});
const Input = connect(input);
在上面的示例中可以看到vue-demi用于定义组件,并且nativescript TextField
组件被桥接起来。
目前,我已经构建了以下组件列表。 (没有像官方包装纸那样详尽无遗的。
使用NativeScript本地组件
- textfield-可以通过调整一些道具 来映射到
- 开关
- datepicker
- timepicker
- listPicker-可以映射到
Select
Input
Textarea
Password
Number
为了测试JSON模式,组件已在Schemafield和LO上注册,并观察到Magic我们拥有JSON模式形式! ð
创建装饰师ð
在正式的情况下,在输入和装饰的组件之间存在明显的分配。强烈指示的基本组件是FormItem
,它照顾了:
- 标签
- 任何描述
- 任何反馈(错误消息等)
- 任何工具提示
由于这在NativeScript中不存在,因此再次创建了初始版本。
这次,需要创建要桥接的组件。
<template>
<StackLayout
:style="wrapperStyle"
:class="wrapperClass"
:orientation="layout"
verticalAlignment="top"
>
<GridLayout columns="*,40" rows="auto" class="w-full items-center">
<Label
:text="`${label}${asterisk && required ? '*' : ''}`"
:style="labelStyle"
verticalAlignment="center"
class="text-lg font-semibold"
:class="labelClass"
:textWrap="labelWrap"
v-if="label"
/>
<Label
v-if="tooltip"
@tap="showTooltip"
col="2"
class="bg-gray-100 rounded-full w-7 h-7 text-center text-xl"
text="ℹ"
horizontalAlignment="right"
/>
</GridLayout>
<GridLayout rows="auto">
<slot></slot>
<!-- slot outlet -->
</GridLayout>
<Label v-if="feedbackText" :text="feedbackText" :class="feedbackClass" />
</StackLayout>
</template>
<script lang="ts">
import { defineComponent } from "vue-demi";
import Vue from "nativescript-vue";
import BottomSheetView from "~/component/BottomSheet/BottomSheetView.vue";
import { OpenRootLayout } from "~/component/OpenRootLayout";
export default defineComponent({
name: "FormItem",
props: {
required: {
type: Boolean,
},
label: {
type: String,
},
labelStyle: {},
labelClass: {},
labelWrap: {
type: Boolean,
default: false,
},
layout: {
type: String,
default: "vertical",
},
tooltip: {},
wrapperStyle: {},
wrapperClass: {},
feedbackText: {},
feedbackStatus: {
type: String,
enum: ["error", "success", "warning"],
}, // error/success/warning
asterisk: {
type: Boolean,
},
gridSpan: {},
},
computed: {
feedbackClass(): string {
switch (this.feedbackStatus) {
case "error":
return "text-red-400";
case "success":
return "text-green-400";
case "warning":
return "text-yellow-400";
default:
return "text-gray-100";
}
},
},
methods: {
showTooltip() {
let tooltipText = this.tooltip;
const view = new Vue({
render: (h) =>
h(BottomSheetView, { props: { label: "Information" } }, [
h("Label", {
attrs: { text: tooltipText, textWrap: true, row: 2 },
class: "w-full text-lg mb-8 leading-tight",
}),
]),
}).$mount().nativeView;
OpenRootLayout(view);
},
},
});
</script>
nativecript在此提供了Web开发人员使用的所有正常VUE功能。有一个微妙的差异:没有HTML属性。但是,在这方面,人们可以轻松地将知识从HTML转移到NativeScript。
-
StackLayout
-让您垂直或水平堆叠孩子 -
GridLayout
-是一个布局容器,可让您以桌子般的方式排列其子元素。网格由行,列和单元组成。单元可以跨越一个或多个行和一个或多个列。它可以包含多个子元素,这些元素可以跨越多行和列,甚至相互重叠。默认情况下,有一列和一行。 -
Label
-持有一些文字
风格的明智之举,因为人们可以轻松地看到正在使用尾风效用课程。
到目前为止,道具公开了必要的功能。
该组件目前有一种方法,即生成工具提示。在这方面,我们可以利用NativeScript提供的另一个布局容器:根布局
rootlayout
<RootLayout> is a layout container designed to be used as the primary root layout container for your app with a built in api to easily control dynamic view layers. It extends a GridLayout so has all the features of a grid but enhanced with additional apis.
是文档给出的定义。
用更谦虚的话来说,想一想这种布局可以在其他所有内容上打开任何组件。这对于底部纸,像模态这样的组件,侧菜单非常好。让您的想象力在这里松动。
使其与NativeScript Vue一起工作。
- 我创建了一个vue组件
- 我安装了视图组件
- 我称之为辅助功能,该函数召唤了rootlayout,并告诉它打开此组件。 这个辅助功能无非是
getRootLayout().open(myComponent, ...some overlay settings like color and opacity, ...some animation setting)
完成桥梁
在此阶段,我们有一个由JSON模式生成的函数形式。但是,数据尚未正确反映。
为什么?
原因很简单,正式希望在change
事件中从组件中收回这些信息。
深入挖掘其元素UI包装器,他们使用VUE-DEMI转换任何组件,以便将Web输入函数映射到此更改事件。
一个问题。
vue不支持input
事件或change
事件。因此,根据组件事件将听众介绍给桥梁(例如:Textfield具有textChanged
)。反过来,此组件特定事件又发出了一个合并事件input
,其中包括组件的值。
这立即将完全反应性归还回到官方。
演示时间
在进行快速动画GIF演示之前。这是使用的演示JSON定义:
{
type: "object",
properties: {
firstName: {
type: "string",
title: "Test2",
required: true,
"x-component": "Input",
"x-component-props": {
hint: "First Name",
},
},
lastName: {
type: "string",
"x-component-props": {
hint: "Last Name",
},
required: true,
"x-component": "Input",
},
username: {
type: "string",
title: "Username",
required: true,
"x-decorator": "FormItem",
"x-component": "Input",
"x-component-props": {
hint: "@ChuckNorris...",
disabled: true,
},
"x-decorator-props": {
tooltip: "Lorem ipsum test a tooltip sheet with some text here.",
},
"x-reactions": {
dependencies: ["firstName", "lastName"],
fulfill: {
state: {
value:
"{{$deps[0] ? `@${$deps[0]}${($deps[1] ? '.' + $deps[1] : '')}` : undefined}}",
},
},
},
},
password: {
type: "string",
title: "Password",
required: true,
"x-decorator": "FormItem",
"x-component": "Password",
pattern: '/^(?=.*[0-9])(?=.*[!@#$%^&*])[a-zA-Z0-9!@#$%^&*]{6,16}$/'
},
testSwitch: {
type: "string",
title: "Rememeber me?",
required: true,
"x-decorator": "FormItem",
"x-component": "Switch",
},
from: {
type: "string",
title: "Appointment Date",
required: true,
"x-decorator": "FormItem",
"x-component": "DatePicker",
},
time: {
type: "string",
title: "Appointment Time",
required: true,
"x-decorator": "FormItem",
"x-component": "TimePicker",
},
country: {
type: "string",
title: "Country",
required: true,
"x-decorator": "FormItem",
"x-component": "Select",
enum: [{
label: "?? Canada",
value: "CA"
},{
label: "?? United Kingdom",
value: "UK"
},{
label: "?? United States",
value: "Us"
}]
},
},
},
}
这是此模式上的一些指示:
- 最终数据对象将拥有的每个嵌套对象(例如
firstName
,lastName
等)的关键。 -
x-component
指示要使用的组件 -
x-decorator
指示输入组件周围的装饰 - 一些基本验证,例如
required
,pattern
作为顶级。其中包括minimum
,maximum
,但还可以包括自定义验证器,包括异步验证 - 一个字段的任何键都可以用
{{}}
写为JSX。这有可能在模式中包括一些逻辑。 -
在用户名段下发现的
x-reactions
会照顾两个依赖项:firstName
和lastName
,并通过根据依赖项调整值来实现反应。官方支持两种类型的反应- 活动:含义当前的活动组件,在另一个组件中更改某些内容
- 反应性:一个组件会倾听到另一个组件的变化。
- 组件和装饰师可以分别使用
x-component-props
和x-decorator-props
接收其他道具。
这是该应用程序的快速屏幕抓取:
包装
可以在以下存储库中找到完整的代码,并且可以使用Stackblitz Preview和NativeScript Preview Application
轻松测试。