带本地搜索功能的选择插件,效果图:

在使用selectfield的过程中,数据过大时,数据加载缓慢,没有模糊查询用户体验也不好,

在selectfield的基础上上稍作修改而成,使用方式同selectfield,代码:

 Ext.define('ux.field.Select', {
extend: 'Ext.field.Text',
xtype: 'uxSelectfield',
alternateClassName: 'ux.form.Select',
requires: [
'Ext.Panel',
'Ext.picker.Picker',
'Ext.data.Store',
'Ext.data.StoreManager',
'Ext.dataview.List'
], /**
* @event change
* Fires when an option selection has changed
* @param {Ext.field.Select} this
* @param {Mixed} newValue The new value
* @param {Mixed} oldValue The old value
*/ /**
* @event focus
* Fires when this field receives input focus. This happens both when you tap on the field and when you focus on the field by using
* 'next' or 'tab' on a keyboard.
*
* Please note that this event is not very reliable on Android. For example, if your Select field is second in your form panel,
* you cannot use the Next button to get to this select field. This functionality works as expected on iOS.
* @param {Ext.field.Select} this This field
* @param {Ext.event.Event} e
*/ config: {
/**
* @cfg
* @inheritdoc
*/
ui: 'select', /**
* @cfg {Boolean} useClearIcon
* @hide
*/ /**
* @cfg {String/Number} valueField The underlying {@link Ext.data.Field#name data value name} (or numeric Array index) to bind to this
* Select control.
* @accessor
*/
valueField: 'value', /**
* @cfg {String/Number} displayField The underlying {@link Ext.data.Field#name data value name} (or numeric Array index) to bind to this
* Select control. This resolved value is the visibly rendered value of the available selection options.
* @accessor
*/
displayField: 'text', /**
* @cfg {Ext.data.Store/Object/String} store The store to provide selection options data.
* Either a Store instance, configuration object or store ID.
* @accessor
*/
store: null, /**
* @cfg {Array} options An array of select options.
*
* [
* {text: 'First Option', value: 'first'},
* {text: 'Second Option', value: 'second'},
* {text: 'Third Option', value: 'third'}
* ]
*
* __Note:__ Option object member names should correspond with defined {@link #valueField valueField} and {@link #displayField displayField} values.
* This config will be ignored if a {@link #store store} instance is provided.
* @accessor
*/
options: null, /**
* @cfg {String} hiddenName Specify a `hiddenName` if you're using the {@link Ext.form.Panel#standardSubmit standardSubmit} option.
* This name will be used to post the underlying value of the select to the server.
* @accessor
*/
hiddenName: null, /**
* @cfg {Object} component
* @accessor
* @hide
*/
component: {
useMask: true
}, /**
* @cfg {Boolean} clearIcon
* @hide
* @accessor
*/
clearIcon: false, /**
* 请勿改动此配置
*/
usePicker: false, /**
* @cfg {Boolean} autoSelect
* `true` to auto select the first value in the {@link #store} or {@link #options} when they are changed. Only happens when
* the {@link #value} is set to `null`.
*/
autoSelect: true, /**
* @cfg {Object} defaultPhonePickerConfig
* The default configuration for the picker component when you are on a phone.
*/
defaultPhonePickerConfig: null, /**
* @cfg {Object} defaultTabletPickerConfig
* The default configuration for the picker component when you are on a tablet.
*/
defaultTabletPickerConfig: null, /**
* @cfg
* @inheritdoc
*/
name: 'picker', /**
* @cfg {String} pickerSlotAlign
* The alignment of text in the picker created by this Select
* @private
*/
pickerSlotAlign: 'center'
}, platformConfig: [
{
theme: ['Windows'],
pickerSlotAlign: 'left'
},
{
theme: ['Tizen'],
usePicker: false
}
], // @private
initialize: function () {
var me = this,
component = me.getComponent(); me.callParent(); component.on({
scope: me,
masktap: 'onMaskTap'
}); component.doMaskTap = Ext.emptyFn; if (Ext.browser.is.AndroidStock2) {
component.input.dom.disabled = true;
} if (Ext.theme.is.Blackberry) {
this.label.on({
scope: me,
tap: "onFocus"
});
}
}, getElementConfig: function () {
if (Ext.theme.is.Blackberry) {
var prefix = Ext.baseCSSPrefix; return {
reference: 'element',
className: 'x-container',
children: [
{
reference: 'innerElement',
cls: prefix + 'component-outer',
children: [
{
reference: 'label',
cls: prefix + 'form-label',
children: [{
reference: 'labelspan',
tag: 'span'
}]
}
]
}
]
};
} else {
return this.callParent(arguments);
}
}, /**
* @private
*/
updateDefaultPhonePickerConfig: function (newConfig) {
var picker = this.picker;
if (picker) {
picker.setConfig(newConfig);
}
}, /**
* @private
*/
updateDefaultTabletPickerConfig: function (newConfig) {
var listPanel = this.listPanel;
if (listPanel) {
listPanel.setConfig(newConfig);
}
}, /**
* @private
* Checks if the value is `auto`. If it is, it only uses the picker if the current device type
* is a phone.
*/
applyUsePicker: function (usePicker) {
if (usePicker == "auto") {
usePicker = (Ext.os.deviceType == 'Phone');
} return Boolean(usePicker);
}, syncEmptyCls: Ext.emptyFn, /**
* @private
*/
applyValue: function (value) {
var record = value,
index, store; //we call this so that the options configruation gets intiailized, so that a store exists, and we can
//find the correct value
this.getOptions(); store = this.getStore(); if ((value != undefined && !value.isModel) && store) {
index = store.find(this.getValueField(), value, null, null, null, true); if (index == -1) {
index = store.find(this.getDisplayField(), value, null, null, null, true);
} record = store.getAt(index);
} return record;
}, updateValue: function (newValue, oldValue) {
this.record = newValue;
this.callParent([(newValue && newValue.isModel) ? newValue.get(this.getDisplayField()) : '']);
}, getValue: function () {
var record = this.record;
return (record && record.isModel) ? record.get(this.getValueField()) : null;
}, /**
* Returns the current selected {@link Ext.data.Model record} instance selected in this field.
* @return {Ext.data.Model} the record.
*/
getRecord: function () {
return this.record;
}, // @private
getPhonePicker: function () {
var config = this.getDefaultPhonePickerConfig(); if (!this.picker) {
this.picker = Ext.create('Ext.picker.Picker', Ext.apply({
slots: [
{
align: this.getPickerSlotAlign(),
name: this.getName(),
valueField: this.getValueField(),
displayField: this.getDisplayField(),
value: this.getValue(),
store: this.getStore()
}
],
listeners: {
change: this.onPickerChange,
scope: this
}
}, config));
} return this.picker;
}, // @private
getTabletPicker: function () {
var config = this.getDefaultTabletPickerConfig(); if (!this.listPanel) {
this.listPanel = Ext.create('Ext.Panel', Ext.apply({
left: 0,
top: 0,
modal: true,
cls: Ext.baseCSSPrefix + 'select-overlay',
layout: 'fit',
hideOnMaskTap: true,
width: Ext.os.is.Phone ? '14em' : '18em',
height: (Ext.os.is.BlackBerry && Ext.os.version.getMajor() === 10) ? '12em' : (Ext.os.is.Phone ? '12.5em' : '22em'),
items: [{
xtype: 'toolbar',
docked: 'top',
items: [
//新增的搜索栏,用于支持模糊查询
{
xtype: 'searchfield',
placeHolder: '请输入关键词',
width:'100%',
clearIcon:false,
listeners: {
keyup: 'onSearch',
scope: this
}
}
]
}, {
xtype: 'list',
store: this.getStore(),
itemTpl: '<span class="x-list-label">{' + this.getDisplayField() + ':htmlEncode}</span>',
listeners: {
select: this.onListSelect,
itemtap: this.onListTap,
scope: this
}
}]
}, config));
} return this.listPanel;
},
//进行模糊查询
onSearchKeyUp: function (value) {
//得到数据仓库和搜索关键词
var store = this.getStore(); //如果是新的关键词,则清除过滤
store.clearFilter(!!value);
//检查值是否存在
if (value) {
//the user could have entered spaces, so we must split them so we can loop through them all
var key = this.getDisplayField(),
searches = value.split(','),
regexps = [],
//获取现实值的name
i, regex; //loop them all
for (i = 0; i < searches.length; i++) {
//if it is nothing, continue
if (!searches[i]) continue; regex = searches[i].trim();
regex = regex.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); //if found, create a new regular expression which is case insenstive
regexps.push(new RegExp(regex.trim(), 'i'));
} //now filter the store by passing a method
//the passed method will be called for each record in the store
store.filter(function (record) {
var matched = []; //loop through each of the regular expressions
for (i = 0; i < regexps.length; i++) {
var search = regexps[i],
didMatch = search.test(record.get(key)); //if it matched the first or last name, push it into the matches array
matched.push(didMatch);
} return (regexps.length && matched.indexOf(true) !== -1);
});
}
},
//进行模糊查询
onSearch: function (field) {
this.onSearchKeyUp(field.getValue());
},
// @private
onMaskTap: function () {
this.onFocus(); return false;
}, /**
* Shows the picker for the select field, whether that is a {@link Ext.picker.Picker} or a simple
* {@link Ext.List list}.
*/
showPicker: function () {
var me = this,
store = me.getStore(),
value = me.getValue(); //check if the store is empty, if it is, return
if (!store || store.getCount() === 0) {
return;
}
if (me.getReadOnly()) {
return;
}
me.isFocused = true; if (me.getUsePicker()) {
var picker = me.getPhonePicker(),
name = me.getName(),
pickerValue = {}; pickerValue[name] = value;
picker.setValue(pickerValue); if (!picker.getParent()) {
Ext.Viewport.add(picker);
} picker.show();
} else {
//先过滤一下避免加载过慢
var record = this.getRecord(),
text='请搜索';
if (record) {
text = record.get(this.getDisplayField());
}
this.onSearchKeyUp(text); var listPanel = me.getTabletPicker(),
list = listPanel.down('list'),
index, record; if (!listPanel.getParent()) {
Ext.Viewport.add(listPanel);
}
//为搜索栏赋值
listPanel.down('searchfield').setValue(text);
listPanel.showBy(me.getComponent(), null);
if (value || me.getAutoSelect()) {
store = list.getStore();
index = store.find(me.getValueField(), value, null, null, null, true);
record = store.getAt(index); if (record) {
list.select(record, null, true);
}
}
}
}, // @private
onListSelect: function (item, record) {
var me = this;
if (record) {
me.setValue(record);
}
}, onListTap: function () {
this.listPanel.hide({
type: 'fade',
out: true,
scope: this
});
}, // @private
onPickerChange: function (picker, value) {
var me = this,
newValue = value[me.getName()],
store = me.getStore(),
index = store.find(me.getValueField(), newValue, null, null, null, true),
record = store.getAt(index); me.setValue(record);
}, onChange: function (component, newValue, oldValue) {
var me = this,
store = me.getStore(),
index = (store) ? store.find(me.getDisplayField(), oldValue, null, null, null, true) : -1,
valueField = me.getValueField(),
record = (store) ? store.getAt(index) : null; oldValue = (record) ? record.get(valueField) : null; me.fireEvent('change', me, me.getValue(), oldValue);
}, /**
* Updates the underlying `<options>` list with new values.
*
* @param {Array} newOptions An array of options configurations to insert or append.
*
* selectBox.setOptions([
* {text: 'First Option', value: 'first'},
* {text: 'Second Option', value: 'second'},
* {text: 'Third Option', value: 'third'}
* ]).setValue('third');
*
* __Note:__ option object member names should correspond with defined {@link #valueField valueField} and
* {@link #displayField displayField} values.
*
* @return {Ext.field.Select} this
*/
updateOptions: function (newOptions) {
var store = this.getStore(); if (!store) {
this.setStore(true);
store = this._store;
} if (!newOptions) {
store.clearData();
}
else {
store.setData(newOptions);
this.onStoreDataChanged(store);
}
return this;
}, applyStore: function (store) {
if (store === true) {
store = Ext.create('Ext.data.Store', {
fields: [this.getValueField(), this.getDisplayField()],
autoDestroy: true
});
} if (store) {
store = Ext.data.StoreManager.lookup(store); store.on({
scope: this,
addrecords: 'onStoreDataChanged',
removerecords: 'onStoreDataChanged',
updaterecord: 'onStoreDataChanged',
refresh: 'onStoreDataChanged'
});
} return store;
}, updateStore: function (newStore) {
if (newStore) {
this.onStoreDataChanged(newStore);
} if (this.getUsePicker() && this.picker) {
this.picker.down('pickerslot').setStore(newStore);
} else if (this.listPanel) {
this.listPanel.down('dataview').setStore(newStore);
}
}, /**
* Called when the internal {@link #store}'s data has changed.
*/
onStoreDataChanged: function (store) {
var initialConfig = this.getInitialConfig(),
value = this.getValue(); if (value || value == 0) {
this.updateValue(this.applyValue(value));
} if (this.getValue() === null) {
if (initialConfig.hasOwnProperty('value')) {
this.setValue(initialConfig.value);
} if (this.getValue() === null && this.getAutoSelect()) {
if (store.getCount() > 0) {
this.setValue(store.getAt(0));
}
}
}
}, /**
* @private
*/
doSetDisabled: function (disabled) {
var component = this.getComponent();
if (component) {
component.setDisabled(disabled);
}
Ext.Component.prototype.doSetDisabled.apply(this, arguments);
}, /**
* @private
*/
setDisabled: function () {
Ext.Component.prototype.setDisabled.apply(this, arguments);
}, // @private
updateLabelWidth: function () {
if (Ext.theme.is.Blackberry) {
return;
} else {
this.callParent(arguments);
}
}, // @private
updateLabelAlign: function () {
if (Ext.theme.is.Blackberry) {
return;
} else {
this.callParent(arguments);
}
}, /**
* Resets the Select field to the value of the first record in the store.
* @return {Ext.field.Select} this
* @chainable
*/
reset: function () {
var me = this,
record; if (me.getAutoSelect()) {
var store = me.getStore(); record = (me.originalValue) ? me.originalValue : store.getAt(0);
} else {
var usePicker = me.getUsePicker(),
picker = usePicker ? me.picker : me.listPanel; if (picker) {
picker = picker.child(usePicker ? 'pickerslot' : 'dataview'); picker.deselectAll();
} record = null;
} me.setValue(record); return me;
}, onFocus: function (e) {
if (this.getDisabled()) {
return false;
}
var component = this.getComponent();
this.fireEvent('focus', this, e); if (Ext.os.is.Android4) {
component.input.dom.focus();
}
component.input.dom.blur(); this.isFocused = true; this.showPicker();
}, destroy: function () {
this.callParent(arguments);
var store = this.getStore(); if (store && store.getAutoDestroy()) {
Ext.destroy(store);
} Ext.destroy(this.listPanel, this.picker);
}
});

