vue-autoui自匹配webapi的UI控件

vue-autoui 是一款基于vueelement扩展的一个自动化UI控件,它主要提供两个控件封装分别是auto-formauto-grid; 通过这两个控件可以完成大多数的信息输入和查询输出的需要.auto-formauto-grid是通过json来描述展示的结构,在处理上要比写html标签来得方便简单, 但这控件的最大优势并不是在这里,它最重要的功能是可以结合webapi的信息来自动输出界面,只需要调整webapi的信息结构即可完成UI的调整。

基础使用

控件可以直接在vuejs功能中使用,但需要结合json来设置具体UI展示,以下是一个简单的例子

    <auto-form ref="form" v-model="data" size="mini" :info="info">

    </auto-form>
    <el-button @click="if($refs.form.success()){alert(JSON.stringify(data))}">确定</el-button>

功能很简单就是显示当前输入并验证通过的数据,下面用json描述信息输入源。

        data(){
            return {
                info: { items: [] },
                data: { },
            };
        },
        mounted(){
            var items = [];
            items.push({
                name: ‘active‘, label: ‘活动名称‘, rules: [
                    { required: true, message: ‘请输入活动名称‘, trigger: ‘blur‘ },
                    { min: 3, max: 5, message: ‘长度在 3 到 5 个字符‘, trigger: ‘blur‘ }
                ]
            });
            items.push({
                name: ‘region‘, label: ‘活动区域‘, type: ‘select‘,
                data: [{ value: ‘广州‘ }, { value: ‘深圳‘ }, { value: ‘上海‘ }, { value: ‘北京‘ }],
                rules: [{ required: true, message: ‘请选择活动区域‘, trigger: ‘change‘ }],
                eof: true
            });
            items.push({ name: ‘starttime‘, label: ‘开启时间‘, type: ‘date‘, rules: [{ type: ‘date‘, required: true, message: ‘请选择日期‘, trigger: ‘change‘ }] });
            items.push({ name: ‘endtime‘, label: ‘-‘, type: ‘date‘, eof: true, rules: [{ type: ‘date‘, required: true, message: ‘请选择日期‘, trigger: ‘change‘ }] });
            items.push({ name: ‘instant‘, type: ‘switch‘, label: ‘即时配送‘, eof: true });
            items.push({
                name: ‘nature‘, type: ‘checkbox‘, label: ‘活动性质‘,
                rules: [{ type: ‘array‘, required: true, message: ‘请至少选择一个活动性质‘, trigger: ‘change‘ }],
                data: [{ value: ‘美食/餐厅线上活动‘ }, { value: ‘地推活动‘ }, { value: ‘线下主题活动‘ }, { value: ‘单纯品牌暴光‘ }], eof: true
            });
            items.push({
                name: ‘resource‘, label: ‘特殊资源‘, type: ‘radio‘, rules: [{ required: true, message: ‘请选择活动资源‘, trigger: ‘change‘ }],
                data: [{ value: ‘线上品牌商赞助‘ }, { value: ‘线下场地免费‘ }], eof: true
            });
            items.push({ name: ‘remark‘, label: ‘活动形式‘, type: ‘remark‘, rules: [{ required: true, message: ‘请填写活动形式‘, trigger: ‘blur‘ }] })
            this.info = { items: items}
        }

以上是使用json来描述一个输出的界面,具体效果如下:

 

虽然用json来描述界面会比html描述会方便一些,但总体上来说工作量还是有些大的,在调整界面的时候也不方便。接下介绍一下如何结合BeetleX.FastHttpApi来进一步简化这些繁琐的操作。

Webapi动态输出

其实在构建vue-autoui的时候更多是考虑和BeetleX.FastHttpApi进行一个整合,通过和后端融合可以把这些UI编写的工作量大大节省下来,让开发这些功能变得更简单方便,更重要的是api变化后界面就自动适应。使用要求:在和BeetleX.FastHttpApi整合还需要引用BeetleX.FastHttpApi.ApiDoc插件,因为这个插件用于给接口输出对应UI的JSON信息。接下来通过几个示例来介绍整合的方便性:

