npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

zerl

v0.4.0

Published

云原生全栈技术框架

Downloads

231

Readme

ZERL 云原生全栈技术框架开发指南

简介

一条来自 MVVM 江湖的传说:

武林至尊,宝刀 React

Vue 不出,谁与争锋。

天下武功,无坚不摧,唯 Solid 不破。

什么是 ZERL ?

  • ZERL 是基于 Solid.js MVVM 框架打造的全栈技术开发框架。

  • ZERL 全面采用 Typescript 进行开发,Typescript 能提供更良好的协作体验,提供实时的代码校验,实现更高质量的交付。

  • ZERL 将更深层次地诠释全栈技术。全栈,一般定义是对工程师技术能力的泛指。是一个组织开发成本控制的有效手段。因此全栈是个人能力的追求,也是组织发展的需要。


ZERL 对全栈实现作出了以下的尝试:

  • 保留了 MVVM 框架的优势,并非只是实现了 SSR
  • 实现了技术栈的统一,而非简单的语言统一或交互标准统一
  • 提供了简便的工程构建和发布部署工具包
  • 构建了云原生开发模式,客户端可直接导入服务端模块并在客户端使用,无需实现 api

开始使用

创建应用

$ npx zerli@latest create zerlapp
或
$ npx zerli@latest -c zerlapp

开发

  • 运行开发环境
$ cd zerlapp
$ npx zerli@latest
或
$ npm run dev

UI 模块开发

规范

UI 模块运行于浏览器上,开发规范及安全性要求须符合 W3C 标准。

ZERL 所有 UI 组件构建于 solid.js 的 MVVM 框架之上,zerl 的所有组件完全兼容 solid.js 所提供的 API。了解 solid.js API 请前往solidjs.com

UI 模块 API
// 导入ZERL API
import { Button } from 'zerl'
// 导入SolidJS API
import { createSignal, createMemo } from 'zerl'

服务模块开发

规范

服务模块运行于服务容器内,负责数据的存储与处理。服务模块使用 Node.JS 为运行时核心,因此可调用 Node.JS 的一切接口。了解 Node.JS API 前往nodejs.org

服务模块由逻辑组件和任务组件构成。

逻辑组件实现与 UI 组件或其他客户端进行数据通信,文件命名规则为:[组件名称].mod.ts。

任务组件在应用启动时触运行,可用于数据初始化、定时任务或启动自定义实例等场景应用,文件命名规则为:[组件名称].job.ts。

服务模块 API
// 导入ZERL API
import { Expose } from 'zerl'

封装

$ npx zerli build@latest
或
$ npm run build
  • 运行 Build 命令后根据运行需求选择相应提示的封装选项即可,封装后把生成的运行文件上传到服务器,直接运行即可。

  • 支持 x64 与 arm64 架构的运行文件封装,不支持交叉编译。生成 x64 运行文件须在 x64cpu 的计算机上进行封装,生成 arm64 运行文件须在 arm64cpu 的计算机上进行封装。


部署

  • Linux 部署环境下实现非阻塞式启动
  1. 使用 vi/vim/nano 或其他编辑工具创建 run.sh 文件
  2. 粘贴以下内容并修改应用程序名称进行保存
  3. 运行./run.sh 即可
log="`date +%Y%m%d%H%M%S`.log"
killall zerlapp*
nohup ./zerlapp-linux > $log 2& > &1 &
  • Docker

应用在封装时,自动检测有否安装 docker,如有安装则会出现 docker 生成镜像的选项,打包后会在本地生成 docker 镜像。


配置

  • 在工程目录(src)内创建工程配置文件(非必要),命名为 application.yml
  • 配置文格式如下:
# app名称
name: your_app_name
# 程序源码目录
root: ./src
# 服务端口
port: 8080
# MySQL数据库连接设置
mysql:
  ### 最大连接数
  connectionLimit: 200
  ### 数据库地址
  host: localhost
  ### 数据库访问端口
  port: 3306
  ### 数据库登录用户名
  user: root
  ### 数据库登录密码
  password: '123456'
  ### 数据库名称
  database: mysql
# Redis连接设置
redis:
  ## 数据库地址
  host: localhost
  ## 数据库访问端口
  port: 6379
  ## 数据库登录密码
  password: '123456'

UI 组件

布局

导入组件

import { Col, Row, Line } from 'zerl'

水平布局组件(Row)

左上角对齐
<Row>
	<div class={styles.block} style={{ height: '50px' }}></div>
	<div class={styles.block} style={{ height: '100px' }}></div>
	<div class={styles.block} style={{ height: '150px' }}></div>
</Row>
左对齐垂直居中
<Row middle class='fill'>
	<div class={styles.block} style={{ height: '50px' }}></div>
	<div class={styles.block} style={{ height: '100px' }}></div>
	<div class={styles.block} style={{ height: '150px' }}></div>
