使用框架和jquery的区别?
1、数据和视图的分离,解耦(开放封闭原则)
2、以数据驱动视图,只关心数据变化,dom操作被封装
MVVM:model(模型数据) view(视图模板) ViewModel(DOM listeners,Date Bingings)一种创新
三要素:响应式、模板引擎、渲染
1.diff算法是linux的基础命令,是git基本工具
2.vdom使用diff算法是为了找出需要更新的节点
3.diff实现,patch(container,vnode)(初次创建),patch(vnode,newVnode)(后面进行diff算法更新)
4.核心逻辑:下面的createElement和updateChildren
1.vdom是什么?为何使用vdom?
是虚拟dom,用js模拟dom结构,dom操作非常昂贵,将dom操作放在js层,提高效率
2.vdom如何使用?核心函数是什么?
可以用snabbdom来举例,核心函数为h函数和patch函数,vue的_c函数是借助snabdom的h函数,基本没变,返回的是Vnode节点
核心三要素:
1。响应式 Object.defineProperty
1)get方法的必要性,可以监听data的哪些数据被用到,没有用到不会走get,set的时候也不用关心,避免不必要的渲染
模拟将data代理到vm上
2.模板 所有的信息都在 render函数-with() (开发中不要使用,vue内部使用)
1)本质:字符串,有逻辑,嵌入html变量
2)有逻辑,如v-if,必须要用js实现,(js才是图灵完备的语言)
3)render最终返回的是节点 调用vm.__patch__进行对比更新dom,执行updateComponent函数,参照snnabdom的patch函数
3.模板解析
render最终返回的是节点 调用vm.__patch__进行对比更新dom,执行updateComponent函数,参照snnabdom的patch函数
VUE整个实现流程
1.解析模板为render函数 2.响应式开始监听 3.首次渲染,显示页面,且绑定依赖 4.data属性变化,触发render
// 以下是手写的render函数
function render () {
with (this) { //this就是vm
return _c(
'div',
{
attrs: {'id': 'app'}
},
[
_c('p', [_v(_s(price))])
]
)
}
}
function render1 () { //不用width
return vm._c(
'div',
{
attrs: {'id': 'app'}
},
[
vm._c('p', [vm._v(vm._s(price))])
]
)
}
// vm._c创建元素 vm._v创建文本节点 vm._s就是转化为字符串
with (this) { //this就是vm
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 //set方法
}
}
}),
_v(' '),
_c('button',
{on: {'click': add}},
[_v('submit')])]),
_v(' '),
_c('div',
[_c('ul',
_l((list), //v-for
function (item) {
return _c('li', [_v(_s(item))])
}
)
)
]
)
]
)
}//v-for vm._l循环创建元素 最终返回的是节点 调用vm.__patch__进行对比更新dom,参照snnabdom的patch函数
// data 独立
var data = {
title: '',
list: []
}
// 初始化 Vue 实例
var vm = new Vue({
el: '#app',
data: data,
methods: {
add: function () {
this.list.push(this.title)
this.title = ''
}
}
})
<div id="app">
<div>
<input v-model="title">
<button v-on:click="add">submit</button>
</div>
<div>
<ul>
<li v-for="item in list">{{item}}</li>
</ul>
</div>
</div>
var vm = {}
var data = {
name: 'lisi',
age: 30
}
var key;
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)
}
<body>
<div id="app">
<input type="text" id="txt">
<p id="show-txt"></p>
</div>
<script>
var obj = {}
Object.defineProperty(obj, 'txt', {
get: function () {
return obj
},
set: function (newValue) {
document.getElementById('txt').value = newValue
document.getElementById('show-txt').innerHTML = newValue
}
})
document.addEventListener('keyup', function (e) {
obj.txt = e.target.value
})
</script>
</body>
createElement节点的创建
function createElement(vnode) {
var tag = vnode.tag // 'ul'
var attrs = vnode.attrs || {}
var children = vnode.children || []
if (!tag) {
return null
}
// 创建真实的 DOM 元素
var elem = document.createElement(tag)
// 属性
var attrName
for (attrName in attrs) {
if (attrs.hasOwnProperty(attrName)) {
// 给 elem 添加属性
elem.setAttribute(attrName, attrs[attrName])
}
}
// 子元素
children.forEach(function (childVnode) {
// 给 elem 添加子元素
elem.appendChild(createElement(childVnode)) // 递归
})
// 返回真实的 DOM 元素
return elem
}
updateChildren和replaceNode节点的更新和替换(暂不考虑,属性,节点的增加删除)
function updateChildren(vnode, newVnode) {
var children = vnode.children || []
var newChildren = newVnode.children || []
children.forEach(function (childVnode, index) {
var newChildVnode = newChildren[index]
if (childVnode.tag === newChildVnode.tag) {
// 深层次对比,递归
updateChildren(childVnode, newChildVnode)
} else {
// 替换
replaceNode(childVnode, newChildVnode)
}
})
}
function replaceNode(vnode, newVnode) {
var elem = vnode.elem // 真实的 DOM 节点
var newElem = createElement(newVnode)
// 替换
}
发表评论: