Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

React & Vue 用法区别记 #86

Open
yanyue404 opened this issue Oct 16, 2019 · 0 comments
Open

React & Vue 用法区别记 #86

yanyue404 opened this issue Oct 16, 2019 · 0 comments

Comments

@yanyue404
Copy link
Owner

1.创建组件

React

React 有两种类型的组件,分别是 functional component, class component,所以有两种定义方式:

functional component

function Test(props) {
  return <div className="container">{props.name}</div>;
}

class component

class Test extends React.Component() {
  constructor(props) {
    // super一定要写,继承React.Component
    super(props);
    // state在里面定义
    this.state = { name: 'daisy' };
  }
  // class创建的组件中 必须有render方法,且显示return内容或者null
  render() {
    return <div className="shopping-list">{this.state.name}</div>;
  }
}

Vue

全局注册

Vue.component('my-component-name', {
  /* ... */
});

局部注册

var ComponentA = {
  /* ... */
};

new Vue({
  el: '#app',
  components: {
    'component-a': ComponentA
  }
});

单文件组件

<template>
  <p class="red">{{ greeting }}</p>
  <other-component></other-component>
</template>

<script>
  import OtherComponent from './OtherComponent.vue';

  export default {
    data() {
      return {
        gretting: 'Hello'
      };
    },
    components: {
      OtherComponent
    }
  };
</script>
<style>
  .red {
    color: red;
  }
</style>

2. 模板语法

通过以下几个方面说:

  • 遍历渲染
  • 条件渲染
  • html 属性
  • 绑定事件

React

遍历渲染: map

  render() {
      var repoList = repos.map(function(repo, index) {
        return (
          <li key={index}>
            <a href={repo.html_url}>{repo.name}</a> ({repo.stargazers_count}{' '}
            stars) <br /> {repo.description}
          </li>
        );
      });
      return (
        <main>
          <ol>{repoList}</ol>
        </main>
      );
    }
  }

条件渲染:使用三目,&&,如果逻辑在复杂一点就得用函数来帮忙了

render() {
  const isLoggedIn = this.state.isLoggedIn;
  return (
    <div>
      isHappy ? <div> yes i am  </div> : <div> no </div>
    </div>
  );
}

render() {
  const isLoggedIn = this.state.isLoggedIn;
  return (
    <div>
       isShow && <div>hello word</div>
    </div>
  );
}

html 属性: 跟原生一样直接写不过要换成驼峰式 tab-index => tabIndex,React 16 以后还支持自定义属性。

<div tabindex="-1" className="test" />

<div mycustomattribute="something" />

绑定事件:改成驼峰onClick这样的形式,同时传入一个函数

<button onClick={this.handleClick}>Activate Lasers</button>

阻止默认事件需要显式使用: e.preventDefault();

Vue

遍历渲染: v-for

<template>
  <li v-else-if="githubStar.length >1" v-for="(record, index) in githubStar">
    <a :href="record.html_url" :class="index<3?'red':''">
      {{ record.name }}
    </a>
    ({{ record.stargazers_count }} stars)
    <br />
    <p v-if="index<3" style="color: #000;">{{ record.description }}</p>
    <p v-else style="color: #333;">{{ record.description }}</p>
  </li>
</template>

条件渲染

  1. vue-if 系列
<div v-if="type === 'A'">
  A
</div>
<div v-else-if="type === 'B'">
  B
</div>
<div v-else-if="type === 'C'">
  C
</div>
<div v-else>
  Not A/B/C
</div>
  1. v-show
<h1 v-show="ok">Hello!</h1>

v-if的逻辑显示不同,v-show只是简单地切换元素的 CSS 属性 display

注意,v-show 不支持 <template> 元素,也不支持 v-else

html 属性:需要用 v-bind 来指定

<!-- 完整语法 -->
<a v-bind:href="url">...</a>

<!-- 缩写 -->
<a :href="url">...</a>
<div :id="dynamicId"></div>
<img :src="imageSrc" />
<div :style="{ fontSize: size + 'px' }"></div>

绑定事件:v-on

<!-- 完整语法 -->
<button v-on:click="doThat('hello', $event)"></button>

<!-- 缩写语句 -->
<button @click="doThat('hello', $event)"></button>

事件修饰符:

<!-- 停止冒泡 -->
<button @click.stop="doThis"></button>
<!-- 阻止默认行为 -->
<button @click.prevent="doThis"></button>
<!-- 阻止默认行为,没有表达式 -->
<form @submit.prevent></form>
<!-- 点击回调只会触发一次 -->
<button v-on:click.once="doThis"></button>
<!-- 键修饰符,键别名 -->
<input @keyup.enter="onEnter" />
<!--  串联修饰符 -->
<button @click.stop.prevent="doThis"></button>

3.流通管道 Props

React

React 的 props 如果是静态的就直接传字符串,动态的就用变量{}来传,还可以传入方法(在子组件上 props 属性获取)。

class Test extends React.Component {
   constructor(super) {
     super(props);
	   this.state = { name : 'daisy'}
   }
   onClick( ) => {
      console.log("onClick");
   }
   render() {
     return (
	      <Welcome name="Sara" />;
        <Welcome name={this.state.name} />;
        <Welcome handleClick={this.onClick} />;
        // 子组件使用的时候,直接this.props.handleClick()就可以了。
	  )
   }
}

Vue

传入的值 title 为一个常量(静态 prop)时,不加 v-bind

<blog-post title="My journey with Vue"></blog-post>

传入的值 title 为一个变量(动态 prop)时,加 v-bind(此时传递的才是变量,然后 vue 会去 data 里找这个值)

<blog-post v-bind:title="titleValue"></blog-post>

传入方法的话,一样要使用 v-on,子组件要用 emit 方法来触发。

<Welcome v-on:handleClick="onClick" />;

// 子组件里要用$emit方法来触发它
<button v-on:click="$emit('handleClick')">Enlarge text</button>;

4. 内部状态 State

React

在 React,组件内部自己维护的状态叫 State,不能直接去改内部状态 state,而是通过setState

class Test extends React.Component() {
 constructor(props) {
   // super一定要写,继承React.Component
    super(props);
	// state在里面定义
	this.state = { name : 'daisy' };
  }
  changeName () => {
     this.setState({ name: 'Lily' })
  }
  render() {
    return (
      <div className="shopping-list" onClick={this.changeName}>
          {this.state.name}
      </div>
    )
  }
}

Vue

在 Vue, 组件内部自己维护的状态其实就是 Data。如果要改的话,直接在方法里通过 this 或者是通过 vue 对象来改。

var vm = new Vue({
  el: '#app',
  //  用于给 View 提供数据,相当于React的state
  data: {
    msg: 'Hello Vue'
  },
  method: {
    changeMsg: function() {
      this.msg = 'Hello daisy';
    }
  }
});

// 或者
vm.msg = 'daisy';

Vue 除了在 Data 里定义的属性之外,还额外定义计算属性跟侦听属性

// 计算属性, reversedMessage 属性将会监听 message 的改变,而自动重新计算
var vm = new Vue({
  el: '#example',
  data: {
    message: 'Hello'
  },
  computed: {
    reversedMessage: function () {
      return this.message.split('').reverse().join('')
    }
  }
})

<div id="example">
  { reversedMessage }
</div>

为啥 React 不需要这个属性呢?

因为 React 有 render 函数,你可以在里面随便多定义一个变量。
每一次 this.state.message 改变的时候,都一定会调用 render 函数重新渲染,所以就相当于重新计算 reversedMessage 了。

render() {
   const reversedMessage = this.state.message.split('').reverse().join('')
    return (
      <div className="shopping-list">
        {reversedMessage}
      </div>
    )
  }

侦听属性感觉跟计算属性很像,但是他们又有不同。
侦听属性是为了可以监听到数据的改变,然后做一些异步的或者开销大的操作。

var watchExampleVM = new Vue({
  el: '#watch-example',
  data: {
    question: 'aaa'
  },
  watch: {
    // 如果 `question` 发生改变,这个函数就会运行
    question: function(newQuestion, oldQuestion) {
      this.getAnswer();
    }
  },
  methods: {
    getAnswer: function() {
      // AJax 请求
    }
  }
});

同样的问题,为啥 React 不需要这个属性呢?

因为 React 里已经有方法可以做到了。
React 15 的版本,可以通过 componentWillReceiveProps 来实现

componentWillReceiveProps(nextProps) {
    if (nextProps.id !== this.props.id) {
    	this.setState({externalData: null});
      this._loadAsyncData(nextProps.id);
    }
  }

React 16 的版本,可以通过 getDerivedStateFromPropscomponentDidUpdate 来实现。

static getDerivedStateFromProps(nextProps, prevState) {
    // Store prevId in state so we can compare when props change.
    if (nextProps.id !== prevState.prevId) {
      return {
        externalData: null,
        prevId: nextProps.id,
      };
    }
    // No state update necessary
    return null;
  }
  componentDidUpdate(prevProps, prevState) {
    if (this.state.externalData === null) {
      this._loadAsyncData(this.props.id);
    }
  }

5. 双向绑定

React

html 标签<input>, <textarea> , 和 <select> 使用受控组件,setState同步更新onChange后的 value

class NameForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = {value: ''};

    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  // 这里通过setState去改变state的值
  handleChange(event) {
    this.setState({value: event.target.value});
  }

  handleSubmit(event) {
    alert('提交的名字: ' + this.state.value);
    event.preventDefault();
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          名字:
		  // 当input的值发生改变的时候就会调用handleChange
		  // 通过state改变value的值,所以这里的显示会随用户
		  // 的输入更新而更新
          <input type="text" value={this.state.value} onChange={this.handleChange} />
        </label>
        <input type="submit" value="提交" />
      </form>
    );

Vue

vue 采用 v-model 的形式

<input v-model="message" placeholder="edit me" />
<p>Message is: {{ message }}</p>

实际上 v-model 是一个语法糖, 上面可以翻译成:

`<input :value="message" @input="message = $event.targer.value" />`

input 本身有个 oninput 事件,每当输入框发生变化,就会触发 onput,将最新的 value 传给他。

此外,v-model 在内部为不同的输入元素使用不同的属性并抛出不同的事件:

  • input 和 textarea 元素使用 value 属性和 input 事件;
  • checkbox 和 radio 使用 checked 属性和 change 事件;
  • select 字段将 value 作为 prop 并将 change 作为事件。

v-model 不仅仅可以用在原生 html 元素上,还可以用在组件上。用在组件上的时候 v-on 用于监听事件,emit 用来触发事件。

<div id="demo">
  <currency-input v-model="price"></currentcy-input>
  // 相当于是<currency-input :value="price" v-on:input="price = arguments[0]"></currentcy-input>
  // 这里用v-on监听事件,相当于传给了子组件value,还有input方法
  <span>{{price}}</span>
</div>
Vue.component('currency-input', {
  template: `
    <span>
      <input
        ref="input"
        :value="value" // 这里将父组件传来的value赋值给input的value
        @input="$emit('input', $event.target.value)" // 这里去触发input方法
      >
    </span>
  `,
  props: ['value'],
})

var demo = new Vue({
  el: '#demo',
  data: {
    price: 100,
  }
})

6. 生命周期

React、vue 的生命周期都大同小异,主要就是创建 -> 更新 -> 销毁。具体一些名字不同而已。

参考

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant