jquery.cxselect.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  1. /*!
  2. * jQuery cxSelect
  3. * @name jquery.cxselect.js
  4. * @version 1.4.1
  5. * @date 2016-11-02
  6. * @author ciaoca
  7. * @email ciaoca@gmail.com
  8. * @site https://github.com/ciaoca/cxSelect
  9. * @license Released under the MIT license
  10. */
  11. (function(factory) {
  12. if (typeof define === 'function' && define.amd) {
  13. define(['jquery'], factory);
  14. } else {
  15. factory(window.jQuery || window.Zepto || window.$);
  16. };
  17. }(function($) {
  18. var cxSelect = function() {
  19. var self = this;
  20. var dom, settings, callback;
  21. // 分配参数
  22. for (var i = 0, l = arguments.length; i < l; i++) {
  23. if (cxSelect.isJquery(arguments[i]) || cxSelect.isZepto(arguments[i])) {
  24. dom = arguments[i];
  25. } else if (cxSelect.isElement(arguments[i])) {
  26. dom = $(arguments[i]);
  27. } else if (typeof arguments[i] === 'function') {
  28. callback = arguments[i];
  29. } else if (typeof arguments[i] === 'object') {
  30. settings = arguments[i];
  31. };
  32. };
  33. var api = new cxSelect.init(dom, settings);
  34. if (typeof callback === 'function') {
  35. callback(api);
  36. };
  37. return api;
  38. };
  39. cxSelect.isElement = function(o){
  40. if (o && (typeof HTMLElement === 'function' || typeof HTMLElement === 'object') && o instanceof HTMLElement) {
  41. return true;
  42. } else {
  43. return (o && o.nodeType && o.nodeType === 1) ? true : false;
  44. };
  45. };
  46. cxSelect.isJquery = function(o){
  47. return (o && o.length && (typeof jQuery === 'function' || typeof jQuery === 'object') && o instanceof jQuery) ? true : false;
  48. };
  49. cxSelect.isZepto = function(o){
  50. return (o && o.length && (typeof Zepto === 'function' || typeof Zepto === 'object') && Zepto.zepto.isZ(o)) ? true : false;
  51. };
  52. cxSelect.getIndex = function(n, required) {
  53. return required ? n : n - 1;
  54. };
  55. cxSelect.getData = function(data, space) {
  56. if (typeof space === 'string' && space.length) {
  57. space = space.split('.');
  58. for (var i = 0, l = space.length; i < l; i++) {
  59. data = data[space[i]];
  60. };
  61. };
  62. return data;
  63. };
  64. cxSelect.init = function(dom, settings) {
  65. var self = this;
  66. if (!cxSelect.isJquery(dom) && !cxSelect.isZepto(dom)) {return};
  67. var theSelect = {
  68. dom: {
  69. box: dom
  70. }
  71. };
  72. self.attach = cxSelect.attach.bind(theSelect);
  73. self.detach = cxSelect.detach.bind(theSelect);
  74. self.setOptions = cxSelect.setOptions.bind(theSelect);
  75. self.clear = cxSelect.clear.bind(theSelect);
  76. theSelect.changeEvent = function() {
  77. cxSelect.selectChange.call(theSelect, this.className);
  78. };
  79. theSelect.settings = $.extend({}, $.cxSelect.defaults, settings, {
  80. url: theSelect.dom.box.data('url'),
  81. emptyStyle: theSelect.dom.box.data('emptyStyle'),
  82. required: theSelect.dom.box.data('required'),
  83. firstTitle: theSelect.dom.box.data('firstTitle'),
  84. firstValue: theSelect.dom.box.data('firstValue'),
  85. jsonSpace: theSelect.dom.box.data('jsonSpace'),
  86. jsonName: theSelect.dom.box.data('jsonName'),
  87. jsonValue: theSelect.dom.box.data('jsonValue'),
  88. jsonSub: theSelect.dom.box.data('jsonSub')
  89. });
  90. var _dataSelects = theSelect.dom.box.data('selects');
  91. if (typeof _dataSelects === 'string' && _dataSelects.length) {
  92. theSelect.settings.selects = _dataSelects.split(',');
  93. };
  94. self.setOptions();
  95. self.attach();
  96. // 使用独立接口获取数据
  97. if (!theSelect.settings.url && !theSelect.settings.data) {
  98. cxSelect.start.apply(theSelect);
  99. // 设置自定义数据
  100. } else if ($.isArray(theSelect.settings.data)) {
  101. cxSelect.start.call(theSelect, theSelect.settings.data);
  102. // 设置 URL,通过 Ajax 获取数据
  103. } else if (typeof theSelect.settings.url === 'string' && theSelect.settings.url.length) {
  104. $.getJSON(theSelect.settings.url, function(json) {
  105. cxSelect.start.call(theSelect, json);
  106. });
  107. };
  108. };
  109. // 设置参数
  110. cxSelect.setOptions = function(opts) {
  111. var self = this;
  112. if (opts) {
  113. $.extend(self.settings, opts);
  114. };
  115. // 初次或重设选择器组
  116. if (!$.isArray(self.selectArray) || !self.selectArray.length || (opts && opts.selects)) {
  117. self.selectArray = [];
  118. if ($.isArray(self.settings.selects) && self.settings.selects.length) {
  119. var _tempSelect;
  120. for (var i = 0, l = self.settings.selects.length; i < l; i++) {
  121. _tempSelect = self.dom.box.find('select.' + self.settings.selects[i]);
  122. if (!_tempSelect || !_tempSelect.length) {break};
  123. self.selectArray.push(_tempSelect);
  124. };
  125. };
  126. };
  127. if (opts) {
  128. if (!$.isArray(opts.data) && typeof opts.url === 'string' && opts.url.length) {
  129. $.getJSON(self.settings.url, function(json) {
  130. cxSelect.start.call(self, json);
  131. });
  132. } else {
  133. cxSelect.start.call(self, opts.data);
  134. };
  135. };
  136. };
  137. // 绑定
  138. cxSelect.attach = function() {
  139. var self = this;
  140. if (!self.attachStatus) {
  141. self.dom.box.on('change', 'select', self.changeEvent);
  142. };
  143. if (typeof self.attachStatus === 'boolean') {
  144. cxSelect.start.call(self);
  145. };
  146. self.attachStatus = true;
  147. };
  148. // 移除绑定
  149. cxSelect.detach = function() {
  150. var self = this;
  151. self.dom.box.off('change', 'select', self.changeEvent);
  152. self.attachStatus = false;
  153. };
  154. // 清空选项
  155. cxSelect.clear = function(index) {
  156. var self = this;
  157. var _style = {
  158. display: '',
  159. visibility: ''
  160. };
  161. index = isNaN(index) ? 0 : index;
  162. // 清空后面的 select
  163. for (var i = index, l = self.selectArray.length; i < l; i++) {
  164. self.selectArray[i].empty().prop('disabled', true);
  165. if (self.settings.emptyStyle === 'none') {
  166. _style.display = 'none';
  167. } else if (self.settings.emptyStyle === 'hidden') {
  168. _style.visibility = 'hidden';
  169. };
  170. self.selectArray[i].css(_style);
  171. };
  172. };
  173. cxSelect.start = function(data) {
  174. var self = this;
  175. if ($.isArray(data)) {
  176. self.settings.data = cxSelect.getData(data, self.settings.jsonSpace);
  177. };
  178. if (!self.selectArray.length) {return};
  179. // 保存默认值
  180. for (var i = 0, l = self.selectArray.length; i < l; i++) {
  181. if (typeof self.selectArray[i].attr('data-value') !== 'string' && self.selectArray[i][0].options.length) {
  182. self.selectArray[i].attr('data-value', self.selectArray[i].val());
  183. };
  184. };
  185. if (self.settings.data || (typeof self.selectArray[0].data('url') === 'string' && self.selectArray[0].data('url').length)) {
  186. cxSelect.getOptionData.call(self, 0);
  187. } else {
  188. self.selectArray[0].prop('disabled', false).css({
  189. 'display': '',
  190. 'visibility': ''
  191. });
  192. };
  193. };
  194. // 获取选项数据
  195. cxSelect.getOptionData = function(index) {
  196. var self = this;
  197. if (typeof index !== 'number' || isNaN(index) || index < 0 || index >= self.selectArray.length) {return};
  198. var _indexPrev = index - 1;
  199. var _select = self.selectArray[index];
  200. var _selectData;
  201. var _valueIndex;
  202. var _dataUrl = _select.data('url');
  203. var _jsonSpace = typeof _select.data('jsonSpace') === 'undefined' ? self.settings.jsonSpace : _select.data('jsonSpace');
  204. var _query = {};
  205. var _queryName;
  206. var _selectName;
  207. var _selectValue;
  208. cxSelect.clear.call(self, index);
  209. // 使用独立接口
  210. if (typeof _dataUrl === 'string' && _dataUrl.length) {
  211. if (index > 0) {
  212. for (var i = 0, j = 1; i < index; i++, j++) {
  213. _queryName = self.selectArray[j].data('queryName');
  214. _selectName = self.selectArray[i].attr('name');
  215. _selectValue = self.selectArray[i].val();
  216. if (typeof _queryName === 'string' && _queryName.length) {
  217. _query[_queryName] = _selectValue;
  218. } else if (typeof _selectName === 'string' && _selectName.length) {
  219. _query[_selectName] = _selectValue;
  220. };
  221. };
  222. };
  223. $.getJSON(_dataUrl, _query, function(json) {
  224. _selectData = cxSelect.getData(json, _jsonSpace);
  225. cxSelect.buildOption.call(self, index, _selectData);
  226. });
  227. // 使用整合数据
  228. } else if (self.settings.data && typeof self.settings.data === 'object') {
  229. _selectData = self.settings.data;
  230. for (var i = 0; i < index; i++) {
  231. _valueIndex = cxSelect.getIndex(self.selectArray[i][0].selectedIndex, typeof self.selectArray[i].data('required') === 'boolean' ? self.selectArray[i].data('required') : self.settings.required);
  232. if (typeof _selectData[_valueIndex] === 'object' && $.isArray(_selectData[_valueIndex][self.settings.jsonSub]) && _selectData[_valueIndex][self.settings.jsonSub].length) {
  233. _selectData = _selectData[_valueIndex][self.settings.jsonSub];
  234. } else {
  235. _selectData = null;
  236. break;
  237. };
  238. };
  239. cxSelect.buildOption.call(self, index, _selectData);
  240. };
  241. };
  242. // 构建选项列表
  243. cxSelect.buildOption = function(index, data) {
  244. var self = this;
  245. var _select = self.selectArray[index];
  246. var _required = typeof _select.data('required') === 'boolean' ? _select.data('required') : self.settings.required;
  247. var _firstTitle = typeof _select.data('firstTitle') === 'undefined' ? self.settings.firstTitle : _select.data('firstTitle');
  248. var _firstValue = typeof _select.data('firstValue') === 'undefined' ? self.settings.firstValue : _select.data('firstValue');
  249. var _jsonName = typeof _select.data('jsonName') === 'undefined' ? self.settings.jsonName : _select.data('jsonName');
  250. var _jsonValue = typeof _select.data('jsonValue') === 'undefined' ? self.settings.jsonValue : _select.data('jsonValue');
  251. if (!$.isArray(data)) {return};
  252. var _html = !_required ? '<option value="' + String(_firstValue) + '">' + String(_firstTitle) + '</option>' : '';
  253. // 区分标题、值的数据
  254. if (typeof _jsonName === 'string' && _jsonName.length) {
  255. // 无值字段时使用标题作为值
  256. if (typeof _jsonValue !== 'string' || !_jsonValue.length) {
  257. _jsonValue = _jsonName;
  258. };
  259. for (var i = 0, l = data.length; i < l; i++) {
  260. _html += '<option value="' + String(data[i][_jsonValue]) + '">' + String(data[i][_jsonName]) + '</option>';
  261. };
  262. // 数组即为值的数据
  263. } else {
  264. for (var i = 0, l = data.length; i < l; i++) {
  265. _html += '<option value="' + String(data[i]) + '">' + String(data[i]) + '</option>';
  266. };
  267. };
  268. _select.html(_html).prop('disabled', false).css({
  269. 'display': '',
  270. 'visibility': ''
  271. });
  272. // 初次加载设置默认值
  273. if (typeof _select.attr('data-value') === 'string') {
  274. _select.val(String(_select.attr('data-value'))).removeAttr('data-value');
  275. if (_select[0].selectedIndex < 0) {
  276. _select[0].options[0].selected = true;
  277. };
  278. };
  279. if (_required || _select[0].selectedIndex > 0) {
  280. _select.trigger('change');
  281. };
  282. };
  283. // 改变选择时的处理
  284. cxSelect.selectChange = function(name) {
  285. var self = this;
  286. if (typeof name !== 'string' || !name.length) {return};
  287. var index;
  288. name = name.replace(/\s+/g, ',');
  289. name = ',' + name + ',';
  290. // 获取当前 select 位置
  291. for (var i = 0, l = self.selectArray.length; i < l; i++) {
  292. if (name.indexOf(',' + self.settings.selects[i] + ',') > -1) {
  293. index = i;
  294. break;
  295. };
  296. };
  297. if (typeof index === 'number' && index > -1) {
  298. index += 1;
  299. cxSelect.getOptionData.call(self, index);
  300. };
  301. };
  302. $.cxSelect = function() {
  303. return cxSelect.apply(this, arguments);
  304. };
  305. // 默认值
  306. $.cxSelect.defaults = {
  307. selects: [], // 下拉选框组
  308. url: null, // 列表数据文件路径(URL)或数组数据
  309. data: null, // 自定义数据
  310. emptyStyle: null, // 无数据状态显示方式
  311. required: false, // 是否为必选
  312. firstTitle: '请选择', // 第一个选项的标题
  313. firstValue: '', // 第一个选项的值
  314. jsonSpace: '', // 数据命名空间
  315. jsonName: 'n', // 数据标题字段名称
  316. jsonValue: '', // 数据值字段名称
  317. jsonSub: 's' // 子集数据字段名称
  318. };
  319. $.fn.cxSelect = function(settings, callback) {
  320. this.each(function(i) {
  321. $.cxSelect(this, settings, callback);
  322. });
  323. return this;
  324. };
  325. }));