Vue和React的一些对比:哪个更适合你?

Vue和React都是目前最流行、生态最好的前端框架之一。框架本身没有优劣之分,只有适用之别,选择符合自身业务场景、团队基础的技术才是我们最主要的目的。

博主1年前用的是Vue框架,近半年转技术栈到React框架,对于Vue和React都有一些基本的了解。接下来将与大家一起走近Vue和React,共同探讨它们的差异。(比如你正在用vue,对react感兴趣也可以看下两者之间的用法差异,反之亦然)

整体内容概览:

Vue和React的一些对比:哪个更适合你?

由于内容较长,将分上、中、下三部分和大家一起共同探讨(有不同意见的欢迎文章下方一起探讨交流,感谢支持)。

1.背景

vue

Google 前工程师尤雨溪于 2014 年创建了这个框架。Vue是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。

react

与 Vue 不同,react 库是由 Facebook 创建的。最初是为了 Facebook 广告流量管理创建的。那时 Facebook 遇到了维护和编码方面的问题。它以动态创建和交互式 UI 的能力而闻名。

2.核心思想

vue与react都推崇组件式的开发理念,但是在设计的核心思想上有很大差别。

vue

vue的整体思想仍然是拥抱经典的html(结构)+css(表现)+js(行为)的形式,vue鼓励开发者使用template模板,并提供指令供开发者使用(v-if、v-show、v-for等等),因此在开发vue应用的时候会有一种在写经典web应用(结构、表现、行为分离)的感觉。另一方面,在针对组件数据上,vue2.0通过Object.defineProperty对数据做到了更细致的监听,精准实现组件级别的更新。

react

react整体上是函数式的思想,组件使用jsx语法,all in js,将html与css全都融入javaScript,jsx语法相对来说更加灵活,我一开始刚转过来也不是很适应,感觉写react应用感觉就像是在写javaScript。当组件调用setState或props变化的时候,组件内部render会重新渲染,子组件也会随之重新渲染,可以通过shouldComponentUpdate或者PureComponent可以避免不必要的重新渲染(个人感觉这一点上不如vue做的好)。

3.组件形式

vue

vue组件定义使用xx.vue文件来表示,vue组件将html、css、js组合到一起,模板部分使用数据使用{{}},形式如下:

<code> 

  

<

div

>

{{name}}

div

>

template

>

<

script

>

export

default

{

name

:

'NewComponent'

, data() {

return

{

name

:

'xx'

} } }

script

>

<

style

scoped

>

style

>

/<code>

组件使用:

<code><

new

-component name=

"xx"

/>/<code>

react

react推荐使用jsx或者js文件来表示组件,react支持class组件和function组件2种形式,react使用{}包裹变量,这点需要注意。

注意: 组件名称必须以大写字母开头。React 会将以小写字母开头的组件视为原生 DOM 标签。例如,

代表 HTML 的 div 标签,而 则代表一个组件,并且需在作用域内使用 Welcome。

(1)class组件

<code>

import

React

from

'react'

;

class

NewComponent

extends

React

.

Component

{

constructor

(props) {

super

(props);

this

.state = {

name

:

'xx'

}; } render() { rerurn(

<

div

>

{name}

div

>

); } }

export

default

NewComponent;/<code>

(2)function组件

hooks的出现赋予了function组件管理state的能力。

<code>

import

React, { useState }

from

'react'

;

function

NewComponent

(

)

{

const

[name, setName] = useState(

''

);

return

(

<

div

>

{name}

div

>

); }

export

default

NewComponent;/<code>

4.数据管理(props、data vs state)

组件数据管理通常包含2部分,来自父组件的数据props与自身的数据。

vue与react中的props都是单向数据流的,父级prop的更新会向下流动到子组件中,但是反过来则不行。prop可以是数组或对象,用于接收来自父组件的数据。

vue

props

vue中的props支持传递静态或动态props,静态props一般传递字符串。

<code>

<

blog-post

title

=

"My journey with Vue"

>

blog-post

>

/<code>

静态prop传递布尔值true可以这样写,传值false仍然需要使用动态prop传值。

<code>

/<code>

动态赋值使用v-bind,可以简写为:。

<code>"tile">

blog-post

>

<

blog-post

:title

=

"tile"

>

blog-post

>

/<code>

动态prop常用来传递对象、数组、布尔值(false值,true值可以直接传属性)等。

