jQuery跟mvvm的区别:
通过一个todolist来对比下。
很明显,jQuery是直接操控dom的,而且视图跟model操作是没有分开的,而且操控的是实际的dom,并非是数据驱动。
而Vue是数据跟视图分离开的,然后由数据驱动视图的更新。
1.数据跟视图的分离,解耦
2.数据驱动视图,只关心数据变化,DOM操作被封装
MVC:view model controller
MVVM:view model viewModel
那么使用mvvm框架中,vue改变model中data的值,会反映到视图的改变,那么vue的响应式是如何实现的呢?
核心api:Object.defineProperty;将data的属性代理到vm上。
下面是模拟实现:
var vm = {} var data = { name: 'zhangsan', age: 20 } var key, value for (key in data) { (function (key) { Object.defineProperty(vm, key, { get: function () { console.log('get', data[key]) // 监听 return data[key] }, set: function (newVal) { console.log('set', newVal) // 监听 data[key] = newVal } }) })(key) }
我们在vue中书写的vue文件模板是没法直接运行的,那么怎么解析模版到最后渲染成正常的html代码呢?
首先我们应该知道模板的本质是什么,模板是一整串有逻辑的字符串。
模板最后必须转换成js代码,因为里面有逻辑(v-if v-for)
,必须使用js才能实现(图灵完备),需要转换成html渲染页面,必须用js才能实现。
因此模板最重要的要能转换成一个js函数返回vnode(render函数)
下面render函数简单模拟实现:
var vm = new Vue({ el: '#app', data: { price: 100 } }) // 以下是模拟的 render 函数 function render() { with(this) { // this 就是 vm return _c( 'div', { attrs: {'id': 'app'} }, [ _c('p', [_v(_s(price))]) ] ) } } function render1() { return vm._c( 'div', { attrs: {'id': 'app'} }, [ vm._c('p', [vm._v(vm._s(vm.price))]) ] ) }
vm._c是创建元素节点,vm._v是创建文本节点,vm._s是toString,vm.price 是把data属性代理到vm,然后返回data.price
那么在vue的生命周期里,render函数是怎么起作用的呢?
下面总结一下vue的整个实现流程
第一步:解析模板成render函数
1.with的用法
2.模板中的信息都被render函数包含
3.模板中用到的data中的属性,都变成了js变量
4.模板中的v-model v-for v-on都变成了js逻辑
5.render函数返回vnode
第二步:响应式开始监听
1.Object.defineProperty
2.将data的属性代理到vm上
var vm = {} var data = { name: 'zhangsan', age: 20 } var key, value for (key in data) { (function (key) { Object.defineProperty(vm, key, { get: function () { console.log('get', data[key]) // 监听 return data[key] }, set: function (newVal) { console.log('set', newVal) // 监听 data[key] = newVal } }) })(key) }
第三部:首次渲染,显示页面,且绑定依赖
1.初次渲染,执行updateComponent,执行vm._render(),也就是第一步返回的render函数
2.执行render函数,会访问到vm.list 和vm.title
3.会被响应式的get方法监听到
4.执行updateComponent,会走到vdom的patch方法,
5.patch将vnode渲染成dom,初次渲染完成
第四部:data属性变化,触发rerender
有了之前第二步的监听属性的set跟get之后
Object.defineProperty(vm, key, { get: function () { console.log('get', data[key]) // 监听 return data[key] }, set: function (newVal) { console.log('set', newVal) // 监听 data[key] = newVal } })
接下来就是第四步的内容了。
1.修改属性被响应式的set监听到
2.set中执行updateComponent,这一步是异步的,所以vue的属性的修改也是异步的
3.updateComponent重新执行vm._render()
4.生成的vnode跟prevVnode,通过patch进行对比
React
组件化的理解:
1.组件的封装:封装组件的视图,数据,变化逻辑
2.组件的复用:props传递,复用
JSX是什么?
JSX其实是语法糖
开发环境将JSX编译成JS代码
JSX的写法大大降低了学习成本跟编码的工作量
JSX和vdom的关系:
1.jsx为什么需要vdom:jsx需要渲染成html,数据驱动视图
React.createElement和h,都生成vnode,createElement需要考虑自定义组件的名称,然后将其解析为自定义组件的render函数。
何时patch:ReactDom.render() 这个方法是在初次渲染的时候,执行了patch($el,Vnode)
setState在数据更新rerender的时候,执行了patch(preVnode,newVnode)
自定义组件的解析:初始化实例,然后执行render
例如List组件, 会经过类似这样的过程: var list =new List({data:this.state.listData}) var vnode=list.render()
React setState的过程
setState是异步的,vue修改属性也是异步的
setState的过程步骤:
1.每个组件的示例,都有renderComponent方法,
2.执行renderComponent会重新执行实例的render
3.render函数返回newVnode,然后拿到preVnode,
4.执行patch(preVnode,newVnode)
模拟代码 renderComponent(){ const prevVnode=this._vnode; const newVnode=this.render(); patch(prevVnode,newVnode); this._vnode=newVnode; }
为什么要异步,提高效率,如果用户多次setState,只要最终效果,渲染一遍。
React 与 Vue 的本质区别
1.vue 本质是MVVM框架,由MVC发展而来。React 本质是前端组件化框架,由后端组件化发展而来
2.vue使用模板,React使用JSX
3.React本身就是组件化,没有组件化就不是React。vue也支持组件化,不过是在MVVM上的扩展
React 与 Vue 共同点
支持组件化,数据驱动视图