用react的方式写vue

在构建html元素时,vue倾向于模板方式,而react则完全使用javascript的编程能力,但vue也具备完全编程的能力(与react一样使用JSX和createElement渲染函数)。所以,当vue使用完全编程方式时,与react可以说是大同小异。

学习react的时候,有一个核心思想:组件就是函数,元素就是值。这对于vue来说也是完全适用的,唯一的区别在于两者的限制和使用条件不同。

JSX

JSX是JavaScript的一个扩展语法,本质是createElement渲染函数的语法糖。react和vue在JSX语法上几乎一致,区别在于属性值的传入上。

react的JSX语法更接近 JavaScript 而不是 HTML,所以 React DOM 使用 camelCase(小驼峰命名)来定义属性的名称,而不使用 HTML 属性名称的命名约定。
例如,JSX 里的 class 变成了 className,而 tabindex 则变为 tabIndex

vue的JSX则使用了一个Babel 插件使其更贴近HTML模板语法,vue对大小写不敏感(实际上vue会将所有属性值转换为小写)。
例如,tabIndex会转化成tabindexclassName会转化为classname

特例,对于属性class,react应写成className,vue应写成class

react引入了Fragments使得react可以有多个根元素,vue没有此功能,只能是单一根元素

元素渲染

react的文档中提到了

元素是构成 React 应用的最小砖块。

const element = <h1>Hello, world</h1> // 定义元素

...
render () {
 return <div>{element}</div> // 使用元素
}

react将元素当作值来对待,你可以直接使用,也可以先赋值给某个变量,然后再使用。
这一点在vue的文档中虽然没有明确提到,但依然适用,vue也可以先将元素赋值给某个变量,然后在适当的位置使用该变量。

