适合React汉子入门Vue的文章

时间:2021-1-8 作者:admin

由于某些不可描述的原因,作为一名 react 死忠的我,最近手操了一个 vue2.x 的项目,听说从精装修到毛坯只要一天,反之则需要一个月。本文旨在通过站在 react 技术的角度,通过一些关键点的对比,来总结一些快速上手 vue2.x 的经验之谈。记住,是快速上手,如果想要精通,那还是老实去多实践把。

组件写法

  • React 组件的写法一般有两种:class 组件和 function 组件
// class组件:一般理解为需要定义复杂组件,可以使用完整的生命周期函数
import React from 'react';

export default class SomeComponent extends React.Component{
  constructor(props){
    super(props);
    this.state = {

    }
  }

  componentDidMount(){

  }

  // 其他代码
  // ...

  render(){
    return (
      <div>这是一个class组件</div>
    )
  }
}
//function组件,一般理解为定义无状态组件或者纯展示组件,当然hooks的出现使得其使用越来强大
export default function({title} = props) {

  return (
    <div>
      {title}
    </div>
  );
}
  • Vue 组件的一般写法:
// html代码写在template里面
<template>
  <div>这是一个vue组件</div>
</template>
// js的逻辑都在script里写
<script>
import SearchForm from '@/components/SearchForm.vue';
export default {
  name:'SomeComponent',// 组件名称
  components:{  // 引入其他组件
    SearchForm
  },
  props: { // 属性
    title: {
      type: String,
      default: ''
    }
  },
  // 定义要改变的数据的地方,注意是一个function,返回object数据
  data(){
    return {

    }
  },
  // 业务逻辑具体方法一般写在methods里面
  methods: {

  },
   // 其他代码
  // ...
}
</script>
<style>
// 样式...
</style>

需要特别注意两点的是:

  • 1、template 元素下必须有且只能有一个根元素
  • 2、vue 的可变状态数据放在 data 里面,data 是一个函数,返回一个 object 的可变数据

修改状态

在 react 中,最重要的莫过于概念莫过于 state。react 中需要随时修改的数据一般定义在 state 中,通过 setState 来修改(hooks 同理)。vue 中也有类似的概念,只不过 vue 中 state 一般叫 data,把要修改的数据定义在 data 中,直接通过 this.xxx = xx 修改

  • react 修改状态
import React from 'react';
import {Button} from 'antd';

export default class SomeComponent extends React.Component{
  constructor(props){
    super(props);
    this.state = {
      click:false
    }
  }

  componentDidMount(){

  }

  changeState = () =>{
    this.setState({click:!this.state.click});
  }

  render(){
    return (
      <div>
        <Button onClick={this.changeState}>
          {!this.state.click ?'你动我一下试试':'就动你了咋的'}
        </Button>
      </div>
    )
  }
}
  • vue 修改状态
<template>
  <div>
    <button @click="changeState">
    {{!click ?'你动我一下试试':'就动你了咋的'}}
    </button>
  </div>
</template>
<script>
export default {
  name:'SomeComponent',// 组件名称
  data(){
    return {
      click:false
    }
  },

  methods: {
    changeState(){
      this.click = !this.click;
    }
  },
   // 其他代码
  // ...
}
</script>
<style>
// 样式...
</style>

组件间通信

  • react 中通信方法

1、props 传递(最最最主要的方式)

// 子组件
function ChildComponet({message,onChange} = props){

  return(
    <div>
      <span>{message}</span>
      <input onChange={onChange}/>
    </div>
  )
}

//父组件
class FatherComponent extends Component{
     constructor(props){
      super(props);
      this.state = {
        sonMsg:''
      }
    }

    onChange = (e) => {
      this.setState({
        sonMsg:e.target.value
      });
    }

    render{
      return(
        <>
          <ChildComponet message={'我去给你买几个橘子,你就站在此地,不要走动'}
                         onChange={onChange} />
           <span>{this.state.sonMsg}</span>
        </>
      )
    }
}

2、redux 等状态管理方案
利用redux或者mobx等状态管理方案共享store数据。不做过多展开。

3、context 方式

context相当于开辟一个全局变量,把要共享的数据放到context里面,然后那里需要自取就好,在此不作展开。

4、发布订阅模式

导入events模块(有可能要安装第三方npm包),在需要接收数据的地方开一个监听器,发送数据方触发监听器,伪码如下:
// 监听器
event.on('received',(msg) => {

});

//触发监听
event.emit('received','这是给你买的橘子');
  • vue 中通信方法

    1、props 传递方式:其实跟 react 类似

// 子组件
<template>
  <div>
     <span>{{message}}</span>
      <input @onChange={onChange}/>
  </div>
</template>
<script>
export default {
  name:'SomeComponent',
  props:{
    message:{
      type:String,
      defalut:''
    }
  },

  methods: {
    changeState(e){
      this.$emit('onChange',e.targe.value)
    }
  },
}
</script>
<style>
// 样式...
</style>
// 父组件
<template>
  <div>
      <SomeComponent message="我去给你买几个橘子,你就站在此地,不要走动"
                    @onChange="onChange"
      />
      <span>{{sonMsg}}</span>
  </div>
</template>
<script>
import SomeComponent from './SomeComponent'
export default {
  name:'FatherComponent',
  components:{
    SomeComponent
  },
  data(){
    return {
      sonMsg:''
    }
  },

  methods: {
    onChange(value){
      this.sonMsg = value;
    }
  },
}
</script>
<style>
// 样式...
</style>

2、vuex 方案

原理跟react中使用redux一样,如果用过redux的话,基本等同于无缝切换

3、$emit/on 方案

  const Event = new Vue();
  Event.$emit(事件名,数据);
  Event.$on(事件名,data => {});

我的理解:其实就是 Vue 默认提供的发布订阅模式

4、其他的一些方案,没有过多研究,不叨叨了

传递代码片段

  • react 中直接通过 props 中默认的 children 属性或者直接传递 jsx
  // 子组件
function ChildComponet({children,renderJsx,message,onChange} = props){

  return(
    <div>
      <span>{message}</span>
      <input onChange={onChange}/>
      {renderJsx}
      {children}
    </div>
  )
}

//父组件
class FatherComponent extends Component{
     constructor(props){
      super(props);
      this.state = {
        sonMsg:''
      }
    }

    onChange = (e) => {
      this.setState({
        sonMsg:e.target.value
      });
    }

    render{
      return(
        <>
          <ChildComponet message={'我去给你买几个橘子,你就站在此地,不要走动'}
                         onChange={onChange}
                         renderJsx={() => (<span>直接jsx片段也行</span>)} >
             <span>这是被组价包起来的元素,在子元素通过children渲染</span>
           </ChildComponet>
           <span>{this.state.sonMsg}</span>

        </>
      )
    }
}
  • vue 中要渲染这种片段:插槽功能

在 vue 中,插槽功能就是专门设计用来渲染这种代码片段功能的。而插槽在 vue 中有好几种玩法。

1、默认插槽

 // 子组件
<template>
  <div>
     <span>{{message}}</span>
      <input @onChange={onChange}/>
      <!--默认插槽-->
      <slot></slot>
  </div>
</template>
<script>
export default {
  name:'SomeComponent',
  props:{
    message:{
      type:String,
      defalut:''
    }
  },

  methods: {
    changeState(e){
      this.$emit('onChange',e.targe.value)
    }
  },
}
</script>
<style>
// 样式...
</style>
// 父组件
<template>
  <div>
      <SomeComponent message="我去给你买几个橘子,你就站在此地,不要走动"
                    @onChange="onChange"
      >
       <div>默认插槽里内容</div>
      </SomeComponent>
      <span>{{sonMsg}}</span>
  </div>
</template>
<script>
import SomeComponent from './SomeComponent'
export default {
  name:'FatherComponent',
  components:{
    SomeComponent
  },
  data(){
    return {
      sonMsg:''
    }
  },

  methods: {
    onChange(value){
      this.sonMsg = value;
    }
  },
}
</script>
<style>
// 样式...
</style>

2 具名插槽

其实就是给插槽取个名字,方便使用的时候在对应的位置插入对应的片段,这样就可以在公用组件中不同的位置设置不同的代码片段。

 // 子组件
<template>
  <div>
     <span>{{message}}</span>
      <input @onChange={onChange}/>
      <!--搞了一个叫haha的具名插槽-->
      <slot name="haha"></slot>
      <!--默认插槽-->
      <slot></slot>
  </div>
</template>
<script>
export default {
  name:'SomeComponent',
  props:{
    message:{
      type:String,
      defalut:''
    }
  },

  methods: {
    changeState(e){
      this.$emit('onChange',e.targe.value)
    }
  },
}
</script>
<style>
// 样式...
</style>
// 父组件
<template>
  <div>
      <SomeComponent message="我去给你买几个橘子,你就站在此地,不要走动"
                    @onChange="onChange"
      >
      <!--通过v-slot:haha 使用具名插槽-->
      <template v-slot:haha>
        <span>这里是要插入到名称为haha的具名插槽的内容</span>
      </template>
       <div>默认插槽里内容</div>
      </SomeComponent>
      <span>{{sonMsg}}</span>
  </div>
</template>
<script>
import SomeComponent from './SomeComponent'
export default {
  name:'FatherComponent',
  components:{
    SomeComponent
  },
  data(){
    return {
      sonMsg:''
    }
  },

  methods: {
    onChange(value){
      this.sonMsg = value;
    }
  },
}
</script>
<style>
// 样式...
</style>

3、作用域插槽

就是在使用插槽插入代码片段的时候,片段中展示的数据来自定义插槽的组件中。感觉有点类似于子组件向父组件传值的味道。

 // 子组件
<template>
  <div>
     <span>{{message}}</span>
      <input @onChange={onChange}/>
      <!--搞了一个叫haha的具名插槽-->
      <slot name="haha"></slot>
      <!--这里搞了个作用域插槽,将msg传出-->
      <slot name="dog" :msg="{name:'二哈'}">
        <!--如果没有片段传进来,则显示土狗-->
        <span>这是什么狗: 土狗🐕</span>
      </slot>
      <!--默认插槽-->
      <slot></slot>
  </div>
</template>
<script>
export default {
  name:'SomeComponent',
  props:{
    message:{
      type:String,
      defalut:''
    }
  },

  methods: {
    changeState(e){
      this.$emit('onChange',e.targe.value)
    }
  },
}
</script>
<style>
// 样式...
</style>
// 父组件
<template>
  <div>
      <SomeComponent message="我去给你买几个橘子,你就站在此地,不要走动"
                    @onChange="onChange"
      >
      <!--通过v-slot:haha 使用具名插槽-->
      <template v-slot:haha>
        <span>这里是要插入到名称为haha的具名插槽的内容</span>
      </template>
      <template v-slot:msg="{msg}">
        <span>打入敌人内部的狗是什么狗:{{msg}}</span>
      </template>
       <div>默认插槽里内容</div>
      </SomeComponent>
      <span>{{sonMsg}}</span>
  </div>
</template>
<script>
import SomeComponent from './SomeComponent'
export default {
  name:'FatherComponent',
  components:{
    SomeComponent
  },
  data(){
    return {
      sonMsg:''
    }
  },

  methods: {
    onChange(value){
      this.sonMsg = value;
    }
  },
}
</script>
<style>
// 样式...
</style>

指令

指令是 vue 中特有的对页面逻辑进行控制东西,在 react 中,因为页面就在 js 中(jsx),所以很多时候要控制页面,一般直接 js 语法逻辑就好。这是我最初喜欢 react 的原因之一。但是 vue 中指令其实并不多,下面用常用的 vue 指令和 react 实现做一个对比,一目了然。

