对JavaScript客户端应用编程的一些建议


Posted in Javascript onJune 24, 2015

你可能注意到了,最近的一段时间越来越多的Web应用有变复杂的趋势,重心从服务端慢慢向着客户端转移。 这是个正常的趋势么?我不知道。支持和反对者的讨论就像是在讨论复活者和圣诞节哪一个更好一样; 很难说哪一方观点就是完全正确的。因此,本文不会探讨究竟哪一方是对的,不过我还是试图解释一下使用大家所熟知的面向对象编程也许可以成功的解决客户端编程中存在的一些问题。

不太规范的代码的示例

为了顾及一个应用的响应以及用户体验, 导致我们创建了持续增长的复杂的代码, 这些代码变得难于理解和维护。 你可以轻松的想到在没有任何构架和遵循规则构建出客户端的JavaScript应用代码将会这样:
 

$(function(){
  $('#form').submit(function(e) {
    e.preventDefault();
 
    $.ajax({
      url: '/animals',
      type: 'POST',
      dataType: 'json',
      data: { text: $('#new-animal').find('textarea').val() },
      success: function(data) {
        $('#animals').append('<li>' + data.text + '</li>');
        $('#new-animal').find('textarea').val('');
      }
     });
   });
});

维护这一类的代码将会很难。因为这短短的一段代码与很多地方都有关联: 它控制着很多的事件 (站点, 用户, 网络事件), 它要处理用户的操作事件, 要解析服务器返回的应答并且产生HTML代码。 有人可能说: “是的,你说的对, 但是如果这不是一个客户端单页的页面应用?这最多算是一次过度使用jQuery类库的例子” ——不是很有说服力的观点, 因为众所周知,易于维护和精心设计的代码是非常重要的。特别是许多的工具或者是框架致力于保持代码可用以便于我们能更简单的去测试、维护、重用、和扩展它。

MVC是什么?

谈到这里。我们能受益于那些基于MVC的JavaScript框架,但这些框架大部分不使用MVC,并且相当于Model和Videw的一种结合,或者在二都之间的一些东西,这很难去分清。这就是为什么说大部分的Javascript框架是基于MV*。

改变方法或许可以提供项目中客户端的组织和架构,这使得代码可以在很长的一段时间内容易维护,即使重构已经有的代码也变得相对容易。知道他如何工作和下面一些问题的答案是必需要要记住的。

  •     我的应用里有哪些类型的数据?-Model
  •     用户应该看到什么?-View
  •     谁是和用户交互的程序?-Controller

使用MVC框架重构代码

受用MVC重构代码有什么好处?

  •     解除DOM和Ajax的依赖
  •     代码有更好的结构,并且更容易测试。
  •     从 $(document).ready()中删除多余的代码,只留下使用Model创建Links的部分。

让我们使用一些简单步骤来重构一个典型的代码块
步骤 1: 创建视图并移动Ajax请求

我们开始解除DOM和Ajax的依赖. 使用prototypes建造者,模式创建'Animals' 对象,并且添加一个 'add' 方法.同时创建视图 'NewAnimalView' , 并且添加方法'addAnimal'、 'appendAnimal' 、'clearInput'.

代码如下:
 

var Animals = function() {
};
 
Animals.prototype.add = function (options) {
   $.ajax({
     url: '/animals',
     type: 'POST',
     dataType: 'json',
     data: { text: options.text },
     success: options.success
   });
};
 
 var NewAnimalView = function (options) {
  this.animals = options.animals;
  var add = $.proxy(this.addAnimal, this);
  $('# form').submit(add);
 };
 
 NewAnimalView.prototype.addAnimal = function(e) {
   e.preventDefault();
   var self = this;
 
   this.animals.add({
     text: $('#new-animal textarea').val(),
     success: function(data) {
       self.appendAnimal (data.text);
       self.clearInput();     
     }
   });
 };
 
