一、JSON字符串配置
; (function () {
var TodoList = function () {
}
TodoList.prototype = {
}
// window.todoList = TodoList
// 不需要写
})
<div class="wrap" data-config='{
"plusBtn": "j-plus-btn",
"inputArea": "input-wrap",
"addBtn": "j-add-item",
"list": "item-list",
"itemClass": "item"
}'></div>
注意: JSON数据必须是双引号
二、获取JSON数据
(1)JSON.parse()
可以把JSON字符串转换成对象
; (function (node) {
var TodoList = function () {
this.node = node;
this.config = this.getConfig();
}
TodoList.prototype = {
getConfig: function () {
return config = JSON.parse(this.node.getAttribute('data-config'))
}
}
new TodoList();
}(document.getElementsByClassName('wrap')[0]));
三、设置默认项
; (function (node) {
var TodoList = function () {
this.node = node;
this.dConfig = {
"plusBtn": "",
"inputArea": "",
"addBtn": "",
"list": "",
"itemClass": ""
}
this.config = this.getConfig();
// 如果配置项未写完整就会抛出错误
for (var key in this.dConfig) {
if (!this.config.hasOwnProperty(key)) {
console.log(errorInfo(key));
return;
}
}
}
TodoList.prototype = {
getConfig: function () {
return config = JSON.parse(this.node.getAttribute('data-config'))
}
}
function errorInfo(key) {
return new Error(
'您没有配置参数' + key + '\n\n' +
'必须配置的参数列表如下:\n' +
'打开输入框按钮元素类名:plusBtn\n' +
'输入框区域元素类名:inputArea\n' +
'增加项目元素类名:addBtn\n' +
'列表承载元素类名:list\n' +
'列表承载元素类名:itemClass'
);
}
new TodoList();
}(document.getElementsByClassName('wrap')[0]));
四、获取元素
; (function (node) {
var TodoList = function () {
this.node = node;
this.dConfig = {
"plusBtn": "",
"inputArea": "",
"addBtn": "",
"list": "",
"itemClass": ""
}
this.config = this.getConfig();
this.itemClass = this.config.itemClass;
for (var key in this.dConfig) {
if (!this.config.hasOwnProperty(key)) {
console.log(errorInfo(key));
return;
}
}
// 获取元素
this.setConfig();
}
TodoList.prototype = {
getConfig: function () {
return config = JSON.parse(this.node.getAttribute('data-config'))
},
setConfig: function () {
var config = this.config,
node = this.node;
this.inputArea = node.getElementsByClassName(config.inputArea)[0];
this.addBtn = this.inputArea.getElementsByClassName(config.addBtn)[0];
this.plusBtn = node.getElementsByClassName(config.plusBtn)[0];
this.oList = node.getElementsByClassName(config.list)[0];
this.content = document.getElementById('itemContent')
}
}
function errorInfo(key) {
return new Error(
'您没有配置参数' + key + '\n\n' +
'必须配置的参数列表如下:\n' +
'打开输入框按钮元素类名:plusBtn\n' +
'输入框区域元素类名:inputArea\n' +
'增加项目元素类名:addBtn\n' +
'列表承载元素类名:list\n' +
'列表承载元素类名:itemClass'
);
}
new TodoList();
}(document.getElementsByClassName('wrap')[0]));
五、绑定事件
; (function (node) {
var TodoList = function () {
var _self = this;
this.node = node;
this.inputShow = false;
this.dConfig = {
"plusBtn": "",
"inputArea": "",
"addBtn": "",
"list": "",
"itemClass": ""
}
this.config = this.getConfig();
this.itemClass = this.config.itemClass;
for (var key in this.dConfig) {
if (!this.config.hasOwnProperty(key)) {
console.log(errorInfo(key));
return;
}
}
this.setConfig();
// 事件绑定
addEvent(this.plusBtn, 'click', function () {
_self.showInput.call(_self); // 第一层修改this指向
})
}
TodoList.prototype = {
getConfig: function () {
return config = JSON.parse(this.node.getAttribute('data-config'))
},
setConfig: function () {
var config = this.config,
node = this.node;
this.inputArea = node.getElementsByClassName(config.inputArea)[0];
this.addBtn = this.inputArea.getElementsByClassName(config.addBtn)[0];
this.plusBtn = node.getElementsByClassName(config.plusBtn)[0];
this.oList = node.getElementsByClassName(config.list)[0];
this.content = document.getElementById('itemContent')
},
showInput: function () {
var _self = this;
if (this.inputShow) {
setInputShow.call(_self, 'close') // 第二层修改this指向
} else {
setInputShow.call(_self, 'open')
}
}
}
function setInputShow(action) {
if (action === 'open') {
this.inputArea.style.display = 'block';
this.inputShow = true;
} else if (action = 'close') {
this.inputArea.style.display = 'none';
this.inputShow = false;
}
}
function errorInfo(key) {
return new Error(
'您没有配置参数' + key + '\n\n' +
'必须配置的参数列表如下:\n' +
'打开输入框按钮元素类名:plusBtn\n' +
'输入框区域元素类名:inputArea\n' +
'增加项目元素类名:addBtn\n' +
'列表承载元素类名:list\n' +
'列表承载元素类名:itemClass'
);
}
new TodoList();
}(document.getElementsByClassName('wrap')[0]));
难点:
- 事件处理函数里面装了一个方法,这个方法里面又嵌套了一个方法,需要每一层都改变this指向,才能找到TodoList的实例对象
- 随时用_self保存函数的this指向,因为指不定往后嵌套的函数会用到
六、总结
(1)call、apply的使用场景
当只有一个参数的时候用call,有多个参数的时候就用apply
(2)书写规范
- 构造函数在最上面
- prototype在中间
- 函数在最下面
(3)顺序
- 获取配置项
- 默认项设置
- 对比默认项与配置项,如果有一项没有配置就抛出错误
- 绑定事件(加号按钮,增加项目按钮,编辑/删除按钮)
- 原形上写方法(showInput、addBtnClick、 listClick)
- 抽象原形方法(setInputShow、setInputStatus、errorInfo、itemTpl)