正常的业务需求中,我们需要封装一些常用的组件。现在有一个最简单的需求,封装一个有特定样式的input框,够简单吧? 好,我们来这样封装:
字符串模板文件命名为 CInput.vue:

<template>
  <input type="text" class="your-custom-class-name" v-model="name" >  
</template>
<style lang="scss">
	.your-custom-class-name {
		...
	}
</style>
<script>
  export default {
    props: {
      name: String
    }
  }
</script>

ok,我们在父组件中引用此组件,父组件的data函数长这样:

data () {
	return {
		name: null,
		... //other data
	}
}

父组件里面引用子组件的代码长这样:

加载页面,ok,完全正常,但是我们在输入框体里面输入值,修改name的值的时候:
这里写图片描述

会出现警告:
这里写图片描述

警告的意思是说,不应该直接将父元素传递给子元素的属性直接挂在到子组件上面【双向绑定】。应该在子组件的data或者计算属性里面基于这个属性来初始化数据。 参考资料:单向数据流

当父组件的属性变化时,将传导给子组件,但是不会反过来。这是为了防止子组件无意修改了父组件的状态——这会让应用的数据流难以理解。

子组件修改父组件数据,最好是通过 eventHub or vuex来实现。当然特定场景使用简单粗暴的this.$parent.xx来修改吧。


回到正题,现在这样来做是肯定不行的,所以后来,我瞎X尝试***【当然这个方法本身是不可取的,请不要采用这个办法】***,将父组件中的name的值,默认设置为一个对象,而不是null.

代码长这样

data () {
	return {
		name: { value: null }
	}
}

然后将子组件的v-model不是绑定name 而是绑定name.value,代码长这样:

  <input type="text" class="your-custom-class-name" v-model="name.value" >  

这样我们在界面上修改值的时候,就不会报警告了。【我们拿错误的实验得到了正确的结果】。 实际上可以点击上面关于单向数据流的链接,可以知道,不应该直接改变父组件的数据,项目复杂度上去之后,难以维护,你根本不知道是谁改变了父组件里面的数据。但是特定场景是需要直接修改父元素的数据,请使用.sync修饰符


然而为什么不用v-model来用于我们自己的组件呢,v-model对数据进行双向绑定实际上是一个语法糖。比如我们对于一个input实现双向绑定。
代码长这样:

<input v-model="data">

实际上是语法糖:

<input 
  v-bind:value="data"
  v-on:input="data = $event.target.value">

input上有一个Input事件,值变化的时候,会将值绑定给这个变量data。
在vue版本2.2.0之后,v-model可以配置:

1,组件定一个属性 value
2, 在有新的值触发或者说值发生变化时,触发input事件 like this:

this.$emit('input', newValue)

好,现在我们来修改上面的代码:

<template>
  <input type="text" :value="currentValue" @input="handleInput">
</template>
<script>
  export default {
    data () {
      return {
        currentValue: this.value //不直接绑定prop,而是在data 或者 computed 里面根据prop初始化自己领域的值
      }
    },
    props: { 
      value: [String, Number] // key code 
    },
    methods: {
      handleInput() {
        const value = event.target.value
        this.currentValue = value
        this.$emit('input', value) // key code 
      }
    }
  }
</script>


binggo! 这样的话,就不会有⚠️了

//父元素的data长这样
data () {
	return {
		name: null,
		... //other data
	}
}

//引用子组件
<c-input v-model="name"> </c-input>

这样也不会报错了!

当然如果子组件里面还有 第三层其他的自定义组件(父亲->子组件->孙子组件),你可能需要监听在子组件里面的v-model=“data” 的data值,使用watch,如果这个值发生了变化,调用 this.$emit('input', newValue)

Logo

前往低代码交流专区

更多推荐