【UI插件】简单的日历插件(下)—— 学习MVC思想

简介:

前言

我们上次写了一个简单的日历插件,但是只是一个半成品,而且做完后发现一些问题,于是我们今天尝试来解决这些问题

PS:距离上次貌似很久了

上次,我们大概遇到哪些问题呢:

① 既然想做一套UI库,那么就应该考虑其它UI库的接入问题

这个意思就是,我们的系统中所有UI插件应该有一些统一行为,我们如果希望统一为所有的插件加一点什么东西,需要有位置可加

这个意味着,可能我们所有的插件需要继承至一个抽象的UI类,并且该类提供了通用的几个事件点

② 上次做的日历插件虽然说是简单,其耦合还是比较严重的(其实也说不上,但是人总有想装B的时候)

这个怎么说呢,就日历而言,我们可以将之分成三个部分

1 日历核心部分,用于生产静态html

2 日历数据部分,用于显示各个特殊信息,比如节日什么的

3 日历事件部分,现在的想法便是可以将事件相关给抽象出来

目的便是html/data/events 分开一点点,这个该怎么做呢?这是我们今天该思考的问题

事情多了就什么都不能解决,所以我们今天暂时便处理以上两个问题即可

MVC的学习

由于我们会依赖于underscore,所以,我们这里有一个underscore的扩展,加一些我们自己需要的东西

  View Code

对的,以上是我们前面实现的继承,我们将之扩展至underscore上,以后以此实现继承

其次,我们便需要思考如何分离我们的数据/模板/事件了

View/Adapter/ViewController

俗话说,大树底下好乘凉,事实上我一些想法来自于我的老大,我老大又借鉴了原来的ios开发,所以这里形成了一些东西,不知道是否合理,我们拿出来看看

View

首先,无论如何我们的应用都会有一个view的存在,我们认为view只做简单的页面渲染就好,与之有关的数据/事件什么的,我们不予关注

  View Code

从代码上看,我们需要注意几个事情:

① View会生成静态HTML

② View会根据当前状态、当前数据生成静态HTML

所以,我们的View事实上只会生成静态HTML,不同的是他会根据不同的状态生成不同的HTML,比如初始状态和加载结束状态

有了View便缺不了数据,也就是所谓的Model,我们这里给他取一个名字,Adapter

Adapter

  View Code

Adapter由以下几个关键组成:

① View观察者

② 数据模型,便是原始的数据

③ viewModel,便是view实际需要的数据

并且每一次数据的改变会通知观察的view,触发其update,所以Adapter的组成也比较干脆,并不复杂

但是,我们的view仍然没有事件,而且Adapter也没有与view联系起来,这个时候我们缺少一个要件,他的名字是Controller

ViewController

控制器是链接模型与视图的桥梁,我们这里也不例外,核心动作皆会在控制器处完成

  View Code

control这里便有所不同,会稍微复杂一点点

① 首先,他会验证自己是否含有view参数,我们这里要求一个控制器必须对应一个view,如果没有指定的话便认为错误

if (!_.property('view')(options)) throw Error('view必须在实例化的时候传入ViewController');

② 然后主要有几个关键事件点,第一个是create

PS:这里会区分是否二次创建该View,这个判断事实上不应该通过dom是否存在来判断,这里后期优化

create调用便会调用view的render方法,然后便会构建相关的dom结构,并且append到container中

③ 第二个关键事件点为show,调用时,dom会真正的显示,并且绑定事件

PS:事件这块借鉴的Backbone的机制,全部绑定值根元素,具体优化后面再说吧

④ 除此之外还有hide、forze(解除事件句柄,释放资源)、destroy等不详说了

说了这么多都是扯淡,我们下面以两个简单的例子做一次说明

实例说明

MVC学习完整代码

有不对的地方请提出

  View Code

underscore扩展

  View Code

简单alert框

首先我们来做一个简单的alert框,这个框在我们点击界面时候弹出一个提示,提示文字由文本框给出

第一步便是简单的HTML了

  View Code

因为该插件本身比较简单,不存在状态值便会,所以view定义如此即可

 1 var htmltemplate = $('#template-alert').html();
 2 
 3 var AlertView = _.inherit(Dalmatian.View, {
 4   templateSet: {
 5     0: htmltemplate
 6   },
 7 
 8   statusSet: {
 9     STATUS_INIT: 0
10   }
11 });