NewAnimalView.prototype.appendAnimal = function(text) {
  $('#animals ul').append('<li>' + data.text + '</li>');
};
NewAnimalView.prototype.clearInput = function() {
  $('#new-animal textarea').val('');
};
 
 $(document).ready(function() {
   var animals = new Animals();
   new NewAnimalView({ animals: animals });
 });

步骤 2: 使用事件解除依赖.

这个例子,利用MVC框架是关键。我们将会用到事件机制, 事件使我们结合和触发自定义事件. 因此,我们创建新的“AnimalsView”和“NewAnimalView”,并且赋予它们不同的显示animals的职责。 使用事件就来区别职责非常简单。如果在方法和事件之间传递职责,如下所示:
 

var events = _.clone(Backbone.Events);
var Animals = function() {
};
 
Animals.prototype.add = function(text) {
   $.ajax({
     url: '/animals',
     type: 'POST',
     dataType: 'json',
     data: { text: text },
     success: function(data) {
      events.trigger('animal:add', data.text);
     }
   });
};
 
var NewAnimalView = function(options) {
  this.animals = options.animals;
  events.on('animal:add', this.clearAnimal, this);
  var add = $.proxy(this.addAnimal, this);
  $('# form').submit(add);
 };
 
NewAnimalView.prototype.addAnimal = function(e) {
   e.preventDefault();
   this.animals.add($('#new-animal textarea').val());
 };
 
NewAnimalView.prototype.clearInput = function() {
  $('#new-animal textarea').val('');
};
 
var AnimalsView = function() {
  events.on('animal:add', this.appendAnimal, this);
};
 
AnimalsView.prototype.appendAnimal = function(text) {
  $('#animals ul').append('<li>' + data.text + '</li>');
};
 
$(document).ready(function() {
   var animals = new Animals();
   new NewAnimalView({ animals: animals });
   new AnimalsView();
});

步骤 3: 传递数据结构到核心框架

最后,最重要的一步,我们使用: models, views and collections.
 

var Animal = Backbone.Model.extend({
  url: '/animals'
});
 
var Animals = Backbone.Collection.extend({
  model: Animal
});
 
var AnimalsView = Backbone.View.extend({
  initialize: function() {
    this.collection.on('add', this.appendAnimal, this);
  },
 
  appendAnimal: function(animal) {
    this.$('ul').append('<li>' + animal.escape('text') + '</li>');
  }
});
 
 
var NewAnimalView = Backbone.View.extend({
  events: {
    'submit form': 'addAnimal'
  },
 
  initialize: function() {
    this.collection.on('add', this.clearInput, this);
  },
 
  addAnimal: function(e) {
    e.preventDefault();
    this.collection.create({ text: this.$('textarea').val() });
  },
 
  clearInput: function() {
    this.$('textarea').val('');
  }
});
 
$(document).ready(function() {
  var animals = new Animals();
  new NewAnimalView({ el: $('#new-animal'), collection: animals });
  new AnimalsView({ el: $('#animals'), collection: animals });
});

总结

我们已经实现什么呢?我们在高度的抽象上工作。代码的维护、重构和扩展变得更容易。我们极大的优化了代码结果,是不是很迷人?太棒了。但是,我可能要给你泼冷水,即使最好的框架,开发的代码仍旧是脆弱并且难以维护。因此,如果你认为使用了一个较好的MV*框架能解决所有代码上的问题是错误的。记住在重构过程中,经历了第二步,代码会变得好很多,我们不使用框架的主要组件。

记住MV*框架是好的这一点,但是所有关注在‘How'去开发一个应用,这让程序开发人员头决定‘What'。每个框架的一个补充,尤其是当项目的Domain很复杂,将是Domain驱动设计方法,这将更关注与下面的方面:“what”, 把需求转化为真正的产品的一个过程。但是,这是我们要讨论的另外一个主题。

