vue是一套用于构建用户界面的渐进式框架,vue的核心库只关注视图层
● 早在jquery的时期,编写代码都是命令式的,命令式框架的特点就是关注过程
● 声明式框架更加注重结果,命令式的代码封装到了vue.js中,过程靠vue.js来实现
声明式代码更加简单,不需要关注实现,按照一定格式填写代码就好了
//命令式编程
let number=[1,2,3,4,5]
let total= 0
for(let 1=0;i<number.length;i++){
total+=numbers[i] //关注了过程
}
console.log(total)
//声明式编程
let total2 = number.reduce((prev,cur)=>prev+=cur,0)
MVC模式(Model-view-controller)是软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型(Model)、视图(View)和控制器(Controller)
1、由客户端发起请求
2、服务端接收请求,并解析请求
3、根据解析出来的请求,找到对应的控制器,并执行控制器
4、控制器调用模型获取数据,并将数据传给视图
5、视图将数据渲染出来
对于前端而言就是如何将数据同步到页面上,也是借鉴后端思想
在mvc模式中数据变化无法同步到视图中,需要将逻辑聚拢在controller层,
当需要绑定的事件越来越多,controller也就越来越多,
● mvc模式:backbone+underscore+jquery
虽然vue并没有完全遵循mvvm模型,但是vue的实际也是受到了它的启发,因此文档中经常会使用vm(viewModel)这个变量名来表示vue实力
● MVVM模式:映射关系的简化(隐藏controller)
传统页面更新,拼接一个完整的字符串innerHTML全部重新渲染,添加虚拟DOM后可以比较新旧虚拟节点,找到变化再进行更新,虚拟DOM就是一个对象,用来描述真实DOM的,(对dom的重绘重渲染不仅浪费计算机的性能,也让程序员要花更多的精力在dom操作上)
虚拟dom实际上只是一层对真实DOM的抽象,以JavaScript 对象 (VNode 节点) 作为基础的树,用对象的属性来描述节点,最终可以通过一系列操作使这棵树映射到真实环境上
在Javascript对象中,虚拟DOM 表现为一个 Object对象(这就是uniapp跨平台的奥秘)。并且最少包含标签名 (tag)、属性 (attrs) 和子元素对象 (children) 三个属性,不同框架对这三个属性的名命可能会有差别
创建虚拟DOM就是为了更好将虚拟的节点渲染到页面视图中,所以虚拟DOM对象的节点与真实DOM的属性一一照应
在vue中同样使用到了虚拟DOM技术
定义真实DOM
<div id="app">
<p class="p">节点内容</p>
<h3>{{ foo }}</h3>
</div>
实例化vue
const app = new Vue({
el:"#app",
data:{
foo:"foo"
}
})
观察render的render,我们能得到虚拟DOM
(function anonymous(
) {
with(this){return _c('div',{attrs:{"id":"app"}},[_c('p',{staticClass:"p"},
[_v("节点内容")]),_v(" "),_c('h3',[_v(_s(foo))])])}})
通过VNode,vue可以对这颗抽象树进行创建节点,删除节点以及修改节点的操作, 经过diff算法得出一些需要修改的最小单位,再更新视图,减少dom操作,从而提高性能
运行时
比如:提供一个 render 函数,接收两个参数,一个是具有一定规范的树型结构的数据对象,一个是要挂载的节点。
开发者把树型结构的数据对象传入 render 函数,然后 render 函数根据改对象递归地将数据渲染成 DOM 元素。
这个树型结构须按照一定的规范,形状如下:
const node = {
tag: 'div', // tag代表标签名称
children: [ // children可以是一个数组,代表子节点
{
tag: 'h1',
children: 'hello' // children也可以是一段文本,代表文本子节点
}
]
}
render 函数的实现如下:
function render (node, root) {
const el = document.createElement(node.tag)
if (typeof node.children === 'string') {
const text = document.createTextNode(node.children)
el.appendChild(text)
}
if (Array.isArray(node.children)) {
node.children.forEach(child => render(child, el)) // 递归地处理节点的渲染
}
root.appendChild(el)
}
这种使用纯 JS 的方式生成页面内容就是运行时框架,很显然,在开发者层面,通过这种方式书写代码一定会非常痛苦。
所以在 Vue 里面,我们写的不是类似上文的代码,而是写 template 模板。
编译时
比如,下面这段代码,浏览器里不能直接跑,需要先编译成 JS ,才能在浏览器里运行。
<template>
<div>
<h1>hello</h1>
</div>
</template>
假设上面的 html 代码,直接编译成命令式的代码,就是编译时代码,如下所示:
const div = document.createElement('div')
const h1 = document.createElement('h1')
h1.innerText = 'hello'
div.appendChild(h1)
document.body.appendChild(div)
开发者只提供 html 模板代码,在框架内部分析开发者提供的代码,编译成命令式的代码,再渲染到页面上。
但是很显然,Vue 不是这么做的,我们在这个 在线网址 里去测试一下:
<template>
<div>
<h1>hello</h1>
</div>
</template>
这段 html 代码在 Vue 内部被编译成下面这段代码。
import { createElementVNode as _createElementVNode, openBlock as _openBlock, createElementBlock as _createElementBlock } from "vue"
export function render(_ctx, _cache, $props, $setup, $data, $options) {
return (_openBlock(), _createElementBlock("template", null, [
_createElementVNode("div", null, [
_createElementVNode("h1", null, "hello")
])
]))
}
这段编译出来的代码,引入了一些乱七八糟的函数,传了一些乱七八糟的参数,很显然,这样的代码不是单纯的操作 DOM 的原生 JS,还包含了创建 VNode 、diff等操作。
由此,我们可以得出结论,Vue 是一个运行时 + 编译时的框架,在编译时把浏览器看不懂的代码转化为 JS 代码,在运行时创建虚拟 DOM,做 diff 对比,更新真实 DOM 等等操作。
举一些实例,比如 jQuery,就是一个运行时框架;Vue 或者 React,就比较折中,是运行时 + 编译时框架;而 Svelte ,就是一个编译时框架。
● 降低耦合度;降低耦合度,单向数据流
● 组件化开发能大幅度提高应用开发效率,测试性,复用性等
● 降低更新范围,只重新渲染变化的组件