change()事件及val()/html()方法不会触发change事件

本文详细介绍了jQuery中change()事件的使用方法及其触发条件,并提供了实际应用案例,展示了如何解决val()和html()方法更改元素值后不触发change事件的问题。

change()事件及val()/html()方法不会触发change事件

一.定义

  • change()函数用于为每个匹配元素的change事件绑定处理函数
  • 当元素的值发生改变时,会发生 change 事件;
  • 适用范围:和以及;
  • change() 函数触发 change 事件,或规定当发生 change 事件时运行的函数;
  • 注意:当用于 select 元素时,change 事件会在选择某个选项时发生;当用于 text field 或 text area 时,该事件会在元素失去焦点时发生。

二.语法

  • jQueryObject.change( [ [ data ,] handler ] )
  • 参数:
    • data:可选/任意类型,触发事件时,需要通过event.data传递给事件处理函数的任意数据
    • handler :可选/Function类型,指定的事件处理函数。

三.val()/html()方法改变元素值后元素change事件无效解决方案:

  • 方法一:手动出发:$(“input”).val(Math.random()).change()
  • 方法二(很好用): (“#querySubSort”).val(“”) ;(“#querySubSort”).trigger(“change”);

四.代码块

$(function() {
    //分类控制子类
    $("#querySort").change(loadQuerySubSort);
    //子类控制条目
    $("#querySubSort").change(loadQueryEntry);
    //加载类别
    loadQuerySort();
});
// 加载类别
function loadQuerySort() {
    jQueryAjaxAsync("/assortAction/sortListByFlowCode", {"flowCode":"INCIDENT"},
        function(sortTree_data){
            loadFormData("querySort", $.parseJSON(sortTree_data));
        });
}
//加载子类
function loadQuerySubSort() {
    var querySortId = $("#querySort").val();
    if (querySortId) {
        jQueryAjaxAsync("/assortAction/subSortList", {"flowCode":"INCIDENT","id":querySortId},
            function(sortTree_data){
                loadFormData("querySubSort", JSON.parse(sortTree_data));
                //当清空子类val()其change事件不会触发
                $("#querySubSort").val("") ;
                //解决方法
                $("#querySubSort").trigger("change");
            });
    }else {
        $("#querySubSort").val("") ;
        $("#querySubSort").trigger("change");
        $("#querySubSort").html("");
        $("#queryEntry").html("");
    }
}
//加载条目
function loadQueryEntry() {
    var querySubSortId = $("#querySubSort").val();
    if (querySubSortId) {
        jQueryAjaxAsync("/assortAction/entryList", {"flowCode": "INCIDENT", "id": querySubSortId},
            function (sortTree_data) {
                loadFormData("queryEntry", JSON.parse(sortTree_data));
                $("#queryEntry").val("") ;
            });
    }else {
        $("#queryEntry").val("") ;
        $("#queryEntry").html("");
    }
}
//点击清除按钮
function clearParam(){
        $(':input','#basicForm,#seniorForm')
        .not(':button, :submit, :reset, :hidden')
        .val('')
        .attr("paramId", "")
        .removeAttr('selected');
    $("#queryStatus").selectpicker('deselectAll');
    //点击清除 :分类/子类/条目 清空  及受理组受理人
    $("#querySort").trigger("change");
    $("#querySubSort").trigger("change");
}
<think> 我们正在处理一个关于Element UI中el-select组件的问题:用户希望在点击页面其他地方(即当el-select失去焦点时)触发change事件。然而,根据常规行为,el-select的change事件是在选项改变时触发的,而是在失去焦点时触发。因此,我们需要模拟在失去焦点时触发change事件。 通常,我们可以通过监听el-select的blur事件来实现。但是,需要注意的是,blur事件change事件触发时机同: - change事件:当选中值发生变化时触发(即用户选择了同的选项) - blur事件:当select失去焦点时触发 用户的需求是:在点击其他地方(即el-select失去焦点)时,触发change事件。这实际上可能change事件的常规用法,因为change事件通常用于值变化。但是,我们可以理解为:用户希望在失去焦点时执行与change事件相同的处理逻辑。 因此,我们可以采取以下步骤: 1. 为el-select添加blur事件监听,当失去焦点时执行一个方法。 2. 在该方法中,我们可以获取当前选中的值,然后执行与change事件相同的逻辑。 然而,需要注意的是,blur事件触发时,change事件可能已经触发过(如果值发生了变化),也可能没有触发(如果值没有变化)。所以,如果用户希望在值没有变化的情况下,失去焦点也执行相同的逻辑,那么我们可以直接调用change事件的处理函数。 但是,如果用户希望的是无论值是否变化,只要失去焦点就触发,那么我们可以将blur事件绑定到change事件的处理函数上。但要注意,change事件处理函数可能会依赖于当前选择的值,而blur事件并没有传递当前值,我们可以通过this获取到绑定的v-model的值。 另外,还需要注意一个问题:blur事件可能会在用户点击下拉选项时触发(因为点击选项会导致下拉框收起,从而失去焦点)。但此时change事件也会触发。因此,我们需要注意避免重复触发。 因此,我们可以这样实现: 方案一:在blur事件中执行change事件处理函数(假设change事件处理函数依赖于事件对象,而是依赖于当前绑定的值) ```html <el-select v-model="value" @change="handleChange" @blur="handleChange"> <el-option ...></el-option> </el-select> ``` 但是,这样会导致: - 当值变化时:先触发change事件,然后触发blur事件(因为选择后下拉框收起,select失去焦点),所以会执行两次handleChange。 这通常是我们想要的。 方案二:只在blur事件触发,而使用change事件。这样,无论是选择选项还是输入框失去焦点(比如用户选择了选项后,然后点击其他地方,或者用户没有选择新选项只是点击了一下输入框然后点击其他地方)都会触发。 但是,如果用户选择了一个新选项,那么此时会先触发change事件(如果我们没有监听change事件,那么就不会执行),然后触发blur事件。所以,我们只监听blur事件,那么就会在失去焦点时执行一次。 然而,需要注意的是,如果用户通过键盘操作改变了值(比如使用键盘上下键选择然后按回车),那么change事件触发,而blur事件不会触发(因为焦点还在select上)。所以,只监听blur事件可能会遗漏这种情况。 因此,我们需要根据实际场景权衡。 实际上,用户可能的需求是:在用户完成选择操作(包括可能通过键盘操作)并且离开输入框时执行某个操作。那么,我们应该同时监听change和blur事件,但需要避免重复执行。 我们可以这样设计: - 在change事件中,标记值已经变化,并执行操作(同时清除标记)。 - 在blur事件中,如果值发生了变化(且尚未处理),则执行操作;或者无论值是否变化,只要失去焦点就执行一次操作(但注意避免与change重复)。 然而,考虑到操作可能是相同的,我们可以通过防抖或标记来避免重复。 但是,根据用户提供的引用[1],我们知道clear事件也会触发change事件,所以如果我们在blur事件中再次触发,可能会带来问题。 因此,更简单的做法是:用户如果只需要在失去焦点时执行操作,那么可以只监听blur事件,而忽略change事件。但要注意,这可能会遗漏键盘操作(键盘操作后如果没有使select失去焦点,则不会触发)。 基于以上分析,这里给出一个方案:使用blur事件触发用户想要的操作,但要注意,如果用户需要实时响应值变化(比如通过键盘操作),那么还需要监听change事件。 如果用户希望的是在离开输入框(失去焦点)时执行一次操作,而关心是变化导致的还是仅仅失去焦点,那么我们可以只使用blur事件。 但是,在Element UI的select中,blur事件会传递一个事件对象,我们可以利用它。 具体实现: 1. 只使用blur事件: ```html <el-select v-model="value" @blur="handleBlur"> <el-option ...></el-option> </el-select> ``` 在方法中: ```javascript methods: { handleBlur(event) { // 执行你想要的操作,这里可以获取到this.value console.log('当前值:', this.value); // 调用你的业务逻辑 } } ``` 2. 如果同时需要change事件和blur事件,但想重复执行,可以使用一个标记来记录change事件是否已经处理过。 ```javascript data() { return { value: '', changed: false }; }, methods: { handleChange() { // 执行操作 this.doSomething(); this.changed = true; // 标记已经由change事件处理 }, handleBlur() { // 如果change事件没有处理过,则执行 if (!this.changed) { this.doSomething(); } // 重置标记 this.changed = false; }, doSomething() { // 实际的操作 } } ``` 但是,这种方法在多次触发时可能标记会被覆盖,需要根据具体情况调整。 3. 另一种思路:使用防抖。在change事件和blur事件中都调用同一个方法,但是通过防抖确保在一段时间内只执行一次。 综上所述,根据用户需求,如果只是希望在失去焦点时触发,那么直接使用blur事件即可。如果希望同时响应值变化和失去焦点,并且避免重复,则可以使用标记或防抖。 由于用户描述为“点击其他地方时让el-select触发change事件”,所以我认为第一种方案(只使用blur事件)更符合要求。因为点击其他地方就是失去焦点(blur),此时无论值是否变化,都执行一次操作。 因此,建议用户在el-select上监听blur事件,并在该事件的处理函数中执行与change事件相同的逻辑(或者将原先change事件的逻辑移到blur事件中)。 注意:如果用户需要区分是值变化还是单纯失去焦点,那么就需要分别处理。 另外,引用[2]中提到,change事件有时会延迟响应,所以使用blur事件可能更符合即时性的需求。 总结:通过监听el-select的blur事件,可以在点击其他地方(即select失去焦点)时执行自定义逻辑。 示例代码: ```html <template> <el-select v-model="selectedValue" @blur="handleBlur" clearable> <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </el-option> </el-select> </template> <script> export default { data() { return { selectedValue: '', options: [ { value: 'option1', label: 'Option 1' }, { value: 'option2', label: 'Option 2' } ] }; }, methods: { handleBlur() { // 这里执行原先change事件中的逻辑 console.log('在blur事件中处理,当前值为:', this.selectedValue); // 调用接口或其他操作 } } }; </script> ``` 这样,当用户点击页面其他地方,使select失去焦点时,就会触发handleBlur方法。 注意:如果用户清除了选择(使用了clearable),那么点击清除按钮也会触发blur事件吗?实际上,清除按钮点击后,输入框仍然处于焦点状态(因为清除按钮在输入框内),所以并不会触发blur事件。但是,清除操作会触发change事件(如果监听了的话)。因此,如果用户希望清除操作后也触发同样的逻辑,那么需要同时监听clear事件(如引用[1]所述),或者继续使用change事件来处理清除操作。 所以,如果用户需要处理清除操作,那么只监听blur事件够的,因为清除操作并不会触发blur。因此,我们需要同时监听change事件来处理清除操作,而blur事件处理失去焦点的情况(此时可能值没有变化)。 这样,我们可能需要同时监听change和blur事件,并且避免重复执行(清除操作会触发change事件,然后如果用户再点击其他地方,会触发blur事件,导致重复执行)。 因此,更完整的方案是:将清除操作和改变操作视为值变化,在change事件中立即执行操作,而在blur事件中,如果值没有变化(即用户只是聚焦了select但没有改变选项就离开了),我们也需要执行一次操作。 我们可以这样设计: - change事件:立即执行操作(比如提交当前值),并记录当前值(用于后续比较)。 - blur事件:比较当前值和change事件发生时记录的值是否相同,如果同,说明值变化已经被change事件处理了;如果相同,说明值没有变化,那么需要执行操作。 但注意,清除操作会触发change事件(值为空),所以会被change事件处理。 示例代码: ```html <template> <el-select v-model="selectedValue" @change="handleChange" @blur="handleBlur" clearable > <el-option ...></el-option> </el-select> </template> <script> export default { data() { return { selectedValue: '', lastChangeValue: null // 记录上次change事件的值 }; }, methods: { handleChange(val) { this.doSomething(val); this.lastChangeValue = val; // 记录这次change事件的值 }, handleBlur() { // 如果当前值等于上一次change事件的值,说明在change事件后值没有变化(即用户只是聚焦又离开,没有改变选项) // 注意:初始情况下lastChangeValue为null,而selectedValue可能是空字符串,所以需要类型比较 if (this.selectedValue === this.lastChangeValue) { return; // 值没有变化,执行操作(因为change事件已经执行过了,或者需要执行) } // 如果当前值等于上一次change事件的值,说明在最后一次change事件后又发生了变化?这应该发生,因为change事件在每次值变化时都会触发。 // 实际上,在blur事件中,当前值应该和最后一次change事件的值相同,除非有异步更新导致一致? // 所以,这里我们可能只需要处理值没有变化的情况:即用户没有改变值就离开了,但我们仍然希望执行操作? // 根据用户需求:点击其他地方触发操作,无论值是否变化。但为了避免与change事件重复,我们这里只处理值没有变化的情况(即用户没有通过选择改变值,只是聚焦然后离开) // 注意:用户可能通过键盘输入改变值(对于可搜索的select),然后离开,这种情况会先触发change事件(每次输入变化都会触发change?实际上,可搜索的select,每次选择选项才会触发change,输入时并不会,除非使用了远程搜索并且输入值改变就会触发) // 因此,这个逻辑比较复杂,可能取决于select的使用方式。 // 另一种思路:在blur事件中,无论值是否变化,都执行操作,但设置一个标志位表示change事件已经执行过,避免重复。 // 由于前面的分析比较复杂,这里我们采用标志位的方法。 } } }; </script> ``` 由于以上逻辑较为复杂,且用户需求可能因场景而异,这里我们回到用户的问题:用户希望点击其他地方触发change事件。如果我们将其理解为:在失去焦点时,管值有没有变化,都执行一次操作(即使值没有变化,只要失去焦点就执行),那么最简单的方式就是只监听blur事件。 但是,如果用户的操作是提交当前值,那么: - 当用户改变选项(包括清除)时,会触发change事件,我们可以在change事件中提交。 - 当用户没有改变选项,只是打开下拉框然后关闭(没有选择新选项)而失去焦点,此时值没有变化,但我们可能也希望提交(或者提交?)。 因此,需要根据业务需求来决定。 如果用户希望的是在失去焦点时提交当前值(无论是否变化),那么只监听blur事件并且在blur事件中提交即可。 最后,根据引用[3]和[4],el-select在初始化时可能会触发change事件,而引用[5]中提到重复点击同一个选项不会触发change事件。这些是el-select本身的事件机制,我们在使用blur事件不会受到影响。 结论:使用blur事件监听失去焦点,并在blur事件处理函数中执行操作,可以实现点击其他地方触发操作的需求。 因此,回答用户:您可以通过监听el-select的blur事件来实现在点击其他地方时(即select失去焦点时)触发自定义操作。 相关问题: 1. 如何区分el-select的blur事件change事件? 2. 如何防止el-select的blur事件change事件重复触发同一逻辑? 3. el-select的clear事件与blur事件的关系是什么? </think> 针对在点击其他地方时触发 `el-select` 的 `change` 事件的需求,以下是完整解决方案和注意事项: ### 解决方案 通过监听 `blur` 事件模拟 `change` 事件触发,同时处理焦点状态管理: ```html <template> <!-- 绑定 blur 和 keydown 事件 --> <el-select v-model="selectedValue" ref="mySelect" @blur="handleBlur" @keydown.esc="handleManualChange" clearable > <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" /> </el-select> </template> <script> export default { data() { return { selectedValue: '', options: [ { value: '1', label: '选项1' }, { value: '2', label: '选项2' } ], preventBlurTrigger: false // 防止重复触发的标志位 } }, methods: { // 监听失去焦点事件 handleBlur(event) { if (this.preventBlurTrigger) return; // 获取焦点关联元素 const relatedTarget = event.relatedTarget; // 排除下拉菜单内的点击 if (!relatedTarget || !this.$refs.mySelect.$el.contains(relatedTarget)) { this.triggerChangeEvent(); } }, // 手动触发change逻辑 triggerChangeEvent() { console.log('外部点击触发change', this.selectedValue); // 这里执行原change事件逻辑 // this.yourChangeHandler(); }, // ESC键手动触发 handleManualChange() { this.preventBlurTrigger = true; this.$nextTick(() => { this.triggerChangeEvent(); this.preventBlurTrigger = false; }); } } } </script> ``` ### 关键实现原理 1. **`blur` 事件监听** 使用 `@blur` 捕获下拉框失去焦点的时机,通过 `event.relatedTarget` 判断点击位置: - 排除下拉菜单内部的点击(避免与正常选择冲突) - 只响应外部区域的点击 2. **防止重复触发机制** - 设置 `preventBlurTrigger` 标志位阻止事件循环 - 配合 `$nextTick` 确保状态重置时机正确 3. **键盘事件扩展** 添加 `@keydown.esc` 支持 ESC 键手动触发,增强交互体验 ### 注意事项 1. **与原生 `change` 事件区别** 此方案模拟的 `change` 可能在以下情况额外触发: - 点击页面空白区域 - 切换浏览器标签页 - 点击其他可聚焦元素 2. **初始化触发问题** 如果绑定值为空数组 `[]` 可能意外触发(引用[4]),建议初始化设为 `null`: ```js data() { return { selectedValue: null // 避免初始化触发 } } ``` 3. **多选模式特殊处理** 多选时需监听 `visible-change` 事件补充逻辑: ```html <el-select @visible-change="handleMenuToggle" multiple > ``` ```js handleMenuToggle(visible) { if (!visible) this.triggerChangeEvent(); } ``` 4. **异步操作同步** 若 `change` 含异步请求,需添加加载状态锁: ```js triggerChangeEvent() { if (this.loading) return; this.loading = true; fetchData().finally(() => this.loading = false); } ``` ### 适用场景 1. 需要保存未修改的表单状态 2. 实现自动提交的表单交互 3. 响应页面切换前的数据追踪 > 通过 `blur` + `focus` 状态管理模拟 `change` 事件是可靠方案,但需注意与原生 `change` 行为的差异[^1][^3]。对于复杂场景建议结合 `visible-change` 事件补充检测[^5]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值