模块化开发 TodoList 应用
为什么要模块化开发
在多人协作开发项目时,模块化开发能够让不同开发者编写的代码相互独立,不会相互影响。同时模块化后的代码可以很方便地与其他模块进行组合,产生更多功能。
如何进行模块化设计
在进行模块化设计时,我们通常会遵循以下原则:
方法写在原型对象上,通过原型继承机制进行共享,保持不变。这是因为方法的逻辑一般是固定的。
属性写在构造函数内部。属性是可以由外部传入配置的,属于会改变的部分,所以要写在构造函数中。
下面是一个模块化设计的简单示例
(function () {
function Test(options) {
// 可配置的属性
this.prop = options.prop;
}
Test.prototype = {
// 方法
method1: function () {
// ...
},
method2: function () {
// ...
},
};
// 将模块暴露给全局
window.Test = Test;
})();
// 使用模块
var test = new Test({
prop: 'foo',
});
test.method1();
模块化开发标准
使用 IIFE 分割作用域
我们可以使用立即调用函数表达式(IIFE)来创建独立的作用域,避免污染全局作用域:
var header = (function () {
// header 模块
})();
var footer = (function () {
// footer 模块
})();
IIFE 会形成一个闭包,模块内部的变量和方法都不会影响到外部。
CSS 命名规范
文件命名
对于一些通用的重置样式表,建议使用common.css
或global.css
这样的文件名,不要使用reset.css
或normalize.css
,因为它们一般是框架或库中自带的。
常用的通用 CSS 样式
下面是一些常用的通用 CSS 样式:
/* 重置 body 的 margin */
body {
margin: 0;
}
/* 去掉 a 元素的下划线 */
a {
text-decoration: none;
}
/* 重置列表元素的样式 */
ul {
padding: 0;
margin: 0;
list-style: none;
}
/*
对于分组选择器,
建议使用竖排格式书写
*/
h1,
h2,
h3,
h4,
h5,
h6,
p {
margin: 0;
font-weight: bold;
}
CSS 选择器匹配规则
对于形如.a .b .c .d
这样的选择器,浏览器的匹配规则是从右到左进行的。
例如.wrap .a .b .c .d .e
,匹配时会先找到所有 class 为e
的元素,然后再去判断其父元素是否有d
类,再判断更上一层是否有c
类,以此类推。
所以我们在书写选择器时,应当尽量减少选择器的层级,以提高匹配效率。
面向对象开发 TodoList
下面是使用面向对象的思想开发 TodoList 应用的示例代码
// 待办事项模型
function TodoItem(options) {
this.content = options.content;
this.completed = false;
}
TodoItem.prototype = {
// 切换完成状态
toggle: function () {
this.completed = !this.completed;
},
};
// 待办事项列表视图
function TodoListView(options) {
this.$el = $(options.el);
this.todos = options.todos;
this.initEvents();
this.render();
}
TodoListView.prototype = {
// 初始化事件
initEvents: function () {
this.$el.on('click', '.toggle', this.toggle.bind(this));
this.$el.on('click', '.remove', this.remove.bind(this));
},
// 渲染列表
render: function () {
var html = this.todos
.map(function (todo) {
return `
<li>
<div class="view">
<input class="toggle" type="checkbox" ${todo.completed ? 'checked' : ''}>
<label>${todo.content}</label>
<button class="remove"></button>
</div>
</li>
`;
})
.join('');
this.$el.html(html);
},
// 切换完成状态
toggle: function (e) {
var index = $(e.target).closest('li').index();
this.todos[index].toggle();
this.render();
},
// 删除任务
remove: function (e) {
var index = $(e.target).closest('li').index();
this.todos.splice(index, 1);
this.render();
},
};
// 创建待办事项列表
var todos = [new TodoItem({ content: '学习 JavaScript' }), new TodoItem({ content: '学习 Vue' }), new TodoItem({ content: '整个牛项目' })];
// 创建视图实例
var todoListView = new TodoListView({
el: '#todoapp',
todos: todos,
});