Adapter也比较简单

var Adapter = _.inherit(Dalmatian.Adapter, {
  parse: function (data) {
    return data;
  }
});

现在重点便是controller了

 1 var Controller = _.inherit(Dalmatian.ViewController, {
 2   render: function () {
 3     var data = this.adapter.viewmodel;
 4     this.view.render(this.viewstatus, data);
 5   },
 6 
 7   set: function (options) {
 8     this.adapter.datamodel.content = options.content;
 9     this.adapter.notifyDataChanged();
10   },
11 
12   events: {
13     "click .cui-btns-cancel": "cancelaction"
14   },
15 
16   cancelaction: function () {
17     this.onCancelBtnClick();
18   },
19 
20   attr: function (key, value) {
21     this[key] = value;
22   }
23 });

这里有个不一样的地方便是,这里有一个Adapter的set方法,set之后会改变其状态,这里会发生一次通知view更新的动作

最后我们将之串联起来

var view = new AlertView()
var adapter = new Adapter();
var controller = new Controller({
  view: view,
  adapter: adapter,
  container: '.container',
  onViewBeforeCreate: function () {

    var origindata = {
      content: 'fuck',
      confirm: 'confirmbtn',
      cancel: 'cancelbtn'
    }

    this.adapter.format(origindata);

    this.adapter.registerObserver(this);
    this.viewstatus = this.view.statusSet.STATUS_INIT;
  },
  onCancelBtnClick: function () {
    alert('cancel 2')
  }
});

然后我们写一段业务代码

1 $('#addbtn').on('click', function (e) {
2   var content = $('#addmsg').val();
3   // adapter.datamodel.content = content;
4   // adapter.notifyDataChanged();
5   controller.set({ content: content });
6   controller.show();
7 });

基本完成我们的操作了

 

事实上,我对这段代码并不是十分满意,于是,我们这里做一次简单重构:

  View Code

这个例子结束后,我们来写另一个例子

todolist

Backbone有一个todoList,我们这里也来写一个阉割版的,因为若是今天全部时间来写这个,后面就没法继续了

这个例子事实上也比较简单了,首先看我们的HTML结构

  View Code

其次是我们的js

  View Code

阶段总结

MVC的学习暂时到这里,我们下面继续日历的的东西,虽然我与老大商量后形成了一些自己觉得不错的东西,但是真正使用过程中还是发现一些问题

① 第一个我认为比较大的问题是viewController中的代码,比如

var controller = new Controller({
  view: view,
  adapter:  new Adapter(),
  container: '.container',
  onViewBeforeCreate: function () {
    this.adapter.format({
      list: []
    });
    this.adapter.registerObserver(this);
    this.viewstatus = this.view.statusSet.STATUS_INIT
  }
});

以及

var controller = new Controller({
  view: view,
  adapter: adapter,
  container: '.container',
  onCancelBtnClick: function () {
    alert('cancel 2')
  }
});

事实上这些代码不应该存在于此,真实情况下我所构想的viewController不会在实例化时候还有如此多的业务相关信息,viewController在实例化时候只应该包含系统级的东西

比如Controller释放出来的接口,比如全局消息监听什么的,显然我们上面代码中的做法是有问题的,这些东西事实上应该在定义ViewController类时,在继承处得到处理

不应该在实例化时候处理,我们viewController实例化时候应该有更重要的使命,这些留待下面解决

上面要表达的意思是,事实上我们ViewController是最后继承下来是需要干业务的事情,所以他应该在几个事件点将要干的事情做完,比如TodoList应该是这样的

  View Code

这样的话,业务应该的代码事实上写到了类的几个事件点中了,这些会在实例化时不同的状态被触发,所以根本不必在实例化时做任何操作

实例化时候应该有他的作用,因为继承到这一层的时候,该业务类便专注于处理这个业务了

简单日历

上次,我们的日历基本都成型了,今天我们便根据前面的想法为他做一次封装......

PS:想想有点很傻很天真的感觉......现在的问题是要将原来一个基本算总体的东西,分成三个部分,说实话这样封装的结构首先是让人阅读上稍微困难了