登陆

登陆功能是比较常见的,接下来看一下使用auto-form如何结合webapi来完成这个功能。

<div>
    <auto-form ref="login" url="/login" v-model="login.data" size="mini">

    </auto-form>
    <el-button size="mini" @click="if($refs.login.success())login.post()">
        登陆
    </el-button>
</div>

以上是一个登陆功能UI的定义,是不是很简单呢?通过指定url的webapi连接即可以自动适应UI;这时候只需要针对登陆接口进行一个定义即可:

        [Input(Label = "用户名", Name = "name", Eof = true)]
        [Required("用户名不能为空", Name = "name")]
        [Input(Label = "密码", Name = "pwd", Type = "password", Eof = true)]
        [Required("用户密码不能为空", Name = "pwd")]
        [Input(Label = "保存状态", Value = true, Name = "saveStatus")]
        public bool Login(string name, string pwd, bool saveStatus)
        {
            Console.WriteLine($"name:{name} pwd:{pwd} saveStatus:{saveStatus}");
            return name == "admin";
        }

注册

接下来定义一个信息多些的注册界面

<div>
    <auto-form ref="login" url="/register" v-model="register.data" size="mini" @completed="onCompleted">

    </auto-form>
    <el-button size="mini" @click="if($refs.login.success())register.post()">
        注册
    </el-button>
</div>

在UI定义上基于没什么变化,只是调整一下对应的url地址,在这里多了一下completed事件,这个事件主要是通过接口加载UI信息才会触发的。对应功能的javascript代码

        data(){
            return {
                register: new beetlexAction(‘/register‘, {}),
                checkConfirmPassword: (rule, value, callback) => {
                    var password = this.$refs.login.getField(‘Password‘);
                    var cpassword = this.$refs.login.getField(‘ConfirmPassword‘);
                    if (password.value != cpassword.value)
                        callback(new Error(‘确认密码不正确!‘));
                    else
                        callback();
                },
            }
        },
        methods: {
            onCompleted(){
                this.$refs.login.getField(‘ConfirmPassword‘).rules.push({ validator: this.checkConfirmPassword, trigger: ‘blur‘ });
            },
        },
        mounted() {

            this.register.requested = (r) => {
                alert(JSON.stringify(r));
            };
        }

代码主要是定密码和确认密码的对比验证,接下来看一下后台注册对应的接口

    [Post]
    public RegisterDto Register(RegisterDto register)
    {
            Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(register));
            return register;
    }
    public class RegisterDto
    {
        [Input(Label = "用户名", Eof = true)]
        [Required("用户名不能为空")]
        [DataRange("用户名的必须大于3个字符", Min = 3)]
        public string Name { get; set; }

        [Input(Label = "邮箱地址", Eof = true)]
        [Required("邮件地址无效", Type = "email")]
        public string Email { get; set; }

        [Input(Label = "密码", Eof = true, Type = "password")]
        [Required("输入密码")]
        public string Password { get; set; }

        [Input(Label = "确认密码", Eof = true, Type = "password")]
        [Required("输入确认密码")]
        public string ConfirmPassword { get; set; }

        [GenderInput(Label = "性别", Value = "男", Eof = true)]
        public string Gender { get; set; }

        [Required("选择所在城市")]
        [CityInput(Label = "城市", Eof = true)]
        public string City { get; set; }

        [HobbyInput(Label = "爱好")]
        [Required("选择爱好", Type = "array", Trigger = "change")]
        public string[] Hobby { get; set; }
    }

服务代码也没太多的变化,只是通过一些标签来标记一下相关属性的数据源和输入要求.具体运行效果如下:

 

数据列表

有应用中除了数据输出外更多的数据列表,auto-grid即是专门用于处理列表的一个控件,这个控件提供分页,选择,编辑和删除的功能;接下来做一个简单的雇员列表示例:

<auto-grid url="/employees" @completed="employees.get()"
           @itemchange="onItemChange"
           @itemdelete="onItemDelete"
           @command="onCommand"
           :data="employees.result"
           size="mini" height="100%"
           edit="true" delete="true">
</auto-grid>

这个列表提供编辑和删除功能,相关脚本代码如下:

        data(){
            return {
                employees: new beetlexAction(‘/employees‘, {}, [])
            }
        },
        methods: {
            onCommand(e){
                this.$open(‘models-employee‘, e.data);
            },
            onItemChange(item){
                if (confirm(‘是否要修改‘ + item.data.FirstName + ‘?‘)) {
                    item.success();
                }
            },
            onItemDelete(item){
                if (confirm(‘是否要删除‘ + item.data.FirstName + ‘?‘)) {
                    item.success();
                }
            },
        },
        mounted() {

        }

接下来的工作就是在服务端定义api来输出结果

        [Column("FirstName", Type = "link")]
        [Column("LastName", Read = true)]
        [Column("Title")]
        [Column("HomePhone")]
        [Column("City")]
        [Column("Address")]
        public object Employees()
        {
            return DataHelper.Defalut.Employees;
        }

 

动态查询

实际应用中需要提供查询条件输入,这个时候就可以把auto-formauto-grid整合起来,以下通过一个简单的订单查询来展示这两个控件结合使用

    <auto-form url="/orders" v-model="orders.data" @completed="orders.get()" size="mini" @fieldchange="orders.get()">

    </auto-form>
    <auto-grid url="/orders" height="300" :data="orders.result.items" :pages="orders.result.pages" :currentpage="orders.result.index" @pagechange="onPageChange" size="mini">

    </auto-grid>

可以在auto-formfieldchange事件中自动执行查询,对应的脚本代码如下:

        data(){
            return {
                orders: new beetlexAction("/orders", {}, { index: 0, pages: 0, items: [] })
            };
        },
        methods: {
            onPageChange(page){
                this.orders.data.index = page;
                this.orders.get();
            },
        },
        mounted(){

        }

接下来需要实现服务端代码,由于方法需要描述输入和列表所以对应的标签比较多

        [Input(Name = "id", Type = "select", DataUrl = "/EmployeeSelecter", Label = "雇员",NullOption =true)]
        [Input(Name = "customerid", Type = "select", DataUrl = "/CustomerSelecter", Label = "客户",NullOption =true,  Eof = true)]
        [SizeInput(Name = "size", Label = "分页记录数")]
        [Input(Name = "index", Hide = true)]

        [Column("OrderID", Read = true)]
        [Column("EmployeeID", Type = "select", DataUrl = "/EmployeeSelecter")]
        [Column("CustomerID", Type = "select", DataUrl = "/CustomerSelecter")]
        [Column("OrderDate", Type = "date")]
        [Column("RequiredDate", Type = "date")]
        [Column("ShippedDate", Type = "date")]
        public object Orders(int id, string customerid, int index, int size, IHttpContext context)
        {
            Func<Order, bool> exp = o => (id == 0 || o.EmployeeID == id)
             && (string.IsNullOrEmpty(customerid) || o.CustomerID == customerid);
            int count = DataHelper.Defalut.Orders.Count(exp);
            if (size == 0)
                size = 20;
            int pages = count / size;
            if (count % size > 0)
                pages++;
            var items = DataHelper.Defalut.Orders.Where(exp).Skip(index * size).Take(size);
            return new { pages, index, items };

        }

 

插件详细代码 https://github.com/IKende/BeetleX-Samples/tree/master/Web.AutoUI

https://github.com/IKende/vue-autoui

原文地址:https://www.cnblogs.com/smark/p/12529957.html

时间: 2024-10-12 22:01:15

vue-autoui自匹配webapi的UI控件的相关文章

跨线程访问UI控件时的Lambda表达式

