關於Vue和React的一些對比及我的思考(上)

前言

Vue和React都是目前最流行、生態最好的前端框架之一。框架自己沒有優劣之分,只有適用之別,選擇符合自身業務場景、團隊基礎的技術纔是咱們最主要的目的。css

博主1年前用的是Vue框架,近半年轉技術棧到React框架,對於Vue和React都有一些基本的瞭解。接下來博主將與你們一塊兒走近Vue和React,共同探討它們的差別。(好比你正在用vue,對react感興趣也能夠看下二者之間的用法差別,反之亦然)html

總體內容概覽:前端

總體內容概覽

因爲內容較長,將分上、中、下三部分和你們一塊兒共同探討(有不一樣意見的歡迎文章下方一塊兒探討交流,感謝支持)。vue

1.背景

vue

Google 前工程師尤雨溪於 2014 年建立了這個框架。Vue是一套用於構建用戶界面的漸進式框架。與其它大型框架不一樣的是,Vue 被設計爲能夠自底向上逐層應用。Vue 的核心庫只關注視圖層,不只易於上手,還便於與第三方庫或既有項目整合。java

react

與 Vue 不一樣,react 庫是由 Facebook 建立的。最初是爲了 Facebook 廣告流量管理建立的。那時 Facebook 遇到了維護和編碼方面的問題。它以動態建立和交互式 UI 的能力而聞名。react

2.核心思想

vue與react都推崇組件式的開發理念,可是在設計的核心思想上有很大差異。es6

vue

vue的總體思想仍然是擁抱經典的html(結構)+css(表現)+js(行爲)的形式,vue鼓勵開發者使用template模板,並提供指令供開發者使用(v-if、v-show、v-for等等),所以在開發vue應用的時候會有一種在寫經典web應用(結構、表現、行爲分離)的感受。另外一方面,在針對組件數據上,vue2.0經過Object.defineProperty對數據作到了更細緻的監聽,精準實現組件級別的更新。web

react

react總體上是函數式的思想,組件使用jsx語法,all in js,將html與css全都融入javaScript,jsx語法相對來講更加靈活,我一開始剛轉過來也不是很適應,感受寫react應用感受就像是在寫javaScript。當組件調用setState或props變化的時候,組件內部render會從新渲染,子組件也會隨之從新渲染,能夠經過shouldComponentUpdate或者PureComponent能夠避免沒必要要的從新渲染(我的感受這一點上不如vue作的好)。api

3.組件形式

vue

vue組件定義使用xx.vue文件來表示,vue組件將html、css、js組合到一塊兒,模板部分使用數據使用{{}},形式以下:數組

// 模板(html)
<template>
  <div>{{name}}</div>
</template>

// 數據管理(js)
<script>
export default {
  name: 'NewComponent',
  data() {
    return {
      name: 'xx'
    }
  }
}
</script>

// 樣式(css)
<style scoped>

</style>
複製代碼

組件使用:

<new-component name="xx" />
複製代碼

react

react推薦使用jsx或者js文件來表示組件,react支持class組件和function組件2種形式,react使用{}包裹變量,這點須要注意。

注意: 組件名稱必須以大寫字母開頭。React 會將以小寫字母開頭的組件視爲原生 DOM 標籤。例如,<div /> 表明 HTML 的 div 標籤,而 <Welcome /> 則表明一個組件,而且需在做用域內使用 Welcome。

(1)class組件

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;
複製代碼

(2)function組件

hooks的出現賦予了function組件管理state的能力。

import React, { useState } from 'react';

function NewComponent() {
  const [name, setName] = useState('');
  return (<div>{name}</div>);
}

export default NewComponent;
複製代碼

4.數據管理(props、data vs state)

組件數據管理一般包含2部分,來自父組件的數據props與自身的數據。

vue與react中的props都是單向數據流的,父級prop的更新會向下流動到子組件中,可是反過來則不行。prop能夠是數組或對象,用於接收來自父組件的數據。

vue

props

vue中的props支持傳遞靜態或動態props,靜態props通常傳遞字符串。

<blog-post title="My journey with Vue"></blog-post>
複製代碼

靜態prop傳遞布爾值true能夠這樣寫,傳值false仍然須要使用動態prop傳值。

<blog-post disabled></blog-post>
複製代碼

動態賦值使用v-bind,能夠簡寫爲:。

<blog-post v-bind:title="tile"></blog-post>
// 簡寫形式
<blog-post :title="tile"></blog-post>
複製代碼

動態prop經常使用來傳遞對象、數組、布爾值(false值,true值能夠直接傳屬性)等。

<blog-post :title="post.title + ' by ' + post.author.name"></blog-post>
複製代碼

data

vue中使用data來管理組件的數據,vue 將會遞歸將 data 的屬性轉換爲 getter/setter,從而讓 data 的屬性可以響應數據變化。對象必須是純粹的對象 (含有零個或多個的 key/value 對)。一旦觀察過,不須要再次在數據對象上添加響應式屬性。所以推薦在建立實例以前,就聲明全部的根級響應式屬性。

當一個組件被定義,data必須聲明爲返回一個初始數據對象的函數。

export default {
  name: 'NewComponent',
  data() {
    return {
      name: 'xxx',
      age: 12
    }
  }
}
複製代碼

當須要在組件內部修改數據時,能夠直接經過vue實例修改:

methods: {
    changeName() {
      this.name = 'new Name';
    }
  }
複製代碼

react

props

react中的props也與vue同樣能夠傳遞靜態或動態props,靜態props通常傳遞字符串。

函數組件和class組件均可以使用props,函數組件使用props參數獲取父組件傳下來的props。

函數組件獲取props:

function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

const element = <Welcome name="Sara" />;
複製代碼

class組件使用this.props獲取組件props

class Welcome extends React.Component {
  constructor(props) {
    super(props);
  }
  render() {
    const { name } = this.props;
    return <div>{name}</div>;
  }
}
複製代碼

動態props:

<Welcome name={name} />
複製代碼

state

react中使用state來管理組件內的數據,hooks的出現使得函數組件也具有管理state的能力。

class組件state

class組件在構造函數(constructor)中定義組件內數據(state),修改數據必須經過setState修改,不能直接修改state,這點很是重要。

class組件使用state:

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 <div onClick={this.changeName}>{name}</div>;
  }
}
複製代碼

關於class組建的setState有如下兩點說明:

  • 1.setState更新是異步的,可是在setTimeout和原生事件中是同步的
  • 2.setState更新的是組件的部分數據,react會自動將數據合併。

當須要使用上一個state值時,可讓 setState() 接收一個函數而不是一個對象。這個函數用上一個 state 做爲第一個參數,將這次更新被應用時的 props 作爲第二個參數:

this.setState((state, props) => ({
  counter: state.counter + props.increment
}));
複製代碼
function組件useState

react 16.0以前函數組件只是純的渲染組件,hooks的出現賦予了函數組件管理state的能力。

useState返回一個state,以及更新state的函數。若是新的 state 須要經過使用先前的 state 計算得出,那麼能夠將函數傳遞給 setState。該函數將接收先前的 state,並返回一個更新後的值。

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>
    </>
  );
}
複製代碼

關於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

<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>
複製代碼

父組件使用@myEvent監聽自定義事件,回調函數參數是子組件傳回的數據:

<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>
複製代碼

react

react中父組件使用props傳遞數據和回調函數給子組件,子組件經過props傳下來的回調函數返回數據,父組件經過回調函數獲取子組件傳遞上來的數據。

子組件經過props接收父組件傳下來的回調事件:

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>;
}
複製代碼

父組件經過回調事件獲取子組件傳遞的參數:

function Parent() {
  const changeName = name => {
    console.log(name);
  };
  return <Children myEvent={changeName}></Children>;
}
複製代碼

5.2.跨組件數據交互(provide/inject vs Context)

vue和react都支持跨組件傳遞數據,vue中主要經過provide / inject實現,react中主要經過Context實現。

vue

vue中經過provide / inject在祖先組件向全部子孫後代注入一個依賴,不論組件層次有多深,並在起上下游關係成立的時間裏始終生效。

祖先組件中定義provide選項,provide選項應該是一個對象或返回一個對象的函數。

<template>
  <div>
    <new-component @myEvent="getName"></new-component>
  </div>
</template>

<script>
import NewComponent from './NewComponent';

export default {
  provide: { // 定義provide選項
    message: 'This is a big news'
  },
  components: {
    NewComponent
  },
  data() {
    return {}
  },
  methods: {
    getName(name) {
      console.log(name)
    }
  }
}
</script>
複製代碼

子組件經過inject選項獲取祖先組件的provide選項值,inject選項應該是一個字符串數組或者對象。

<template>
  <div>{{message}}</div>