首先仍然是定义view的事情,首先一来就遇到个比较烦的地方,因为之前我们将模板分的很细:

① 星期显示模板

② 月模板

③ 日模板

所以,我们这里便不太好区分,而且还有一定嵌套关系,这里小钗费了一点功夫......

由这块的操作,我们甚至可以调整原来view的逻辑,优化由此一点一点慢慢就开始了......

  View Code

首次调整后,大概的东西出来了,这样一次操作后就会发现之前定义的MVC一些不合理的地方

① 操作Adapter有parse与format两个地方,我们用着用着就会分不清,应该只对外暴露一个借口

② Controller处操作Adapter以及view也会有多个地方事实上有一些必定会发生的流程我们应该封装起来,类似:

//使用adpter之前必须注册监听以及格式化viewModel,此操作应该封装起来
this.adapter.registerObserver(this);
this.adapter.format(this._getMonthData(this.dateObj.getFullYear(), this.dateObj.getMonth()));

//view显示之前必定会给予状态,此应该封装
this.viewstatus = this.view.statusSet.STATUS_INIT;

③ 整个MVC的逻辑还是有一些不太清晰的地方,这个留待后续调整

这个时候我们将之前的一些借口加入进来,比如我们的handleDay

handleDay: function (dateStr, fn) {
  if (dateUtil.isDate(dateStr)) dateStr = dateUtil.format(dateStr, 'Y-m-d');
  var el = this.viewcontent.find('[data-date="' + dateStr + '"]');

  if (typeof fn == 'function') fn(el, dateUtil.parse(dateStr, 'y-m-d'), this);

}
var calendar = new CalendarController();
calendar.show();

calendar.handleDay(new Date(), function (el, date, calendar) {
  el.html('今天');
});

现在如果有事件绑定的话,便注册至viewController即可,我这里便暂时结束了

结语

通过今天的学习,我将与我老大研究出来的MVC的东东搞了出来,事实证明还是需要有一些优化的......

今天状态不是太好,今天暂时到此,剩下的我们后面点来,这块还有很多东西要清理呢。。。。






本文转自叶小钗博客园博客,原文链接:http://www.cnblogs.com/yexiaochai/p/3705123.html,如需转载请自行联系原作者

相关文章
|
4月前
|
JavaScript
Vue在Element UI下使用富文本框插件quill-editor(我个人不推荐用这个复杂的富文本插件)
Vue在Element UI下使用富文本框插件quill-editor(我个人不推荐用这个复杂的富文本插件)
|
1月前
SAP UI5 Link 控件的使用方法介绍 - 后续学习 Fiori Elements Smart Link 的基础试读版
SAP UI5 Link 控件的使用方法介绍 - 后续学习 Fiori Elements Smart Link 的基础试读版
15 0
|
2月前
|
JSON 监控 数据格式
Easy UI datagrid的学习
Easy UI datagrid的学习
|
3月前
|
前端开发 Java 应用服务中间件
快速上手:探索Spring MVC的学习秘籍!
快速上手:探索Spring MVC的学习秘籍!
|
3月前
|
前端开发 Java 数据库
MVC架构学习归纳总结(小傅哥の码场 学习专栏)
MVC架构学习归纳总结(小傅哥の码场 学习专栏)
20 0
|
4月前
|
JavaScript
【Vue学习】—Vue UI组件库(二十八)
【Vue学习】—Vue UI组件库(二十八)
|
5月前
|
XML 数据安全/隐私保护 数据格式
Morn UI 学习总结
Morn UI 学习总结
47 0
|
5月前
|
设计模式 前端开发 Java
一篇文章让使你的Spring Mvc学习入门,还不来了解吗?
一篇文章让使你的Spring Mvc学习入门,还不来了解吗?
|
5月前
|
Serverless 开发者
函数计算FC中ebsynth_utility插件安装了,但重载UI后一直不显示的情况
函数计算FC中ebsynth_utility插件安装了,但重载UI后一直不显示的情况
257 3
|
5月前
|
监控 前端开发 Java
学习 [Spring MVC] 的JSR 303和拦截器,提高开发效率
学习 [Spring MVC] 的JSR 303和拦截器,提高开发效率
32 0

相关实验场景

更多