blog
blog copied to clipboard
React & Vue 用法区别记
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>
条件渲染
-
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>
-
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 的版本,可以通过 getDerivedStateFromProps
,componentDidUpdate
来实现。
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 的生命周期都大同小异,主要就是创建 -> 更新 -> 销毁。具体一些名字不同而已。
参考
- https://zhuanlan.zhihu.com/p/70888985
- https://juejin.im/post/5b8b56e3f265da434c1f5f76