您的位置:首页 > Web前端 > Vue.js

Vue源码分析(流程分析)

2020-08-25 14:22 946 查看

流程分析

使用步骤
1.编写 页面 模板
1.直接在HTML标签中写
2.使用template
3.使用单文件(<template>)
2.创建Vue实例
1.在Vue 的构造函数中:data,methods,computer,watcher,props,...
3.将Vue挂载到页面中(mount)

数据驱动模型
Vue执行流程
1.获得模板:模板中有‘坑’
2.利用Vue构造函数提供的数据来‘填坑’,就可以得到页面显示的'标签'了
3.替换原来有坑的标签
Vue 利用 我们提供的数据 和 页面的 模板 生成了一个新的HTML标签(node元素),替换到了 页面中 放置模板的位置

流程=》最简单的逻辑源码

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id='app'>
<h1>{{name}}</h1>
</div>
</body>
<script>
//步骤拆解
//1.拿到模板
//2.拿到数据(data)
//3.将数据与模板结合  得到HTML(DOM元素)
//4.放到页面中

//1
let template = document.querySelector('#app')
//2
let data = {
name:'xa'
}
//3
//将数据放到模板中
//递归
//在这个案例中 template 是DOM
//在Vue源码中是DOM=>字符串模板=>VNode=>真正的DOM
function complier(template,data){
let childNodes = template.childNodes
for (let i = 0; i < childNodes.length; i++) {
let type = childNodes[i].nodeType //1元素  3 文本
if( type ===3 ){
//{{}}
let rex = /\{\{(.+?)\}\}/g
let txt = childNodes[i].nodeValue //文本内容

//有没有花括号
//replace 使用正则匹配一次  函数被调用一次
//函数的第0个参数  表示匹配到的内容
//函数的n个参数表示正则的第n组
txt = txt.replace(rex, function (_, g) {
g.trim()//双花括号里面的东西
let value = data[g]
//将值替换{{}}
return value
})

//修改DOM元素
childNodes[i].nodeValue = txt
}
else if(type ===1){
//递归处理元素
complier(childNodes[i],data)
}

}
}

let genNode = template.cloneNode(true) //克隆dom

//如果不克隆 没有生成新的template 这里直接在页面生成数据, DOM是引用类型
//这样做模板就没了
console.log(template)
complier(genNode, data)
console.log(genNode)

//4
app.parentNode.replaceChild(genNode, app)

//上面的思路有问题
//1.VUE使用的 虚拟DOM
//2.只考虑了单属性{{name}}  vue 大量使用层级 ({{child.name.firstname }})
//3.代码没有整合
</script>
</html>

构造函数形式

<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>

<body>
<div id='app'>
<h1>{{name.firstName}}</h1>
</div>
</body>
<script>
function complier(template, data) {
let childNodes = template.childNodes
for (let i = 0; i < childNodes.length; i++) {
let type = childNodes[i].nodeType //1元素  3 文本
if (type === 3) {
//{{}}
let rex = /\{\{(.+?)\}\}/g
let txt = childNodes[i].nodeValue //文本内容
txt = txt.replace(rex, function (_, g) {
let path = g.trim()//双花括号里面的东西
let value = getValueByPath(data, path)
//将值替换{{}}
return value
})

//修改DOM元素
childNodes[i].nodeValue = txt
}
else if (type === 1) {
//递归处理元素
complier(childNodes[i], data)
}

}
}

function MVue(options) {
//习惯 内部数据使用下划线开头  只读$开头
this._data = options.data;
this._el = options.el

//准备工作(准备模板)
this._templateDOM = document.querySelector(this._el)
this._parent = this._templateDOM.parentNode

//渲染工作
this.render()

}

//将模板结合数据, 得到HTML  加到页面
MVue.prototype.render = function () {
this.complier()
}

//编译  将模板与数据结合  得到真正Dom
MVue.prototype.complier = function () {
let realHTMLDom = this._templateDOM.cloneNode(true)//拷贝DOm
complier(realHTMLDom, this._data)
this.update(realHTMLDom)
}

//更新  放到页面
MVue.prototype.update = function (real) {
this._parent.replaceChild(real, document.querySelector('#app'))
}

let app = new MVue({
el: '#app',
data: {
name: {
firstName: 'xa'
}
}
})

//使用‘xxx.yyy’ 来访问对象
//就是用该字符中的路径来访问对象成员
function getValueByPath(obj, path) {
let paths = path.split('.')
//先取得 xxx 再取得结果中的yyy
let res = obj
let prop
while (prop = paths.shift()) {
res = res[prop]
}

return res

}

//vue源码实现方式的设计模式
//函数柯里化处理
//Vue 编译模板时生成
//模板=》抽象语法树=》虚拟dom
// function createGetValueByPath(path) {
//     let paths = path.split('.')

//     return function getValueByPath(obj) {
//         let res = obj
//         let prop
//         while (prop = paths.shift()) {
//             res = res[pop]
//         }

//         return res
//     }
// }

//通过这种处理,因为模板是不变的  所以我们每次使用 只需要传入对象
//减少函数的调用 提升性能
// let getValueByPath = createGetValueByPath('name.first')
// let res = getValueByPath(obj)

</script>

</html>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: