自定义组件v-model的实质性理解

时间: 2018-10-08阅读: 1480标签: react

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

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


父组件:

class Calculator extends React.Component {
  constructor(props) {
    super(props);
    this.handleCelsiusChange = this.handleCelsiusChange.bind(this);
    this.handleFahrenheitChange = this.handleFahrenheitChange.bind(this);
    this.state = {temperature: '', scale: 'c'};
  }

  handleCelsiusChange(temperature) {
    this.setState({scale: 'c', temperature});
  }

  handleFahrenheitChange(temperature) {
    this.setState({scale: 'f', temperature});
  }

  render() {
    const scale = this.state.scale;
    const temperature = this.state.temperature;
    const celsius = scale === 'f' ? tryConvert(temperature, toCelsius) : temperature;
    const fahrenheit = scale === 'c' ? tryConvert(temperature, toFahrenheit) : temperature;

    return (
      <div>
        <TemperatureInput
          scale="c"
          temperature={celsius}
          onTemperatureChange={this.handleCelsiusChange} />

        <TemperatureInput
          scale="f"
          temperature={fahrenheit}
          onTemperatureChange={this.handleFahrenheitChange} />

        <BoilingVerdict
          celsius={parseFloat(celsius)} />

      </div>
    );
  }
}

子组件:

class TemperatureInput extends React.Component {
  constructor(props) {
    super(props);
    this.handleChange = this.handleChange.bind(this);
  }

  handleChange(e) {
    this.props.onTemperatureChange(e.target.value);
  }

  render() {
    const temperature = this.props.temperature;
    const scale = this.props.scale;
    return (
      <fieldset>
        <legend>Enter temperature in {scaleNames[scale]}:</legend>
        <input value={temperature}
               onChange={this.handleChange} />
      </fieldset>
    );
  }
}

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


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

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

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 选项可以用来避免这样的冲突:

Vue.component('base-checkbox', {
  model: {
    prop: 'checked',
    event: 'change'
  },
  props: {
    checked: Boolean
  },
  template: `
    <input
      type="checkbox"
      v-bind:checked="checked"
      v-on:change="$emit('change', $event.target.checked)"
    >
  `
})


现在在这个组件上使用 v-model 的时候:

<base-checkbox v-model="lovingVue"></base-checkbox>

这里的 lovingVue 的值将会传入这个名为 checked 的 prop。同时当 <base-checkbox> 触发一个 change 事件并附带一个新的值的时候,这个 lovingVue 的属性将会被更新。其实就是将原来v-model默认使用的名为value的prop与名为input的event自定义一个名字使用,在上面自定义组件中存在

props: {
    checked: Boolean
  }


说明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的状态;

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

Vue.component('base-checkbox', {
  model: {
    prop: 'checked',
    event: 'test'
  },
  props: {
    checked: Boolean
  },
  template: `
    <input
      type="checkbox"
      v-bind:checked="checked"
      v-on:change="$emit('test', $event.target.checked)"
    >
  `
})

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

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

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


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


站长推荐

1.云服务推荐: 国内主流云服务商,各类云产品的最新活动,优惠券领取。地址:阿里云腾讯云华为云

链接: http://www.fly63.com/article/detial/1127

react生命周期详解_深入理解React生命周期

React主要思想是通过构建可复用组件来构建用户界面,每个组件都有自己的生命周期,它规定了组件的状态和方法需要在哪个阶段改变和执行。所谓组件就是有限状态机,,表示有限个状态以及在这些状态之间的转移和动作行为的模型。

用思维模型去理解 React

我了解到,掌握了某种语言、框架或工具的人与没有掌握的人之间的最大区别在于他们所使用的思维模型(Mental Model)。前者拥有清晰而先进的思维模型,而后者则没有。

React 服务端渲染方案完美的解决方案

最近在开发一个服务端渲染工具,通过一篇小文大致介绍下服务端渲染,和服务端渲染的方式方法。在此文后面有两中服务端渲染方式的构思,根据你对服务端渲染的利弊权衡,你会选择哪一种服务端渲染方式呢?

React事件绑定几种方法测试

es6写法的类方法默认没有绑定this,不手动绑定this值为undefined。因此讨论以下几种绑定方式。构造函数constructor中用bind绑定、在调用的时候使用bind绑定this、在调用的时候使用箭头函数绑定this、使用属性初始化器语法绑定this

React使用propTypes进行类型检查

注意: React.PropTypes 自 React v15.5 起已弃用。请使用 prop-types 库代替。随着你的应用的开发,你会使用类型检查的方法来捕获很多bug。对于一些应用,你可以使用js扩展就像Flow或者TypeScript去对整个应用进行类型检查

React事件处理函数必须使用bind(this)的原因

学习React的过程中发现调用函数的时候必须使用bind(this),之后直接在class中声明函数即可正常使用,但是为什么呢,博主进行了一番查阅,总结如下。

React中富文本编辑器的技术选型调研

富文本编辑器是项目中不可或缺的部分,目前市面上可以选择的富文本编辑器种类繁多,如何在项目中选择一款集轻量,美观,稳定,坑少,满足需求的富文本编辑器变成了团队中一个重要的问题。我对这两款富文本编辑器都进行了使用,并结合目前的项目需求进行了比较:react-quill、braft-editor

React 是否保持 state 更新的顺序?

我知道 React 的状态更新是异步执行的,为了性能优化,状态是批量更新的。所以你永远不能确信在调用 setState 后状态是否更新了。但是你是否可以确认 setState 调用后状态的更新顺序呢?

React 代码共享最佳实践方式

任何一个项目发展到一定复杂性的时候,必然会面临逻辑复用的问题。在React中实现逻辑复用通常有以下几种方式:Mixin、高阶组件(HOC)、修饰器(decorator)、Render Props、Hook。本文主要就以上几种方式的优缺点作分析

一文看懂React Hooks

React Hooks是从React 16.8版本推出的新特性,目的是解决React的状态共享以及组件生命周期管理混乱的问题。React Hooks的出现标志着,React不会再存在无状态组件的情况,React将只有类组件和函数组件的概念

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!