微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

vue原理四效果图

                          完整效果图 HTML:  
<div id="container">
    {{ msg }}<br>
    <input class="inp-text" type="text" v-model="inpText">
    <p>{{ inpText }}</p>
    <div class="text-Box">
        <p class="show-text">{{ msg }}</p>
    </div>
</div>

javascript:

function Publisher(){
        this.subs = [];
    }
    Publisher.prototype = {
        constructor: Publisher,
        add: function(sub){
            this.subs.push(sub);
        },
        notify: function(){
            this.subs.forEach(function(sub){
                sub.update();
            });
        }
    };
 
    function Subscriber(node, vm, name){
        Publisher.global = this;
        this.node = node;
        this.vm = vm;
        this.name = name;
        this.update();
        Publisher.global = null; // 清空
    }
    Subscriber.prototype = {
        constructor: Subscriber,
        update: function(){
            let vm = this.vm;
            let node = this.node;
            let name = this.name;
            switch(this.node.nodeType){
                case 1:
                    node.value = vm[name];
                    break;
                case 3:
                    node.nodeValue = vm[name];
                    break;
                default:
                    break;
            }
        }
    };
 
    function virtualDom(node, data){
        let frag = document.createDocumentFragment();
        let child;
        // 遍历dom节点
        while(child = node.firstChild){
            compile(child, data);
            frag.appendChild(child);
        }
        return frag;
    }
 
    function compile(node, data){
        let reg = /\{\{(.*)\}\}/g;
        if(node.nodeType === 1){ // 标签
            let attr = node.attributes;
            for(let i = 0, len = attr.length; i < len; i++){
                // console.log(attr[i].nodeName, attr[i].nodeValue);
                if(attr[i].nodeName === 'v-model'){
                    let name = attr[i].nodeValue;
                    // node.value = data[name];
 
                    // ------------------------添加监听事件
                    node.addEventListener('keyup', function(e){
                        data[name] = e.target.value;
                    }, false);
 
                    new Subscriber(node, data, name);
 
                }
            }
            if(node.hasChildNodes()){
                node.childNodes.forEach((item) => {
                    compile(item, data);
                });
            }
        }
        if(node.nodeType === 3){ // 文本节点
            if(reg.test(node.nodeValue)){
                let name = RegExp.$1;
                name = name.trim();
                // node.nodeValue = data[name];
 
                new Subscriber(node, data, name);
            }
        }
    }
 
 
    function defineReact(data, key, value){
        let publisher = new Publisher();
        Object.defineProperty(data, key, {
            set: function(newValue){
                console.log(`触发setter`);
                value = newValue;
                console.log(value);
                publisher.notify(); // 发布订阅
            },
            get: function(){
                console.log(`触发getter`);
                if(Publisher.global){
                    publisher.add(Publisher.global); // 添加订阅者
                }
                return value;
            }
        });
    }
 
 
    // 将data中数据绑定到vm实例对象上
    function observe(data, vm){
        Object.keys(data).forEach((key) => {
            defineReact(vm, key, data[key]);
        })
    }
 
 
    function Vue(options){
        this.data = options.data;
        let id = options.el;
 
        observe(this.data, this); // 将每个data属相绑定到Vue的实例vm上
 
        //------------------------
        let container = document.getElementById(id);
        let fragment = virtualDom(container, this); // 这里通过vm对象初始化
        container.appendChild(fragment);
 
    }
 
 
    var vm = new Vue({
        el: 'container',
        data: {
            msg: 'Hello World!',
            inpText: 'Input text'
        }
    });

               总结:

倘若用一句话来概括vue,那么我首先想到的便是官方文档中的一句话:

Vue.js(读音 /vjuː/,类似于 view) 是一套构建用户界面的渐进式框架。

这句话可能大家并不陌生,但是真正理解这句话的可能并不多,其实,读懂了这句话,也就明白了vue的核心理念.

那么,怎样理解什么是渐进式框架?在这之前,我们首先要理解什么是框架.在最初的前端开发中,为了完成某个功能,我们需要通过js在HTML页面中获得dom节点,随后获得dom节点中的文本内容或者在dom节点上添加事件,进行一系列的程序操作,但是,如果任务量很大的情况下,代码会随着业务的增加而变得臃肿和混乱,在现实的开发中,负责的逻辑和巨大的开发量,是原生js无法完成的.

这个时候,开发人员将js代码分为了三个板块,数据(Model),逻辑控制(*),视图(View),数据板块只负责数据部分,视图板块负责更改样式,逻辑控制负责联系视图板块和数据板块,这样子有很大的好处,当需求发生变动时,只需要修改对应的板块就好

这种开发模式,就是所谓的MV*结构,我们现在了解的MVC,MVP,MVVM都是MV*的衍生物,对比这几种框架模式,我们会总结出来一个本质的特点,那就是这些开发模式都是让视图和数据间不会发生直接联系.对比用原生JS获得dom的操作,你会发现原生dom流其实是将dom作为数据,从dom中获得Model,随后又更改dom来实现更新视图,视图和模型其实混在一起,所以代码自然混乱,不易维护.

在具有响应式系统的Vue实例中,DOM状态只是数据状态的一个映射 即 UI=VM(State) ,当等式右边State改变了,页面展示部分UI就会发生相应改变。很多人初次上手Vue时,觉得很好用,原因就是这个.不过,Vue的核心定位并不是一个框架,设计上也没有完全遵循MVVM模式,可以看到在图中只有State和View两部分, Vue的核心功能强调的是状态到界面的映射,对于代码的结构组织并不重视, 所以单纯只使用其核心功能时,它并不是一个框架,而更像一个视图模板引擎,这也是为什么Vue开发者把其命名成读音类似于view的原因。

上文提到,Vue的核心的功能,是一个视图模板引擎,但这不是说Vue就不能成为一个框架。如下图所示,这里包含了Vue的所有部件,在声明式渲染(视图模板引擎)的基础上,我们可以通过添加组件系统、客户端路由、大规模状态管理来构建一个完整的框架。更重要的是,这些功能相互独立,你可以在核心功能的基础上任意选用其他的部件,不一定要全部整合在一起。可以看到,所说的“渐进式”,其实就是Vue的使用方式,同时也体现了Vue的设计的理念.

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