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

@zenweb/form

v6.0.0

Published

Zenweb Form module

Downloads

763

Readme

form - 表单构建与数据验证

ZenWeb

服务端表单构建与数据验证系统

功能特色:

  • 服务器端控制
  • 数据验证
  • 前后分离设计
  • 多种前端渲染支持
  • 快速构建产品

安装

服务端

yarn add @zenweb/form

配置

import { create } from 'zenweb';
import modForm from '@zenweb/form';

create()
.setup(modForm())
.start();
import { inject, Context, mapping, Body } from 'zenweb';
import { FormBase, fields } from '@zenweb/form';

export class ExampleForm extends FormBase {
  setup() {
    return {
      username: fields.text('!string').minLength(2).maxLength(12).label('用户名'),
      desc: fields.textarea('string').default('descdefault').minLength(3).maxLength(1000)
      .label('自我描述').rows(3, 10).help('自我描述不要超过1000字,最少3个字'),
      age: fields.text('int').validate({
        gte: 18,
        lte: 50,
      }).label('年龄').help('年龄18-50'),
      date: fields.date('date').label('日期'),
      time: fields.time('string').label('时间'),
      datetime: fields.datetime('date').label('日期时间'),
      upload: fields.localUpload('trim[]').label('本地上传'),
      remote: fields.remoteUpload('trim[]').label('远程上传').to('/upload').maxFiles(3),
      gender: fields.radio('trim1').label('性别').choices([
        '男',
        {value: 2, label: '女'},
      ]),
      shengxiao: fields.select('int').label('生肖').choices([
        {value: 1, label: '🐭'},
        {value: 2, label: '🐂'},
        {value: 3, label: '🐯'},
        {value: 4, label: '🐰', disabled: true},
      ]),
      interest: fields.multiple('int[]').label('感兴趣的').choices([
        {value: 1, label: '钓鱼'},
        {value: 2, label: '编程'},
        {value: 3, label: '厨艺'},
        {value: 4, label: '手工'},
      ]).max(3).min(1),
      agreement: fields.onebox('bool').label('同意并遵守注册协议'),
      readonly: fields.text('string').label('只读字段').readonly().placeholder('看看'),
      daterange: fields.dateRange('date[]').label('日期范围').start(new Date('2023-1-1')).end(new Date()),
      cas: fields.cascader('int[]').label("级连选择").choices([
        { label: "第一层", value: 1 },
        { label: "第二层1", value: 2, parent: 1 },
        { label: "第二层2", value: 3, parent: 1 },
        { label: "第三层1", value: 4, parent: 2, disabled: true },
        { label: "第一层2", value: 10 },
      ]),
    }
  }

  @inject ctx!: Context;

  // 表单后置校验字段数据
  clean_username(data: string) {
    if (data.includes('admin')) {
      this.fail('like-admin');
    }
    return data; // 返回数据
  }

  // 整体清理
  clean() {
    console.log('clean!');
  }
}

export class UserController {
  @mapping({ path: '/form' })
  formGet(form: UserForm) {
    return form;
  }

  @mapping({ path: '/form', method: 'POST' })
  formPost(form: UserForm, input: ObjectBody) {
    await form.assert(input);
    return form.data;
  }
}

使用内置的 template 渲染

内置 html template 渲染目前支持 nunjucks 模板引擎

配置

import { create } from 'zenweb';
import modForm, { formTemplate } from '@zenweb/form';
import template from '@zenweb/template';
import nunjucks from '@zenweb/template-nunjucks';

create()
.setup(modForm())
.setup(template({
  engine: nunjucks({
    path: [
      './template',
      formTemplate, // 添加 form template 目录
    ],
  }),
}))
.start();

使用

template/form.html.njk

{% from "zenweb/form/macro.html.njk" import formFields, formStyle, formScript %}

{{formStyle()}}

<div style="max-width:500px;margin: 10px auto;">
  {% if ok %}
  <div style="background-color:#138515;color:#fff;padding:5px;text-align:center;margin-bottom:20px;">提交完成!</div>
  {% endif %}

  <form method="POST" action="">
    {{ formFields(form, input) }}
    <button type="submit">提交</button>
  </form>
</div>

{{formScript()}}
export class DemoController {
  @mapping({ method: ['GET', 'POST'] })
  async html(ctx: Context, form: UserForm, input: ObjectBody) {
    ctx.template('form.html.njk');
    form.data = { username: 'default value' };
    let ok = false;
    if (ctx.method === 'POST') {
      ok = await form.validate(input);
      if (ok) {
        // some code
      }
    }
    return { form, input, ok };
  }
}

使用 vue 渲染

Vue 渲染目前支持 vue2 element 组件渲染

Vue 项目详细使用方式请查看 @zenweb/form-vue-element