由于最近工作的变化,直接由React转为Vue,所以就有了这篇博客,主要是为了记录,好记性不如烂笔头嘛
由于才上手写博客,所以排版不易阅读,请耐心享用
对于内容方面,请指正,勿苛责~

1.基础语法
1.1 插值表达式
React:{this.state.msg}
Vue:{{msg}}
1.2 判断输出
React:<p v-if="seen">123</p>
Vue:{this.state.seen?<p>123</p>:""}
1.3 属性绑定
React:<div title = {this.state.name}></div>
Vue:<div :title="name"></div> //还可以绑定自定义的属性,将title改为你自定义的属性
,name为属性值,即data里的值
1.4 仅渲染一次(虽然我不是很明白它的应用场景)
React:render渲染,渲染中不产生变化
Vue:<span v-once>{{msg}}</span>
1.5 DOM插入
React:{this.state.DOM}//DOM在数据中心的形式为(<div>...</div>)
Vue:<span v-html="Html"></span>
1.6 点击事件
React:<a onclick = {this.doSomething}>...</a>//doSomething为箭头函数,this不变,不需要手动绑定
若非箭头函数,则<a onclick = {this.doSomething.bind(this)}>...</a>
Vue:<a @click="doSomething">...</a>//click也可改为你自定义事件
1.7 监听事件
React:
<input onChange={this.changeName}>
changeName = (e) =>{
console.log(e.target.value)
}
Vue:
<input v-on:nameValue="getNameValue" />
//v-on简写 :nameValue
<script>
methods:{
getNameValue:function(value){
console.log(value)
}
}
</script>
1.8 修饰符
React:
<form onSubmit={this.handleSubmit}>...</form>
handleSubmit = (event) =>{
event.preventDefault();
}
Vue:<form v-on:submit.prevent="onSubmit">...</form>
1.9 表单绑定
React:
<input value={this.state.msg} onChange={this.changeValue}>
changeValue = (e)=>{
this.setState({
msg:e.target.value
})
}
Vue:<input v-model="msg">
1.10 列表渲染
React:
<ul>
this.state.items.map((item,index)=>{
return (
<li key={index}>
{item}
</li>
)
})
this.state = {
items:[
{message:'Foo'},
{message:'Bar'}
]
}
Vue:
<ul>
<li v-for="(item,index) in items" :key="index">
{{item.message}}
</li>
</ul>
data:{
items:[
{message:'Foo'},
{message:'Bar'}
]
}
1.11 状态管理
React:数据由state属性管理,但不能直接改变state的状态,state对象在react应用中不可变的, 需要使用setState方法更新状态
export default class App extends Component{
constructor(props){
super(props);
this.state = {iptVal:0}
}
componentDidMount(){
this.setState({
iptVal:1
})
}
render(){
return (
<div>{this.state.iptVal}</div>
)
}
}
Vue:数据由data属性在Vue对象中进行管理,可以通过this.a进行改变
在Vue实例中:new Vue({
data:{
a:1
}
})
在组件化的项目中:
export default{
data(){
return {
a:1
}
}
}
//使用return包裹后数据中的变量只在当前组件中生效,不会影响其他组件,从而避免数据在全局可见,造成污染
1.12 组件间通信
React:
父传子:子组件通过this.props来获取
父:
...
<Child toChild = "zxc"/>
...
子:
在子组件内,均可以通过this.props.toChild来获取"zxc"这个字符串
子传父:子组件通过调用父组件传给子组件的方法完成传值
父:
...
getChildValue = (value) =>{
console.log(value) //-----子组件传来的ldh
}
<Child toChildFun = {this.getChildValue} />
...
子:
...
toParent = () = >{
this.props.toChild('ldh')
}
<button onClick = {this.toParent}>..</button>
非父子组件:需要一个公共的父组件,然后通过两两之间的父子关系完成数据的传输
Vue:
父传子:通过父组件绑定自定义属性(或通过v-bind绑定动态属性),子组件使用props选项时显式声明props,
以便它可以从父组件接收到期望的数据
子:
<template>
<div><p>{{message}}</p></div>
</template>
<script>
export default{
props:["message"]
}
</script>
父:
<template>
<div>
<child :message="hello"></child>
</div>
</template>
<script>
import child from './child'
export default {
name:'father',
data(){
return {
hello:"zczxczxc"
}
},
components:{
child
}
}
</script>
子传父:通过父组件绑定自定义事件,子组件通过this.emit('自定义事件',value)传值。在上面的基础上修改
子:
<template>
<div>
<p>{{message}}</p>
<button @click = "ToParent">事件触发</button>
</div>
</template>
<script>
export default{
props:["message"],
methods:{
ToParent:function(){
this.$emit("getFormChild","abcabc")
}
}
}
</script>
父:
<template>
<div>
<child :message="hello" v-on:getFormChild="showDataFromChild"></child>
</div>
</template>
<script>
import child from './child'
export default {
name:'father',
data(){
return {
hello:"zczxczxc"
}
},
components:{
child
},
showDataFromChild:function(data){
console.log(data)
}
}
</script>
非父子:可以使用一个空的Vue实例绑定在Vue实例的原型上作为一个事件总线中心,用emit触发事件,on监听事件。
公共实例文件bus.js,作为公共数控中央总线
import Vue from 'vue';
export default new Vue();
第一个组件first.vue
import Bus from './bus.js'
export default {
name:'first',
data(){
return {
value:'我来自first.vue组件!'
}
},
methods:{
add(){
Bus.$emit('txt',this.value);
}
}
}
第二个组件second.vue
import Bus from './bus.js'
export default {
name:'second',
data(){
return {
}
},
mounted:function(){
Bus.$on('txt',function(val){
console.log(val)
});
}
}
1.13 指令函数
React:这部分,我只是觉得,React的组件化模式有点像,通过exports default xxxx暴露,
通过import直接引入,然后使用<xxxx />进行调用
Vue:
注册:
//全局
Vue.directive('focus',{
//当被当定的元素插入到DOM中时...
inserted:function(el){
el.focus()//聚焦元素
}
})
//组件
directives:{
focus:{
inserted:function(el){
el.focus()
}
}
}
使用
<input v-focus />
总结:对于基础语法,两者的共同点都是去更改数据中心的数据(data()/this.state),不同点是Vue提供了更多的指令以及修饰符等,在开发过程中提供方便
2.书写模板
Vue:它把html、css、js组合到一起,用各自的处理方式,允许开发者声明式地将数据绑定到DOM元素上。Vue.js的核心是一个允许你采用简洁的模板语法来声明式地将数据渲染进DOM的系统,例:
<template>
<div>
<button @click = "clickbtn">{{message}}</button>
</div>
</template>
<script>
export default{
name:'Test',
data(){
return{
message:'今日事,今日毕'
}
}
methods:{
clickbtn:function(){
this.message='改变了'
}
}
}
</script>
React:使用JSX模板,也就是说HTML语言直接写在JavaScript语言之中,不加任何引号,它允许HTML与JavaScript的混写,例:
import { Component } from 'react'
export default class Button extends Component{
constructor(props){
super(props);
this.state = {label:'按钮'}
}
btnClick = () =>{
this.setState({
label:'改变了'
})
}
render(){
return (
<button onClick = {this.btnClick} >{this.state.label}</button>
)
}
}
3.生命周期
React:
常用生命周期
- 挂载阶段:constructor => render => componentDidMount =>结束
- 更新阶段:render => componentDidUpdate =>结束
- 卸载阶段:componentWillUnmount =>结束
完整生命周期
Mounting,挂载阶段,涉及4个钩子函数: 1.constructor():加载的时候调用一次,可以初始化state
2.static getDerivedStateFromProps(props,state):组件每次被render的时候,包括在组件构建之后(虚拟dom之后,实际dom挂载之前),每次获取新的props或state之后,每次接收新的props之后都会返回一个对象作为新的state,返回null则说明不需要更新state;配合componentDidUpdate,可以覆盖componentWillReceiveProps的所有用法
3.render():react最重要的步骤,创建虚拟dom,进行diff算法,更新dom树都在此进行
4.componentDidMount():组件渲染之后调用,只调用一次
Updating,更新阶段,涉及5个钩子函数: 1.static getDerivedStateFromProps(props,state):组件每次被render的时候,包括在组件构建之后(虚拟dom之后,实际dom挂载之前),每次获取新的props或state之后,每次接收新的props之后都会返回一个对象作为新的state,返回null则说明不需要更新state;配合componentDidUpdate,可以覆盖componentWillReceiveProps的所有用法
2.shouldComponentUpdate(nextProps,nextState):组件接收到新的props或者state时调用,return true就会更新dom(使用diff算法更新),return false能阻止更新(不调用render
3.render()
- getSnapshotBeforeUpdate(prevProps,prevState):触发时间,update发生的时候,在render之后,在组件dom渲染之前,返回一个值,作为componentDidUpdate的第三个参数;配合componentDidUpdate,可以覆盖componentWillUpdate的所有用法
5.componentDidUpdate():组件加载时不调用,组件更新完成后调用
Unmounting,卸载阶段,涉及1个钩子函数: 1.componentWillUnmount:组件渲染之后调用,只调用一次
Vue
完整生命周期如下:
beforeCreate:在实例初始化之后,数据观测(data observer)和event/watcher事件配置之前被调用
created:实例已经创建完成之后被调用。在这一步,实例已完成以下配置:数据观测,属性和方法的运算,event/watch事件回调。然而,挂载阶段还没开始,$el属性目前不可见
beforeMount:在挂载开始之前被调用:相关的render函数首次被调用
mounted:el被新建的vm.$el替换,并挂载到实例上去之后调用该钩子,平时接口的调用也是放在这边。
beforeUpdate:数据更新时调用,发生在虚拟DOM重新渲染和打补丁之前。你可以在这个钩子中进一步地更改状态,这不会触发附加的重渲染过程。
updated:由于数据更改导致的虚拟DOM重新渲染和打补丁,在这之后会调用该钩子。当这个钩子被调用时,组件DOM已经更新,所以你现在可以执行依赖于DOM的操作。然而在大多情况下,你应该避免在此期间更改状态,因为着可能会导致更新无限循环。该钩子在服务器渲染期间不被调用
beforeDestory:实例销毁之前调用,在这一步,实例仍然完全可用。
destroyed:Vue实例销毁后调用。调用后,Vue实例指示的所有东西都会解绑,所有的事件监听器会被移除,所有的子实例也会被销毁。该钩子在服务器端渲染期间不被调用
4. 数据中心(框架)
React-->dva
1.state:是储存数据的地方,且数据不可变,每次都是用新的state替换旧的state,通过connect包裹组件,获取数据
import { connect } from 'dva'
function mapStateToProps(state){
return { todos:state.todos}
}
connect(mapStateToProps)(App)
//mapStateToProps函数会返回一个对象,用于建立state到props的映射关系
2.action:是用来描述UI层事件的一个对象,即变化的数据
dispatch是一个函数方法,用来将Action发送给state
dispatch({
type:'abc', //type为action名称,namespace/action名称
payload:this.state.form //变化的数据
})
3.Effect:action处理器,处理异步任务,相当于Vuex中的action,处理完成后同样需要发送类似action到reducer中
function *qwe(action,{ put,call }){
yield call (delay,1000);
yield put ({type:'add'});
}
dva提供多个effect函数内部的处理函数,比较常用的是call和put
call:执行异步函数
put:发出一个action,类似于dispatch
4.reducer:action处理器,用来处理同步操作,相当于Vuex的Mutation
//往{todos:[],loading:true}里添加一个新todo,并标记loading为false
function addTodo(state,action){
return {
...state,
todos:state.todos.concat(action.payload),
loading:false
}
}
5.Model:dva应用的最简结构,根节点下可以包含多个Model,每个Model对应一个page或一个文件夹等,但根节点只有一个Model,即所有数据最后会汇聚到根节点下的Model,一个dva即Model,至少包含:
namespace:当前Model的名称。整个应用的state,由多个小的Model的state以namespace为key合成 state:该Model当前的状态。数据保存再这里,直接决定了视图层的输出 reducers:action处理器,处理同步动作,用来算出最新的state effects:action处理器,处理异步动作
{
namespace:'count',//用于action寻找
state:0,
reducers:{
add(state){ return state + 1}
},
effects:{
*abc(action,{ call,put }){
yield call(delay,1000)
yield put({type:'add'})
}
}
}
Vue-->Vuex
1.store:同样是数据中心,单个数据组件通过this.$store访问到所需数据,数据过多可以使用mapState辅助函数,返回的是一个对象,通过展开运算符与其他数据进行混合,如下:
mapState({
count: state => state.count,
//传字符串参数'count'等同于state=>state.count
countAlias:'count',
//为了能够使用this获取局部状态,必须使用常规函数,也可以进行数据的计算
countPlusLocalState(state){
return state.count + this.localCount
}
})
Getter方法,store中对数据进行计算处理的公共方法,getter的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算,例:
export default {
computed:{
//使用对象展开运算符将getter混入computed对象中
...mapGetters([
'doneTodosCount',
'anotherGetter'
])
}
}
在store中:store.getters.doneTodos进行获取
在组件中:this.$store.getters.doneTodosCount
2.Mutation:同步任务处理中心,也是更改store中的状态的唯一方法,通过stire.commit('xxxx方法')
在同一model内:
store.commit({
type:'abc',
amount:10//也可以写成payload
})
发送对应的Mutation方法
在组件内:
this.$store.commit('xxxx')
或通过映射来进行调用:
methods:{
...mapMutations([
'abc',//将this.abc映射为this.$store.commit('abc')
])
...mapMutations([
'abc',//将this.abc(参数)映射为this.$store.commit('abc',参数)
])
...mapMutations([
add:'abc',//将this.add映射为this.$store.commit('abc')
])
}
3.action:处理异步请求,然后再调用Mutation,commit更新store,例:
在组件内:
this.$store.dispath('xxxx')派发action
或通过映射来进行调用:
methods:{
...mapActions([
'abc',//将this.abc映射为this.$store.dispath('abc')
])
...mapMutations([
'abc',//将this.abc(参数)映射为this.$store.dispath('abc',参数)
])
...mapMutations([
add:'abc',//将this.add映射为this.$store.dispath('abc')
])
}
5.不完整mock数据层-service层-view层
React
mock数据层:通过模块的暴露(module.exports = {}),使mock数据的方法可以被调用,而实际的data在方法里return {}输出,最后主文件引入对应的文件,通过 const router = express.Router(); router.post('/api/login',(req,res)=>{ res.json(req.body) }) 以express充当服务器的角色,给对应的url以对应的方法(即数据),最后service通过url调用到数据 export function getTableListData(param){ return requset({ url:'/api/login', method:'get', params }) }
Vue
1.直接暴露一个数组,包含多个对象,如下: { url:'/aaa/bbb', type:'post', response:config =>{ return { code:'000', message:'success' } } } //中间经过index汇总mock数据,并加工形成标准形式,提供给mock-server对应的url提供给service层请求 2.service层通过request/url+type进行请求//一般request会进行二次封装,包括基础前缀路径,请求超时、请求拦截等 3.view层引入service的请求方法,然后调用: Testzxp({//这边写参数}).then(res=>{ this.message = res.data })