</Row>
左下角对齐
<Row bottom class='fill'>
	<div class={styles.block} style={{ height: '50px' }}></div>
	<div class={styles.block} style={{ height: '100px' }}></div>
	<div class={styles.block} style={{ height: '150px' }}></div>
</Row>
完全居中
<Row center class='fill'>
	<div class={styles.block} style={{ height: '50px' }}></div>
	<div class={styles.block} style={{ height: '100px' }}></div>
	<div class={styles.block} style={{ height: '150px' }}></div>
</Row>
靠顶部水平居中
<Row top center class='fill'>
	<div class={styles.block} style={{ height: '50px' }}></div>
	<div class={styles.block} style={{ height: '100px' }}></div>
	<div class={styles.block} style={{ height: '150px' }}></div>
</Row>
靠底部水平居中
<Row bottom center class='fill'>
	<div class={styles.block} style={{ height: '50px' }}></div>
	<div class={styles.block} style={{ height: '100px' }}></div>
	<div class={styles.block} style={{ height: '150px' }}></div>
</Row>
右上角对齐
<Row right class='fill'>
	<div class={styles.block} style={{ height: '50px' }}></div>
	<div class={styles.block} style={{ height: '100px' }}></div>
	<div class={styles.block} style={{ height: '150px' }}></div>
</Row>
右对齐垂直居中
<Row right middle class='fill'>
	<div class={styles.block} style={{ height: '50px' }}></div>
	<div class={styles.block} style={{ height: '100px' }}></div>
	<div class={styles.block} style={{ height: '150px' }}></div>
</Row>
右下角对齐
<Row right bottom class='fill'>
	<div class={styles.block} style={{ height: '50px' }}></div>
	<div class={styles.block} style={{ height: '100px' }}></div>
	<div class={styles.block} style={{ height: '150px' }}></div>
</Row>
属性说明

垂直布局组件(Col)

左上角对齐
<Col class='fill' style={{ 'min-height': '300px' }}>
	<div class={styles.block} style={{ width: '50px' }}></div>
	<div class={styles.block} style={{ width: '100px' }}></div>
	<div class={styles.block} style={{ width: '150px' }}></div>
</Col>
靠左居中
<Col middle class='fill' style={{ 'min-height': '300px' }}>
	<div class={styles.block} style={{ width: '50px' }}></div>
	<div class={styles.block} style={{ width: '100px' }}></div>
	<div class={styles.block} style={{ width: '150px' }}></div>
</Col>
左下角对齐
<Col bottom class='fill'>
	<div class={styles.block} style={{ height: '50px' }}></div>
	<div class={styles.block} style={{ height: '100px' }}></div>
	<div class={styles.block} style={{ height: '150px' }}></div>
</Col>
完全居中
<Col center class='fill'>
	<div class={styles.block} style={{ height: '50px' }}></div>
	<div class={styles.block} style={{ height: '100px' }}></div>
	<div class={styles.block} style={{ height: '150px' }}></div>
</Col>
靠顶部水平居中
<Col top center class='fill'>
	<div class={styles.block} style={{ height: '50px' }}></div>
	<div class={styles.block} style={{ height: '100px' }}></div>
	<div class={styles.block} style={{ height: '150px' }}></div>
</Col>
靠底部水平居中
<Col bottom center class='fill'>
	<div class={styles.block} style={{ height: '50px' }}></div>
	<div class={styles.block} style={{ height: '100px' }}></div>
	<div class={styles.block} style={{ height: '150px' }}></div>
</Col>
右上角对齐
<Col right class='fill'>
	<div class={styles.block} style={{ height: '50px' }}></div>
	<div class={styles.block} style={{ height: '100px' }}></div>
	<div class={styles.block} style={{ height: '150px' }}></div>
</Col>
右对齐垂直居中
<Col right middle class='fill'>
	<div class={styles.block} style={{ height: '50px' }}></div>
	<div class={styles.block} style={{ height: '100px' }}></div>
	<div class={styles.block} style={{ height: '150px' }}></div>
</Col>
右下角对齐
<Col right bottom class='fill'>
	<div class={styles.block} style={{ height: '50px' }}></div>
	<div class={styles.block} style={{ height: '100px' }}></div>
	<div class={styles.block} style={{ height: '150px' }}></div>
</Col>
属性说明

分割线

水平分割线
<Line style={{ width: '400px' }} />
垂直分割线
<Line vertical style={{ height: '50px' }} />
属性说明

路由

导入组件

import { Route, Navigate } from 'zerl'
import Home from './page/home.tsx'

视图加载

同步加载
<div class="main">
  <Route default="/home" routers={import.meta.globEager("./pages/**/*.tsx")}/>
</div>
异步加载
<div class="main">
  <Route default="/home" routers={import.meta.glob("./pages/**/*.tsx")}/>
</div>
自定义加载
<div class="main">
  <Route routers={{"/": Home,"/about": () => lazy(import("./pages/about.tsx"))}}/>
</div>

导航

菜单导航
<Menu width={200} theme="simple">
  <Group name="功能组">
    <Item route="/main">
      功能
    </Item>
  </Group>
</Menu>
脚本导航
Navigate('/main')

属性说明


按钮

导入组件

import { Button } from 'zerl'

普通按钮

<Button>普通按钮</Button>

缩小设置

小号
<Button mini>小号按钮</Button>
超小号
<Button tiny>超小号按钮</Button>

状态设置

成功状态
<Button success>成功状态</Button>
<Button success mini>成功状态</Button>
<Button success tiny>成功状态</Button>
警告状态
<Button warning>警告状态</Button>
<Button warning mini>警告状态</Button>
<Button warning tiny>警告状态</Button>
危险状态
<Button danger>危险状态</Button>
<Button danger mini>危险状态</Button>
<Button danger tiny>危险状态</Button>
信息状态
<Button info>信息状态</Button>
<Button info mini>信息状态</Button>
<Button info tiny>信息状态</Button>
简单状态
<Button simple>简单状态</Button>
<Button simple mini>简单状态</Button>
<Button simple tiny>简单状态</Button>

形状设置

圆角
<Button rounded>圆角按钮</Button>
<Button rounded mini>圆角按钮</Button>
<Button rounded tiny>圆角按钮</Button>
圆形
<Button circle>圆</Button>
<Button circle mini>圆</Button>
<Button circle tiny>圆</Button>
方形
<Button square>方</Button>
<Button square mini>方</Button>
<Button square tiny>方</Button>

明亮模式

<Button lighten>明亮模式</Button>
<Button lighten success>明亮模式</Button>
<Button lighten warning>明亮模式</Button>
<Button lighten danger>明亮模式</Button>
<Button lighten info>明亮模式</Button>

属性说明


单选

导入组件

import { createSignal, createMemo, Button, Option } from 'zerl'

定义变量

const [getRadioValue1, setRadioValue1] = createSignal(0)
const [getRadioValue2, setRadioValue2] = createSignal(1)
const getRadioValue3 = createMemo(() => 2)

水平排列

<Button name='radio1' type='radio' value={getRadioValue1()} onChange={value => setRadioValue1(value)}>
  <Option name='优秀' value={0} />
  <Option name='良好' value={1} />
  <Option name='一般' value={2} />
  <Option name='差' value={3} />
</Button>

垂直排列

<Button name='radio2' vertical type='radio' value={getRadioValue2()} onChange={value => setRadioValue2(value)}>
  <Option name='优秀' value={0} />
  <Option name='良好' value={1} />
  <Option name='一般' value={2} />
  <Option name='差' value={3} />
</Button>

只读模式

<Button readonly name='radio3' type='radio' value={getRadioValue3()}>
  <Option name='优秀' value={0} />
  <Option name='良好' value={1} />
  <Option name='一般' value={2} />
  <Option name='差' value={3} />
</Button>

属性说明


多选

导入组件

import { createSignal, createMemo, Button, Option } from 'zerl'

定义变量

const [getCheckValue1, setCheckValue1] = createSignal([0])
const [getCheckValue2, setCheckValue2] = createSignal([1])
const getCheckValue3 = createMemo(() => [0, 2])

水平排列

<Button name='check1' type='check' value={getCheckValue1()} onChange={value => setCheckValue1(value)}>
  <Option name='优秀' value={0} />
  <Option name='良好' value={1} />
  <Option name='一般' value={2} />
  <Option name='差' value={3} />
</Button>

垂直排列

<Button name='check2' vertical type='check' value={getCheckValue2()} onChange={value => setCheckValue2(value)}>
  <Option name='优秀' value={0} />
  <Option name='良好' value={1} />
  <Option name='一般' value={2} />
  <Option name='差' value={3} />
</Button>

只读模式

<Button readonly name='check3' type='check' value={getCheckValue3()}>
  <Option name='优秀' value={0} />
  <Option name='良好' value={1} />
  <Option name='一般' value={2} />
  <Option name='差' value={3} />
</Button>

属性说明


提示

导入组件

import { Alert } from 'zerl'

简单的提示

Alert('这是一个提示')

提示样式

Alert('这是一个成功样式的提示', { type: 'success' })

Alert('这是一个警告样式的提示', { type: 'warning' })

Alert('这是一个危险样式的提示', { type: 'danger' })

Alert('这是一个信息样式的提示', { type: 'info' })

提示方向

Alert('这是一个上方弹出的提示', { direction: 'ttb' })

Alert('这是一个下方弹出的提示', { direction: 'btt' })

Alert('这是一个右上方弹出的提示', { direction: 'rttl' })

Alert('这是一个右下方弹出的提示', { direction: 'rbtt' })

自动关闭

Alert('这是一个自动关闭的提示', { delay: 2 })

深色模式

Alert('这是一个深色模式的提示', { mode: 'darken' })

参数说明

options 参数说明


确认

导入组件

import { Confirm } from 'zerl'

组件使用

async function() {
	const res = await Confirm('确认提醒信息', () => (
		<div>
			<h3>提示信息</h3>
			<span>这是一条提示信息</span>
		</div>
	))
}

