前端的小玩意(9.1)——做一个仿360工具箱的web页面(Tab按钮切换)
http://blog.csdn.net/qq20004604/article/details/52216203
前端的小玩意(9.2)——做一个仿360工具箱的web页面(全部工具里面的模板)
http://blog.csdn.net/qq20004604/article/details/52226223
前端的小玩意(9.3)——做一个仿360工具箱的web页面(我的工具里的模板和样式)
http://blog.csdn.net/qq20004604/article/details/52235854
前端的小玩意(9.4)——做一个仿360工具箱的web页面(自动生成所有图标,对图标添加响应逻辑)
http://blog.csdn.net/qq20004604/article/details/52246586
DEMO网址:
http://jianwangsan.cn/toolbox
(五)添加、点击和移动的逻辑
我反思了一下,在(四)中我写的并不好,事实上,无论是大按钮,还是被添加到我的工具,或者是添加到常用工具栏,他都是一个按钮,因此,应该共享状态,即他们属于同一个tool实例,并能互相影响。
需求分析:
在重写Tool类之前,需要明确分析按钮的逻辑。
在全部工具页面:
①当按钮未被添加时,鼠标移动上去会有添加按钮显示;
②当按钮未被添加时,鼠标无论点击按钮本身还是点击添加按钮,都执行添加逻辑,将添加按钮显示为取消,执行一次添加动画,添加完成后,按钮隐藏;
③当按钮已被添加时,鼠标点击会启用按钮本身的逻辑(比如打开软件);
在我的工具页面:
①当按钮未被添加时,不显示;
②当按钮被添加时,显示按钮;
③点击按钮时,点击会启用按钮本身的逻辑(比如打开软件);
④长按按钮,可以拖动按钮,原有按钮位置不被占用,显示为空白;
⑤按钮拖动中时,若经过某个已有按钮的位置,原按钮位置不再被占用,经过的位置被空白占用,相当于把空白占位符从DOM中的原位置挪到了DOM树中的新位置;
⑥按钮拖动时,可以离开工具箱的页面显示范围,但不会显示出来(类似overflow:hidden)的效果;
⑦当按钮拖动到主界面快捷入口的四个图标范围时,若原位置有图标,再该位置图标及右侧所有图标依次向右移动一位;当离开这个位置时,原有图标立刻返回原位置;
⑧主界面快捷入口最多有四个图标,假如新插入一个,那么原本最右边的将被移除;
⑨点击编辑按钮时,所有图标右上角都会出现一个红叉符号;
(10)当编辑状态时,点击主界面快捷入口的四个图标的红叉时,将移除被点击的那个图标;
(11)当编辑状态时,点击我的工具的图标的红叉,将删除该图标(全部工具里的添加按钮恢复);若该图标在快捷入口也存在时,快捷入口的该图标也被删除。
因此,这个Tool类也能满足以上功能;
更新模板和样式;
①要有四种状态的图标,依次为全部工具页面的大图标、普通图标,我的工具页面的普通图标、快捷入口图标;
②并且,要能创建这些图标,并且,由于之前没有设计全部工具页面的取消按钮、我的工具页面里的编辑按钮,因此要添上;
我的工具里图标的html模板:,编辑按钮默认为不显示:
div.tool-my div.img div.text 小清新日历 div.edit-img.displayNONE
快捷入口的按钮的html模板:
div.tool-foot div.img div.text 系统急救箱 div.edit-img.displayNONE
取消按钮添加后的大图标:
div.BigTool span.img span.mask div.text div.title div.description div.Button.add 添 加 div.Button.cancel.displayNONE 取 消
取消按钮添加后的html模板:
div.normalTool div.img div.text div.title div.description div.Button.add 添 加 div.Button.cancel.displayNONE 取 消
另附2个新增的CSS样式:
.back .contentbox .toolbox-my .toolbox-content .tool-my .edit-img { position: absolute; right: 14px; top: 13px; width: 18px; height: 17px; background-image: url(../img/toolbox.png); background-position: -80px -50px; } .back .contentbox .toolbox-my .toolbox-foot .edit-img { position: absolute; right: 14px; top: 10px; width: 18px; height: 17px; background-image: url(../img/toolbox.png); background-position: -80px -50px; }
然后是样式修改:
显示大图标的:
把原来的addButton拆分成Button、add和cancel
.back .contentbox .toolbox-all .firstRow .BigTool .Button { display: none; position: absolute; bottom: 10px; right: 12px; width: 60px; height: 22px; font-size: 12px; text-align: center; line-height: 20px; -webkit-border-radius: 1px; -moz-border-radius: 1px; border-radius: 1px; } .back .contentbox .toolbox-all .firstRow .BigTool .Button.add { background-image: linear-gradient(rgb(98, 227, 25) 0%, rgb(68, 208, 27) 100%); color: white; border: 1px solid rgb(65, 199, 36); } .back .contentbox .toolbox-all .firstRow .BigTool .Button.cancel { background-image: linear-gradient(#f3f3f3 0%, #dfdfdf 100%); color: black; border: 1px solid #b6b6b6; display: block; } .back .contentbox .toolbox-all .firstRow .BigTool:hover .add { display: block; }
另外一个类似
.back .contentbox .commonRow .normalTool .Button { display: none; position: absolute; top: 7px; right: 15px; width: 60px; height: 22px; font-size: 12px; text-align: center; line-height: 20px; -webkit-border-radius: 1px; -moz-border-radius: 1px; border-radius: 1px; } .back .contentbox .commonRow .normalTool .add { background-image: linear-gradient(rgb(98, 227, 25) 0%, rgb(68, 208, 27) 100%); border: 1px solid rgb(65, 199, 36); color: white; } .back .contentbox .commonRow .normalTool .cancel { background-image: linear-gradient(#f3f3f3 0%, #dfdfdf 100%); color: black; border: 1px solid #b6b6b6; display: block; } .back .contentbox .commonRow .normalTool:hover .add { display: block; }
为了符合实际需求,我们需要做以下工作:
①重构Tool类(之前实在太简陋了);
②需要一个函数,专用进行操作;
③需要一个runAfter函数,他的效果是,监听某个对象的某个方法,在该方法执行完后执行runAfter的回调函数;
④然后利用这个runAfter监听一些函数,并在该函数触发时做一些事情。
重构Tool类:
他分为以下几个部分:
①变量声明(私有变量):
var Tool = function (obj, myToolDom) { var self = this; var obj = obj; // 0表示未加载到我的工具,1表示加载到我的工具,-1表示添加中(未使用) var state = 0; var BigImgDom = null; //全部工具大图标 var NormalToolDom = null; //全部工具小图标 var addButton = null; //确认按钮 var cancelButton = null; //取消按钮(有,但是实际未使用) var InMyToolDom = null; //我的工具大图标 var editButtonInMyToolDom = null; //我的工具页面的编辑红叉按钮 var SmallToolDom = null; //快捷入口图标 var editButtonInSmallToolDom = null; //快捷入口图标的编辑按钮 var DomClickEvent = null; //这个是该dom点击事件的回调函数 var editing = false; //编辑状态 var move = false; //我的工具大图标移动状态 var SmallIconMove = false; //我的工具小图标移动状态 //如果有传参则用传参,如果没有则用默认值 var MyToolDom = myToolDom ? myToolDom : $(".toolbox-my .toolbox-content");
注意,以上四种图标,最多只会存在三种(所有工具的大图标和小图标只能存在一种状态)
②dom获取
根据实际需求,我们有时候需要获取dom,其中一个是私有的(只在tool类里调用),一个是公有的(会在外面调用),所以声明方式不同:
//获取DOM var getDomInAllTools = function () { return BigImgDom ? BigImgDom : NormalToolDom; //因为只有一个存在 }; this.getDomInMyTools = function () { return InMyToolDom; };
③创建图标
我们自然需要创建图标,四种图标都需要一个函数(因为他们的dom结构不同);
//全部工具页面 // 大按钮 this.createBigImgDom = function (callback) { var str = '<div class="BigTool">' + '<span class="img" style="background-position: ' + obj.bigImg.ImgPosition.x + ' ' + obj.bigImg.ImgPosition.y + '"></span>' + '<span class="mask"></span>' + '<div class="text">' + '<div class="title">' + obj.title + '</div>' + '<div class="description">' + obj.description + '</div>' + '</div>' + '<div class="Button add">添 加</div>' + '<div class="Button cancel displayNONE">取 消</div>' + '</div>'; BigImgDom = $(str); addButton = BigImgDom.find(".add"); cancelButton = BigImgDom.find(".cancel"); DomClickEvent = callback; setClickEvent(); return getDomInAllTools(); }; // 普通按钮 this.createNormalToolDom = function (callback) { var str = '<div class="normalTool">' + '<div class="img" style="background-position: ' + obj.commonImg.ImgPosition.x + ' ' + obj.commonImg.ImgPosition.y + '"></div>' + '<div class="text">' + '<div class="title">' + obj.title + '</div>' + '<div class="description">' + obj.description + '</div>' + '</div>' + '<div class="Button add">添 加</div>' + '<div class="Button cancel displayNONE">取 消</div>' + '</div>'; NormalToolDom = $(str); addButton = NormalToolDom.find(".add"); cancelButton = NormalToolDom.find(".cancel"); DomClickEvent = callback; setClickEvent(); return getDomInAllTools(); }; //我的工具页面 // 创建普通的dom var createInMyToolDom = function () { var str = '<div class="tool-my">' + '<div class="img" style="background-position: ' + obj.commonImg.ImgPosition.x + ' ' + obj.commonImg.ImgPosition.y + '"></div>' + '<div class="text">' + obj.title + '</div>' + '<div class="edit-img displayNONE"></div>' + '</div>' var node = $(str); return node; } // 创建小的dom var createSmallTool = function () { var position_x = parseInt(obj.commonImg.ImgPosition.x) * 0.615 + "px"; var position_y = parseInt(obj.commonImg.ImgPosition.y) * 0.615 + "px"; var str = '<div class="tool-foot">' + '<div class="img" style="background-position: ' + position_x + ' ' + position_y + '"></div>' + '<div class="text">' + obj.title + '</div>' + '<div class="edit-img displayNONE"></div>' + '</div>'; var node = $(str); return node; };
注:
(1)以上四个创建图标,在全部工具里的两种还额外获取了编辑按钮;
(2)创建全部工具的图标时,顺便获取了响应函数
④响应逻辑:
图标创建了必然需要对她设置事件,
(1)比如全部工具里图标的点击事件:
// 设置全部工具里的点击事件 var setClickEvent = function () { var node = BigImgDom ? BigImgDom : NormalToolDom; node.click(function (event) { if (state) { DomClickEvent(); } else if (state === 0) { self.addDomToMyTools(); } }); };
(2)以上点击事件又分为两种,已添加时,触发正常的响应逻辑(在创建图标时作为参数传进来的回调函数);
未添加时,用于添加到我的工具里的函数:
//将dom添加到我的工具里 this.addDomToMyTools = function () { addButton.addClass("displayNONE"); state = 1; //设置其状态为已添加 //现在是在mytools里添加 if (!InMyToolDom) { InMyToolDom = createInMyToolDom(); editButtonInMyToolDom = InMyToolDom.find(".edit-img"); //setMyToolEditEvent(editButtonInMyToolDom); //废弃,同下被整合 //setMyToolClickEvent(InMyToolDom); //废弃,被整合进移动按钮的逻辑中 setMyToolsDomMoveEvent(); } MyToolDom.append(InMyToolDom); };
(3)这个添加事件又分为:
设置添加按钮为隐藏,设置添加状态为已添加;
没有dom的时候,创建dom并为其绑定事件,绑定的事件有:
【1】点击事件:
(但事实上这个已废弃,因为后面涉及到移动按钮的函数,被整合在那里了)
// 设置我的工具页面的两种按钮的点击事件 var setMyToolClickEvent = function (node) { node.click(function (event) { if (!editing) { DomClickEvent(); } }); };
【2】编辑按钮点击事件:
(同样已废弃,因为后面涉及到移动按钮的函数,被整合在那里了)
【3】设置按钮的移动函数,包括以上两个被整合的事件:
//我的工具大图标的移动函数 var setMyToolsDomMoveEvent = function () { var mouseX = null; var mouseY = null; var startLeft = null; var startTop = null; var placeHholderDom = $('<div class="tool-my .ItsplaceHolder"></div>'); InMyToolDom.mousedown(function (evt) { if (evt.button != 0) { return; } if (editing & $(evt.target)[0] == editButtonInMyToolDom[0]) { self.setStateToUnadd(); InMyToolDom.detach(); if ($(".shortcut .tool-foot").filter(placeHholderDom[0])) { SmallToolDom.detach(); $(".shortcut").append('<div class="tool-foot placeholder">' + '<div class="placeholder-img"></div>' + '<div class="text">拖拽到此</div>' + '</div>') } event.stopPropagation(); return; } mouseX = evt.clientX; //这里的值是鼠标坐标 mouseY = evt.clientY; var position = InMyToolDom.position(); startLeft = position.left; //没有px startTop = position.top; InMyToolDom.css("position", "absolute"); InMyToolDom.css("left", startLeft + "px"); InMyToolDom.css("top", startTop + "px"); InMyToolDom.after(placeHholderDom); move = true; }); $(".toolbox-my").mousemove(function (evt) { if (!evt.buttons & move) { //只有不在按,且当前是true的时候,才触发 move = false; placeHholderDom.after(InMyToolDom); placeHholderDom.remove(); InMyToolDom.css("position", "relative"); InMyToolDom.css("left", "0"); InMyToolDom.css("top", "0"); self.InMyToolDomEndMoving(); if (mouseX == evt.clientX & mouseY == evt.clientY) { if (!editing) { DomClickEvent(); } } } if (move) { self.InMyToolDomMoving([placeHholderDom, evt]); var offsetX = evt.clientX - mouseX; var offsetY = evt.clientY - mouseY; InMyToolDom.css("left", offsetX + startLeft + "px"); InMyToolDom.css("top", offsetY + startTop + "px"); } }); InMyToolDom.mouseup(function (evt) { if (move) { move = false; placeHholderDom.after(InMyToolDom); placeHholderDom.remove(); InMyToolDom.css("position", "relative"); InMyToolDom.css("left", "0"); InMyToolDom.css("top", "0"); self.InMyToolDomEndMoving(); if (mouseX == evt.clientX & mouseY == evt.clientY) { if (!editing) { DomClickEvent(); } } } }) };
解释:
以上这个函数干了以下事:
《1》只有鼠标左键按下才有效;
《2》编辑状态时,按编辑按钮是有效的;(因此我们需要一个设置编辑状态的函数)
《3》编辑状态时点击编辑按钮,会删除当前按钮,并用一个空白的按钮替代;
《4》这个dom移除,为了不移除他的事件,因此用的是jquery的detach()方法,并阻止该按钮事件的冒泡;
《5》非编辑状态时,可以移动按钮,原理是设置该按钮的定位为绝对定位,并用一个空白按钮放在该按钮的DOM后起到占位作用,并设置该按钮可移动;
《6》由于代码本身写的并不是很好,因此移动状态被取消时,计算移动距离,如果没有位移偏差,且非编辑状态,触发该按钮的点击事件;(如果要写的好的话,该按钮的移动状态设置,应该在移动位置有偏差之后才设置position为绝对定位);
《7》移动时触发一个InMyToolDomMoving方法,这个要被runAfter方法所监视,返回值是空白dom和鼠标移动时触发的event事件。该事件会决定该按钮和其他按钮的互动;
《8》移动结束后,会触发一个InMyToolDomEndMoving方法,该方法同样被监视。并且设置移动结束后的鼠标弹起事件(同移动中的那个)。
《9》移动结束后,把图标放在占位图标之前(注意,该占位图标的位置可能移动),并解除移动状态,取消绝对定位,移除占位图标;
【4】然后是我的工具的大图标的移动中事件:
this.InMyToolDomEndMoving = function () { if (!SmallToolDom) { SmallToolDom = createSmallTool(); //setMyToolClickEvent(SmallToolDom); editButtonInSmallToolDom = SmallToolDom.find(".edit-img"); setSmallEditEvent(editButtonInSmallToolDom); setSmallToolDomMoveEvent(); } return SmallToolDom; };
他会返回小图标,如果没有小图标则创建,并为他绑定事件。
绑定事件有:
《1》点击事件(整合进移动相关函数);
《2》编辑按钮点击事件:
// 设置小的dom的编辑按钮的点击事件 var setSmallEditEvent = function (editNode) { editNode.click(function (event) { self.removeSmallTool(); editButtonInSmallToolDom.addClass("displayNONE"); SmallToolDom.detach(); event.stopPropagation(); }) };
《3》移动事件;
var setSmallToolDomMoveEvent = function () { var mouseX = null; var mouseY = null; var startLeft = null; var startTop = null; var placeHholderDom = $('<div class="tool-foot placeholder SmallToolHolder">' + '<div class="placeholder-img"></div>' + '<div class="text">拖拽到此</div>' + '</div>'); SmallToolDom.mousedown(function (evt) { if (evt.button != 0) { return; } if (editing & $(evt.target)[0] == editButtonInSmallToolDom[0]) { event.stopPropagation(); return; } mouseX = evt.clientX; //这里的值是鼠标坐标 mouseY = evt.clientY; var position = SmallToolDom.position(); startLeft = position.left; //没有px startTop = position.top; SmallToolDom.css("position", "absolute"); SmallToolDom.css("left", startLeft + "px"); SmallToolDom.css("top", startTop + "px"); SmallToolDom.after(placeHholderDom); SmallIconMove = true; if ($(".SmallToolHolder").length > 1) { $(".SmallToolHolder")[1].remove(); } }); $(".toolbox-my").mousemove(function (evt) { if (!evt.buttons & SmallIconMove) { //只有不在按,且当前是true的时候,才触发 SmallIconMove = false; placeHholderDom.before(SmallToolDom); placeHholderDom.remove(); SmallToolDom.css("position", "relative"); SmallToolDom.css("left", "0"); SmallToolDom.css("top", "0"); $(".SmallToolHolder").remove(); if (mouseX == evt.clientX & mouseY == evt.clientY) { if (!editing) { DomClickEvent(); } } } if (SmallIconMove) { self.SmallToolDomMoving([placeHholderDom, evt]); var offsetX = evt.clientX - mouseX; var offsetY = evt.clientY - mouseY; SmallToolDom.css("left", offsetX + startLeft + "px"); SmallToolDom.css("top", offsetY + startTop + "px"); if ($(".SmallToolHolder").length > 1) { $(".SmallToolHolder")[1].remove(); } } }); SmallToolDom.mouseup(function (evt) { if (SmallIconMove) { SmallIconMove = false; placeHholderDom.before(SmallToolDom); placeHholderDom.remove(); SmallToolDom.css("position", "relative"); SmallToolDom.css("left", "0"); SmallToolDom.css("top", "0"); $(".SmallToolHolder").remove(); if (mouseX == evt.clientX & mouseY == evt.clientY) { if (!editing) { DomClickEvent(); } } } }) }
由于和大图标的移动按钮事件类似,就不细说了
总之,他在移动的时候,会触发一个SmallToolDomMoving方法,runAfter会监视他。
【5】下来是两个按钮移动时触发的事件和移动结束后触发的事件:
//移动时会触发这个方法 this.InMyToolDomMoving = function (arr) { return arr; }; this.InMyToolDomEndMoving = function () { if (!SmallToolDom) { SmallToolDom = createSmallTool(); //setMyToolClickEvent(SmallToolDom); editButtonInSmallToolDom = SmallToolDom.find(".edit-img"); setSmallEditEvent(editButtonInSmallToolDom); setSmallToolDomMoveEvent(); } return SmallToolDom; }; this.SmallToolDomMoving = function (arr) { return arr; };
⑤其他事件:
//设置编辑或者结束编辑 this.setEditing = function () { editing = true; editButtonInMyToolDom ? editButtonInMyToolDom.removeClass("displayNONE") : ""; editButtonInSmallToolDom ? editButtonInSmallToolDom.removeClass("displayNONE") : ""; }; this.cancelEditing = function () { editing = false; editButtonInMyToolDom.addClass("displayNONE"); editButtonInSmallToolDom ? editButtonInSmallToolDom.addClass("displayNONE") : ""; } //设置dom为未添加状态 this.setStateToUnadd = function () { addButton.removeClass("displayNONE"); editButtonInMyToolDom.addClass("displayNONE"); if (editButtonInSmallToolDom) { editButtonInSmallToolDom.addClass("displayNONE"); } state = 0; //设置其状态为未添加 }
编辑状态的两个方法用于设置可编辑或者不可编辑;
另一个用于在删除按钮时调用;
——————————————————————————
重写ToolsConfigJsonLoad函数:
这个函数做了这些事情:
①读取json;
②把json转化为Tool类的数据来源;
③创建Tool类实例,并监听其事件;
④在创建图标的时候,添加分割线、或者创建占位图标等;
声明这个函数:
var ToolsConfigJsonLoad = function (InMyToolArray, url) { this.url = url ? url : "data/tools.json";
这个函数只有一个公有方法,那就是读取json:
this.load = function () { var self = this; $.ajax({ url: self.url, dataType: "json", type: "GET", success: function (data) { addToolsInToolbox_all(data); } }) };
读取json成功之后调用的函数:
//将内容添加到全部工具页面中 var addToolsInToolbox_all = function (data) { var type = []; data[0].BigImg.forEach(function (obj) { var tool = new Tool(obj); var mixin = new MixinTool(obj); var callback = mixin.mixin() listenToolEvent(tool); $(".firstRow").append(tool.createBigImgDom(callback)); }) data[0].CommonImg.forEach(function (obj) { if (type.indexOf(obj.type) < 0) { type.push(obj.type); } var tool = new Tool(obj); var mixin = new MixinTool(obj); var callback = mixin.mixin() listenToolEvent(tool); $(".commonRow." + obj.type).append(tool.createNormalToolDom(callback)); }) addPlaceHolderWhenOnlyTwoToolsInToolbox_All(type); addDottedLineInToolbox_All(); };
监听事件先略过;
添加分割线:
// 这个目的是为了给全部工具中的多行工具之间添加分割线 var addDottedLineInToolbox_All = function () { $(".commonRow .normalTool:nth-child(3n+4)").before('<div class="dotted"></div>'); };
为保证美观,添加占位图标:
// 这个目的是当某一行只有两个图标时,创造一个占位的图标 var addPlaceHolderWhenOnlyTwoToolsInToolbox_All = function (type) { type.forEach(function (obj) { var length = $(".commonRow." + obj + " > *").length; if (length % 3 == 2) { $(".commonRow." + obj).append($('<div class="normalToolHolder" style="cursor:default"></div>')); } }) };
下来事件监听函数的原型:
//参数1是对象,参数2是方法名(字符串),参数三是该方法执行后执行的函数 var runAfter = function (obj, runEvent, AfterEvent) { var temp = obj[runEvent]; obj[runEvent] = function (arguments) { var result = temp(arguments); AfterEvent(obj, result); } }
类似dojo的aspect.after方法
最后是利用runAfter函数进行事件监听,调用它时只需要传递Tool类的实例。
//监听事件 var listenToolEvent = function (tool) {
他包含以下方法:
①当图标添加进我的工具时,将实例添加到一个数组中:
runAfter(tool, "addDomToMyTools", function () { InMyToolArray.push(tool); });
②或者是删除我的工具里的按钮时,移除这个实例:
runAfter(tool, "setStateToUnadd", function () { var MyToolIndex = InMyToolArray.indexOf(tool); InMyToolArray.splice(MyToolIndex, 1); });
</pre><p>③还需要一个占位图标,用于图标在移动时占位:</p><pre name="code" class="javascript">var placeHolderInSmall = $('<div class="tool-foot placeholder">' + '<div class="placeholder-img"></div>' + '<div class="text">拖拽到此</div>' + '</div>')
④监听图标移动时的方法,他涉及到我的工具页面里大图标的互动,和快捷入口小图标的互动:
runAfter(tool, "InMyToolDomMoving", function (obj, result) { var placeHolder = result[0]; var event = result[1]; InMyToolArray.forEach(function (tool) { var node = tool.getDomInMyTools(); if (node.css("position") !== "absolute") { var position = node.offset(); //获取相对于文档的位置 if (event.clientY > position.top & event.clientY < position.top + 100 & event.clientX > position.left & event.clientX < position.left + 100) { if (node.index() < placeHolder.index()) { //根据索引决定放在前还是后面 node.before(placeHolder); } else { node.after(placeHolder); } } } }); var theNodeInSmallTools = false; //是否重合 $(".tool-foot").toArray().forEach(function (node, index) { var position = $(node).offset(); //获取相对于文档的位置 if (event.clientY > position.top & event.clientY < position.top + 70 & event.clientX > position.left & event.clientX < position.left + 76) { theNodeInSmallTools = true; if ($(node) != placeHolderInSmall) { $(node).before(placeHolderInSmall); } } }); //如果重合 if (theNodeInSmallTools) { $(".shortcut .tool-foot:last-child").addClass("displayNONE"); } //如果不重合 else { placeHolderInSmall.remove(); $(".shortcut .tool-foot.displayNONE").removeClass("displayNONE"); } });
</pre><p>⑤当图标停止移动时,需要决定他是否被移动到一个新位置,或者是添加到快捷入口那里;</p><pre name="code" class="javascript">runAfter(tool, "InMyToolDomEndMoving", function (obj, node) { var sign = false; $(".tool-foot").toArray().forEach(function (node, index) { if ($(node)[0] == placeHolderInSmall[0]) { sign = true; } }) if (sign) { if (node.hasClass("displayNONE")) { node.removeClass("displayNONE"); } placeHolderInSmall.before(node); placeHolderInSmall.remove(); } if ($(".tool-foot").length < 4) { var temp = '<div class="tool-foot placeholder">' + '<div class="placeholder-img"></div>' + '<div class="text">拖拽到此</div>' + '</div>'; $(".shortcut").append(temp); } else if ($(".tool-foot").length > 4) { $(".tool-foot")[4].remove(); //移除第五个 } else { $(".tool-foot.displayNONE").removeClass("displayNONE"); } $(".shortcut").append($(".tool-foot.placeholder")); }) ⑥还有小图标移动时,需要和小图标互动,例如可能需要交换位置: runAfter(tool, "SmallToolDomMoving", function (obj, result) { var placeHolder = result[0]; var event = result[1]; $(".tool-foot").toArray().forEach(function (node) { var position = $(node).offset(); //获取相对于文档的位置 if ($(node).css("position") !== "absolute") { if (event.clientY > position.top & event.clientY < position.top + 70 & event.clientX > position.left & event.clientX < position.left + 76) { if ($(node).index() < placeHolder.index()) { //根据索引决定放在前还是后面 $(node).before(placeHolder); } else { $(node).after(placeHolder); } } } }); });
——————————————————————
让工具箱运行起来:
以上代码,只涉及到工具箱页面各个图标的交互逻辑,但是并没有真正运行起来(例如,没有显式调用load()方法),并且也没有编辑图标的逻辑。
因此,我们需要一个函数补全剩下的部分:
var ToolBoxEvent = function () { var InMyToolArray = []; var jsonLoad = new ToolsConfigJsonLoad(InMyToolArray); jsonLoad.load(); $("#edit").click(function () { //编辑中 if ($(this).hasClass("editing")) { InMyToolArray.forEach(function (item) { item.cancelEditing(); }) //设置编辑按钮的样式变更 $(this).removeClass("editing"); var text = $(this).find(".text"); text.text("编辑"); text.css("width", "32px"); text.css("margin-left", "0px"); } else { InMyToolArray.forEach(function (item) { item.setEditing(); }) //设置编辑按钮的样式变更 $(this).addClass("editing"); var text = $(this).find(".text"); text.text("退出编辑"); text.css("width", "52px"); text.css("margin-left", "-10px"); } }); }
这个函数干了两件事:
①声明一个ToolsConfigJsonLoad类的实例,并调用它的load方法(加载工具箱);
②设置编辑按钮的事件。
这样的话,工具箱就可以正常跑起来了。
当然,还有一些小BUG,需要被修复,不过这并不影响整体功能的运转,作为一个DEMO来说,程度是足够了,如果真要跑生产环境,那么这些BUG必须被fix
js全部代码:
http://jianwangsan.cn/javascripts/toolboxes.js
css全部代码:
http://jianwangsan.cn/stylesheets/toolboxes.css