• MVVM架构方式


    一、概念

    ①常见的架构方式或者开发思想还有MVC、MVP和MVVM,参考文章:MVC,MVP 和 MVVM 的图示

    ②MVC:视图(View),指用户界面;控制器(Controller),指业务逻辑;模型(Model),指数据保存

    ③MVP:将 Controller 改名为 Presenter,同时改变了通信方向

    ④MVVM:M,即model 业务数据模型,指操作数据的类;V,即view 视图界面,HTML用户界面;VM,viewModel 视图数据模型,指驱动视图改变的data数据。核心思想就是数据驱动视图。

    二、MVVM的优点

    低耦合。视图(View)可以独立于Model变化和修改,一个ViewModel可以绑定到不同的"View"上,当View变化的时候Model可以不变,当Model变化的时候View也可以不变。
    可重用性。你可以把一些视图逻辑放在一个ViewModel里面,让很多view重用这段视图逻辑。
    独立开发。开发人员可以专注于业务逻辑和数据的开发(ViewModel),设计人员可以专注于页面设计,使用Expression Blend可以很容易设计界面并生成xml代码。
    可测试。界面素来是比较难于测试的,而现在测试可以针对ViewModel来写。

    三、vue原理简单剖析

      <div id="app">
            {{message}}
            <h1>{{message}}</h1>
        </div>
        <script>
            function Vue(options){
                var {el,data}=options;
                // 根节点
                var rootEl=document.querySelector(el);
                var childNodes=rootEl.childNodes;
                var domAndKey={
    
                };
                // 编译模板
                for(var i=0;i<childNodes.length;i++){
                    let node=childNodes[i];
                    switch(node.nodeType){
                        case 1: 
                            //console.log(node,'标签节点')
                            break
                        case 3: 
                            //console.log(node,'文本节点')
                            var matches=/{{(.+)}}/.exec(node.textContent);
                            if(matches){
                                var dataKey=matches[1].trim();
                                //console.log(dataKey);
                                // 记住这个节点以及这个节点所绑定的数据成员
                                domAndKey[dataKey] = node;
                            }
                            break
                        default: 
                            break
                    }
                }
                // 数据观测
                for(let key in data){
                    Object.defineProperty(this,key,{
                        get(){
                            
                        },
                        set(val){
                            domAndKey['message'].textContent = val
                        }
                    })
                }
            }
            var app =new Vue({
                el:'#app',
                data:{
                    message:'hello vue'
                },
            });
        </script>

    四、双向绑定原理

    ①事件订阅发布模型

    // 设计模式:事件发布/订阅模型
    /* 构造函数 */
    function EventEmit(){
        this.callbacks={}
    };
    /* 添加原型方法 */
    EventEmit.prototype.on=function(eventName,fn){
        if(!this.callbacks[eventName]){
            this.callbacks[eventName]=[]
        }
        this.callbacks[eventName].push(fn)
    };
    /* 添加原型方法 */
    EventEmit.prototype.emit=function(eventName){
        if(!this.callbacks[eventName]){
            return
        }
        this.callbacks[eventName].forEach(fn => {
            fn()      
        });
    }
    
    //创建实例对象
    var el=new EventEmit();
    // 订阅事件
    el.on('message',function(){
        console.log('aaa')
    }) 
    el.on('message',function(){
        console.log('bbb')
    })
    el.on('message',function(){
        console.log('ccc')
    })
    // 发布事件
    el.emit('a')

    ②双向绑定实现

        <div id="app">
            {{message}}
            <input type="text" v-model='message'>
            <h1>{{message}}</h1>
            <div>
                <div>{{message}}</div>
                <div>
                    <h1>{{message}}</h1>
                </div>
            </div>
        </div>
        <!-- 引入事件订阅发布模型文件 -->
        <script src="eventemit.js"></script><!--  -->
        <script>
            //双向绑定实现原理的核心就是Object.defineProperty和事件订阅发布模型
            (function(){
                function Vue(options){
                    var {el,data}=options;
                    // 根节点
                    var rootEl=document.querySelector(el);
                    var _date={};
                    var _event=new EventEmit();
                    // 数据观测:当date中的数据发生变化时,发出事件通知,所有订阅了该事件的DOM都会得到更新
                    for(let key in data){
                        _date[key]=data[key];//把data中的数据往_data里复制一份,当通过 实例访问data中的数据时,实际上访问的是_data中的数据
                        Object.defineProperty(this,key,{
                            get(){
                                return _data[key]
                            },
                            set(val){
                                _date[key]=val;
                                _event.emit(key);
                            },
                        });
                    }
                    // 递归解析模板,注册数据绑定事件
                    function compile(childNodes){
                        childNodes.forEach((node,index) => {
                            switch(node.nodeType){
                                case 1: //处理input类型的标签
                                    if(node.nodeName==='INPUT'){
                                        const vModel=node.attributes['v-model'];
                                        if(!vModel){
                                            return
                                        }
                                        var dataKey=vModel.value.trim();
                                        node.oninput=()=>{
                                            this[dataKey]=node.value;
                                        }
                                    }
                                    compile.call(this,node.childNodes);//标签节点继续递归调用
                                break
                                case 3: 
                                    var matches=/{{(.+)}}/.exec(node.textContent);
                                    if(matches){
                                        var dataKey=matches[1].trim();
                                        _event.on(dataKey,()=>{
                                            node.textContent=_date[dataKey];
                                        })
                                    }
                                break
                            }
                        });
                    }
                    compile.call(this,rootEl.childNodes)
                } 
                window.Vue=Vue
            })();
            var app =new Vue({
                el:'#app',
                data:{
                    message:'hello vue',
                },
            });
        </script>

  • 相关阅读:
    C字符串格式化
    oms登录bug
    宏旺文章审核功能使用指引
    phpcms文章审核
    html5的pushState 无刷新, 前进后退等
    js路由—backbone的路由的实现02
    js路由—backbone的路由的实现01
    js路由—简单路由的实现
    img标签和css的background-image的区别
    querySelector与querySelectorAll
  • 原文地址:https://www.cnblogs.com/EricZLin/p/9401985.html
Copyright © 2020-2023  润新知