sencha touch 带本地搜索功能的selectfield(选择插件)的更多相关文章

  1. (转)Sencha Touch和jQuery Mobile的比较

    原文:http://extjs.org.cn/node/664 Sencha Touch和jQuery Mobile的比较 Posted 周三, 08/07/2013 - 10:07 by admin ...

  2. html5外包—长年承接html5外包业务:《Sencha Touch权威指南》下载

    <Sencha Touch权威指南>内容简介:如何才能全面而透彻地理解和掌握移动应用开发框架Sencha Touch并开发出令人心动的移动应用?<Sencha Touch权威指南&g ...

  3. Sencha Touch和jQuery Mobile的比较

    第一组-行销和平台支持 Sencha Touch和jQuery Mobile都以HTML5框架著称.jQuery Mobile谦虚的说自己只是内建于所有流行的移动设备平台,而Sencha Touch则 ...

  4. 基于jQuery带备忘录功能的日期选择器

    今天给大家分享一款基于jQuery带备忘录功能的日期选择器.这款日期控制带有备记忘录功能.有备忘录的日期有一个圆圈,单击圆圈显示备忘录.该实例适用浏览器:360.FireFox.Chrome.Safa ...

  5. 选择移动web开发框架研究——有mui、frozenui以及Sencha Touch等

    纯粹的总结一下移动web开发框架,移动 web开发框架有jQuery Mobile .Sencha Touch等等,他们都来源于web开发,是成熟的框架,jQuery Mobile出自于jQuery家 ...

  6. [Phonegap+Sencha Touch] 移动开发76 让cordova app訪问远端站点也能调用cordova插件功能

    原文链接:http://blog.csdn.net/lovelyelfpop/article/details/50735395 我相信.应该会有一些cordova开发人员想过实现以下这种app: 使用 ...

  7. sencha touch打包成安装程序

    为了更好地向大家演示如何打包一个sencha touch的项目,我们用sencha cmd创建一个演示项目,如果你的sencha cmd环境还没有配置,请参照 sencha touch 入门系列 (二 ...

  8. sencha touch 入门系列 (二)sencha touch 开发准备

    这是本人第一次写博客教程,没什么经验,文笔也不是很好,写这教程一方面为了巩固自己这段时间的学习成果,一方面帮助大家解决问题,欢迎大家多提建议,指出问题.接下来我们就开始我们的sencha touch开 ...

  9. sencha touch 开发准备

    这是本人第一次写博客教程,没什么经验,文笔也不是很好,写这教程一方面为了巩固自己这段时间的学习成果,一方面帮助大家解决问题,欢迎大家多提建议,指出问题.接下来我们就开始我们的sencha touch开 ...

随机推荐

  1. AngularJS中页面呈现html代码段

    如何在页面呈现一段html代码段呢? 在textarea中我们这样写: <textarea name="" id="" cols="30&quo ...

  2. AngularJS中介者模式实例

    在任何应用程序中,中介者模式随处可见. → 有一个事件源,触发事件,传递参数→ 中介者记下这个事件,向外界广播,并带上参赛→ 有一个地方侦听中介者事件,一旦事件源触发事件,就从中介者手里获取事件相关参 ...

  3. 移动端适配方案 flexible.js

    前言 移动端适配一直以来都是前端开发中不可或缺的重要组成部分,如果没有了它,那么你做出来的页面极有可能会出现各种意外(写出来的页面与设计稿之间的差别).所有我们得找到一种相对来说让人比较满意的解决方案 ...

  4. 9.7 dubbo心跳机制

    dubbo的心跳机制: 目的:检测provider与consumer之间的connection连接是不是还连接着,如果连接断了,需要作出相应的处理. 原理: provider:dubbo的心跳默认是在 ...

  5. windows 系统中的 afd 驱动

    afd 的全称是 Ancillary Function Driver for WinSock,是 windows 系统网络部分的核心工具.同 Linux 类似,windows 的 socket 最终也 ...

  6. Long polling failed, will retry in 16 seconds. appId: zeus-guard, cluster: default, namespaces: application, long polling url: null, reason: Get config services failed from···

    当dubbo应用启动之前, 如果apollo 未启动好,那么我们dubbo应用会一直等待,直到apollo准备就绪,注意其中轮询时间是从1,2,3,4,8,14,32, 方式一直增长,单位是s.

  7. 海量数据拆分到nosql系统的一种方案

    获取某用户的好友最新动态. 我们大体上来说先按照用户ID将用户的好友一致性哈希到几个mongodb集群,然后把用户的最新信息也存储到mongodb中.然后利用消息系统保持数据库中的数据和mongdb中 ...

  8. 【Android】Android的进程优先级

    android对于所有进程的处理态度都是尽可能不杀死.然而,资源总共就那么多,要是对所有进程都保持宽容的话,资源总会有消耗殆尽的时候.因此,在内存不足的情况,android系统需要根据一定的策略,选择 ...

  9. Android UI系列-----LinearLayout的综合使用

    这里将会对LinearLayout的布局方式进行一个综合的使用,通过一个例子来看看LinearLayout的嵌套布局方式,在这之前首先介绍三个属性: 1.①android:layout_weigth: ...

  10. VSCode配置TypeScript

    网上教程一堆,记录下我认为的关键点: 1.创建tsconfig.json,使用命令行在项目文件夹下输入“tsc --init”即可: 2.创建tasks.json,在VSCode中,使用ctrl+sh ...