vue 源码实现(v-if-show)

案例

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>
    <style>
        .cover {
            display: flex;
        }

        .box {
            height: 100px;
            width: 100px;
            border: 1px solid #333;
            margin-right: 30px;
            line-height: 100px;
            text-align: center;
            color: #fff;
        }

        .box1 {
            background-color: aqua;
        }

        .box2 {
            background-color: #789;
        }

        .box3 {
            background-color: rgb(53, 26, 102);
        }

        .box4 {
            background-color: rgb(139, 37, 59);
        }

        .btn_cover {
            margin-top: 30px;
            display: flex;
        }

        button {
            margin-right: 20px;
        }
    </style>
</head>

<body>
    <div id="app">
        <div class="cover">
            <div class="box box1" v-if="isshow1">
                box1
            </div>
            <div class="box box2" v-if="isshow2">
                box2
            </div>
            <div class="box box3" v-show="isshow3">
                box3
            </div>
            <div class="box box4" v-show="isshow4"> 
                box4
            </div>
        </div>

        <div class="btn_cover">
            <button @click="changeShow1">btn1</button>
            <button @click="changeShow2">btn2</button> 
            <button @click="changeShow3">btn3</button> 
            <button @click="changeShow4">btn4</button>
        </div>
    </div>
</body>
<script src="./index.js"></script>
<script>
    new myProxy({
        el: "#app",
        data: {
            isshow1: false,
            isshow2: false,
            isshow3: false,
            isshow4: false
        },
        methods: {
            changeShow1() {
                this.data.isshow1 = !this.data.isshow1
            },
            changeShow2() {
                this.data.isshow2 = !this.data.isshow2
            },
            changeShow3() {
                this.data.isshow3 = !this.data.isshow3
            },
            changeShow4() {
                this.data.isshow4 = !this.data.isshow4
            },
        }
    })
</script>

</html>

js


class myProxy {
    constructor(options) {
        let { el, data, methods } = options

        this.el = document.querySelector(el)
        this.data = data
        this.methods = methods

        this.eventPool = new Map()
        this.dataPool = new Map()

        this.init()
    }

    init() {
        this.initData()     //data中的数据添加响应式
        this.initDom(this.el)       // 收集数据,methods pool
        this.initView(this.dataPool)       // 将收集到的数据 初始化到具体的节点,控制节点的初始化显示和隐藏
        this.initEvent(this.eventPool)      // 给收集到的eventPool 绑定事件到具体的节点
    }

    initData() {    
        let that = this
        this.data = new Proxy(this.data, {
            get(target, key) {      // 还有一个没有完成的功能,this=>this.data
                // console.log("get--", target[key]);
                return Reflect.get(target, key)
            },
            set(target, key, value) {
                // console.log("set--", value);
                that.changeView(key, that.dataPool)
                return Reflect.set(target, key, value)
            }
        })
    }

    initDom(el) {
        let childNodes = el.childNodes

        if (childNodes.length === 0) {      // 文本节点
            return
        }

        childNodes.forEach(item => {
            if (item.nodeType === 1) {     // 元素节点
                const vIf = item.getAttribute("v-if")
                const vShow = item.getAttribute("v-show")
                const vEvent = item.getAttribute("@click")
                if (vIf) {
                     // 收集数据
                    this.dataPool.set(item, {
                        type: "if",
                        show: this.data[vIf],
                        data: vIf
                    })
                }

                if (vShow) {
                    this.dataPool.set(item, {
                        type: "show",
                        show: this.data[vShow],
                        data: vShow
                    })
                }

                if (vEvent) {
                    this.eventPool.set(item, this.methods[vEvent])
                }
            }
            this.initDom(item)
        })
    }

    initView(dataPool) {
        // 切换视图
        this.changeView(null, dataPool)
    }

    changeView(data = null, dataPool) {
        if (!data) {   // 初始化
            for (let [k, v] of dataPool) {
                switch (v.type) {
                    case "if":
                        v.comment = document.createComment('V-IF')  // 创建一个文本节点来替换
                        !v.show && k.parentNode.replaceChild(v.comment, k)
                        break;
                    case "show":
                        !v.show && (k.style.display = "none")
                        break;
                    default:
                        break;
                }
            }
            return
        }

        // 数据修改时执行
        for (let [k, v] of dataPool) {
            if (v.data === data) {
                switch (v.type) {
                    case "if":
                        v.show ? k.parentNode.replaceChild(v.comment, k)
                            : v.comment.parentNode.replaceChild(k, v.comment)
                        v.show = !v.show

                        break;
                    case "show":
                        v.show ? (k.style.display = "none") :
                            (k.style.display = "block")
                        v.show = !v.show
                        break;
                    default:
                        break;
                }
            }

        }
    }

    initEvent(eventPool) {
        for (let [k, v] of eventPool) {
            k.addEventListener("click", v.bind(this), false)
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值