</template>

<script>
export default {
  name: 'Children',
  inject: ['message'],
  data() {
    return {}
  }
}
</script>
複製代碼

注意:provide 和 inject 綁定並非可響應的。這是刻意爲之的。然而,若是你傳入了一個可監聽的對象,那麼其對象的屬性仍是可響應的。

react

Context 提供了一個無需爲每層組件手動添加 props,就能在組件樹間進行數據傳遞的方法。

在父組件建立一個Context對象,經過Context.provider的value屬性向消費組件傳值。

import React, { useState } from 'react';

// 建立Context對象
const MyContext = React.createContext({ theme: 'black' });

function Parent() {
  const changeName = name => {
    console.log(name);
  };
  // Context.provider向消費組件傳值
  return (<MyContext.Provider value={{ theme: 'white' }}>
    <Children myEvent={changeName}></Children>;
  </MyContext.Provider>);

}
複製代碼

消費組件獲取Context有2種方式:

(1)class組件經過contextType獲取最近Context上的那個值。

class DeepChildren1 extends React.Component {
  constructor(props) {
    super(props);
  }

  static contextType = MyContext;

  render() {
    return <div>{this.context.theme}123</div>;
  }
}
複製代碼

(2)函數式組件經過Context.Consumer訂閱到Context的變動。

function DeepChildren(props) {
  return (<MyContext.Consumer>
    {
      (value) => (
        <div>{value.theme}</div>
      )
    }
  </MyContext.Consumer>);
}
複製代碼

關於Context須要注意:

當Provider的父組件進行重渲染時,consumers組件會從新渲染,而且沒有辦法避免,應該儘可能避免使用Context。

6.class與style

關於class與style處理上,vue與react也存在較大差別。

vue

vue對class與style特地作了加強,能夠傳字符串、對象、數組。

class

(1)給class綁定字符串:

<div class="hello"></div>
複製代碼

(2)給class綁定對象:

<div
  class="static"
  :class="{ active: isActive, 'text-danger': hasError }"
></div>
複製代碼

data以下:

data: {
  isActive: true,
  hasError: false
}
複製代碼

HTML 將被渲染爲:

<div class="static active"></div>
複製代碼

(3)給class綁定數組:

<div :class="[activeClass, errorClass]"></div>
複製代碼

data以下:

data: {
  activeClass: 'active',
  errorClass: 'text-danger'
}
複製代碼

HTML 將被渲染爲:

<div class="active text-danger"></div>
複製代碼

(4)class還能夠直接綁定到組件上,這一點react並不支持。

聲明組件以下:

Vue.component('my-component', {
  template: '<p class="foo bar">Hi</p>'
})
複製代碼

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

<my-component class="baz boo"></my-component>
複製代碼

HTML 將被渲染爲:

<p class="foo bar baz boo">Hi</p>
複製代碼

style

style用來綁定內聯樣式,支持傳對象、數組,使用須要添加瀏覽器引擎前綴的 CSS 屬性時,如 transform,Vue.js 會自動偵測並添加相應的前綴。

(1)傳對象,CSS 屬性名能夠用駝峯式 (camelCase) 或短橫線分隔 (kebab-case,記得用引號括起來) 來命名:

<div :style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>
複製代碼

data以下:

data: {
  activeColor: 'red',
  fontSize: 20
}
複製代碼

HTML將被渲染爲:

<div style="color: red; font-size: 20px;"></div>
複製代碼

(2)傳數組將多個樣式應用到同一個元素上

<div :style="[baseStyles, overridingStyles]"></div>
複製代碼

data以下:

baseStyles: {
  fontSize: '20px',
  color: 'blue'
},
overridingStyles: {
  height: '80px'
}
複製代碼

HTML將被渲染爲:

<div style="font-size: 20px; color: blue; height: 80px;"></div>
複製代碼

react

react使用className用於指定css的class,react中不能直接爲組件指定class。

className

react中className通常傳值字符串常量或者字符串變量,不能傳遞數組或者對象語法。

(1)傳字符串常量:

function NewComponent() {
  return <div className="container" >This is New Component.</div>;
}
複製代碼

(2)傳字符串變量:

function NewComponent() {
  const newClass = 'conrainer'
  return <div className={newClass}>This is New Component.</div>;
}
複製代碼

(3)傳遞多個class,可使用es6的模板字符串實現:

function NewComponent() {
  const newClass = 'conrainer'
  return <div className={`${newClass} new-container`}>This is New Component.</div>;
}
複製代碼

當須要傳遞數組或者對象語法時,能夠引入classnames庫實現:

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>;
}
複製代碼

html將被渲染爲:

<div class="container newContainer bar new-class c">This is New Component.</div>
複製代碼

style

一般不推薦將 style 屬性做爲設置元素樣式的主要方式。在多數狀況下,應使用 className 屬性來引用外部 CSS 樣式表中定義的 class。style 在 React 應用中多用於在渲染過程當中添加動態計算的樣式。

style接收一個對象

const divStyle = {
  color: 'blue',
  backgroundImage: 'url(' + imgUrl + ')',
};

function HelloWorldComponent() {
  return <div style={divStyle}>Hello World!</div>;
}
複製代碼

注意:樣式不會自動補齊前綴。如需支持舊版瀏覽器,請手動補充對應的樣式屬性:

const divStyle = {
  WebkitTransition: 'all', // note the capital 'W' here
  msTransition: 'all' // 'ms' is the only lowercase vendor prefix
};

function ComponentWithTransition() {
  return <div style={divStyle}>This should work cross-browser</div>;
}
複製代碼

7.生命週期

組件的生命週期通常包含:初始化、掛載、更新、卸載四個大階段,接下來分別看下vue和reac的生命週期。

vue

vue生命週期圖示:

vue生命週期

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以前生命週期以下:

react 16.0以前生命週期

(1)初始化

  • constructor
    是class組件的默認方法,經常使用來初始化state或者設置屬性等。
class Counter extends React.component{
    constructor(props){
        super(props); // 聲明constructor時必須調用super方法
        this.state = {
          count: 0
        };
        this.color = 'red';
    }
}
複製代碼

(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)

生命週期以下:

react 16.0以後生命週期

總結:
(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的時候適用該方法。

示例以下:

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>
    );
  }
}
複製代碼

(2)getSnapshotBeforeUpdate(prevProps, prevState)

getSnapshotBeforeUpdate() 在最近一次渲染輸出(提交到 DOM 節點)以前調用。它使得組件能在發生更改以前從 DOM 中捕獲一些信息(例如,滾動位置)。今生命週期的任何返回值將做爲參數傳遞給 componentDidUpdate()。此用法並不常見,但它可能出如今 UI 處理中,如須要以特殊方式處理滾動位置的聊天線程等。應返回 snapshot 的值(或 null)。

示例以下:

class ScrollingList extends React.Component {
  constructor(props) {
    super(props);
    this.listRef = React.createRef();
  }

  getSnapshotBeforeUpdate(prevProps, prevState) {
    // 咱們是否在 list 中添加新的 items ?
    // 捕獲滾動​​位置以便咱們稍後調整滾動位置。
    if (prevProps.list.length < this.props.list.length) {
      const list = this.listRef.current;
      return list.scrollHeight - list.scrollTop;
    }
    return null;
  }

  componentDidUpdate(prevProps, prevState, snapshot) {
    // 若是咱們 snapshot 有值,說明咱們剛剛添加了新的 items,
    // 調整滾動位置使得這些新 items 不會將舊的 items 推出視圖。
    //(這裏的 snapshot 是 getSnapshotBeforeUpdate 的返回值)
    if (snapshot !== null) {
      const list = this.listRef.current;
      list.scrollTop = list.scrollHeight - snapshot;
    }
  }

  render() {
    return (
      <div ref={this.listRef}>{/* ...contents... */}</div>
    );
  }
}
複製代碼

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

vue與react在針對事件處理上的用法上也有較大不一樣。

vue

vue中使用 v-on 指令監聽 DOM 事件,並在觸發時運行一些 JavaScript 代碼。一般使用v-on接收一個須要調用的方法名稱。

(1)直接綁定方法,不傳任何參數,回調函數參數是瀏覽器事件event對象。

示例:

<div  @click="greet">Greet</div>
複製代碼

method:

methods: {
    greet(event) {
      console.log(event);
    }
  }
複製代碼

(2)內聯調用方法

示例:

<div  @click="greet('hello')">Greet</div>
複製代碼

method:

methods: {
  greet(message) {
    this.message = message;
  }
}
複製代碼

有時也須要在method中訪問原生DOM事件,能夠將$event顯式傳入method中。

<div  @click="greet('hello', $event)">Greet</div>
複製代碼

method:

methods: {
  greet(message, event) {
    this.message = message;
  }
}
複製代碼

(3)事件修飾符和按鍵修飾符

Vue.js爲事件添加了事件修飾符和按鍵修飾符(我的感受這個是vue作的很好的點,讓用戶更加聚焦數據邏輯,無需花費更多的精力處理DOM事件細節)。

Ⅰ. 事件修飾符

在事件處理程序中調用 event.preventDefault() 或 event.stopPropagation() 是很是常見的需求。爲了解決這個問題,Vue.js 爲 v-on 提供了事件修飾符,修飾符是由點開頭的指令後綴來表示的。

  • .stop:阻止事件繼續傳播
  • .prevent:阻止事件默認行爲
  • .capture:添加事件監聽器時使用事件捕獲模式
  • .self:當前元素觸發時才觸發事件處理函數
  • .once:事件只觸發一次
  • .passive:告訴瀏覽器你不想阻止事件的默認行爲,不能和.prevent一塊兒使用。

示例:

<!-- 阻止單擊事件繼續傳播 -->
<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>

<!-- 只當在 event.target 是當前元素自身時觸發處理函數 -->
<!-- 即事件不是從內部元素觸發的 -->
<div v-on:click.self="doThat">...</div>

<!-- 點擊事件將只會觸發一次 -->
<a v-on:click.once="doThis"></a>

<!-- 滾動事件的默認行爲 (即滾動行爲) 將會當即觸發 -->
<!-- 而不會等待 `onScroll` 完成  -->
<!-- 這其中包含 `event.preventDefault()` 的狀況 --
<div v-on:scroll.passive="onScroll">...</div>
複製代碼

Ⅱ. 按鍵修飾符

在監聽鍵盤事件時,咱們常常須要檢查詳細的按鍵。Vue 容許爲 v-on 在監聽鍵盤事件時添加按鍵修飾符。 你能夠直接將 KeyboardEvent.key 暴露的任意有效按鍵名轉換爲 kebab-case 來做爲修飾符。

① 按鍵碼
Vue 提供了絕大多數經常使用的按鍵碼的別名

  • .enter
  • .tab
  • .delete (捕獲「刪除」和「退格」鍵)
  • .esc
  • .space
  • .up
  • .down
  • .left
  • .right

使用 keyCode 特性也是容許的:

<input v-on:keyup.13="submit">
複製代碼

② 系統修飾鍵
能夠用以下修飾符來實現僅在按下相應按鍵時才觸發鼠標或鍵盤事件的監聽器。

  • .ctrl
  • .alt
  • .shift
  • .meta

③ .exact 修飾符
.exact 修飾符容許你控制由精確的系統修飾符組合觸發的事件。

<!-- 有且只有 Ctrl 被按下的時候才觸發 -->
<button @click.ctrl.exact="onCtrlClick">A</button>
複製代碼

④ 鼠標按鈕修飾符
這些修飾符會限制處理函數僅響應特定的鼠標按鈕。

  • .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:

class NewComponent extends React.Component {
  constructor(props) {
    super(props);
    this.handleClick = this.handleClick.bind(this); // 顯示綁定this.handleClick
  }

  handleClick(e) {
    e.preventDefault();
    console.log(e.target);
  }

  render() {
    return <div onClick={this.handleClick}>Click me</div>;
  }
}
複製代碼

箭頭函數:

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>;
  }
}
複製代碼

(2)事件處理程序傳遞參數

一般咱們會爲事件處理函數傳遞額外的參數,有兩種方式向事件處理函數傳遞參數:

Ⅰ. 箭頭函數傳遞參數
經過箭頭函數的方式,事件對象e必需顯示的進行傳遞。

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>;
  }
}
複製代碼

Ⅱ. 經過bind形式傳遞參數
e做爲第二個參數傳遞,事件對象以及更多的參數將會被隱式的傳遞。

class NewComponent extends React.Component {
  constructor(props) {
    super(props);
  }

  handleClick(message, e) { // e做爲第二個參數
    e.preventDefault();
    console.log(message);
  };

  render() {
    return <div onClick={this.handleClick.bind(this, 'hello')}>Click me</div>;
  }
}
複製代碼

結語

以上就是博主關於react和vue的一些對比以及我的思考的上部,以爲有收穫的能夠關注一波,點贊一波,碼字不易,萬分感謝,後續中部和下部會盡快持續更新,感謝關注。

相關文章
相關標籤/搜索