MVVM 和 VUE

vue

一,使用jquery和使用vue的区别

二,对MVVM的理解

三,vue中如何实现响应式

四,vue如何解析模版

五,vue整个实现流程

 

一,使用jquery和使用vue的区别

jquery实现todo-list

<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="UTF-8">

<title>todo-list-jquery</title>

</head>

<body>

<div>

<input type="text" id="txt-title">

<button id="btn-submit">submit</button>

</div>

<ul id="ul-list"></ul>

<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>

<script>

var $txtTitle = $('#txt-title');

var $btnSubmit = $('#btn-submit');

var $ulList = $('#ul-list');

$btnSubmit.click(function() {

var title = $txtTitle.val();

if (!title) {

return;

}

var $li = $('<li>' + title + '</li>');

$ulList.append($li);

$txtTitle.val('');

})

</script>

</body>

</html>

vue实现todo-list

<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="UTF-8">

<title>todo-list-vue</title>

<script src="./vue-2.5.13.js"></script>

</head>

<body>

<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>

var vm = new Vue({

el: "#app",

data: {

title: '',

list: [],

},

methods: {

add: function() {

if (this.title) {

this.list.push(this.title);

this.title = '';

}

}

}

})

</script>

</body>

</html> 

jquery和vue两者的区别:

数据和视图的分离-解耦(开放封闭原则)

以数据驱动视图-只关心数据变化,DOM操作被封装

 

二,对MVVM的理解

1,先说下MVC:

M-Model 数据

V-VIew 视图、界面

C-Controller 控制器、逻辑处理

两种场景:

2,MVVM

Model-模型、数据

View-视图、模版(视图和模型是分离的)

ViewModel-连接Model和View,“桥”

 

3,关于ViewModel

MVVM不算是一种创新-是微创新

但其中的ViewModel是一种创新

真正结合前端场景应用的创建

 

 

 

4,MVVM框架的三大要素(实现的三要素)

响应式:vue如何间听到data的每个属性变化?

模版引擎:vue的模版如何被解析,指令如何处理?

渲染:vue的模版如何被渲染成html?以及渲染过程

 

三,vue中如何实现响应式

1,什么是响应式

修改data属性之后,vue立刻监听到

data属性被代理到vm(this)上,data的属性,同时也变成了this的属性

例:

<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="UTF-8">

<title>vue-demo</title>

<script src="https://cdn.bootcss.com/vue/2.5.16/vue.min.js"></script>

</head>

<body>

<div id="app">

<p>{{name}}</p>

<p>{{age}}</p>

</div>

<script>

var vm = new Vue({

el:'#app',

data:{

name:'zs',

age:20

}

})

console.log(vm.age)

</script>

</body>

</html>

 在控制台修改vm.age  或者vm.name,立刻会被监听渲染出来

2,Object.defineProperty:直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象。

语法:

Object.defineProperty(obj, prop, descriptor)

例子:

    var obj = {};

var _name = 'zs';

Object.defineProperty(obj,'name',{

get:function(){

console.log('get',_name);//监听

return _name;

},

set:function(newVal){

console.log('set',newVal);//监听

_name = newVal;

}

});

3,模拟实现(监听+代理)

    var vm = {};

var data = {

name: 'zs',

age: 20

};

var key, value;

for (key in data) {

// 命中闭包,新建一个函数,保证key的独立的作用域

(function(key) {

Object.defineProperty(vm, key, { //data属性代理到vm上

get: function() {

console.log('get', data[key]); //监听

return data[key];

},

set: function(newVal) {

console.log('set', newVal); //监听

data[key] = newVal;

}

})

})(key)

}

看下控制台中,此时打印的vm

 

四,vue如何解析模版

1,模版是什么

本质:字符串

有逻辑,如v-if,v-for等

与html格式很像,但有很大区别(html静态的,没有逻辑)

要转换为html来显示

 

模版最终必须要转换成js代码,原因如下:

有逻辑(v-if,v-for),前端必须用js才能实现(图灵完备)

转换为html渲染页面,前端必须用js才能实现

因此,模版最终要转换成一个js函数(render函数,即渲染函数)

 

2,render函数

render函数-with的用法(with可以了解下实现,但是实际开发中最好不要用,问题比较多)

