关闭

VUE双向绑定实现

标签: vue
101人阅读 评论(0) 收藏 举报
分类:
<!DOCTYPE html>
<html lang="en">

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

<body>
    <div id="app">
        <input type="text" v-model="text" /> {{ text }}
    </div>
    <script>
        function Vue(obj) {
            this.id = obj.el,
                this.data = obj.data
            listenData(this.data, this)
            var flag = nodeToFragment(document.getElementById(this.id), this)
            document.getElementById(this.id).appendChild(flag)
        }
        function listenData(data, vue) {
            Object.keys(data).forEach(function (key) {
                var dep = new Dep()
                Object.defineProperty(vue, key, {
                    set(value) {
                        if (!(vue.data[key] == value)) {
                            vue.data[key] = value
                            console.log(vue.data[key])
                            dep.notify()
                        }
                    },
                    get() {
                        if (Dep.newSubScribers) dep.addSubScribers(Dep.newSubScribers)
                        return vue.data[key]
                    }
                })
            })
        }
        function Dep() {
            this.subScribers = []
        }
        Dep.prototype = {
            addSubScribers(sub) {
                this.subScribers.push(sub)
            },
            notify() {
                this.subScribers.forEach(function (sub) {
                    sub.updata()
                })
            }
        }
        function nodeToFragment(node, vue) {
            var flag = document.createDocumentFragment()
            while (node.firstChild) {
                compile(node.firstChild, vue)
                flag.appendChild(node.firstChild)
            }
            return flag
        }
        function compile(node, vue) {
            var reg = /\{\{(.*)\}\}/
            if (node.nodeType === 1) {
                var attr = node.attributes
                for (var i = 0; i < attr.length; i++) {
                    if (attr[i].nodeName == "v-model") {
                        var name = attr[i].nodeValue
                        node.addEventListener('input', function (e) {
                            vue[name] = e.target.value
                        })
                        node.removeAttribute('v-model')
                        new Watcher(node, name, vue)
                    }
                }
            }
            if (node.nodeType === 3) {
                if (reg.test(node.nodeValue)) {
                    var name = RegExp.$1
                    name = name.trim()
                    node.nodeValue = vue[name]
                    new Watcher(node, name, vue)
                }
            }
        }
        function Watcher(node, name, vue) {
            Dep.newSubScribers = this
            this.node = node
            this.name = name
            this.vue = vue
            this.value = vue[name]
            Dep.newSubScribers = null
        }
        Watcher.prototype = {
            updata() {
                if (this.node.nodeType === 1) {
                    this.node.value = this.vue[this.name]
                }
                if (this.node.nodeType === 3) {
                    this.node.nodeValue = this.vue[this.name]
                }
            }
        }
        var vue = new Vue({
            el: 'app',
            data: {
                text: 'hello world'
            }
        })
    </script>
</body>

</html>
<!-- http://transcoder.baiducontent.com/from=1012852y/bd_page_type=1/ssid=0/uid=0/pu=usm%401%2Csz%40320_1004%2Cta%40iphone_2_6.0_11_9.1/baiduid=7FFB1B3B6229E8E723991DE796900A1B/w=0_10_/t=iphone/l=3/tc?ref=www_iphone&lid=13311096275631538808&order=1&fm=alop&h5ad=1&srd=1&dict=32&tj=www_normal_1_0_10_title&vit=osres&m=8&cltj=cloud_title&asres=1&nt=wnor&title=Vue.js%E5%8F%8C%E5%90%91%E7%BB%91%E5%AE%9A%E7%9A%84%E5%AE%9E%E7%8E%B0%E5%8E%9F%E7%90%86-kidney-%E5%8D%9A%E5%AE%A2%E5%9B%AD&w_qd=IlPT2AEptyoA_yijCULhngvYOjMmtXdTo6lb&sec=23604&di=004609dd99d90bdd&bdenc=1&tch=124.0.67.295.0.0&nsrc=IlPT2AEptyoA_yixCFOxXnANedT62v3IEQGG_ytK1DK6mlrte4viZQRAWTbrLnq4ZpPPtCPQpxcFxXKi0GEskNYWgLdnpS-bll_aurmqs1CLHaB_s255J2DUVzMr64rFiO2ewAoy0Adf&eqid=b8ba8389980b00001000000659a6a966&wd=&clk_info=%7B%22srcid%22%3A%221599%22%2C%22tplname%22%3A%22www_normal%22%2C%22t%22%3A1504094568858%2C%22sig%22%3A%222004%22%2C%22xpath%22%3A%22div-div-div-a-div-img%22%7D 
//Object.keys() 方法会返回一个由给定对象的所有可枚举自身属性的属性名组成的数组,
//数组中属性名的排列顺序和使用for-in循环遍历该对象时返回的顺序一致
//(两者的主要区别是 for-in 还会遍历出一个对象从其原型链上继承到的可枚举属性)。
var flag = document.createDocumentFragment()
// DocumentFragment(文档片段)可以看作节点容器,它可以包含多个子节点
// 当我们将它插入到 DOM 中时,只有它的子节点会插入目标节点,所以把它看作一组节点的容器。
flag.appendChild(child) //child在dom树消失 变为DocumentFragment内部节点
document.getElementById(id).appendChild(flag) //把DocumentFragment加进dom树,此时DocumentFragment容器为空,即内部节点移动到dom树,此为DocumentFragment特性
-->

思路是别人的,代码是自己打的,大家可以去看原文,原文有详细解释

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:2179次
    • 积分:66
    • 等级:
    • 排名:千里之外
    • 原创:1篇
    • 转载:0篇
    • 译文:0篇
    • 评论:1条
    文章分类
    文章存档
    最新评论