我是靠谱客的博主 刻苦啤酒,最近开发中收集的这篇文章主要介绍微博@输入功能的ExtJS实现,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

微博的@辅助输入功能具有方便快捷的特点,基础功能描述为:

  • 1.在TextArea内输入“@”时,在光标处弹出选项列表。
  • 2.通过键盘或者鼠标选择选项,文本插入到textArea。

 

人肉相关文章之后才知道:在非ie浏览器下,获得TextArea的光标位置不是一件容易的事情!

目前大家常用的实现思路是:采用一个屏幕外的div模拟TextArea,通用地插入内容,通过div内光标位置来获得textarea内的光标位置。

这篇文章有详细的叙述:

http://yiminghe.iteye.com/blog/1482102

 

具体技术实现,jquery的找到一些,比如这篇文章:

http://lecoding.com/articles/316.html。

 

extjs下的实现则几乎没找到,只找到这一篇:

http://www.rahulsingla.com/blog/2010/12/extjs-re-usable-dropdownlist-for-any-form-field

作者是在ext3.1下实现的,对于这个实现我不甚满意:

  • 1.用DataView不是好选择

  简单的选项可以用Menu,复杂的用ListView,没必要去折腾DataView+Layer组合。

  即这个自定义派生类是不必要的。

  

  • 2.该实现并没有完善对有无弹出菜单两种情形下,对键盘事件的处理,连回车键录入都不能支持。

 

没办法,自己造轮子吧!

综合上述文章,实现思路如下:

  • 1.派生ExtJS的TextArea,实现支持@输入功能的增强版TextArea。
  • 2.采用ListView(GridPanel)作为弹出菜单,因为它已经支持showAt方法,可以在指定坐标显示。
  • 3.采用离屏div获得textarea内的光标坐标。
  • 4.为了处理菜单可见/隐藏 两种状态下的键盘事件,结合了extjs的三种键盘处理机制:

  listener: "specialkey" "keyup",

  以及Ext.KeyNav。

  原因是:前两种无法接管“回车”键,而第三种在接管之后,我没有找到何时的方法,将键盘消息传递回textarea,获得相同的效果

  (试了fireEvent,没成功。)

  

  • 5.关键点:通过程序语句选择菜单项时 XXX.getSelectionModel().select(0,true,true);

  后两个参数必须加上——阻止触发相关event,否则存在性能问题——响应严重延迟。

  

  • 6.代码采用ExtJS4.2,在chromefirefox下测试通过。

完整代码如下:

 

