惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Security Latest
Security Latest
Recorded Future
Recorded Future
人人都是产品经理
人人都是产品经理
S
SegmentFault 最新的问题
Hacker News - Newest:
Hacker News - Newest: "LLM"
C
CXSECURITY Database RSS Feed - CXSecurity.com
博客园 - 三生石上(FineUI控件)
博客园 - 聂微东
P
Privacy & Cybersecurity Law Blog
WordPress大学
WordPress大学
Know Your Adversary
Know Your Adversary
Spread Privacy
Spread Privacy
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
量子位
L
LINUX DO - 热门话题
L
Lohrmann on Cybersecurity
博客园 - Franky
酷 壳 – CoolShell
酷 壳 – CoolShell
T
Tor Project blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
雷峰网
雷峰网
阮一峰的网络日志
阮一峰的网络日志
V
Visual Studio Blog
T
Threatpost
T
Tenable Blog
有赞技术团队
有赞技术团队
大猫的无限游戏
大猫的无限游戏
Engineering at Meta
Engineering at Meta
GbyAI
GbyAI
C
Cisco Blogs
H
Heimdal Security Blog
Attack and Defense Labs
Attack and Defense Labs
A
About on SuperTechFans
Last Week in AI
Last Week in AI
N
News and Events Feed by Topic
T
Threat Research - Cisco Blogs
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
I
Intezer
V
V2EX
Cyberwarzone
Cyberwarzone
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
B
Blog RSS Feed
V
Vulnerabilities – Threatpost
N
Netflix TechBlog - Medium
T
The Blog of Author Tim Ferriss
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
U
Unit 42
PCI Perspectives
PCI Perspectives
P
Privacy International News Feed
D
Docker

博客园 - Insus.NET

User Profile Service 服务未能登录 Visual Studio2026创建Vue项目 安装与配置node.js HTTP Error 403.14 - Forbidden VisualStudio2026回滚上一版本 消息认证码(加强) 网站无法使用插值字符串语法 HMAC(Hash-based Message Authentication Code)认证示例 浏览器自动发送域凭据 企业内小网站兼用Windows验证登录 访问用户控件的函数 onblur事件改为监听处理 将警报消息改为吐司消息 混合式提高用户编辑与操作效率 光标离开文框后即刻更新 WebForm实现Web API JavaScript对GridView删除行后并重新给其数据绑定 把CS值传给JS使用 v2 确认信息confirm由C#后端移至javascript前端 无法发布网站Web Site JavaScript判断字符是否为decimal 点击单元格弹出窗口处理数据返回父页 GridView数据控件中实现单选功能 文本框输入完后直接按回车提交数据 GridView对行进行全选或单选 TextBox文本框允许用户输入正或负小数 用户单击文本并复制至剪帖板 Vue3格式化日期时间与插值 SQL Server中验证大小字母和数字 MS SQL Server 数据加密与解密实例 相册由原来Lightbox升级至Vue2瀑布流 从Visual Studio 2022升级至Visual Studio 2026 报表应用图表charts显示数据 钉钉(DingTalk)免登录 Upgrade Outlook Connector 程序中真实应用SignalR Web API路径与IIS站点应用程序名或虚拟目录 在您可以登录前,此副本的 Windows 必须被 Microsoft 激活。您想现在激活它吗 电脑系统由Win10降级Win7折腾还是折腾 System.ComponentModel.Win32Exception: Access is denied
内容有无变化OnBlur即时更新引起的问题与解决
Insus.NET · 2026-04-30 · via 博客园 - Insus.NET

文本框中onblur事件,实现用户输入完成后,光标离开文本框实现即时更新。
但是,用户只要用鼠标点击文本框离开后,它均会执行更新操作,文本框内容是否有变化都会进行。

这是一种不好的性能影响。

先示例,然后看看Insus.NET怎样去解决它的。
数据还是使用下面随笔中的数据表,存储过程等。为了能看到效果,在数据表中添加一个字段,UpdatedDate来记录更新时间。
修改表:

ALTER TABLE [dbo].[ZTestData]
ADD [UpdatedDate] DATETIME NOT NULL DEFAULT(GETDATE())
GO

View Code

修改更新的存储过程:

ALTER PROCEDURE [dbo].[usp_ZTestData_UpdateBeiZhu]
@ID INT,
@BeiZhu NVARCHAR(30)
AS
BEGIN
    UPDATE [dbo].[ZTestData]
    SET
        [BeiZhu] = @BeiZhu,
        [UpdatedDate] = GETDATE()
    WHERE 
        [ID] = @ID
END
GO

View Code

修改获取记录的存储过程:

ALTER PROCEDURE [dbo].[usp_ZTestData_SelectAll]
AS
BEGIN
    SELECT 
        [ID],
        [IMT_pz],
        [IMT_gx],
        [BeiZhu],
        [UpdatedDate]
    FROM [dbo].[ZTestData]
END
GO

View Code

下面是修改App_Code下的ZTestData.cs类:
2026-04-29_16-40-45

此篇随笔,演示示例,由GridView改为html table呈现,
2026-04-29_16-45-20

<form id="form1" runat="server">
    <div>
        <table>
            <thead>
                <tr>
                    <td>ID</td>
                    <td>Remarks</td>
                    <td>Update Time</td>
                </tr>
            </thead>
            <tbody >
                <tr>
                    <td>
                        <%# Eval("ID") %>
                        <input id="HiddenID" type="hidden" value=' <%# Eval("ID") %>' />
                    </td>
                    <td>
                        <input id="TextBeiZhu" type="text" value='<%# Eval("BeiZhu") %>' onblur="update(event);" />
                    </td>
                    <td>
                        <%# Eval("UpdatedDate") %>
                    </td>
                </tr>
            </tbody>
            <tfoot>
            </tfoot>
        </table>
    </div>
    <asp:Button ID="ButtonRefreshData" runat="server" Text="RefreshData" Style="display:none" OnClick="ButtonRefreshData_Click" />
</form>

View Code

cs后端对html table数据绑定,
2026-04-29_16-53-27

public object DataItem { get; set; }

protected void Page_Load(object sender, EventArgs e)
{
    if (!IsPostBack)
    {
        Data_Binding();
    }

}

private void Data_Binding()
{
    ZTestDataEntity ztde = new ZTestDataEntity();
    DataView dv = ztde.Get_DataTable_GetData().DefaultView;
    dv.RowFilter = "ID = 2"; //指定记录主键,只是为了演示。
    DataItem = dv.ToTable().DefaultView[0];
    DataBind();
}

View Code

宣告一个对象object(第1个红色感叹号)。
第2处注意的地方,ztde.Get_DataTable_GetData()返回的是DataTable。

把它转为DefaultView后,可以对从数据库得到数据进行RowFilter过滤。过滤条件你可以自定。
还有一行是dv.ToTable().DefaultView[0];
给它一个0索引。受到过滤条件影响,有时也许返回不一定是1条记录。

还有一个隐藏服务控件Button按钮OnClick事件,
2026-04-29_17-08-37


最后是html input的text的 onblur="update(event);"事件,
照搬随笔最初参考随笔的链接的写法(不过仍有一些细节修改而变化):
2026-04-29_17-16-00

 <script src="Scripts/axios.min.js"></script>
 <script type="text/javascript">

     //onblur事件
     function update(event) {
         updateBeizhuByTextBox(event.target)
             .catch(console.warn);
     }

     function updateBeizhuByTextBox(txtboxElement) {
         return new Promise((resolve, reject) => {

             let url = '/api/MyTest/UpdateBeiZhu';
             var postData = {
                 ID: HiddenID.value,
                 BeiZhu: txtboxElement.value.trim()
             };

             axios.post(url, JSON.stringify(postData), {
                 headers: { 'Content-Type': 'application/json; charset=utf-8' }
             })
                 .then(response => {
                     if (!response.data.Status) {
                         alert(response.data.Message);
                         reject(response.data.Message);
                     } else {
                         alert(response.data.Message);
                         resolve(response.data);
                     }
                 })
                 .catch(error => {
                     console.error(error);
                     reject(error);
                 })
                 .finally(() => {
                     refreshData();
                 });
         });
     }

     function refreshData() {
         document.getElementById('<%= ButtonRefreshData.ClientID %>').click();
     }


 </script>

View Code


在#95行代码是为刷新呈现的数表而已。

看看效果(关注Update time栏位时间变化):
update_data_byonblur


从效果中看到,内容无变化,它更新了。
如何解决它呢?Insus.NET想到2种方法:
从数据端入手,写个INSTEAD OF UPDATE触发器,
2026-04-30_09-02-56

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author:        leo yeung
-- Create date: 2026-04-30
-- Description:    更新备注前验证是否有变化
-- =============================================
CREATE TRIGGER [dbo].[tri_ZTestData_UpdateBeiZhu]
ON  [dbo].[ZTestData]
INSTEAD OF UPDATE 
AS 
BEGIN    
    SET NOCOUNT ON;

    IF NOT EXISTS
    (
        SELECT 1 FROM inserted i 
        INNER JOIN deleted d ON (i.[ID] = d.[ID] AND i.[BeiZhu] = d.[BeiZhu]
    ))
    BEGIN        
        UPDATE target
        SET
            [IMT_pz] = i.[IMT_pz],
            [IMT_gx] = i.[IMT_gx],
            [BeiZhu] = i.[BeiZhu],
            [UpdatedDate] =i.[UpdatedDate]
        FROM [dbo].[ZTestData] target
        INNER JOIN inserted i ON target.[ID] = i.[ID];        
    END
    ELSE
    BEGIN
        RAISERROR(N'备注内容无任何变化,更新略过。',16,1)
    END
END
GO

View Code

如果不想写触发器,那就改更新存储过程,
2026-04-30_09-22-13

ALTER PROCEDURE [dbo].[usp_ZTestData_UpdateBeiZhu]
    @ID INT,
    @BeiZhu NVARCHAR(30)
AS
BEGIN
    IF NOT EXISTS
    (
        SELECT 1 FROM [dbo].[ZTestData]
        WHERE 
            [ID] = @ID
            AND[BeiZhu] = @BeiZhu
    )
    BEGIN    
        UPDATE [dbo].[ZTestData]
        SET
            [BeiZhu] = @BeiZhu,
            [UpdatedDate] = GETDATE()
        WHERE 
            [ID] = @ID
    END
    ELSE
    BEGIN
        RAISERROR(N'备注内容无任何变化,更新略过。',16,1)
        RETURN
    END
END
GO

View Code

上面数据库改正,它只是让更新是否继续。性能还是不容乐观,因为网络连接还是要连,数据sql语句还是要执行一遍。

不防改前端,参考如下,
2026-04-30_10-33-44

 window.lastSavedData = window.lastSavedData || new Map();

 function updateBeizhuByTextBox(txtboxElement) {
     return new Promise((resolve, reject) => {       

         var uniqueKey = txtboxElement.id + '_' + HiddenID.value.trim();                
         var newValue = txtboxElement.value.trim();

         // 检查是否与上次成功保存的值相同
         var lastValue = window.lastSavedData.get(uniqueKey);
         if (lastValue === newValue) {
             console.log("内容未改变,无需保存", uniqueKey, newValue);
             return resolve("内容未改变");
         }

         let url = '/api/IMT/UpdateBeiZhu';
         var postData = {
             ID: HiddenID.value,
             BeiZhu: newValue
         };

         axios.post(url, JSON.stringify(postData), {
             headers: { 'Content-Type': 'application/json; charset=utf-8' }
         })
             .then(response => {
                 if (response.data.Status !== true && response.data.Status !== "true") {
                     alert(response.data.Message);
                     reject(response.data.Message);
                 } else {
                     alert(response.data.Message);
                     window.lastSavedData.set(uniqueKey, newValue);
                     console.log("已记录", uniqueKey, newValue);
                     resolve(response.data);
                 }
             })
             .catch(error => {
                 console.error(error);
                 alert("保存失败,请重试!", true);
                 reject(error);
             })
             .finally(() => {
                 //
             });
     });
 }       

View Code

这样一改,可以防止同一文本框第2次更新时,不会去呼叫Web API把数据上传至数据库进行更新。
虽然不是很完善,已经做出很大改善了。

是否有更好方案?期待......