撸个toyVue
响应式reactive和副作用函数effects
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>toy-vue</title>
</head>
<body>
<div id="app">
<p>{{message}}</p>
</div>
<script type="module">
import { toyVue } from './toyVue.js'
var app = new toyVue({
el: '#app',
data: {
message: 'Hello Vue!'
}
})
</script>
</body>
</html>
export class toyVue {
constructor(config) {
// 初始化根节点
this.template = document.querySelector(config.el)
// 绑定属性到vue示例 并且加上响应式
this.data = reactive(config.data)
this.traversal(this.template)
}
// 遍历属性通过匹配 vue固定的属性标签和符号 设置的变量 动态更新dom
traversal(node) {
// 如果是当前node节点为文本节点
if(node.nodeType === Node.TEXT_NODE) {
if (node.textContent.trim().match(/^{{([\s\S]+)}}$/)) {
let name = RegExp.$1.trim()
// 在执行 属性get操作时候将方法绑定到属性上面
effect(() => node.textContent = this.data[name])
}
}
// 循环所有的node节点
if (node.childNodes && node.childNodes.length) {
for (const child of node.childNodes) {
this.traversal(child)
}
}
}
}
// 将属性上面绑定的方法全部储存到对象里面
let effects = {}
// 执行effects中对应属性的所有方法
let curentEffect = null
function effect(fn) {
curentEffect = fn
fn()
curentEffect = null
}
// 给属性绑定响应式
function reactive(object) {
let reactived = new Proxy(object, {
// 给属性加上拦截器 当执行 获取属性操作时候给属性绑定方法
get(obj, prop) {
if (curentEffect) {
if(!effects[prop]) {
effects[prop] = []
}
effects[prop].push(curentEffect)
}
return obj[prop];
},
set(obj, prop, value) {
obj[prop] = value;
if (obj[prop]) {
for (let effectItem of effects[prop]) {
effectItem()
}
}
return true
}
});
return reactived
}
v-model的实现
主要通过在traversal方法中增加方法来实现,监听输入事件改变属性
traversal(node) {
...
if(node.nodeType === Node.ELEMENT_NODE) {
let attrs = node.attributes
for(let attr of attrs) {
// 设置v-model 监听输入事件改变属性
if (attr.name === 'v-model') {
let name = attr.value
effect(() => node.value = this.data[name])
node.addEventListener('input', event => { this.data[name] = node.value})
}
...
}
}
...
}
v-bind的实现
动态设置属性
traversal(node) {
...
if(node.nodeType === Node.ELEMENT_NODE) {
let attrs = node.attributes
for(let attr of attrs) {
// 设置v-bind 动态设置属性
if (attr.name.match(/^v\-bind:([\s\S]+)$/)) {
let name = attr.value
let attrName = RegExp.$1
effect(() => node.setAttribute(attrName, this.data[name]))
}
...
}
}
...
}
v-on的实现
监听事件
traversal(node) {
...
if(node.nodeType === Node.ELEMENT_NODE) {
let attrs = node.attributes
for(let attr of attrs) {
// 设置v-on 监听事件
if (attr.name.match(/^v\-on:([\s\S]+)$/)) {
let fnname = attr.value
let eventName = RegExp.$1
node.addEventListener(eventName, this[fnname])
}
...
}
}
...
}

191

被折叠的 条评论
为什么被折叠?



