踩坑:el-checkbox 绑定的值变化但没有触发change事件

8,370 阅读1分钟

问题描述


mounted中修改checkbox的值,设想应该会触发change事件,但实际上并没有触发。

代码如下:

<template>
	   <el-checkbox v-model="checkBox" @change="change">测试</el-checkbox>
</template>
<script>
  export default{
  	data() {
      return {
        checkBox: false,
      }
    },
    methods:{
    	change(){
      	console.log('改变了值')
      }
    },
    mounted(){
    	this.checkBox = true
    }
  }
</script>

原因探究


html中checkbox 的实现:

我们先来看看在html中checkbox 的实现:<input type="checkbox">

其中checked属性用于控制控件是否被选中,onchange事件,在元素值被改变时执行。

这里要注意:

当我们用js修改checked绑定的值时,并不会触发onchange事件,用鼠标点击会checkbox框会触发onchange事件。

如下边这段代码

<body>
	<section id="app">
		<button onclick="alterCheckboxValue()">切换!</button>
		<input type="checkbox" id="checkbox1" onchange="handleChange()">
	</section>
	<script>
		function alterCheckboxValue() {
			const el = document.querySelector("#checkbox1");
			el.checked = !el.checked;
		}
		function handleChange(e) {
			console.log("触发change事件");
		}
	</script>
</body>

v-model指令

v-model本质是个语法糖,它负责监听用户的输入事件以更新数据,并对一些极端场景进行一些特殊处理。它实际上是做了两步动作:

  • 绑定数据value
  • 触发输入事件input

看看下边这两段代码就清楚了:

<input type="text" v-model="msg">
// 等价于
<input type="text" v-bind:value="msg" v-on:input="msg=$event.target.value">

v-model :value="msg" ``@input="msg=$event.target.value"的语法糖,

其中

  • :value="msg"是绑定了数据,value就是input输入框里的值;
  • @input="msg=$event.target.value"就是监听input输入框里值的变化,然后改变值。

一句话概括就是,绑定数据并且监听数据改变


出错的代码

我们再来看看出错的代码

<el-checkbox v-model="value" @change="HandleChange">

根据上边内容,我们可以知道,这段代码中

  • v-model = "value" ****应该就是对input标签checked属性与value进行了一个绑定
  • @change = "HandleChange"就是onchange事件

如果elmentUI没有做特殊处理,当我们通过JS修改value值时,也不会触发HandleChange方法

el-checkbox源码:

我们再来看看el-checkbox源码:

参考:blog.csdn.net/tangran0526…

查看源码可以看到,确实如我们所想,当绑定的值变化后,并没有触发这个 handleChange事件,而是触发了el-form父元素的change事件。

watch: {
  		// el-checkbox绑定的值
      value(value) {
        this.dispatch('ElFormItem', 'el.form.change', value);
      }
    }

解决


重新封装el-checkbox,添加vaule的监听属性,触发change事件。

<!--子组件-->
<template>
  <el-checkbox v-model="model"/>
</template>

<script>
export default {
  name: 'my-checkBox',
  props: {
    value: false,
    autoChange: {
      type: Function,
      default: () => {
      }
    }
  },
  data() {
    return {
      selfModel: false,
    }
  },
  computed: {
    model: {
      get() {
        return this.value !== undefined
            ? this.value : this.selfModel
      },

      set(val) {
        this.$emit('input', val)
        this.selfModel = val;
      }
    },
  },
  watch: {
    value() {
      this.$emit('autoChange', this.value)
    }
  }
}
</script>

父组件中使用:

  <auto-checkbox v-model:value="item.checkBoxShow" @autoChange="layerChange(item)"/>