Javascript 相关文章推荐
js实现省市联动效果的简单实例
Feb 10 Javascript
使用JS画图之点、线、面
Jan 12 Javascript
jQuery中 attr() 方法使用小结
May 03 Javascript
Jquery attr()方法 属性赋值和属性获取详解
Apr 15 Javascript
BootStrap 图标icon符号图标glyphicons不正常显示的快速解决办法
Dec 08 Javascript
多个上传文件用js验证文件的格式和大小的方法(推荐)
Mar 09 Javascript
微信小程序之数据缓存的实例详解
Sep 29 Javascript
vue中vee validate表单校验的几种基本使用
Jun 25 Javascript
javascript动态创建对象的属性详解
Nov 07 Javascript
大转盘抽奖小程序版 转盘抽奖网页版
Apr 16 Javascript
vue使用video.js进行视频播放功能
Jul 18 Javascript
Vue $attrs &amp; inheritAttr实现button禁用效果案例
Dec 07 Vue.js
javascript删除数组重复元素的方法汇总
Jun 24 #Javascript
js实现跨域的方法实例详解
Jun 24 #Javascript
JavaScript中的Promise使用详解
Jun 24 #Javascript
JavaScript面对国际化编程时的一些建议
Jun 24 #Javascript
对JavaScript的全文搜索实现相关度评分的功能的方法
Jun 24 #Javascript
在Mac OS下使用Node.js的简单教程
Jun 24 #Javascript
在Node.js应用中使用Redis的方法简介
Jun 24 #Javascript
You might like
PHP 绘制网站登录首页图片验证码
2016/04/12 PHP
对象的类型:本地对象(1)
2006/12/29 Javascript
通过Unicode转义序列来加密,按你说的可以算是混淆吧
2007/05/06 Javascript
ajax不执行success回调而是执行了error回调
2012/12/10 Javascript
JavaScript prototype 使用介绍
2013/08/29 Javascript
js图片向右一张张滚动效果实例代码
2013/11/23 Javascript
Javascript的&amp;&amp;和||的另类用法
2014/07/23 Javascript
JQuery中DOM事件合成用法实例分析
2015/06/13 Javascript
今天抽时间给大家整理jquery和ajax的相关知识
2015/11/17 Javascript
JavaScript中获取纯正的undefined的方法
2016/03/06 Javascript
jquery+ajax实现直接提交表单实例分析
2016/06/17 Javascript
AngularJS学习笔记(三)数据双向绑定的简单实例
2016/11/08 Javascript
Angular 常用指令实例总结整理
2016/12/13 Javascript
AngularJS定时器的使用与移除操作方法【interval与timeout】
2016/12/14 Javascript
微信JSSDK调用微信扫一扫功能的方法
2017/07/25 Javascript
JSON生成Form表单的方法示例
2018/11/21 Javascript
微信小程序功能之全屏滚动效果的实现代码
2018/11/22 Javascript
深入理解Vue.js轻量高效的前端组件化方案
2018/12/10 Javascript
JavaScript检测浏览器是否支持CSS变量代码实例
2020/04/03 Javascript
angular组件间通讯的实现方法示例
2020/05/07 Javascript
Python中的__SLOTS__属性使用示例
2015/02/18 Python
详解Python的Django框架中的通用视图
2015/05/04 Python
django Serializer序列化使用方法详解
2018/10/16 Python
Flask-WTF表单的使用方法
2019/07/12 Python
CSS3教程:新增加的结构伪类
2009/04/02 HTML / CSS
水上运动奥特莱斯:Wasterports Outlet
2018/08/08 全球购物
英国家电购物网站:Sonic Direct
2019/03/26 全球购物
Ajax的工作原理
2015/12/04 面试题
企业管理专业个人求职信范文
2013/09/24 职场文书
文明风采获奖感言
2014/02/18 职场文书
党员干部2014全国两会学习心得体会
2014/03/10 职场文书
2014年采购部工作总结
2014/11/20 职场文书
你对自己的信用报告有过了解吗?
2019/07/09 职场文书
CSS实现漂亮的时钟动画效果的实例代码
2021/03/30 HTML / CSS
Windows 11要来了?微软文档揭示Win11太阳谷 / Win10有两个不同版本
2021/11/21 数码科技
JavaScript流程控制(循环)
2021/12/06 Javascript