撸个toyVue

撸个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])
                }
                
                ...
            }
        }
		
        ...
    }
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值