因业务需要,只能动手来研究一个拖拽模块。研究之前觉得很简单,在我印象里好想类似的 Vue,jQuery 的插件非常多。应该是分分钟就可以搞定。结果花了很长的时间来研究这个玩意。现在把思路记下来方便下次查阅。
- 创建拖拽对象
- 确定“接受拖拽对象的”区域
- 新建一个类,用于实现 ExtJS 中关于 “拖拽” 方法的实现
- 使用新编写带有实现的类应用到拖拽对象中
- 编写CSS来提升用户体验
- 拖拽结束之后的节点复制和移动
基本上就是上述的几个步骤,为了方便查阅我把所有的脚本都构建在一个 JS 文件中,若真用到项目中,请严格按照 Sencha ExtJS 的 MVC 标准做代码的分离。代码如下:
/*
* author: liucan
* email: [email protected]
* description: 系统顶部模块
*/
// 在这里需要重写拖拽的方法,基础的 API 并没有基于业务的实现。
// 拖拽完成,必须要判定是否拖放在指定的区域中,并且长宽要一致
// 对其当前的容器元素,TOP,LEFT 必须为 0
var overrides = {
startDrag: function () {
this.originalXY = this.el.getXY();
},
onDrag: function () {
this.el.addCls('item-draging');
},
onDragEnter: function (e, id) {
// console.log('onDragEnter');
if(id != this.el.dom.parentNode.id){
this.el.addCls('item-drag-ok');
}else{
this.onDragOut();
}
},
onDragOver: function (e, id) {
},
onDragOut: function (e, id) {
this.el.removeCls('item-drag-ok');
},
onDragDrop: function (e, id) {
},
onInvalidDrop: function () {
// 无效拖动,需要使用动画还原。
this.invalidDrop = true;
this.el.removeCls('item-draging');
},
endDrag: function (e, id) {
this.el.removeCls('item-draging');
if(this.invalidDrop === true){
// 无效的移动
var animCfgObj = {
easing: 'elasticOut',
duration: 1,
scope: this,
callback: function(){
this.el.dom.style.postion = '';
}
}
this.el.setXY(this.originalXY);
delete this.invalidDrop;
}else{
// 判定 TARGET 的值,并且做好磁力贴效果
// 复制节点到指定元素,删除原有节点
var newNode = this.el;
if(e.item){
e.item.firstChild.append(newNode.dom)
newNode.dom.style = "";
}
}
}
};
var pinyinTpl = new Ext.XTemplate(
'<div id="pinyin_panel" class="pinyin-panel">',
'<tpl for=".">',
'<div class="pinyin-item">{.}<div class="reset-this">x</div></div>',
'</tpl>',
'</div>'
);
var fontTpl = new Ext.XTemplate(
'<div class="font-panel">',
'<tpl for=".">',
'<div class="thumb-wrap">',
'<div class="thumb-pinyin"></div>',
'<div class="thumb-font">{.}</div>',
'</div>',
'</tpl>',
'<div style="clear: both"></div>',
'</div>'
);
Ext.define('xjcms.view.util.Pinyin', {
extend: 'Ext.window.Window',
alias: 'widget.Pinyin',
title: '生成拼音',
requires: [
'xjcms.view.util.pinyin.PinyinController',
'xjcms.view.util.pinyin.PinyinModel'
],
controller: {
type: 'pinyin'
},
viewModel: 'pinyin',
width: 600,
minHeight: 320,
layout: 'fit',
scrollable: false,
// 遮罩层
modal: true,
constrain: true,
closable: true,
autoDestroy: true,
draggable: true,
resizable: false,
items: [{
xtype: 'form',
bodyPadding: '10 10 10 10',
items: [{
xtype: 'container',
layout: 'hbox',
items: [{
xtype: 'textfield',
fieldLabel: '文字',
labelWidth: 60,
width: 500,
emptyText: '请输入文字',
regex: /^([\u4e00-\u9fa5]+)/,
regexText: '该输入框仅仅只支持输入汉字',
value: ''
}, {
xtype: 'button',
text: '生成拼音',
handler: function () {
// word-lib/convert2Pinyin
var text = this.prev().getValue();
var vm = this.up('window').getViewModel();
var vmStores = vm.storeInfo;
var fontData = [];
text = Ext.util.Format.trim(text);
// 请求数据
Ext.Ajax.request({
url: 'https://easy-mock.com/mock/5ae02d829c4a407f53115d81/rms/py',
method: 'GET',
params: {
font: text
},
success: function (response, opts) {
var obj = Ext.decode(response.responseText);
// 中文字和拼音字母
var font = obj.data.font;
var py = obj.data.py;
vmStores['fontStore'] = Ext.create('Ext.data.Store', {
data: font
});
vmStores['pinyinStore'] = Ext.create('Ext.data.Store', {
data: py
});
vm.setStores(vmStores);
},
failure: function (response, opts) {
console.log('server-side failure with status code ' + response.status);
}
});
}
}]
}, {
xtype: 'dataview',
tpl: pinyinTpl,
itemSelector: 'div.pinyin-item',
bind: {store: '{pinyinStore}'},
listeners: {
'refresh': function () {
var pinyins = Ext.select('.pinyin-item');
Ext.each(pinyins.elements, function (el) {
// 第一步,创建可拖动的元素
var dd = Ext.create('Ext.dd.DD', el, 'pyDDGroup', {
isTarget: false
});
Ext.apply(dd, overrides);
})
}
}
}, {
// 拼音的拖拽区域
xtype: 'dataview',
tpl: fontTpl,
bind: {store: '{fontStore}'},
itemSelector: 'div.thumb-wrap',
emptyText: '<div class="font-none-data">暂时还没有任何文字哦</div>',
listeners: {
'refresh': function () {
var thumbWrap = Ext.select('.thumb-wrap');
// 第二步,创建可以用于接收的元素
Ext.each(thumbWrap.elements, function (el) {
var thumbWrapDDTarget = Ext.create('Ext.dd.DDTarget', el, 'pyDDGroup', {
ignoreSelf: false
});
})
},
'itemclick': function(thisViewObj, record, item, index, e, eOpts){
var clsName = e.target.className;
if(clsName === 'reset-this'){
// 移除这个元素
var pNode = e.target.parentNode;
// console.dir(pNode);
Ext.get('pinyin_panel').appendChild(pNode);
}
}
}
}],
buttons: [{
xtype: 'button',
text: '确定'
}, {
xtype: 'button',
text: '取消',
handler: function () {
this.up('window').destroy();
}
}]
}]
});