vue学习:MVVM简介及vue实现流程

606 阅读2分钟

简单展示什么是mvvm

题目

  • 说一下使用jQuery和使用框架的区别
  • 说一下对MVVM的理解
  • vue中是如何实现响应式
  • vue中如何解析模板
  • vue的整个实现流程


使用jQuery和使用vue的区别

  • 数据和视图的分离
  • 以数据驱动视图

说一下对MVVM的理解

  • MVVM - Model View ViewModel

MVVM三要素

  • 响应式:vue如何监听到data的每个属性变化
  • 模板引擎:vue的模板如何被解析,指令如何处理
  • 渲染:vue的模板如何被渲染成html?以及渲染过程

要素1:vue如何实现响应式

  • 关键是理解Object.defineProperty
  • 将data的属性代理到vm上
// 模拟vue的将data属性代理到vue实例,并监听其数据变化,利用Object.defineProperty方法
	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(data[key])  //监听
					return data[key]
				},
				set: function (newVal) {
					console.log(newVal)  //监听
					data[key] = newVal
				}
			})
		})(key)
	} 

要素2:vue如何解析模板

  • 模板是什么
    • 本质:字符串
    • 有逻辑,如v-if v-for
    • 与html格式很像,但是有很大区别
    • 最终还是要转化为html显示
    • 模板是需要先转化为js代码(render函数)

要素3:渲染

  • render函数

vue的整个实现流程

  • 解析模板成render函数
  • 响应式开始监听
  • 首次渲染,显示页面,且绑定依赖
  • data属性变化,出发rerender(重新pacth)
<div id="app">
		<div>
			<input v-model="title">
			<button v-on:click="add">submit</button>
		</div>
		<ul>
			<li v-for="item in list">{{item}}</li>
		</ul>
	</div>
	<script src="vue.js"></script>
	<script>
		var vm = new Vue({
			el: '#app',
			data: {
				title: '',
				list: []
			},
			methods: {
				add: function () {
					this.list.push(this.title)
					this.title = ''
				}
			}
		})
	</script>
第一步:解析模板成render函数
<div id="app">
		<div>
			<input v-model="title">
			<button v-on:click="add">submit</button>
		</div>
		<ul>
			<li v-for="item in list">{{item}}</li>
		</ul>
	</div>
//render函数,返回vnode
with(this){return _c('div',{attrs:{"id":"app"}},[_c('div',[_c('input',{directives:[{name:"model",rawName:"v-model",value:(title),expression:"title"}],domProps:{"value":(title)},on:{"input":function($event){if($event.target.composing)return;title=$event.target.value}}}),_v(" "),_c('button',{on:{"click":add}},[_v("submit")])]),_v(" "),_c('ul',_l((list),function(item){return _c('li',[_v(_s(item))])}),0)])}
第二步,响应式开始监听
第三步:首次渲染,显示页面,绑定依赖
vm._updata(vnode) {
		const preVnode = vm.vnode //老的vnode
		vm._vnode = vnode //新vnode赋值
		if (!preVnode) {
			vm.$el = vm.__patch__(vm.$el, vnode)
		} else {
			vm.$el = vm.__patch__(preVnode, vnode)
		}

	}
	function updataeComponent() {
		vm._update(vm._render())
	}
  • 初次渲染,执行updateComponent ,执行vm._render()
  • 执行render函数,会访问到vm.list 和 vm.title
  • 会被响应式get方法监听到
  • 执行updateComponent , 会走到vdom的patch方法
  • patch 将 vnode 渲染成 DOM ,初次渲染完成
第四步:data属性变化,触发rerender
  • 修改属性,被响应式的set监听到
  • set中执行updateComponent
  • updateComponent重新执行vm._render()
  • 生成的vnode 和 preVnode, 通过patch进行对比
  • 渲染到html中