<code>:title=

"post.title + ' by ' + post.author.name"

>/<code>

data

vue中使用data来管理组件的数据,vue 将会递归将 data 的属性转换为 getter/setter,从而让 data 的属性能够响应数据变化。对象必须是纯粹的对象 (含有零个或多个的 key/value 对)。一旦观察过,不需要再次在数据对象上添加响应式属性。因此推荐在创建实例之前,就声明所有的根级响应式属性。

当一个组件被定义,data必须声明为返回一个初始数据对象的函数。

<code>

export

default

{

name

:

'NewComponent'

,

data

() { return { name:

'xxx'

, age:

12

} } }/<code>

当需要在组件内部修改数据时,可以直接通过vue实例修改:

<code>  methods: {
    changeName() {
      

this

.name =

'new Name'

; } }/<code>

react

props

react中的props也与vue一样可以传递静态或动态props,静态props一般传递字符串。

函数组件和class组件都可以使用props,函数组件使用props参数获取父组件传下来的props。

函数组件获取props:

<code>

function

Welcome

(

props

)

{

return

<

h1

>

Hello, {props.name}

h1

>

; }

const

element =

<

Welcome

name

=

"Sara"

/>

; 复制代码

/<code>

class组件使用this.props获取组件props:

<code>

class

Welcome

extends

React

.

Component

{

constructor

(props) {

super

(props); } render() {

const

{ name } =

this

.props;

return

<

div

>

{name}

div

>

; } }/<code>

动态props:

<code>

<

Welcome

name

=

{name}

/>

/<code>

state

react中使用state来管理组件内的数据,hooks的出现使得函数组件也具备管理state的能力。

class组件state

class组件在构造函数(constructor)中定义组件内数据(state),修改数据必须通过setState修改,不能直接修改state,这点非常重要。

class组件使用state:

<code>

class

Welcome

extends

React

.

Component

{

constructor

(props) {

super

(props);

this

.state = { name:

'xx'

};

this

.changeName =

this

.changeName.bind(

this

); } changeName() {

this

.setState({ name:

'new name'

}); } render() {

const

{ name } =

this

.state;

return

this.changeName}>{name}

; } }/<code>

关于class组建的setState有以下两点说明:

  • 1.setState更新是异步的,但是在setTimeout和原生事件中是同步的
  • 2.setState更新的是组件的部分数据,react会自动将数据合并。

当需要使用上一个state值时,可以让 setState() 接收一个函数而不是一个对象。这个函数用上一个 state 作为第一个参数,将此次更新被应用时的 props 做为第二个参数:

<code>

this

.setState(

(state, props)

=>

({ counter: state.counter + props.increment })); /<code>
function组件useState

react 16.0之前函数组件只是纯的渲染组件,hooks的出现赋予了函数组件管理state的能力。

useState返回一个state,以及更新state的函数。如果新的 state 需要通过使用先前的 state 计算得出,那么可以将函数传递给 setState。该函数将接收先前的 state,并返回一个更新后的值。

<code>

import

React, { useState }

from

'react'

;

function

Counter

(

{initialCount}

)

{

const

[count, setCount] = useState(initialCount);

return

(

<>

Count: {count}

<

button

onClick

=

{()

=>

setCount(initialCount)}>Reset

button

>

<

button

onClick

=

{()

=>

setCount(prevCount => prevCount - 1)}>-

button

>

<

button

onClick

=

{()

=>

setCount(prevCount => prevCount + 1)}>+

button

>

>

); }

/<code>

关于setState有以下三点说明:

1.与 class 组件中的 setState 方法不同,useState 不会自动合并更新对象。2.只能在函数最外层调用 Hook。不要在循环、条件判断或者子函数中调用。3.只能在 React 的函数组件或自定义hook中调用 Hook。不要在其他 JavaScript 函数中调用。

5.组件数据交互

组件数据交互是指父子组件、兄弟组件、跨层组件之间传递数据。 兄弟组件之间可以通过事件总线或者通过父组件传递数据,这里就不详细赘述。

5.1.父子组件数据交互(props+自定义事件 vs props+回调)

对于父子组件数据交互,vue中使用prop+自定义事件实现,react通过props+回调实现。

vue

vue中父组件通过props传递数据给子组件,子组件使用$emit触发自定义事件,父组件中监听子组件的自定义事件获取子组件传递来的数据。

