封装数据劫持 + 函数渲染

75 阅读1分钟

模拟一个其他人写的代码, 框架的源码 把需要渲染的代码, 都放到HTML 中, 然后由我这段代码帮助我们去渲染



    <div id="app">
        <h1>{{name}}</h1>
        <h1>{{age}}</h1>
        <h1>{{sex}}</h1>
        <h1>{{height}}</h1>
    </div>

       <script>
        // 模拟一个其他人写的代码, 框架的源码 把需要渲染的代码, 都放到HTML 中, 然后由我这段代码帮助我们去渲染
        function observer(options) {
            /**
             *   options 是 函数 observer de 形参 传递进来的实参是 调用函数 observer 是 给的实参 *     {foot:'#app',
             *     data:{
             *     name:'张三',   
             *     age:18,
             *     sex:'男'}
             *           
            */


            //1验证 root 有没有传递
            if (options.foot === undefined) {
                //手动配置报错
                throw new Error('您没有传递 root 属性,请从新传递')
            }
            //2验证root节点有没有获取到
            const rootHtml = document.querySelector(options.foot)
            //    console.log(footHtml)
            if (rootHtml === null) {
                //手动配置报错
                throw new Error('您传递的foot 的属性有问题请从新传递')
            }
            //3验证 data 没有有传递
            if (options.data === undefined) {
                //手动配置报错
                throw new Error('您没有传递 data 请从新传递')
            }
            //4验证传递的data是不是一个 对象
            if (options.data.constructor !== Object) {
                //手动配置报错
                throw new Error('您传递的data 不是一个对象 请重新配置')
            }
            //4.1 备份一份最处的 html  文本
            const rootHtmlStr = rootHtml.innerHTML
            //5将劫持的数据完整的劫持一份到 对象 _data 中
            const _data = {}
            //5.1循环遍历 对象 observer 里 的 对象 data  拿到每一个 k
            for (let k in options.data) {
                // 5.2 劫持的数据完整的劫持一份到 对象 _data 中  
                Object.defineProperty(_data, k, {
                    get() {
                        //函数执行 返回 这个对象里所有的 k
                        return options.data[k]

                    },
                    set(val) {
                        //做出修改时 将修改的值赋值给 这个对像 对应的 k
                        options.data[k] = val
                        rander(rootHtml, _data, rootHtmlStr )
                    }
                })
            }
            //5.3 首次执行 渲染页面 通过回调函数 来渲染
            rander(rootHtml, _data, rootHtmlStr )
            //5.4 返回一个 劫持后的数据
            return _data
        }

        //准备函数 用来回调
        function rander(rootHtml, _data, str) {
            //准备正则 要符合 当前节点中 的 打印出来的 字符形式 ---> console.log(rootHtmlStr)
            // console.log(rootHtml)
            // console.log(_data)
            // console.log(str)
            const reg = /{{ *(\w+) *}}/g
            //匹配节点中所有的花括号, 存放在一个数组中 返回值是一个包含所有 符合 正则的 要求 的字符串组成的数组
            const res = str.match(reg)
            console.log(res)

            //遍历数组,拿到每一个 花括号
            res.forEach((item) => {

            //拿到花括号里的 文本 因为这是 对象 中的 key
            const key = reg.exec(str)[1]
            console.log(key)

            // 将原本花括号内部的文本, 全部替换为 截取到数据的那个对象里 的实际的值
             str = str.replace(/{{ *(\w+) *}}/, _data[key])
             console.log(str)
             console.log(_data[key])
            })

            //最后将修改完成的字符串 渲染到页面
            rootHtml.innerHTML = str

        }
        const app = observer({
            foot: '#app',
            data: {
                name: '张三',
                age: 18,
                sex: '男',
                height:180 
            }
        })
        console.log(app)
       
    </script>