参数说明

返回值说明


输入

导入组件

import { createSignal, createMemo, Text } from 'zerl'

定义变量

const [getInputValue, setInputValue] = createSignal('')
const [getDateValue, setDateValue] = createSignal(new Date())
const [getDateRangeValue, setDateRangeValue] = createSignal([])
const getValue = createMemo(() => 'readonly')

普通输入框

<Text placeholder='这是一个普通的输入框' value={getInputValue1()} onInput={e => setInputValue(e)} />

数字输入

<Text type='digit' placeholder='这是一个只能输入数字的输入框' value={getInputValue()} onInput={e => setInputValue(e)} />

密码输入

<Text type='password' placeholder='这是一个密码输入框'value={getInputValue()} onInput={e => setInputValue(e)}/>

只读模式

<Text readonly value={getValue()} />

多行输入

多行输入框
<Text type='multi' placeholder='这是一个普通的多行输入框' value={getInputValue()} onInput={e => setInputValue(e)}/>
设置行数
<Text type='multi' rows={10} placeholder='这是一个设置高度为10行的多行输入框' value={getInputValue()} onInput={e => setInputValue(e)}/>
富文本编辑器
<Text type='rich' value={getInputValue()} onInput={e => setInputValue(e)} placeholder='这是一个富文本编辑器' style={{ height: '300px' }}/>

日期时间输入

日期输入框
<Text type='date' placeholder='这是一个日期组件' value={getDateValue()} onInput={e => setDateValue(new Date(e))}/>
日期范围输入框
<Text type='daterange' placeholder='这是一个日期范围组件' value={getDateRangeValue()} onInput={([a, b]) => setDateRangeValue([new Date(a), b ? new Date(b) : null])}/>
时间输入框
<Text type='time' placeholder='这是一个时间组件' value={getDateValue()} onInput={e => setDateValue(new Date(e))}/>
日期时间输入框
<Text type='datetime'placeholder='这是一个日期时间组件' value={getDateValue9()} onInput={e => setDateValue(new Date(e))}/>
日期时间范围输入框
<Text type='datetimerange' placeholder='这是一个日期时间范围组件' value={getDateRangeValue()} onInput={([a, b]) => setDateRangeValue([new Date(a), b ? new Date(b) : null])}/>

属性说明


下拉

导入组件

import { Picker, Option, createSignal } from 'zerl'

定义变量

const [getSingleValue, setSingleValue] = createSignal()
const [getMultiValue, setMultiValue] = createSignal([])

单选框

 <Picker placeholder='这是一个单选下拉组件' value={getSingleValue()} onSelected={e => { setSingleValue(e) }}>
  <Option name='红色' value='Red' />
  <Option name='黄色' value='Yellow' />
  <Option name='蓝色' value='Blue' />
  <Option name='白色' value='White' />
  <Option name='黑色' value='Black' />
</Picker>
只读
<Picker readonly placeholder='这是一个单选下拉组件' value={getSingleValue()} onSelected={e => { setSingleValue(e) }}>
  <Option name='红色' value='Red' />
  <Option name='黄色' value='Yellow' />
  <Option name='蓝色' value='Blue' />
  <Option name='白色' value='White' />
  <Option name='黑色' value='Black' />
</Picker>
搜索
<Picker max={3} placeholder='这是一个单选下拉组件' value={getSingleValue()} onSelected={e => { setSingleValue(e) }}>
  <Option name='红色' value='Red' />
  <Option name='黄色' value='Yellow' />
  <Option name='蓝色' value='Blue' />
  <Option name='白色' value='White' />
  <Option name='黑色' value='Black' />
</Picker>

多选框

<Picker multi placeholder='这是一个多选下拉组件' value={getMultiValue2()} onSelected={e => {setMultiValue2(e) }}>
  <Option name='红色' value='Red' />
  <Option name='黄色' value='Yellow' />
  <Option name='蓝色' value='Blue' />
  <Option name='白色' value='White' />
  <Option name='黑色' value='Black' />
  <Option name='青色' value='Cyan' />
  <Option name='紫色' value='Purple' />
</Picker>
只读
<Picker multi readonly placeholder='这是一个多选下拉组件' value={getMultiValue2()} onSelected={e => {setMultiValue2(e) }}>
  <Option name='红色' value='Red' />
  <Option name='黄色' value='Yellow' />
  <Option name='蓝色' value='Blue' />
  <Option name='白色' value='White' />
  <Option name='黑色' value='Black' />
  <Option name='青色' value='Cyan' />
  <Option name='紫色' value='Purple' />
</Picker>
搜索
<Picker multi max={3} placeholder='这是一个多选下拉组件' value={getMultiValue2()} onSelected={e => {setMultiValue2(e) }}>
  <Option name='红色' value='Red' />
  <Option name='黄色' value='Yellow' />
  <Option name='蓝色' value='Blue' />
  <Option name='白色' value='White' />
  <Option name='黑色' value='Black' />
  <Option name='青色' value='Cyan' />
  <Option name='紫色' value='Purple' />