子组件使用$emit传递自定义事件myEvent:

<code>

<

template

>

<

div

@

click

=

"changeName"

>

{{name}}

div

>

template

>

<

script

>

export

default

{

name

:

'NewComponent'

, data() {

return

{

name

:

'xxx'

,

age

:

12

} },

methods

: { changeName() {

this

.name =

'new Name'

;

this

.$emit(

'myEvent'

,

this

.name); } } }

script

>

/<code>

父组件使用@myEvent监听自定义事件,回调函数参数是子组件传回的数据:

<code>

<

template

>

<

div

>

<

new-component

@

myEvent

=

"getName"

>

new-component

>

div

>

template

>

<

script

>

import

NewComponent

from

'./NewComponent'

;

export

default

{

components

: { NewComponent }, data() {

return

{} },

methods

: { getName(name) {

console

.log(name) } } }

script

>

/<code>

react

react中父组件使用props传递数据和回调函数给子组件,子组件通过props传下来的回调函数返回数据,父组件通过回调函数获取子组件传递上来的数据。

子组件通过props接收父组件传下来的回调事件:

<code>

import

React, { useState }

from

'react'

;

function

Children

(

props

)

{

const

{ myEvent } = props;

const

[name, setName] = useState(

'xxx'

);

const

changeName =

()

=>

{ setName(

'new name'

); myEvent(

'new name'

); };

return

<

div

onClick

=

{changeName}

>

{name}

div

>

; }/<code>

父组件通过回调事件获取子组件传递的参数:

<code>

function

Parent

(

)

{

const

changeName =

name

=>

{

console

.log(name); };

return

<

Children

myEvent

=

{changeName}

>

Children

>

; }/<code>

5.2.跨组件数据交互(provide/inject vs Context)

vue和react都支持跨组件传递数据,vue中主要通过provide / inject实现,react中主要通过Context实现。

vue

vue中通过provide / inject在祖先组件向所有子孙后代注入一个依赖,不论组件层次有多深,并在起上下游关系成立的时间里始终生效。

祖先组件中定义provide选项,provide选项应该是一个对象或返回一个对象的函数。

<code>

<

template

>

<

div

>

<

new-component

@

myEvent

=

"getName"

>

new-component

>

div

>

template

>

<

script

>

import

NewComponent

from

'./NewComponent'

;

export

default

{

provide

: {

message

:

'This is a big news'

},

components

: { NewComponent }, data() {

return

{} },

methods

: { getName(name) {

console

.log(name) } } }

script

>

/<code>

子组件通过inject选项获取祖先组件的provide选项值,inject选项应该是一个字符串数组或者对象。

<code>

<

template

>

<

div

>

{{message}}

div

>

template

>

<

script

>

export

default

{

name

:

'Children'

,

inject

: [

'message'

], data() {

return

{} } }

script

>

/<code>

注意:provide 和 inject 绑定并不是可响应的。这是刻意为之的。然而,如果你传入了一个可监听的对象,那么其对象的属性还是可响应的。

react

Context 提供了一个无需为每层组件手动添加 props,就能在组件树间进行数据传递的方法。

在父组件创建一个Context对象,通过Context.provider的value属性向消费组件传值。

<code>

import

React, { useState }

from

'react'

;

const

MyContext = React.createContext({

theme

:

'black'

});

function

Parent

(

)

{

const

changeName =

name

=>

{

console

.log(name); };

return

(

<

MyContext.Provider

value

=

{{

theme:

'

white

' }}>

<

Children

myEvent

=

{changeName}

>

Children

>

;

MyContext.Provider

>

); }/<code>

消费组件获取Context有2种方式:

(1)class组件通过contextType获取最近Context上的那个值。

<code>

class

DeepChildren1

extends

React

.

Component

{

constructor

(props) {

super

(props); }

static

contextType = MyContext; render() {

return

<

div

>

{this.context.theme}123

div

>

; } }/<code>

(2)函数式组件通过Context.Consumer订阅到Context的变更。

<code>

function

DeepChildren

(

props

)

{

return

(

<

MyContext.Consumer

>

{ (value) => (

<

div

>

{value.theme}

div

>

) }

MyContext.Consumer

>

); }/<code>

关于Context需要注意:

当Provider的父组件进行重渲染时,consumers组件会重新渲染,并且没有办法避免,应该尽量避免使用Context。

6.class与style

关于class与style处理上,vue与react也存在较大差异。

vue

vue对class与style特意做了增强,可以传字符串、对象、数组。

class

(1)给class绑定字符串:

<code>

class

=

"hello"

>

div

>

(2)给class绑定对象:

<code>

class

=

"static"

:

class

=

"{ active: isActive, 'text-danger': hasError }"

>

div

>

data如下:

<code>

data:

{

isActive:

true

,

hasError:

false

}

/<code>

HTML 将被渲染为:

<code>

class

=

"static active"

>

div

>

(3)给class绑定数组:

<code>

:class=

"[activeClass, errorClass]"

>

/<code>

data如下:

<code>

data

: {

activeClass

:

'active'

, errorClass:

'text-danger'

}/<code>

HTML 将被渲染为:

<code>

class

=

"active text-danger"

>

div

>

(4)class还可以直接绑定到组件上,这一点react并不支持。

声明组件如下:

<code>

Vue

.component

(

'my-component'

, {

template

:

Hi

'/<code>

在使用它的时候添加一些 class:

<code>

class

=

"baz boo"

>

my-component

>

/<code>

HTML 将被渲染为:

<code>

class="foo bar baz boo">Hi

/<code>

style

style用来绑定内联样式,支持传对象、数组,使用需要添加浏览器引擎前缀的 CSS 属性时,如 transform,Vue.js 会自动侦测并添加相应的前缀。

(1)传对象,CSS 属性名可以用驼峰式 (camelCase) 或短横线分隔 (kebab-case,记得用引号括起来) 来命名:

<code>

:style=

"{ color: activeColor, fontSize: fontSize + 'px' }"

>

/<code>

data如下:

<code>

data

: {

activeColor

:

'red'

, fontSize:

20

}/<code>

HTML将被渲染为:

<code> 

<

div

style

=

"color: red; font-size: 20px;"

>

div

>

/<code>

(2)传数组将多个样式应用到同一个元素上

<code>

:style=

"[baseStyles, overridingStyles]"

>

/<code>

data如下:

<code>

baseStyles

: {

fontSize

:

'20px'

, color:

'blue'

},

overridingStyles

: {

height

:

'80px'

}/<code>

HTML将被渲染为:

<code>

<

div

style

=

"font-size: 20px; color: blue; height: 80px;"

>

div

>

/<code>

react

react使用className用于指定css的class,react中不能直接为组件指定class。

className

react中className一般传值字符串常量或者字符串变量,不能传递数组或者对象语法。

(1)传字符串常量:

<code>

function

NewComponent

(

)

{

return

<

div

className

=

"container"

>

This is New Component.

div

>

; }/<code>

(2)传字符串变量:

<code>

function

NewComponent

(

)

{

const

newClass =

'conrainer'

return

<

div

className

=

{newClass}

>

This is New Component.

div

>

; }/<code>

(3)传递多个class,可以使用es6的模板字符串实现:

<code>

function

NewComponent

(

)

{

const

newClass =

'conrainer'

return

<

div

className

=

{

`${

newClass

}

new-container

`}>

This is New Component.

div

>

; }/<code>

当需要传递数组或者对象语法时,可以引入classnames库实现:

<code>

import

classNames

from

'classnnames'

;

function

NewComponent

(

)

{

const

newClass =

'container'

;

return

<

div

className

=

{classNames(newClass,

'

newContainer

', {

bar:

true

}, ['

new-class

', {

c:

true

}])}>

This is New Component.

div

>

; }/<code>

html将被渲染为:

<code>

class=

"container newContainer bar new-class c"

>This

is

New Component.

/<code>

style

通常不推荐将 style 属性作为设置元素样式的主要方式。在多数情况下,应使用 className 属性来引用外部 CSS 样式表中定义的 class。style 在 React 应用中多用于在渲染过程中添加动态计算的样式。

style接收一个对象

<code>

const

divStyle = {

color

:

'blue'

,

backgroundImage

:

'url('

+ imgUrl +

')'

, };

function

HelloWorldComponent

(

)

{

return

<

div

style

=

{divStyle}

>

Hello World!

div

>

; }/<code>

注意:样式不会自动补齐前缀。如需支持旧版浏览器,请手动补充对应的样式属性:

<code>

const

divStyle = {

WebkitTransition

:

'all'

,

msTransition

:

'all'

};

function

ComponentWithTransition

(

)

{

return

<

div

style

=

{divStyle}

>

This should work cross-browser

div

>

; }/<code>

7.生命周期

组件的生命周期一般包含:初始化、挂载、更新、卸载四个大阶段,接下来分别看下vue和reac的生命周期。

vue

vue生命周期图示:

Vue和React的一些对比:哪个更适合你?

vue生命周期包含:

  • beforeCreate
    实例组件刚创建,元素DOM和数据都还没有初始化,暂时不能在这个周期里面进行任何操作。
  • created
    数据data已经初始化完成,方法也已经可以调用,但是DOM未渲染。调用后台接口获取数据可以在这个阶段完成。
  • beforeMount
    DOM未完成挂载,数据也初始化完成,但是数据的双向绑定还是显示{{}},虚拟DOM结构已经生成。
  • mounted
    数据和DOM都完成挂载,在上一个周期占位的数据把值给渲染进去。这个周期适合执行初始化需要操作DOM的方法。
  • beforeUpdate
    页面数据改变了都会触发,在更新前触发,此时的数据还是未更新前的数据,没有数据改变则不执行。
  • updated
    页面数据改变都会触发,在更新完成之后触发,此时的数据是更新后的数据。

注意:在这里操作数据很容易引起卡死。

  • beforeDestroy
    组件销毁之前执行,在这个周期里仍然可以访问data和method,多组件间通信需要发布信息时可以在该阶段完成。
  • destroyed
    当离开组件对应页面时组件销毁时触发,主要用于取消一些副作用(取消事件监听、取消定时器、取消不必要的请求等)

react

react生命周期分为16.0之前和16.0之后:

16.0之前

react16.0之前生命周期如下:

Vue和React的一些对比:哪个更适合你?

(1)初始化

  • constructor
    是class组件的默认方法,常用来初始化state或者设置属性等。
<code>

class

Counter

extends

React

.

component

{

constructor

(props){

super

(props);

this

.state = {

count

:

0

};

this

.color =

'red'

; } }/<code>

(2)挂载阶段

  • componentWillMount()
    组件挂载之前调用,并且只会调用一次。
  • render
    render是一个React组件必须定义的生命周期函数,用来渲染DOM。 并必须 return 一个React元素(描述组件,即UI),不负责组件实际渲染工作,之后由React自身根据此元素去渲染出页面DOM。

不要在render里面修改state,会引起死循环导致卡死。

  • componentDidMount()
    组件挂在完成之后调用,在这个阶段可以获取真实dom元素,常用来发起异步请求获取数据。

(3)更新阶段

当通过setState修改state或父组件重新render引起props更新,都会引起子组件的重新render。

  • componentWillReceiveProps(nextProps)
    props发生变化以及父组件重新渲染时都会触发该生命周期函数。在该阶段可以通过参数nextProps获取变化后的props参数, 通过this.props访问之前的props。该生命周期内可以进行setState。
  • shouldComponentUpdate(nextProps,nextState)
    组件每次setState或者父组件重新render都会引起子组件render,可以使用该钩子比较nextProps,nextState及当前组件的this.props,this.state的状态用来判断是否需要重新渲染。默认返回true,需要重新render,返回false则不触发渲染。

一般我们通过该钩子来优化性能,避免子组件不必要的渲染。

  • componentWillUpdate(nextProps, nextState)
    当组件收到新的 props 或 state 时,会在渲染之前调用。使用此作为在更新发生之前执行准备更新的机会。初始渲染不会调用此方法。

注意:不能在此方法中调用this.setState

  • componentDidUpdate(prevProps, prevState) 此方法在组件更新后被调用。首次渲染不会执行此方法。当组件更新后,可以在此处对DOM进行操作。

注意:可以在componentDidUpdate()中直接调用setState(),但是它必需被包裹在一个条件语句里,否则会导致死循环。

(4)卸载阶段

  • componentWillUnmount()
    会在组件卸载及销毁之前直接调用。在此方法中执行必要的清理操作,例如,清除 timer,取消网络请求或清除在componentDidMount() 中创建的订阅等。

注意:componentWillUnmount() 中不应调用 setState(),因为该组件将永远不会重新渲染。

16.0之后

react 16.0之后移除的生命周期函数:

  • componentWillMount
  • componentWillReceiveProps
  • componentWillUpdate

但是为了向下兼容,react并未删除这三个生命周期,新增以 UNSAFE_ 前缀为别名的三个函数 UNSAFE_componentWillMount()、
UNSAFE_componentWillReceiveProps()、
UNSAFE_componentWillUpdate()。

新增的生命周期函数:

  • static getDerivedStateFromProps(nextProps, prevState)
  • getSnapshotBeforeUpdate(prevProps, prevState)

生命周期如下:

Vue和React的一些对比:哪个更适合你?

总结:(1)初始化阶段保持不变(2)挂载阶段: getDerivedStateFromProps => render => componentDidMount(3)更新阶段 getDerivedStateFromProps => shoudeComponentUpdate => render => getSnapshotBeforeUpdate => componentDidUpdate(4)卸载阶段保持不变

接下来重点介绍getDerivedStateFromProps、getSnapshotBeforeUpdate两个方法。

(1)static getDerivedStateFromProps(props, state)

getDerivedStateFromProps 会在调用 render 方法之前调用,并且在初始挂载及后续更新时都会被调用。它应返回一个对象来更新 state,如果返回 null 则不更新任何内容。

当state的值在任何时候都取决于props的时候适用该方法。

示例如下:

<code>

class

ScrollingList

extends

React

.

Component

{

constructor

(props) {

super

(props); }

static

getDerivedStateFromProps(nextProps, prevState) {

if

(nextProps.type !== prevState.type) {

return

{

type

: nextProps.type, }; }

return

null

; } render() {

return

(

<

div

>

{/* ...contents... */}

div

>

); } }/<code>

(2)getSnapshotBeforeUpdate(prevProps, prevState)

getSnapshotBeforeUpdate() 在最近一次渲染输出(提交到 DOM 节点)之前调用。它使得组件能在发生更改之前从 DOM 中捕获一些信息(例如,滚动位置)。此生命周期的任何返回值将作为参数传递给 componentDidUpdate()。此用法并不常见,但它可能出现在 UI 处理中,如需要以特殊方式处理滚动位置的聊天线程等。应返回 snapshot 的值(或 null)。

示例如下:

<code>

class

ScrollingList

extends

React

.

Component

{

constructor

(props) {

super

(props);

this

.listRef = React.createRef(); } getSnapshotBeforeUpdate(prevProps, prevState) {

if

(prevProps.list.length

this

.props.list.length) {

const

list =

this

.listRef.current;

return

list.scrollHeight - list.scrollTop; }

return

null

; } componentDidUpdate(prevProps, prevState, snapshot) {

if

(snapshot !==

null

) {

const

list =

this

.listRef.current; list.scrollTop = list.scrollHeight - snapshot; } } render() {

return

(

this.listRef}>{ }

); } }/<code>

8.事件处理(@Click vs onClick)

vue与react在针对事件处理上的用法上也有较大不同。

vue

vue中使用 v-on 指令监听 DOM 事件,并在触发时运行一些 JavaScript 代码。通常使用v-on接收一个需要调用的方法名称。

(1)直接绑定方法,不传任何参数,回调函数参数是浏览器事件event对象。

示例:

<code>

<

div

@

click

=

"greet"

>

Greet

div

>

/<code>

method:

<code>  methods: {
    greet(

event

) { console.log(

event

); } }/<code>

(2)内联调用方法

示例:

<code>

<

div

@

click

=

"greet('hello')"

>

Greet

div

>

/<code>

method:

<code>methods: {
  greet(message) {
    

this

.message = message; } }/<code>

有时也需要在method中访问原生DOM事件,可以将$event显式传入method中。

<code>/<code>

method:

<code>methods: {
  greet(message, 

event

) {

this

.message = message; } }/<code>

(3)事件修饰符和按键修饰符

Vue.js为事件添加了事件修饰符和按键修饰符(个人感觉这个是vue做的很好的点,让用户更加聚焦数据逻辑,无需花费更多的精力处理DOM事件细节)。

Ⅰ. 事件修饰符

在事件处理程序中调用 event.preventDefault() 或 event.stopPropagation() 是非常常见的需求。为了解决这个问题,Vue.js 为 v-on 提供了事件修饰符,修饰符是由点开头的指令后缀来表示的。

  • .stop:阻止事件继续传播
  • .prevent:阻止事件默认行为
  • .capture:添加事件监听器时使用事件捕获模式
  • .self:当前元素触发时才触发事件处理函数
  • .once:事件只触发一次
  • .passive:告诉浏览器你不想阻止事件的默认行为,不能和.prevent一起使用。

示例:

<code> 

<

a

v-on:click.stop

=

"doThis"

>

a

>

<

form

v-on:submit.prevent

=

"onSubmit"

>

form

>

<

a

v-on:click.stop.prevent

=

"doThat"

>

a

>

<

form

v-on:submit.prevent

>

form

>

<

div

v-on:click.capture

=

"doThis"

>

...

div

>

<

div

v-on:click.self

=

"doThat"

>

...

div

>

<

a

v-on:click.once

=

"doThis"

>

a

>

<

button

@

click.ctrl.exact

=

"onCtrlClick"

>

A

button

>

/<code>

④ 鼠标按钮修饰符这些修饰符会限制处理函数仅响应特定的鼠标按钮。

  • .left
  • .right
  • .middle

关于v-on处理事件的好处:1.扫一眼 HTML 模板便能轻松定位在 JavaScript 代码里对应的方法。2.因为你无须在 JavaScript 里手动绑定事件,你的 ViewModel 代码可以是非常纯粹的逻辑,和 DOM 完全解耦,更易于测试。3.当一个 ViewModel 被销毁时,所有的事件处理器都会自动被删除。你无须担心如何清理它们。

react

React 元素的事件处理和 DOM 元素的很相似,但是有一点语法上的不同:

  • React 事件的命名采用小驼峰式(camelCase),而不是纯小写。
  • 使用 JSX 语法时你需要传入一个函数作为事件处理函数,而不是一个字符串。

(1)事件处理程序不传参数

在class组件中使用回调函数,需要显式绑定this或者使用箭头函数。

不传参数时,默认参数是e,这是一个合成事件。React 根据 W3C 规范来定义这些合成事件,所以你不需要担心跨浏览器的兼容性问题。

在React中不能通过返回false的方式阻止默认行为,你必须显式的使用preventDefault。

显示绑定this:

<code>

class

NewComponent

extends

React

.

Component

{

constructor

(props) {

super

(props);

this

.handleClick =

this

.handleClick.bind(

this

); } handleClick(e) { e.preventDefault();

console

.log(e.target); } render() {

return

<

div

onClick

=

{this.handleClick}

>

Click me

div

>

; } } /<code>

箭头函数:

<code>

class

NewComponent

extends

React

.

Component

{

constructor

(props) {

super

(props); } handleClick =

(

e

) =>

{ e.preventDefault();

console

.log(e.target); }; render() {

return

<

div

onClick

=

{this.handleClick}

>

Click me

div

>

; } } /<code>

(2)事件处理程序传递参数

通常我们会为事件处理函数传递额外的参数,有两种方式向事件处理函数传递参数:

Ⅰ. 箭头函数传递参数通过箭头函数的方式,事件对象e必需显示的进行传递。

<code>

class

NewComponent

extends

React

.

Component

{

constructor

(props) {

super

(props);

this

.handleClick =

this

.handleClick.bind(

this

); } handleClick(e, message) { e.preventDefault();

console

.log(message); }; render() {

return

<

div

onClick

=

{(e)

=>

this.handleClick(e, 'hello')}>Click me

div

>

; } } /<code>

Ⅱ. 通过bind形式传递参数e作为第二个参数传递,事件对象以及更多的参数将会被隐式的传递。

<code>

class

NewComponent

extends

React

.

Component

{

constructor

(props) {

super

(props); } handleClick(message, e) { e.preventDefault();

console

.log(message); }; render() {

return

<

div

onClick

=

{this.handleClick.bind(this,

'

hello

')}>

Click me

div

>

; } } /<code>

结语

以上就是博主关于react和vue的一些对比以及个人思考的上部,觉得有收获的可以关注一波,后续中部和下部会尽快持续更新,感谢关注。

作者:笪笪来源:掘金


为感谢您对我们的认可,特意准备了一些IT入门和进阶的干货

包括:Java、UI设计、H5前端、Python+人工智能、软件测试和新媒体运营六大学科视频资料。以及IT就业大礼包。

线上视频、音频,随时学习观看

关注我们并私信“资料”即可获取。

收藏

举报

源码时代/<code>
/<code>

扫码下载今日头条

/<code>
/<code>


分享到:


相關文章: