经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » JSJS库框架 » JavaScript » 查看文章
自定义组件v-model的实质性理解
来源:cnblogs  作者:cumi  时间:2018/10/8 9:07:01  对本文有异议

用了几个月Vue一直很纠结自定义组件的v-model实现,最近开始学习React时,React中受控组件与状态提升的理念与v-model不谋而合。

 转载请注明地址: https://www.cnblogs.com/sonoda-umi/p/9750188.html

在Vue与React中其实都存在单向数据流的概念,只不过Vue中通过各种语法糖被弱化了,比如React与Vue中的props都是单向传输数据的。在React中如果想实现类似于v-model的功能,需要这样实现:

父组件:

  1. class Calculator extends React.Component {
  2. constructor(props) {
  3. super(props);
  4. this.handleCelsiusChange = this.handleCelsiusChange.bind(this);
  5. this.handleFahrenheitChange = this.handleFahrenheitChange.bind(this);
  6. this.state = {temperature: '', scale: 'c'};
  7. }
  8. handleCelsiusChange(temperature) {
  9. this.setState({scale: 'c', temperature});
  10. }
  11. handleFahrenheitChange(temperature) {
  12. this.setState({scale: 'f', temperature});
  13. }
  14. render() {
  15. const scale = this.state.scale;
  16. const temperature = this.state.temperature;
  17. const celsius = scale === 'f' ? tryConvert(temperature, toCelsius) : temperature;
  18. const fahrenheit = scale === 'c' ? tryConvert(temperature, toFahrenheit) : temperature;
  19. return (
  20. <div>
  21. <TemperatureInput
  22. scale="c"
  23. temperature={celsius}
  24. onTemperatureChange={this.handleCelsiusChange} />
  25.  
  26. <TemperatureInput
  27. scale="f"
  28. temperature={fahrenheit}
  29. onTemperatureChange={this.handleFahrenheitChange} />
  30.  
  31. <BoilingVerdict
  32. celsius={parseFloat(celsius)} />
  33.  
  34. </div>
  35. );
  36. }
  37. }

子组件:

  1. class TemperatureInput extends React.Component {
  2. constructor(props) {
  3. super(props);
  4. this.handleChange = this.handleChange.bind(this);
  5. }
  6. handleChange(e) {
  7. this.props.onTemperatureChange(e.target.value);
  8. }
  9. render() {
  10. const temperature = this.props.temperature;
  11. const scale = this.props.scale;
  12. return (
  13. <fieldset>
  14. <legend>Enter temperature in {scaleNames[scale]}:</legend>
  15. <input value={temperature}
  16. onChange={this.handleChange} />
  17. </fieldset>
  18. );
  19. }
  20. }

这是一个输入水温从而监控水是否沸腾的一个小组件。子组件是一个温度输入的input控件,父组件是由两个温度输入(华氏与摄氏)与一个现实水是否沸腾的指示器组成。父组件存在一个state作为唯一数据源用于存放温度等值于状态,温度通过子组件的prop传入子组件内部通过input的value属性显示在基础输入框中,当在基础输入框中触发输入时间时,onChange事件触发由prop传入的onTempreture事件并附带变化后的值,再由父组件的handleCelsiusChange/handleFahrenheitChange事件处理方法将基础输入框传来的值写入state中,再由state通过prop将温度传入子组件完成一次数据的更新。这其中其实已经完成了对Vue中基础组件v-model的理解与自定义组件v-model的理解。

转载请注明地址: https://www.cnblogs.com/sonoda-umi/p/9750188.html

在Vue官方文档中,对原生组件v-model的解释是这样的:

  1. <input
  2. v-bind:value="searchText"
  3. v-on:input="searchText = $event.target.value"
  4. >

v-model其实是上面写法的语法糖。其实就是将this.searchText的值通过名为value的prop传入input组件内,而后当input事件触发时将事件带来的input的新值写入this.searchText中,然后根据this.searchText中值的变化通过value的prop传入input控件完成input控件上值的变化,如果去掉v-on...后,这个控件将变为一个只读控件。

对于自定义组件,文档中有这样的解释:

一个组件上的 v-model 默认会利用名为 value 的 prop 和名为 input 的事件,但是像单选框、复选框等类型的输入控件可能会将 value 特性用于不同的目的。model 选项可以用来避免这样的冲突:

  1. Vue.component('base-checkbox', {
  2. model: {
  3. prop: 'checked',
  4. event: 'change'
  5. },
  6. props: {
  7. checked: Boolean
  8. },
  9. template: `
  10. <input
  11. type="checkbox"
  12. v-bind:checked="checked"
  13. v-on:change="$emit('change', $event.target.checked)"
  14. >
  15. `
  16. })
  1. 现在在这个组件上使用 v-model 的时候:
  1. <base-checkbox v-model="lovingVue"></base-checkbox>
  1. 这里的 lovingVue 的值将会传入这个名为 checked prop。同时当 <base-checkbox> 触发一个 change 事件并附带一个新的值的时候,这个 lovingVue 的属性将会被更新。

其实就是将原来v-model默认使用的名为value的prop与名为input的event自定义一个名字使用,在上面自定义组件中存在

  1. props: {
  2. checked: Boolean
  3. }

说明checked本质上还是一个prop,然后在子组件的model属性中将自定义的prop与event注册,而触发model中event时也就是通过触发子组件的事件在父组件中修改绑定自定义prop的变量的值的过程,这样这个过程就很明显了:

1.父组件创建一个名为tmp变量绑定名为checked的prop的值(已被修饰为v-model)并根据父组件中tmp值的变化将变化后的值传入子组件中,引起子组件checkbox状态变化;

2.子组件中checkbox被勾选,触发checkbox的change事件,通过this.$emit方法触发子组件的change事件并将change事件产生的新值传入;

3.因为在model属性中已将v-model语法糖中event注册为change(换成其他名字也都可以),v-model会自动将子组件传来的值传入tmp变量中;

4.Vue监听到tmp值的变化,执行第一步,更新子组件中checkbox的状态;

 

其实上面的子组件可以换个写法更容易理解:

  1. Vue.component('base-checkbox', {
  2. model: {
  3. prop: 'checked',
  4. event: 'test'
  5. },
  6. props: {
  7. checked: Boolean
  8. },
  9. template: `
  10. <input
  11. type="checkbox"
  12. v-bind:checked="checked"
  13. v-on:change="$emit('test', $event.target.checked)"
  14. >
  15. `
  16. })

父组件中调用时可以这样写:

  1. <base-checkbox :checked="something" @test="something='子组件中的$event.target.value'"></base-checkbox>

这样对v-model的理解也就一目了然了。

转载请注明地址: https://www.cnblogs.com/sonoda-umi/p/9750188.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号