</Picker>

属性说明


表格

导入组件

import { createSignal, createMemo, Table, Meta } from 'zerl'

数据定义

const data = [
	{
		module: '用户管理',
		name: '用户信息',
		type: 'ILF',
		fp: 10,
		degree: '高'
	},
	{
		module: '用户管理',
		name: '添加、修改用户信息',
		type: 'EI',
		fp: 4,
		degree: '高'
	},
	{
		module: '用户管理',
		name: '删除用户信息',
		type: 'EI',
		fp: 4,
		degree: '高'
	},
	{
		module: '用户管理',
		name: '用户信息列表、条件筛选',
		type: 'EQ',
		fp: 4,
		degree: '高'
	},
	{
		module: '用户管理',
		name: '用户详细信息',
		type: 'EQ',
		fp: 4,
		degree: '高'
	}
]

基本表格

<Table dataset={data}>
  <Meta name='模块' key='module' />
  <Meta name='功能点名称' key='name' />
  <Meta name='功能点类型' key='type' />
  <Meta name='UFP' key='fp' />
  <Meta name='重用度' key='degree' />
</Table>

列属性设置

<Table dataset={data} width='700'>
  <Meta name='模块' key='module' width='100' align='center' />
  <Meta name='功能点名称' key='name' align='center' />
  <Meta name='功能点类型' key='type' width='100' align='center' />
  <Meta name='UFP' key='fp' width='100' align='center' />
  <Meta name='重用度' key='degree' width='100' align='center' />
</Table>

定义单元格数据

<Table dataset={data}>
	<Meta name='序号' width='50' align='center'>
		{(_, index) => index + 1}
	</Meta>
	<Meta name='模块' key='module' width='100' align='center' />
	<Meta name='功能点名称' key='name' align='center' />
	<Meta name='功能点类型' key='type' width='100' align='center' />
	<Meta name='UFP' key='fp' width='100' align='center' />
	<Meta name='重用度' key='degree' width='100' align='center' />
	<Meta name='费用(元)' width='120' align='center'>
		{(item) => {
			return (
				(20000 *
					item.fp *
					1.21 *
					(item.degree === '高' ? 1 / 3 : item.degree === '中' ? 2 / 3 : 1) *
					7.19) /
				174
			).toFixed(2)
		}}
	</Meta>
</Table>

紧凑模式

<Table dataset={data} slim>
  <Meta name='模块' key='module' width='100' align='center' />
  <Meta name='功能点名称' key='name' align='center' />
  <Meta name='功能点类型' key='type' width='100' align='center' />
  <Meta name='UFP' key='fp' width='100' align='center' />
  <Meta name='重用度' key='degree' width='100' align='center' />
</Table>

主题

深色
<Table dataset={data} theme='darken'>
  <Meta name='模块' key='module' width='100' align='center' />
  <Meta name='功能点名称' key='name' align='center' />
  <Meta name='功能点类型' key='type' width='100' align='center' />
  <Meta name='UFP' key='fp' width='100' align='center' />
  <Meta name='重用度' key='degree' width='100' align='center' />
</Table>
浅色
<Table dataset={data} theme='lighten'>
  <Meta name='模块' key='module' width='100' align='center' />
  <Meta name='功能点名称' key='name' align='center' />
  <Meta name='功能点类型' key='type' width='100' align='center' />
  <Meta name='UFP' key='fp' width='100' align='center' />
  <Meta name='重用度' key='degree' width='100' align='center' />
</Table>

属性说明


分页

导入组件

import { Pagi, PagiHandler } from 'zerl'

组件使用

let pagi: PagiHandler

const pageChange = (page) => dataloader(page)

const setLength = () => pagi.setLength
<Pagi ref={ (handler::PagiHandler) => pagi = handler} onClick={ (page:Number) => pageChange(page)}/>

属性说明


对话框

导入组件

import { Dialog } from 'zerl'

数据定义

const title = () => (
	<div>
		这里设置<span style={{ color: '#857' }}>标题</span>
	</div>
)
const content = () => <div>这里设置对话框内容</div>

普通对话框

const dialog = Dialog({ content })
dialog.open() //打开对话框

设置对话框标题

const dialog = Dialog({ title, content })
dialog.open() //打开对话框

设置对话框尺寸

const dialog = Dialog({ title, content, width: 500, height: 300 })
dialog.open() //打开对话框

设置全屏对话框

const dialog = Dialog({ title, content, fullscreen: true })
dialog.open() //打开对话框

设置对话框背景滤镜

const dialog = Dialog({ title, content, filter: 30 })
dialog.open() //打开对话框

设置抽屉

