AJax技术

老生常谈js中的MVC

字号+ 作者:H5之家 来源:H5之家 2017-08-24 09:00 我要评论( )

下面小编就为大家带来一篇老生常谈js中的MVC。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧

时间:2017-07-25来源: 作者:源码库 文章热度: ℃

MVC是什么?

MVC是一种架构模式,它将应用抽象为3个部分:模型(数据)、视图、控制器(分发器)。

本文将用一个经典的例子todoList来展开(代码在最后)。

js,MVC

一个事件发生的过程(通信单向流动):

1、

2、M改变状态(读写数据)

3、V,更新数据,展现给用户

js传统开发模式,大多基于事件驱动的

1、hash驱动

2、DOM事件,用来驱动视图

3模型事件(业务模型事件和数据模型事件),用来驱动模型和模型结合

单向流动、事件驱动

一)模型

每一条记录与之有关的逻辑。

模型不关心,不包含视图和控制器的逻辑。它们应该是互相解耦的。这里提一点,模型视图的耦合显然是违反MVC架构原则,但往往我们有时候却因为业务关系而无法完全解耦

模型表现了领域特定的数据当一个模型有所改变的时候它会通知它的观察者(视图)

二)视图

视图是呈现给用户的,是用户交互的第一入口。它定义配置管理着每个页面相应的模板与组件,它表现一个模型的当前状态视图通过观察者模式监视模型,以获得最新的数据,来呈现最新的页面所以,页面首次加载时,往往是从接收模型的数据开始。

三)控制器

控制器分发器),是模型和视图之间的桥梁,集中式配置和管理事件分发、模型分发、视图分发,还用来权限控制、异常处理等。我们的应用中往往是有多个控制器的

触发控制器的事件处理机制去派发新的事件,通知模型更新数据(这样就回到了第一步了)

Demo-todoList

单独分离开来举例子不好讲,所以在代码中进行注释。首先简单理下下边代码的思路:

1、V层定义配置了一个显示数据的字符串模板,同时定义一个订阅者的回调函数render() 用于页面更新数据。

2、C层监听用户的添加与删除操作,添加是add() 函数 它执行了回调函数render,同时向M层写入数据,通知M层改变。删除操作同理。

3、M层是本地存储localStorage,模拟一个存储数据对象的后台模型。

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>todo</title> </head> <body> <header> <h3>待定事项</h3> </header> <main> <ul id="todoList"></ul> <input type="text" id="content"> <button id="confirm">确认</button> </main> <script> (function () { const ADD_KEY = '__todoList__' const Utils = { // 模拟 Modal(实体模型) store(key, data) { if (arguments.length > 1) { return localStorage.setItem(key, JSON.stringify(data)); } else { let storeData = localStorage.getItem(key); return (storeData && JSON.parse(storeData)) || []; // 这里一定要设置初始值为 [] } } } class Todo { constructor(id, text = "") { this.id = id this.text = text } } let App = { init() { // this.todos 为一个存储json对象的数组, 是一个实例化的数据对象,可任意调用 this.todos = Utils.store(ADD_KEY) this.findDom() this.bindEvent() this.render() // 初始化渲染 }, findDom() { this.contentBox = document.querySelector("#content") this.confirm = document.querySelector("#confirm") this.todoList = document.querySelector("#todoList") this.todoListItem = document.getElementsByTagName("li") }, // 模拟 Controller (业务逻辑层) bindEvent() { this.confirm.addEventListener('click', () => { // 要求模型 M 改变状态,add()函数是写入数据操作 this.add() }, false) this.todoList.addEventListener('click', (item) => { // 事件委托,优化性能 this.remove(item) }, false) }, // 这里勉强抽象成一个视图吧!!! view() { let fragment = document.createDocumentFragment() // 减少回流次数 fragment = '' for (let i = 0; i < this.todos.length; i++) { // 一次性DOM节点生成 // 这里使用拼接字符串代替视图的模板, // *******注意模板并不是一个视图,模板是由视图定义配置出来的,并被其管理着******* // 模板是用一种声明的方式指定部分甚至所有的视图对象 fragment += `<li>${this.todos[i].text}</li>` } this.todoList.innerHTML = fragment }, // render()函数作为一个订阅者的回调函数,数据的变化会反馈到模型 store // 换句话说:视图通过观察者模式,观察模型 store,当模型发生改变,触发视图更新 render() { this.view() /** * 这里需要特别提一下,按照 MVC 原则这里本不应该出现下面的代码的 * 因为业务逻辑关系(我本地存储使用的是同一个key值,再次写入数据会覆盖原来的数据,), * 所以必须通知模型 M 保存数据, V 层处理了不该它处理的逻辑,导致 M 与 V 耦合 * * 解决办法是:将其抽象出来编写一个 视图助手 helper */ Utils.store(ADD_KEY, this.todos) }, getItemIndex(item) { let itemIndex if (item.target.tagName.toLowerCase() === 'li') { let arr = Array.prototype.slice.call(this.todoListItem) let index = arr.indexOf(item.target) return itemIndex = index } }, add(e) { let id = Number(new Date()) let text = this.contentBox.value let addTodo = new Todo(id, text) this.todos.unshift(addTodo) // 模型发生改变 this.render() // 当模型发生改变,触发视图更新 }, remove(item) { let index = this.getItemIndex(item) this.todos.splice(index, 1) this.render() } } App.init() })() </script> </body> </html>

mvc模式的优点

 

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

相关文章
  • Django中的Ajax,DjangoAjax

    Django中的Ajax,DjangoAjax

    2017-08-03 12:00

  • 毕业论文:Ajax技术及其在web中的应用

    毕业论文:Ajax技术及其在web中的应用

    2017-07-30 09:03

  • jQuery高级篇 第二章 Ajax在jQuery中的使用视频课程

    jQuery高级篇 第二章 Ajax在jQuery中的使用视频课程

    2017-07-23 13:07

  • Ajax技术在WebGIS中的应用分析.pdf

    Ajax技术在WebGIS中的应用分析.pdf

    2017-07-16 10:00

网友点评
>