两者在使用时的区别在于:

  • react可以在任意位置(组件内和组件外)定义元素并使用
  • vue只能在组件内定义元素(只要是组件内,任意位置都可以,render函数内,data数据或者其他位置),在组件外定义则会报错(h is not defined

报错原因:网上找到的一个说法是vue中组件外没有上下文联系,找不到渲染函数。
思来想去只能归结于两者的渲染机制不同(没有依据,瞎猜的😜:react可能是先赋值后渲染,vue可能是先渲染后赋值)

组件定义

react定义组件有两种方式,函数组件和class组件,两者在一定条件下可以相互转换,函数式组件是无状态组件,没有state状态和生命周期

// 函数组件
cosnt MyComponent = props => {
  return <div>{props.title}</div>
}

// class组件
class MyComponent extends React.Component {
  static defaultProps = {} // 设置默认传入值
  constructor(props) {
    super()
    this.state = {} // 设置状态值
  }
  ... // 其他组件函数:自定义方法,生命周期方法...
  render() {
   return <div>{this.props.title}</div>
  }
}

vue文档给出的组件定义只有一种方式(如下),函数式组件(无状态)是在普通组件的基础上添加functional标记

Vue.component('my-component', {
  props: {title:String},
  ...
  render () {
    return <div>{this.title}</div>
  }
})

实际上,上诉方式是官方给出的一种完整使用(组件定义和全局注册),在实际项目中通常组件定义和注册都是分开的(即组件的局部注册)。

而react没有组件注册这一说法,只有定义和使用,vue实际上也可以和react一样,直接定义并使用,前提是使用JSX语法,如果使用createElement渲染函数和模板方式,仍然需要进行组件注册。

vue定义组件方式如下

// 函数式组件
const MyComponent = {
  functional: true, // 函数式组件标记,
  props: {title:String},  // 设置传入值
  // 为了弥补缺少的实例,提供第二个参数作为上下文
  render(h, context) {
   return <div>{this.props.title}</div>
  }
}
// 函数式组件的变种写法 -- 函数方式,对照了react的函数组件的写法
// vue官方文档中没有提到这种写法,但这种写法依然生效
// 与react函数式组件的不同之处在于,react函数式组件的传入值是props,vue函数组件传入值是context上下文
cosnt MyComponent = context => {
  return <div>{context.props.title}</div>
}

// 普通组件
const MyComponent = {
  props: {title:String},  // 设置传入值
  data () { return { user: '' } }, // 数据
  computed: {}, // 计算属性
  watch: {}, // 监听属性
  methods: {}, // 自定义方法
  ... // 其他生命周期方法,钩子函数等...
  render() {
   return <div>{this.props.title}</div>
  }
}

从上面react和vue的代码片段中可以看出,react定义组件用的是class对象,vue定义组件用的是Object对象,两者的区别在于:

  • class对象方法之间不需要分隔符,Object对象的属性之间需要逗号,分隔
  • 对于传入值,两者都是使用的props,react只能定义默认值,vue则可以限制传入类型并进行数据验证(react要实现类型验证需要引入prop-types
  • 对于状态值,react将状态值放入class对象的属性值state里,并在constructor构造函数中完成数据初始化,vue则将状态值放入data方法的返回值中
  • 对于自定义方法,react可直接书写在class对象下,vue则必需放入methods字段中
  • 数据监听,react在生命周期方法componentDidUpdate中监听数据变化,vue则提供了更为方便的computedwatch

组件传值

react和vue的组件传值都是通过组件属性进行传递的。

  • react,不管是函数式组件还是普通组件,将组件的所有属性都当作prop传入;
  • vue,对于函数式组件
    • 版本2.3.0之前,如果一个函数式组件想要接收 prop,则 props 选项是必须的;
    • 版本2.3.0或以上,如果定义了props选项,则只能接收定义的prop
    • 版本2.3.0或以上,如果省略 props 选项,组件上所有的 attribute 都会被自动隐式解析为 prop
  • vue,对于普通组件
    • 特殊属性class、style,直接挂载到组件根元素上,与组件内的class和style叠加合并;
    • 组件上的属性如果在props中的定义了,则作为prop传入;
    • 对于没有声明的属性,默认自动挂载到组件根元素上,并覆盖原来的属性值(可通过设置inheritAttrs属性开关此功能,默认开启);

内容分发

说完组件传值,那就不得不说组件的内容分发,这是一种特殊的组件传值(其本质还是组件传值)。
在vue中,内容分发使用的是插槽slot,react则称为组件组合,并且react特意强调了

React 中没有“槽”这一概念的限制,你可以将任何东西作为 props 进行传递

最常见的就是如下以子节点(children)方式

<MyComponent>hello world</MyComponent>
  • react提供了一个特殊的children prop用来接收分发内容,
  • vue函数式组件即可以通过children来接收内容,也可以通过slots().default方式,
  • vue普通组件只能通过$slots.default的方式分发

vue函数式组件和普通组件对插槽slot使用的区别主要式因为函数式组件没有实列this,而是使用上下文context,详见vue函数式组件
vue的插槽分为普通插槽slots和作用域插槽scopedSlots,作用域插槽可以完全替代普通插槽,建议使用使用scopedSlots

简单的示列如下

// react 函数式组件
const MyComponent = props => {
  return <div>{props.children}</div>
}
// react class组件
class MyComponent extends React.Component {
  render() {
    return <div>{this.props.children}</div>
  }
}

// vue 函数式组件
const MyComponent = context => {
  // children方式分发
  const { children } = context
  return <div>{children}</div>
  // 通过插槽方式分发
  // const { slots } = context
  // return <div>{slots().default}</div>
}
// vue 普通组件
const MyComponent = {
  render () {
    return <div>{this.$scopedSlots.default()}</div>
  }
}

多内容分发

  • react只需要传入对应的prop即可
  • vue使用slotsscopedSlots进行分发
// react
...
  render () {
    return (
      <div>
        <header>{props.header}</header>
        <main>{props.children}</main>
        <footer>{props.footer}</footer>
      </div>
    )
  }
...
// react使用
<MyComponent
  header='hello world'
  chilren={<p>Lorem ipsum dolor sit amet</p>}
  footer='this is footer'
/>


// vue
...
  render () {
    return (
      <div>
        <header>{this.$scopedSlots.header()}</header>
        <main>{this.$scopedSlots.default()}</main>
        <footer>{this.$scopedSlots.footer()}</footer>
      </div>
    )
  }
...
// vue使用
<MyComponent
  scopedSlots={{    
    header: props => `hello, world`,
    default: props => <p>Lorem ipsum dolor sit amet</p>,
    footer: props => 'this is footer'
  }}
/>

对于内容分发,react显得十分灵活及简便,vue在使用上相对有部分限制,vue可以使用作用域插槽,react只能通过其他方式实现类似功能。vue插槽的JSX使用方式

实际上,如果vue不使用插槽方式,改用props也可以和react一样实现内容分发

// vue 使用 props 实现了内容分发,定义和使用方式和 react 几乎一样
const MyComponent = {
  props: ['header', 'children', 'footer'],
  render () {
    return (
      <div>
        <header>{this.header}</header>
        <main>{this.children}</main>
        <footer>{this.footer}</footer>
      </div>
    )
  }
}

export default {
  render () {
    return (
      <MyComponent
        header='hello, world'
        children={<p>Lorem ipsum dolor sit amet</p>}
        footer={'this is footer'}
      />
    )
  }
}

数据响应

响应式数据更新方式是vue与react的一个重要区别之一

  • vue的数据加入到响应式系统中,直接操作数据会同步更新视图
  • react必需使用setState方法更新数据以便实现视图的同步更新

事件处理

react的事件处理为了在回调中使用 this,必须为该方法绑定this(在构造函数中绑定或在事件处理程序传递参数),vue则不需要这个绑定过程。

展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客
应支付0元
点击重新获取
扫码支付

支付成功即可阅读