先看下with的简单用法:

    var obj = {

name: 'xx',

age:20,

getAddress:function(){

console.log('bj');

}

}

// 不用with

function fn(){

console.log(obj.name);

console.log(obj.age);

obj.getAddress();

}

fn()

// 使用with

function fn1(){

with(obj) {

console.log(name);

console.log(age);

getAddress();

}

}

fn1()

3,render函数

模版:

    <div id="app">

<p>{{price}}</p>

</div>

<script>

var vm = new Vue({

el:'#app',

data:{

price:100

}

})

</script>

render函数如下:

    // 以下是手写的 render 函数 使用 with ,代码简洁一些

function render() {

with(this) {

return _c(

'div', {

attrs: { "id", "app" }

}, [

_c('p', [_v(_s(price))])

]

)

}

}

// 不用 with 的改写的 render 函数

function render1() {

return vm._c(

'div', {

attrs: { "id", "app" }

}, [

vm._c('p', [_vm.v(vm._s(vm.price))])

]

)

}

// 模版中所有信息都包含在了 render 函数中

// this === vm

// price 即 this.price 即vm.price, 即 data 中的 price

// _c 即 this._c , 即 vm._c

看下控制台:

问题:

从哪里可以看到render函数?

复杂一点的例子,render函数是什么样子的?

v-if, v-for, v-on都是怎么处理的?

 

回顾之前的demo

<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函数:(通过在vue-2.5.13.js源码中 console.log(code.render)得出)

    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)

)

]

)

}

)

]

)

}

根据todo-list demo的render函数:

v-model是怎么实现的?:双向数据绑定,既有get,又有set

v-on:click是怎么实现的?:渲染时绑定click事件

v-for是怎么实现的?:对数组进行遍历,li标签,最后归结为数组,作为ul的子元素

 

模版生成html  

vm.c其实就相当于snabbdom中的h函数

render函数执行之后,返回的是vnode

vm._update(vnode) {

const prevVnode = vm._vnode;

vm._vnode = vnode;

if (!prevVnode) {

// 初次渲染

vm.$el = vm.__patch__(vm.$el, vnode);

} else {

// re-render

vm.$el = vm.__patch__(prevVnode, vnode);

}

}

function updateComponent() {

// vm._render即上面的render函数,返回vnode

vm._update(vm._render())

}

// updateComponent实现了vdom的patch

// 页面首次渲染执行updateComponent(执行第一个patch)

// data中每次修改属性,执行updateComponent,修改data,set中可以执行updateComponent

vue如何解析模版:

模版:字符串(本质),有逻辑,嵌入js变量...

模版必须转换为js代码(有逻辑,渲染html,js变量)前端中,只有js才能处理逻辑和渲染html等

render函数: with语法,就是snabbdom里h函数的样子

render函数执行是返回vnode

updateComponent 首次渲染,非首次渲染(data属性修改)

 

五,vue的整个实现流程

第一步:解析模版成render函数

with用法(了解即可,自己开发的时候,尽量避免使用)

模版中的所有信息都被render函数包含

模版中用到的data中的属性,都变成了js变量

模版中的v-model,v-for,v-on都变成了js逻辑

render函数返回vnode

 

第二步:响应式开始监听

Object.defineProperty中设置监听

将data的属性代理到vm上

 

第三步:首次渲染,显示页面,且绑定依赖

初次渲染,执行updateComponent,执行vm._render()

执行render函数,会访问到vm.list和vm.title

会被响应式的get方法监听到(后面详细讲)

执行updateComponent,会走到vdom的patch方法

patch将vnode渲染成DOM,初次渲染完成

疑问:

为何要监听get,直接监听set不行吗?

data中有很多属性,有些被用到,有些可能不被用到

被用到的会走到get,不被用到的不会走到get

未走到get中的属性,set的时候我们也无须关心

避免不必要的重复渲染

 

第四步:data属性变化,触发rerender

修改属性,被响应式的set监听到

set中执行updateComponent (这里是异步的)

updateComponent重新执行vm._render()

生成的vnode和prevVnode,通过patch进行对比

渲染到html中

附:Vue的生命周期 

vue调试工具vue-devtools安装及使用

以上是 MVVM 和 VUE 的全部内容, 来源链接: utcz.com/z/375879.html

回到顶部