从左往右打开
const dialog = Dialog({ title, content, direction: 'ltr' })
dialog.open() //打开对话框
从上向下打开
const dialog = Dialog({ title, content, direction: 'ttb' })
dialog.open() //打开对话框
从右向左打开
const dialog = Dialog({ title, content, direction: 'rtl' })
dialog.open() //打开对话框
从下往上打开
const dialog = Dialog({ title, content, direction: 'btt' })
dialog.open() //打开对话框
关闭对话框
dialog.close() //关闭对话框

属性说明


菜单

导入组件

import { Menu, Group, Item } from 'zerl'

基本菜单

<Menu width={200}>
  <Group name='功能组一'>
    <Item>功能一</Item>
    <Item>功能二</Item>
  </Group>
  <Group name='功能组二' expanded>
    <Item>功能三</Item>
    <Item>功能四</Item>
  </Group>
</Menu>

横向排列

<Menu width={400} direction='horizontal'>
  <Group name='功能组一'>
    <Item>功能一</Item>
    <Item>功能二</Item>
  </Group>
  <Group name='功能组二' expanded>
    <Item>功能三</Item>
    <Item>功能四</Item>
  </Group>
</Menu>

主题

深色
<Menu width={200} theme='darken'>
  <Group name='功能组一'>
    <Item>功能一</Item>
    <Item>功能二</Item>
  </Group>
  <Group name='功能组二' expanded>
    <Item>功能三</Item>
    <Item>功能四</Item>
  </Group>
</Menu>
简单
<Menu width={200} theme='simple'>
  <Group name='功能组一'>
    <Item>功能一</Item>
    <Item>功能二</Item>
  </Group>
  <Group name='功能组二' expanded>
    <Item>功能三</Item>
    <Item>功能四</Item>
  </Group>
</Menu>

属性说明


导入组件

import { Tree } from 'zerl'

初始化数据

let treeHandler: TreeHandler
const data = [
	{
		id: '1',
		title: '新节点1',
		children: [
			{ id: '4', title: '新节点1.1' },
			{ id: '5', title: '新节点1.2' }
		]
	},
	{ id: '2', title: '新节点2' },
	{ id: '3', title: '新节点2' }
]

组件的使用

<Tree title='Root Name' callback={(el:TreeHandler) => treeHandler = el} dataset={data}
/>

属性说明

页签

导入组件

import { Tabs, Tab } from 'zerl'

简单的页签

<Tabs>
  <Tab name='tab1' label='页签一'>
    <h1>这是页签一</h1>
  </Tab>
  <Tab name='tab2' label='页签二'>
    <h1>这是页签二</h1>
  </Tab>
  <Tab name='tab3' label='页签三'>
    <h1>这是页签三</h1>
  </Tab>
</Tabs>

可关闭页签

<Tabs>
  <Tab name='tab1' label='页签一' closable>
    <h1>这是页签一</h1>
  </Tab>
  <Tab name='tab2' label='页签二'>
    <h1>这是页签二</h1>
  </Tab>
  <Tab name='tab3' label='页签三' closable>
    <h1>这是页签三</h1>
  </Tab>
</Tabs>

动态页签

const [tabs, setTabs] = createSignal()
const tabHandler = () => {
	tabs().create({
		name: 'tab1',
		label: '动态页签',
		closable: true,
		children: <h1>这是新页签,新添加的</h1>
	})
}
<Tabs ref={el => setTabs(el)}>

属性说明


轮播

导入组件

import { Row, Swiper, Slide } from 'zerl'

简单的轮播组件

<Swiper>
  <Slide>
    <Row class='fill' center>
      <h1>Slide A</h1>
    </Row>
  </Slide>
  <Slide>
    <Row class='fill' center>
      <h1>Slide B</h1>
    </Row>
  </Slide>
</Swiper>

带导航的轮播组件

<Swiper nav>
  <Slide>
    <Row class='fill' center>
      <h1>Slide A</h1>
    </Row>
  </Slide>
  <Slide>
    <Row class='fill' center>
      <h1>Slide B</h1>
    </Row>
  </Slide>
</Swiper>

带分页的轮播组件

普通分页
<Swiper pagi>
  <Slide>
    <Row class='fill' center>
      <h1>Slide A</h1>
    </Row>
  </Slide>
  <Slide>
    <Row class='fill' center>
      <h1>Slide B</h1>
    </Row>
  </Slide>
</Swiper>
数字分页
<Swiper pagi='fraction'>
  <Slide>
    <Row class='fill' center>
      <h1>Slide A</h1>
    </Row>
  </Slide>
  <Slide>
    <Row class='fill' center>
      <h1>Slide B</h1>
    </Row>
  </Slide>
</Swiper>
进度条分页
<Swiper pagi='progressbar'>
  <Slide>
    <Row class='fill' center>
      <h1>Slide A</h1>
    </Row>
  </Slide>
  <Slide>
    <Row class='fill' center>
      <h1>Slide B</h1>
    </Row>
  </Slide>
</Swiper>
自定义分页
<Swiper pagi={(index, className) => (
    <div class={`${className} ${styles.bullets}`}>{index + 1}</div>
  )}
