vue的最基本功能实现(挂载元素、双向数据绑定)

以下代码实现了可以将vue对象实例挂载到某个元素,并在挂载元素的后代元素上将vue实例data内的数据通过v-model属性绑定到表单元素上。也可以通过{{ key }}将data内的数据渲染到页面中

html:

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

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="./vueDemo.js"></script>
</head>

<body>
    <div id="app">
        <div>
            <input type="text" v-model="name" placeholder="姓名">
            <input type="text" v-model="age" placeholder="年龄">
            <input type="text" v-model="email" placeholder="邮箱">
        </div>
        <div>
            <p>姓名:<span>{{ name }}</span></p>
            <p>年龄:<span>{{ age }}</span></p>
            <p>邮箱:<span>{{ email }}</span></p>
        </div>
    </div>

    <script>
        let vm = new Vue({
            el: "#app",
            data: {
                name: "张三",
                age: 22,
                email: "123@qq.com"
            }
        })
        vm.mount()  // 调用挂载函数

    </script>
</body>

</html>

vueDemo.js

class Vue {
    constructor({ el = "#app", data = {} }) {
        this.$el = document.querySelector(el)  // 设置挂载元素
        this.data = data    // 存放数据
        this.changeDom = {} // 存放进行文本替换的dom元素
    }
    // 挂载时执行主要函数
    mount() {
        this.initDom()
        this.initData()
    }
    // 使用数据劫持将数据转化为响应式
    initData() {
        const _this = this
        for (let key in _this.data) {  // 遍历data中的数据
            Object.defineProperty(_this, key, {
                get() {
                    return _this.data[key]  // 返回data中对应字段的值
                },
                set(value) {    // 传入值时
                    // 修改data内对应字段的值
                    _this.data[key] = value
                    // 修改dom对应文本的值
                    _this.changeDom[key].innerText = value
                    // console.log("变值节点", _this.changeDom[key], "变值", value)
                }
            })
        }
    }
    // 执行dom相关函数
    initDom() {
        this.bindDomList(this.$el)  // 获取绑定v-model的元素,并存储
        this.bindDomData(this.$el)  // 替换文本节点值并存储
        console.log("被替换文本节点的元素", this.changeDom)
    }
    // 获取绑定有v-model属性的元素
    bindDomData(father) {
        const child = father.childNodes
        child.forEach(node => {
            if (node.nodeType == 3) {   // 寻找子节点中的文本节点

                // 判断节点值内是否存在双花括号{{}},进行数据替换
                let _nodeValue = node.nodeValue  // 获取当前节点值,去空
                let reg = /\{\{(.+?)\}\}/   // 正则匹配最短双花括号中间值

                // 判断文本是否为空,并且是否能匹配到
                if (_nodeValue.trim().length > 0 && reg.test(_nodeValue)) {
                    // 匹配到则获取匹配结果
                    let _key = _nodeValue.match(/\{\{(.+?)\}\}/)[1].trim();
                    // console.log("待绑定键名", _key, "对应值", this.data[_key])
                    // console.log("当前节点", node)
                    this.changeDom[_key] = node.parentNode  // 存入被替换文本节点的父节点
                    // 将文本节点中的双花括号部分替换为data中对应的值
                    node.nodeValue = _nodeValue.replace(reg, this.data[_key] || "")

                }
            }
            if (node.childNodes) {  // 如果当前节点存在子节点,则进行递归
                this.bindDomData(node)
            }
        });
    }
    // 获取绑定有v-model属性的元素,并进行数据双向绑定
    bindDomList(father) {
        const child = father.childNodes
        child.forEach(node => {
            // 如果当前节点为元素节点,并且拥有v-model属性
            if (node.nodeType == 1 && node.getAttribute("v-model")) {
                const _vModel = node.getAttribute("v-model")
                node.value = this.data[_vModel] || ''  // 将data中的值赋值给元素
                node.addEventListener("input", this.bindTwoWayData.bind(this, _vModel, node), false)
            }
            if (node.childNodes) {  // 如果当前节点存在子节点,则进行递归
                this.bindDomList(node)
            }
        })
    }
    // 进行数据双向绑定
    bindTwoWayData(_key, _ele) {
        let _value = _ele.value
        this.data[_key] = _value
        this[_key] = _value

        // const _value = input.value;
        //this.data[key] = _value;
        //    this[key] = _value;
    }

}

代码中若有误的地方,欢迎大佬们指正!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值