zoukankan      html  css  js  c++  java
  • 重复提交按钮

    首先说说防止重复提交按钮是啥东西:
    我们在访问有的网站,输入表单完成以后,单击提交按钮进行提交以后,提交按钮就会变为灰色,用户不能再单击第二次,直到重新加载页面或者跳转。这样,可以一定程度上防止用户重复提交导致应用程序上逻辑错误。有朋友说,这个按钮完全可以用js来做,是的。不过当你需要大量这种按钮时,是否为每一个都去编程而不封装一个呢?
    另外,为了增加其功能性,我们除了让他有防止重复提交的功能以外,还可以给他弹出提示框,就像单击删除按钮时,用户会受到一个提示再次确认是否真的删除。

    好,接下来,第一步:知识储备,
    我们知道,要防止重复提交,要在客户端设法使用户单击一次以后按钮变灰,这种客户端行为显然只能借助js代码来完成,服务器端运行的ASP.NET是做不到的。那要让客户端用户单击按钮后立即收到一条再次确认消息,在确认之前不会提交到服务器,也需要js代码。因此,我们基本的丝路就是在页面加载按钮时,一并把所需的js代码发送到客户端去。而该按钮都是适用js脚本,因此不影响服务器端行为。

    第二步:从Button继承。
    因为它是一个按钮,拥有按钮所需要的全部特征属性,因此我们就从System.Web.UI.WebControls.Button这个类继承。而防止重复提交按钮在按钮变成灰色以后,应该显示什么文本呢?新增一个AfterSubmitText属性来指示;采用一个Bool值“ShowMessageBox”属性来确定是否需要在客户端弹出提示;使用WarningText属性来指示客户端弹出提示的内容。

    第三步:
    现在,我们就来改写AddAttributesToRender方法,ASP.NET在渲染该控件到输出时,会调用该方法我们所改写的方法,以达到将JS代码发送到客户端的目的。具体代码如下:
    程序代码:
            protected override void AddAttributesToRender(HtmlTextWriter writer)
            {
                System.Text.StringBuilder ClientSideEventReference = new System.Text.StringBuilder();

                if (((this.Page != null) && this.CausesValidation) && (this.Page.Validators.Count > 0))
                {
                    ClientSideEventReference.Append("if (typeof(Page_ClientValidate) == 'function'){if (Page_ClientValidate() == false){return false;}}");
                }
                //ShowMessageBox?
                if (this.ShowMessageBox)
                {
                    ClientSideEventReference.Append("if (!confirm('" + this.WarningText + "')){return false}");
                }
                ClientSideEventReference.AppendFormat("this.value = '{0}';", (string)this.ViewState["afterSubmitText"]);
                ClientSideEventReference.Append("this.disabled = true;");
                ClientSideEventReference.Append(this.Page.ClientScript.GetPostBackEventReference(this, string.Empty));


                writer.AddAttribute(HtmlTextWriterAttribute.Onclick, ClientSideEventReference.ToString(), true);
                base.AddAttributesToRender(writer);
            }
    我们把发送到客户端的js代码看作是一个字符串,为了提高性能,用StringBuilder来对象来构造这个字符串。
    首先根据页面对象存在且控件启用了验证(该属性从父继承),且页面对象的验证器内计数大于0来决定输出一段引发验证的js代码,
    根据ShowMessageBox属性来决定输出一个弹出提示的代码,并且弹出提示的内容由WarningText属性给出。
    书写一个js脚本为按钮赋值为提交后文本,并且将按钮设置为禁用以变灰色。
    最后附加一段由ASP.NET提供的用于影射回调事件引用的js脚本(this.Page.ClientScript.GetPostBackEventReference(this, string.Empty)方法将返回一个回送事件引用的js脚本字符串)

    将StringBuilder对象内构造的字符串用HtmlTextWriter对象的AddAttribute方法写入按钮的OnClick事件中。

    调用父类的AddAttributesToRender方法让父类有机会完成其他的配置等操作。


    完整的ClickOnceButton代码如下:
    程序代码:
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Text;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;

    namespace BlogLan.Web.Controls
    {
        /// <summary>
        /// 表示一个防止重复提交的按钮。当用户单击按钮以后,该按钮变灰,不能再次单击,直到重新加载页面或者跳转。
        /// </summary>
        [DefaultProperty("Text")]
        [ToolboxData("<{0}:ClickOnceButton runat=server></{0}:ClickOnceButton>")]
        public class ClickOnceButton : System.Web.UI.WebControls.Button
        {
            /// <summary>
            /// 默认的构造函数。
            /// </summary>
            public ClickOnceButton()
            {
                this.ViewState["afterSubmitText"] = "正在提交,请稍候...";
                base.Text = "ClickOnceButton";
                this.ViewState["showMessageBox"] = false;
                this.ViewState["warningText"] = "确定要提交吗?";
            }

            /// <summary>
            /// 获取或设置单击按钮后,按钮上所显示的文本。
            /// </summary>
            [Bindable(true),
            Category("Appearance"),
            DefaultValue("正在提交,请稍候..."),
            Description("指示单击提交后,按钮上所显示的文本。")]
            public string AfterSubmitText
            {
                get
                {
                    string afterSubmitText = (string)this.ViewState["afterSubmitText"];
                    if (afterSubmitText != null)
                    {
                        return afterSubmitText;
                    }
                    else
                    {
                        return string.Empty;
                    }
                }
                set
                {
                    this.ViewState["afterSubmitText"] = value;
                }
            }

            [Bindable(true),
            Category("Appearance"),
            DefaultValue(false),
            Description("指示是否要显示一个提示框。")]
            public bool ShowMessageBox
            {
                get
                {
                    return (bool)this.ViewState["showMessageBox"];
                }
                set
                {
                    this.ViewState["showMessageBox"] = value;
                }
            }


            [Bindable(true),
            Category("Appearance"),
            DefaultValue("确定要提交吗?"),
            Description("指示提示框内所包含的内容。")]
            public string WarningText
            {
                get
                {
                    return (string)this.ViewState["warningText"];
                }
                set
                {
                    this.ViewState["warningText"] = value;
                }
            }

            /// <summary>
            /// AddAttributesToRender
            /// </summary>
            /// <param name="writer">HtmlTextWriter</param>
            protected override void AddAttributesToRender(HtmlTextWriter writer)
            {
                System.Text.StringBuilder ClientSideEventReference = new System.Text.StringBuilder();

                if (((this.Page != null) && this.CausesValidation) && (this.Page.Validators.Count > 0))
                {
                    ClientSideEventReference.Append("if (typeof(Page_ClientValidate) == 'function'){if (Page_ClientValidate() == false){return false;}}");
                }
                //ShowMessageBox?
                if (this.ShowMessageBox)
                {
                    ClientSideEventReference.Append("if (!confirm('" + this.WarningText + "')){return false}");
                }
                ClientSideEventReference.AppendFormat("this.value = '{0}';", (string)this.ViewState["afterSubmitText"]);
                ClientSideEventReference.Append("this.disabled = true;");
                ClientSideEventReference.Append(this.Page.ClientScript.GetPostBackEventReference(this, string.Empty));


                writer.AddAttribute(HtmlTextWriterAttribute.Onclick, ClientSideEventReference.ToString(), true);
                base.AddAttributesToRender(writer);
            }
        }
    }
    你可以把它编译为dll,放置在工具箱中,随意拖放到网页上即可使用。因为继承了Button控件,它拥有Button的全部特性,并且自动继承了Button的设计时支持。


    后记:
    当我决定自己开发自定义控件时,这是我第一个想到的,因为明确它就是在一个Button控件基础上,并用JS代码来实现功能。因此,它应该是一个比较简单的东西了。
    代码贴出来,与各位分享,尽管现在新技术层出不穷,用AJAX也可以达到效果,不过假如你只是想要防止重复提交,也不用劳烦AJAX这个沉重的框架来完成,有点杀鸡用牛刀了。
    愿各位朋友举一反三,深入探讨。


       本人博客的文章大部分来自网络转载,因为时间的关系,没有写明转载出处和作者。所以在些郑重的说明:文章只限交流,版权归作者。谢谢

  • 相关阅读:
    URL编码和Bsae64编码
    在控制台保存下载数据文件方法
    前端下载文件的几种方式
    npm i error:0909006C:PEM routines:get_name:no start line 遇到问题解决
    MapTalks.js 使用小结(三): 各类地图加载
    在线瓦片地图服务资源 总结
    npm webpack 遇到的问题解决方案总结
    MapTalks.js 使用小结(二)
    可拖动的进度条 in vue
    滚动条vue-seamless-scroll的使用
  • 原文地址:https://www.cnblogs.com/wzg0319/p/1418499.html
Copyright © 2011-2022 走看看