v-if 和 v-show

// vue
<template>
  <div>
    <button @click="changeState">
    {{!click ?'叫爸爸':'爸爸去哪儿了'}}
    </button>
    <span v-if="click">你就站在此地,不要走动,叫爸爸,我就回来了</span>
    <span v-show="click">爸爸一直在你身边,叫爸爸,我就出现了</span>
  </div>
</template>
<script>
export default {
  name:'SomeComponent',// 组件名称
  data(){
    return {
      click:false
    }
  },

  methods: {
    changeState(){
      this.click = !this.click;
    }
  },
   // 其他代码
  // ...
}
</script>
<style>
// 样式...
</style>
// react
import React from 'react';
import {Button} from 'antd';

export default class SomeComponent extends React.Component{
  constructor(props){
    super(props);
    this.state = {
      click:false
    }
  }

  componentDidMount(){

  }

  changeState = () =>{
    this.setState({click:!this.state.click});
  }

  render(){
    return (
      <div>
        <Button onClick={this.changeState}>
          {!this.state.click ?'叫爸爸':'爸爸去哪儿了'}
        </Button>
        {this.state.click && <span>你就站在此地,不要走动,叫爸爸,我就回来了</span>}
        <span style={{display:`${this.state.click?'':'none'}`}}>爸爸一直在你身边,叫爸爸,我就出现了</span>
      </div>
    )
  }
}

v-show 这个指令跟 v-if 效果一样,但是 v-show 相当于 display 来做显示和隐藏,v-if 是直接添加把 dom 干掉或者添加。

v-for

// vue
<template>
  <div>
    <ul v-for="item in list" :key="item.value">
      <li>{{item.label}}</li>
    </ul>
  </div>
</template>
<script>
export default {
  name:'SomeComponent',// 组件名称
  data(){
    return {
      list:[
       {value:1,label:'二狗子'},
       {value:2,label:'王尼玛'},
       {value:3,label:'他大舅'},
      ]
    }
  },

}
</script>
// react
import React from 'react';

export default class SomeComponent extends React.Component{
  constructor(props){
    super(props);
    this.state = {
       list:[
       {value:1,label:'二狗子'},
       {value:2,label:'王尼玛'},
       {value:3,label:'他大舅'},
      ]
    }
  }


  render(){
    return (
      <div>
        {
          this.state.list.map(item => {
            return (
              <li key={item.value}>{item.label}</li>
            )
          })
        }
      </div>
    )
  }
}

注意:循环中都需要设置 key

v-bind 和 v-on

在 vue 中,v-bind 是用来绑定动态可变的数据的,简写为冒号:,v-on 是用来监听事件的,简写为@。

// vue
<template>
  <div>
    <button @click="changeState">点击+1</button>
    <input :value="value"/>
    </button>
  </div>
</template>
<script>
export default {
  name:'SomeComponent',// 组件名称
  data(){
    return {
      value:0
    }
  },

  methods: {
    changeState(){
      this.value = this.value + 1;
    }
  },
// react
import React from 'react';
import {Button} from 'antd';

export default class SomeComponent extends React.Component{
  constructor(props){
    super(props);
    this.state = {
      value:0
    }
  }

  componentDidMount(){

  }

  changeState = () =>{
    this.setState({value:this.state.value + 1});
  }

  render(){
    return (
      <div>
        <Button onClick={this.changeState}>
        点击+1
        </Button>
       <input value={this.state.value}/>
      </div>
    )
  }
}

感觉 react 更加方便快捷。

监听属性的变化

  • react 中监听属性的变化:

react16.8之前的版本用此属性,后面会弃用

componentWillReceiveProps

之后的新版本推荐下面两个配合使用:

componentDidUpdate

getDerivedStateFromProps

import React from 'react';
import {Button} from 'antd';

export default class SomeComponent extends React.Component{
  constructor(props){
    super(props);
    this.state = {
      value:0,
      someProps:{}
    }
  }

  componentDidUpdate(prevProps){
        if(prevProps.someProps!==this.state.someProps){
            this.setState({ someProps:props.someProps});
        }
   }

  getDerivedStateFromProps(props, currentState) {
    if(props.someProps!==currentState.someProps){
        return props.someProps;
    }
    // 必须返回null
    return null
}

  changeState = () =>{
    this.setState({value:this.state.value + 1});
  }

  render(){
    return (
      <div>
        <Button onClick={this.changeState}>
        点击+1
        </Button>
       <input value={this.state.value}/>
      </div>
    )
  }
}
  • vue 中监听属性的变化:
<script>
export default {
    props: {
        names: {
            type: [Array, String],
            default: () => {
                return [];
            },
        },
        },
     watch: {
            names: {
                handler: function(newProps,oldProps) {
                    if(newPros.names !== oldProps.names){
                      //做点啥...
                    }
                },
                deep: true,//复杂数据类型的变化设置deep:true
            },
        },
</script>

复杂的数据展示

  • react 中可以直接在 jsx 中计算,也可以提出来在方法中计算好
import React from 'react';
import {Button} from 'antd';

export default class SomeComponent extends React.Component{
  constructor(props){
    super(props);
    this.state = {
      user:{
        name:'张三',
        age:29,
        gender:'女'
      }
    }
  }

  //提出来计算的
  getUserDes = () =>{
     const {user} = this.state;
     return `${user.name},${user.age},${user.gender}`
  }

  render(){
    const {user} = this.state;
    return (
      <div>
        <span>用户信息介绍:{user.name},{user.age},{user.gender}</span>
        <span>用户信息介绍:{this.getUserDes()}</span>
      </div>
    )
  }
}
  • vue 中,一般在 comput 中计算
// vue
<template>
  <div>
     <span>用户信息介绍:{{getUserDes}}</span>
  </div>
</template>
<script>
export default {
  name:'SomeComponent',// 组件名称
  data(){
    return {
       user:{
        name:'张三',
        age:29,
        gender:'女'
      }
    }
  },

  computed: {
    getUserDes(){
      return `${this.user.name},${this.user.age},${this.user.gender}`
    }
  },

关于 vue 中的 comput 和 watch 的区别:

  • 1、简单的理解就是 comput 是为了把复杂的计算提出来,计算出结果后在返回给页面展示。
  • 2、watch 主要是监听属性和状态的变化,然后做某些事情的功能。
  • 3、comput 要求必须要有返回值,watch 则不必须。

路由 router

其实关于 router 的部分,基本上 vue 和 react 没有太大区别了,基本上都是会用一种就会用另一种的感觉。只说一点,vue 路由中的路由守卫功能真是无比的好用。其他的不再赘述。

总结

行文至此,做一个简单总结把:

  • 1、vue 和 react 在组件的写法上区别较大,不过不是特别难理解,主要几分钟适应就好
  • 2、vue 和 react 同为 mvvm 类的前端框架,核心概念:状态,属性,组件间通信等有很多相似的地方,相互之间换技术栈不是大问题。
  • 3、react 因为完全使用 jsx,其实也就是 js,所以有些功能比较灵活,vue 则需要记一些指令之类的。
  • 4、vue 中监听数据的变化可以用 watch,计算复杂的数据用 comput,react 中则简单粗暴的多。
  • 5、再说一遍,vue 的路由守卫功能对于做鉴权来说,感觉非常良心了,react 则需要自己做一些封装。

作为一个写惯了 react 的人来说,感觉 react 很多东西都是简单粗暴直接,就好像一个直男。而 vue 更像一个小清新的少女/男,有小可爱的成分,有萌萌哒的成分,有善解人意的成分,当不适应他某些小脾气的时候,感觉她/他为啥要这样?但是千万不要忽视他能做的事情。而最后,传说已久的 vue3.0 已经发车,感觉头上越来越凉了。。。。。

声明:本文内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎进行举报,并提供相关证据,工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。