工作中经常会用到跨线程访问UI控件的情况,由于.net本身机制,是不允许在非UI线程访问UI控件的,实际上跨线程访问UI控件还是 将访问UI的操作交给UI线程来处理的, 利用Control.Invoke方法,将操作传递给UI线程,不推荐使用CheckForIllegalCrossThreadCalls = false; Control.Invoke的签名 // // 摘要: // 在拥有此控件的基础窗口句柄的线程上执行指定的委托. // // 参数: // method: // 包含要在控件的线

实现Winform 跨线程安全访问UI控件

在多线程操作WinForm窗体上的控件时,出现"线程间操作无效:从不是创建控件XXXX的线程访问它",那是因为默认情况下,在Windows应用程序中,.NET Framework不允许在一个线程中直接操作另一个线程中的控件(因为访问Windows窗体控件本质上不是线程安全的).微软为了线程安全,窗体上的控件只能通过创建控件的线程来操作控件的数据,也就是只能是UI线程来操作窗体上的控件!可看看Control的Invoke和BeginInvoke 要解决这个问题可以用以下方法: 1.关闭线

android_常用UI控件_01_TextView3_点击打开新的activity

点击textview打开新的activity (1) MainActivity.java package com.example.android_textview_opennewactivity; import android.os.Bundle; import android.app.Activity; import android.content.Intent; import android.text.SpannableString; import android.text.Spanned;

android_常用UI控件_01_TextView4_rollingsubtitles效果加链接文字

(1)Mainactivity.java package com.example.android_textview_rollingsubtitles; import java.sql.Wrapper; import android.os.Bundle; import android.app.Activity; import android.text.Html; import android.text.TextUtils; import android.text.TextUtils.Truncat

C# WPF 使用委托修改UI控件

近段时间在自学WPF,是一个完全不懂WPF的菜鸟,对于在线程中修改UI控件使用委托做一个记录,给自已以后查询也给需要的参考: 界面只放一个RichTextBox,在窗体启动时开起两个线程,调用两个函数,每隔1秒写一次当前时间 一 界面XAML如下: <Window x:Class="WpfApplication1.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation&qu

UI控件

在iOSAPP中,能在屏幕上显示的按钮.文本标签.文字输入框等等,都是UI控件. UIview: 苹果把所有UI控件的共同属性抽出来放在UIView中,即所有UI控件都是UIView的子类(不一定是直接子类). 注意:UIView继承自UIresponder,可以响应用户的操作. UIView的重要属性 frame:View的位置和宽高 bounce:相对于自己的左上角的位置和宽高 center:中心点的坐标 backgroundcolor:背景颜色 UIView的常用方法:UIView既可以显

Atitit.swt&#160;线程调用ui控件的方法

Atitit.swt 线程调用ui控件的方法 1 SwingUtilities.invokeLater1 2 display.asyncExec方法1 3  display.timerExec(500,timer);2 4 .但有时候并不一定要程序执行时就要定时检测,有时需要外部事情激发这就出现了第2种解决方案,写一个内置类,可以放在事件监听的方法中,然后激发:2 5 参考3 1   SwingUtilities.invokeLater SwingUtilities.invokeLater(ne

iOS UI控件没有显示时的调试技巧

1.遇到UI控件没有显示的问题,可以给这个控件设置背景色 假设这个控件是UIBUtton 如果背景色能显示,那问题就出在image和title值为空 如果背景色不能显示,重写控件的description方法,把控件的frame打印出来分析 2.以下是打印UIView的frame的分类 #import <UIKit/UIKit.h> @interface UIView (Log) @end 1 #import "UIView+Log.h" 2 3 @implementatio

JavaFX - UI控件 - 标签

  2标签(Label) 本章主要介绍如何使用标签(Label),该类位于JavaFX API的javafx.scene.control包中,用于显示一个文本元素. 接下来会介绍如何让文本元素自动换行来适应受限空间,添加一个图标,或使用视觉特效. 图2 - 1显示了标签的三种常见用法. 左边的标签是一个带图标的文本,中间的展示了旋转效果,右边的使用了自动换行设置. 图2 - 1 标签示例 这幅图显示了三个标签,他们被放在了同一行. 左边的标签有一个看起来像个放大镜的图标和一个"Searc