<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 举报,一经查实,本站将立刻删除。