vue的底层原理已经是近期前端面试中常被问到一个问题了。这里就用原生js简单的实现一下大概的原理,方便各位刚刚学习vue的小伙伴理解一下(文章最后附上实现代码及注释)
在此之前我们先简单讲一下vue的原理机制
因为vue文件中很多语法都是浏览器不认识的,如v–model等,所以我们的目的就是写一个compile(编译器) 用于解析指令。
而在解析模板过程中所发现的数值以及相对应的更新函数传递给watcher
然而为什么需要dep用于管理watcher呢?
<span>{
{name}}<span/>
<span>{
{age}}<span/>
<span>{
{name}}<span/>
这里{
{name}}运用了两次 等于 往dep(name)中 添加两个 watcher
而开发中往往是不止两次的,所以需要一个dep管理着这些相同的watcher
data: {
name: "hello world",
age: 18,
}
而在初始化的时候observer就会对data里的对象进行劫持,当里面的值发生变化的时候就会通知相应dep(具体的响应式原理可以参考vue文档中的深入响应式原理,或者参考下方的代码进行理解)
特别注明:Object.defineProperty是用来做响应式更新的,和双向绑定没有任何关系。双向绑定只不过是vue的语法糖,他本质还是单向数据流
等dep接到通知后分发给相应的watcher
watcher接到通知后就会对视图进行更新操作。
完整代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Document</title>
</head>
<body>
<div id="app">
<!-- 插值绑定 -->
<p>{
{
name}}</p>
<!-- 指令解析 -->
<p w-text="name"></p>
<p>{
{
age}}</p>
<p>{
{
doubleAge}}</p>
<!-- 双向绑定 -->
<input type="text" w-model="name" />
<!-- 事件处理 -->
<button @click="changeName">button</button>
<!-- html内容解析 -->
<div w-html="html"></div>
<img id="img" :src="{
{src}}" alt="" />
</div>
</body>
<script>
class Compile {
constructor(el, vm) {
this.$el = document.querySelector(el);
this.$vm = vm;
// 编译
if (this.$el) {
// 转换内部内容为片段
this.$fragment = this.node2Fragment(this.$el);
// 执行编译
this.compile(this.$fragment);
// 将编译完的片段追加到$el内
this.$el.