Ext.define('Ext.form.TA', {
extend: 'Ext.form.TextArea',
config: {
enableKeyEvents:true,
listeners:{
'specialkey': function(field, e){
this.onKey(e);
},
'keyup':function(ta,e,opt){
var me=this;
switch(e.keyCode){
case 50:
me.showMenu();
break;
}
}
}
},
showMenu:function(){
var ta = this;
var pos = ta.inputEl.dom.selectionStart;
var txt = ta.getRawValue( ).substring(0,pos);
var p0 = ta.getXY();
var x = p0[0]+ta.getDivWidth(txt);
var y = p0[1]+ta.getDivHeight(txt);
//contactsDropDown.bindElement(ta.el);
var mnu = this.mnu;
mnu.showAt([x,y]);
mnu.getSelectionModel().select(0,true,true);
this.focus();
},
hideMenu:function(){
this.mnu.hide();
},
constructor: function (config) {
config.width =config.width||400;
config.height =config.height||200;
this.callParent(arguments);
},
getDivHeight:function(text){
this.heightDiv.setHTML(text.replace(/n/g, '<br/>'));
return this.heightDiv.getHeight() + 10;
},
getDivWidth:function(text){
var h = this.getDivHeight('x');
var olen = this.getDivHeight(text);
if (h != olen) {
for (var i = 0; i < text.length; ++i) {
var s = text.substr(0, text.length - i);
var len = this.getDivHeight(s);
if (len != olen) {
text = text.substr(text.length - i);
break;
}
}
}
this.widthDiv.setHTML(text);
return this.widthDiv.getWidth();
},
buildMenu:function(){
var me=this;
me.ds = Ext.create('Ext.data.Store', {
storeId:'simpsonsStore',
fields:['name', 'email', 'phone'],
data:{'items':[
{ 'name': 'Lisa',
"email":"lisa@simpsons.com",
"phone":"555-111-1224"
},
{ 'name': 'Bart',
"email":"bart@simpsons.com",
"phone":"555-222-1234" },
{ 'name': 'Homer', "email":"home@simpsons.com",
"phone":"555-222-1244"
},
{ 'name': 'Marge', "email":"marge@simpsons.com", "phone":"555-222-1254"
}
]},
proxy: {
type: 'memory',
reader: {
type: 'json',
root: 'items'
}
}
});
me.mnu=Ext.create('Ext.grid.Panel', {
floating:true,
//title: 'Simpsons',
selModel: 'SINGLE',
store: Ext.data.StoreManager.lookup('simpsonsStore'),
columns: [
{ text: 'Name',
dataIndex: 'name' },
{ text: 'Email', dataIndex: 'email', flex: 1 },
{ text: 'Phone', dataIndex: 'phone' }
],
height: 200,
width: 400
});
me.mnu.on("itemclick",function(gd, record, item, index, e, eOpts ){
me.onSelOk();
});
},
insertText:function(val){
var value=val=='rn'?val:val+' ';
var ta = this.inputEl.dom;
var oriValue = this.getValue();
var pos_start = ta.selectionStart;
this.setValue(oriValue.substring(0,ta.selectionStart) + value + oriValue.substring(ta.selectionEnd));
//ta.setValue(oriValue.toString() + value );
ta.selectionStart = pos_start+value.length;
ta.selectionEnd = ta.selectionStart;
//this.focus();
},
onSelOk:function(){
var sel = this.mnu.getSelectionModel();
var si = sel.getSelection();
if(!si || si.length==0)
return;
this.insertText(si[0].data['name']);
this.hideMenu();
},
onKey: function(e){
if(!this.mnu.isVisible()){
if(e.getKey()==e.ENTER){
this.insertText('rn');
}
return;
}
e.stopEvent();
// e.HOME, e.END, e.PAGE_UP, e.PAGE_DOWN,
// e.TAB, e.ESC, arrow keys: e.LEFT, e.RIGHT, e.UP, e.DOWN
var sel = this.mnu.getSelectionModel();
var si = sel.getSelection();
var pos = 0;
if(si && si.length>0){
pos = si[0].index;
}
var mnu = this.mnu;
switch(e.getKey()){
case e.DOWN:
pos++
if(pos>=this.ds.getCount())
pos=0;
this.mnu.getSelectionModel().select(pos,true,true);
break;
case e.UP:
pos--;
if(pos<0)
pos=this.ds.getCount()-1;
this.mnu.getSelectionModel().select(pos,true,true);
break;
case e.ESC:
this.hideMenu();
break;
case e.ENTER:
this.onSelOk();
break;
}
//this.focus();
},
buildKey:function(){
this.keyNav = new Ext.KeyNav(this.inputEl, {
"enter": function(e) {
console.log('enter');
this.onKey(e);
},
"esc": function(e) {
console.log('esc');
this.onKey(e);
},
"tab": function(e) {
console.log('tab');
this.onKey(e);
},
scope: this
});
},
onRender: function () {
this.callParent();
this.heightDiv = Ext.DomHelper.append(document.body,{tag:'div',id:'height_div',style:'visibility:hidden;position:absolute;z-index:10000;top:0px;left:3000px;word-break:break-all;word-wrap:break-word'},true);
this.heightDiv.setWidth(this.getWidth());
this.heightDiv.setStyle('font-size',this.inputEl.getStyle('font-size'));
this.widthDiv = Ext.DomHelper.append(document.body,{tag:'div',id:'width_div',style:'visibility:hidden;position:absolute;z-index:10000;top:0px;left:3000px;'},true);
this.widthDiv.setHeight(this.getHeight());
this.widthDiv.setStyle('font-size',this.inputEl.getStyle('font-size'));
this.buildMenu();
this.buildKey();
}
});

 

附@弹出效果截图:

 

 

  

最后

以上就是刻苦啤酒为你收集整理的微博@输入功能的ExtJS实现的全部内容,希望文章能够帮你解决微博@输入功能的ExtJS实现所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(79)

评论列表共有 0 条评论

立即
投稿
返回
顶部