>
  <Slide>
    <Row class='fill' center>
      <h1>Slide A</h1>
    </Row>
  </Slide>
  <Slide>
    <Row class='fill' center>
      <h1>Slide B</h1>
    </Row>
  </Slide>
</Swiper>

纵向轮播

<Swiper pagi vertical>
  <Slide>
    <Row class='fill' center>
      <h1>Slide A</h1>
    </Row>
  </Slide>
  <Slide>
    <Row class='fill' center>
      <h1>Slide B</h1>
    </Row>
  </Slide>
</Swiper>

自动轮播

<Swiper pagi autoplay='5'>
  <Slide>
    <Row class='fill' center>
      <h1>Slide A</h1>
    </Row>
  </Slide>
  <Slide>
    <Row class='fill' center>
      <h1>Slide B</h1>
    </Row>
  </Slide>
</Swiper>

循环轮播

<Swiper pagi loop nav>
  <Slide>
    <Row class='fill' center>
      <h1>Slide A</h1>
    </Row>
  </Slide>
  <Slide>
    <Row class='fill' center>
      <h1>Slide B</h1>
    </Row>
  </Slide>
</Swiper>

属性说明


表单

表单的基本结构

获取表单句柄

const [getForm, setForm] = createSignal()
<form action='form.simple' ref={el => setForm1(el)}>
...
</form>

action 指向处理数据的模块,格式:[模块名称].[方法名称]

表单的验证

<form action='form.simple' ref={el => setForm2(el)}>
  <Col>
    <Row class='fill' middle>
      <Text
        title='标题'
        name='title'
        rule={val => val.length > 4}
        placeholder='请输入信息标题'
        hint='至少输入不少于5个字符'
      />
      <Button
        type='radio'
        title='类型'
        name='category'
        rule='required'
        hint='需要选择类型'
      >
        <Option name='内部信息' value='inner' />
        <Option name='保密信息' value='secret' />
        <Option name='对外信息' value='external' />
      </Button>
    </Row>
    <Row class='fill' middle>
      <Text
        type='date'
        title='显示日期'
        name='displayDate'
        rule='required'
        placeholder='请输入显示日期'
        hint='显示日期不能为空'
      />
      <Button
        type='check'
        title='标签'
        name='label'
        rule={val => val.length > 2}
        hint='至少选择三项'
      >
        <Option name='文娱' value='culture' />
        <Option name='科技' value='tech' />
        <Option name='教育' value='edu' />
        <Option name='健康' value='health' />
        <Option name='时事' value='news' />
      </Button>
    </Row>
    <Row class='fill' middle>
      <Text type='multi' title='内容' name='content' />
    </Row>
    <Row class='fill' right>
      <Button
        onClick={async () => {
          const result = await form2().submit()
          if (result) {
            Confirm(
              '表单提交信息',
              <div>
                {Object.keys(result).map(key => {
                  return (
                    <Row>
                      <div
                        style={{
                          width: '120px',
                          'font-weight': 'bold'
                        }}
                      >
                        {key}
                      </div>
                      {JSON.stringify(result[key])}
                    </Row>
                  )
                })}
              </div>
            )
          }
        }}
      >
        保存
      </Button>
    </Row>
  </Col>
</form>

文件

导入组件

import { FileList, File } from 'zerl'

简单的文件组件

<FileList />

文件多选

<FileList multiple/>

初始化文件列表

<FileList multiple>
  <File id='2fed96c8130e804e8c6f940981370fb7'></File>
  <File id='096f60ff49ec8b3039902e190c26ee10'></File>
</FileList>

文件上传

let fileList
<FileList ref={el=>fileList = el}/>
<Button onClick={async ()=>{const fileIds = await fileList.upload()}}/>

属性说明

服务组件

逻辑

组件功能

实现服务端数据处理的逻辑组件,用于与浏览器或其他客户端进行数据交互

模块文件

在模块文件头部添加 #!module 标志

组件使用

组件定义
#!module
import type { Context } from 'zerl'
export default class {
	public async save(data: Schema) {
		return data
	}
	public async load(data: queryData, ctx: Context) {
		return [data]
	}
}
UI 模块调用
import { Button } from 'zerl'
import Service from './Service'
const service = new Service()
<Button onClick = {async ()=> {
  const remoteData = await service.save({data: ‘test data’})
  }
}>
  get remote data
</Button>

远程组件调用

// 普通远程组件调用
import Service from 'rpc://192.168.1.10:8080/Service'
// ssl远程组件调用
import Service from 'rpcs://192.168.1.11:8080?Service'

任务

组件功能

应用启动时一并启动的工作任务线程,可设置一次性运行任务与周期性运行任务

任务文件

在任务文件头部添加 #!job 标志

组件使用

#!job
import { Once, Timer } from "zerl"
import type { Context, ServerInstance } from "zerl"
export default class {
  // 声明后自动注入当前启动的服务实例
  private getCurrentInstance!: ServerInstance
  @Once()
  public init(){
    // 获取服务实例
    const server = this.getCurrentInstance()
    // 添加新的服务中间件
    server.use(async (ctx: Context, next:any) => {
      if(/^\/api/?/.test(ctx.url)){
        ctx.body = "append new middleware"
      } else {
        await next()
      }
    })
  }

  @Timer(60)
  public synchronize(){
    ...
  }
}

访问控制

组件功能

服务模块的会根据客户端发起的请求进行访问权限验证,使用@Expose 装饰器则不验证访问权限

授权与撤销权限

#!module
import { Expose, Grent, Revoke } from 'zerl'
import type { Context } from 'zerl'
export default class {
	// 访问时,不验证UI端访问权限
	@Expose public async login(data, ctx: Context) {
		Grent(ctx) //授权访问权限
	}

	// 只有授权后,UI端才能访问此方法
	public async logout(data: ant, ctx: Context) {
		Revoke(ctx) //回收访问权限
	}
}

MySQL

组件使用

#!module
import { MySQL, Schema } from 'zerl'
@Schema('TABLE', 'ID')
export default class extends MySQL {
	// 数据插入
	public async insertData(data: any) {
		this.insert(data)
		return { result: 'ok' }
	}
	// 数据更新
	public async updateData(data: any) {
		this.update(data)
		return { result: 'ok' }
	}

	// 数据删除
	public async removeData(data: any) {
		this.remove({ ID: data.id })
		return { result: 'ok' }
	}

	// 数据查询
	public async queryData(data: any) {
		return await this.query('SELECT * FROM TABLE WHERE ID=?', [data.id])
	}

	// 事务处理
	public async transaction(data: any) {
		const flow = this.flow()
		flow.insert(data)
		flow.update({ name: 'new name' })
		flow.pipe('DELETE FROM TABLE WHERE ID = 3')
		await flow.exec()
		return { result: 'ok' }
	}
}

SQL 文件

命名

[文件名].sql

文件格式
--table.sql
--define query

SELECT * FROM TABLE;

每个 sql 语句结束后必须加“;”,sql 语句头部需要定义语句的变量名,声明格式:--define xxx

调用 SQL 语句
this.query('sql:table.query')

Redis

组件使用

#!module
import { Redis } from "zerl"
// 数据模型
export default class{
  public async load(data: any){
    return await Redis(async (client) => {
      const { keys } = await
      client.scan(0, { MATCH: "*,name,*" })
      return client.hGetAll(keys[0])
    }
  }
}

操作命令参考Redis 命令文档


装饰器

MySQL 控制表定义

@Schema([表名],[主键])
// 设置表定义后,所有MySQL操作都默认使用设置的表名和主键名
#!module
@Schema('TABLE', 'ID')
export default class extends MySQL {
  ...
}

访问暴露(逻辑组件内使用)

// 设置访问暴露装饰器后,该方法访问对外完全公开,不受权限控制影响。
@Expose public async login(data: any){
  ...
}

一次性执行方法(任务组件内使用)

// 应用程序启动时立即启动
@Once() public runAtStart(){
  ...
}
// 应用程序启动时,延迟5秒启动
@Once(5) public runAtStart(){
  ...
}

定时执行方法(任务组件内使用)

// 应用程序启动时,触发启动定时器,方法每5秒执行一次
@Timer(5) public tikTok(){
  ...
}

扩展类型

日期+

格式化日期
// fmt: 日期格式 y-年,M-月,d-日,h-小时,m-分钟,s-秒,q-季度,S-毫秒
Date.format(fmt: string): string
日期推算
//	year 当前日期累加年数
//  month 当前日期累加月数
//	day 当前日期累加日数
Date.calc(year: number, month: number, day: number): Date
输出日期文本格式 yyyy-MM-dd
//	year 当前日期累加年数
//  month 当前日期累加月数
//	day 当前日期累加日数
Date.date(year?: number, month?: number, day?: number): string
输出时间文本格式 hh:mm:ss
Date.time(): string
输出日期时间文本格式 yyyy-MM-dd hh:mm:ss
//	year 当前日期累加年数
//  month 当前日期累加月数
//	day 当前日期累加日数
Date.datetime(year?: number, month?: number, day?: number): string
月份数量计算
// reference 比较日期 yyyy-MM-dd hh:mm:ss
// 返回相隔月份数量
Date.monthdiff(reference: string | Date): number
时间戳
Date.timestamp(): number

字符串+

驼峰格式转连接符格式
// separator: 连接字符
String.camelfalt(separator: string): string
定长前补零
// digit: 字符串总长度
String.prefix(digit:number): string
Base64 字符串转 Blob 类型
String.blob(): Blob
字符串加密(服务组件内使用)
String.encode(): string
字符串解密(服务组件内使用)
String.decode(): string
生成 MD5 摘要信息
String.md5(): string

数字+

千分位格式
Number.thou(): string

数组+

数组分组
// algorithm: 分组函数 function(element: any): string, element为数组中的每个元素的值,返回值为分组名称
Array.group(algorithm: Function): object